Hi, here is a quick tip for you to learn:
- what is topology
- how to make use of it within Visualize
- some ideas to go beyond
Topology:
In CAD, topology represents structure of a solid and relationship between faces and edges. The key element here is that an edge can be shared amongst multiple faces. This is different from the tessellation edges and we can leverage it.
Use topology to select neighbours of a face
We will customize the default selection operator that we provide with the mfcsandbox project.
- Let’s update the mouse event to make use of our future fonctions.
- Let’s output the hierarchy with Components to verify we have the right information.
void SandboxHighlightOperator::DebugComponentHierarchy()
- Let’s list the neighbours of a face.
HPS::ComponentArray SandboxHighlightOperator::GetNeighbours(HPS::Component a_face)
- Let’s update the display to also highlight the neighbour faces.
void SandboxHighlightOperator::ShowNeighbours()
Preparation:
//! [OnMouseDown]
bool SandboxHighlightOperator::OnMouseDown(
HPS::MouseState const & in_state)
{
auto sel_opts = GetSelectionOptions();
sel_opts.SetLevel(SandboxHighlightOperator::SelectionLevel);
SetSelectionOptions(sel_opts);
if (IsMouseTriggered(in_state) && HPS::SelectOperator::OnMouseDown(in_state))
{
HighlightCommon();
DebugComponentHierarchy();
ShowNeighbours();
return true;
}
return false;
}
First, we will output a little bit of code to get type of the component and go up the hierarchy. You can then set appropriate breakpoint and select an edge and see the output like below
// Used to output the structure of Components when imported via Exchange.
void SandboxHighlightOperator::DebugComponentHierarchy()
{
// we will use this and select an edge to display the hierarchy
// Typical output in debugger console if you output "type" value in the debugger:
/* ExchangeTopoEdge(20487)
ExchangeTopoCoEdge(20486)
ExchangeTopoLoop(20485)
ExchangeTopoFace(20484)
ExchangeTopoShell(20483)
ExchangeTopoConnex(20482)
ExchangeTopoBody(20481)
ExchangeRIBRepModel(12289)
ExchangePartDefinition(4099)
ExchangeProductOccurrence(4098)*/
// Notice there are some differences with the structure from HOOPS Exchange structures.
HPS::SelectionResults selection_results = GetActiveSelection();
size_t selected_count = selection_results.GetCount();
if (selected_count > 0)
{
HPS::CADModel cad_model = cview->GetDocument()->GetCADModel();
HPS::SelectionResultsIterator it = selection_results.GetIterator();
if (it.IsValid())
{
HPS::ComponentPath component_path = cad_model.GetComponentPath(it.GetItem());
HPS::Component c = component_path.Front();
while (c.GetOwners().size() > 0)
{
auto type = c.GetComponentType();
c = c.GetOwners()[0];
}
}
}
}
Getting the list of neighbours is quite straighforward once you understand the hierarchy in place.
// Will return the adjacent faces using topology
HPS::ComponentArray SandboxHighlightOperator::GetNeighbours(HPS::Component a_face)
{
HPS::ComponentArray neighbours;
auto model = cview->GetCanvas().GetFrontView().GetAttachedModel();
HPS::Exchange::CADModel cadModel = HPS::Exchange::CADModel(model);
// Get list of edges. Edges are shared amongts adjacent faces
auto edgesArray = a_face.GetAllSubcomponents(HPS::Component::ComponentType::ExchangeTopoEdge);
for (int i = 0; i < edgesArray.size(); i++)
{
auto edge = edgesArray[i];
auto owners = edge.GetOwners();
// Recap of hierarchy: edge->coedge->loop->face
// Test if this is not an open edge (no other neihgbour for this edge)
if (owners.size() != 1)
{
for (int j = 0; j < owners.size(); j++)
{
auto coedge = owners[j];
auto loop = coedge.GetOwners()[0];
auto face = loop.GetOwners()[0];
// we don't want to add current face, so we need to test the returned face in the array.
if (!face.Equals(a_face))
{
neighbours.push_back(face);
}
}
}
}
return neighbours;
}
Here we simply show the neighbour faces with same color highlight than the current face.
// Will highlight the neighbour faces of selected elements
void SandboxHighlightOperator::ShowNeighbours()
{
HPS::Canvas canvas = cview->GetCanvas();
HPS::HighlightOptionsKit highlight_options(HPS::HighlightOptionsKit::GetDefault());
highlight_options.SetStyleName("highlight_style");
highlight_options.SetSubentityHighlighting(SelectionLevel == HPS::Selection::Level::Subentity);
highlight_options.SetOverlay(HPS::Drawing::Overlay::InPlace);
HPS::SelectionResults selection_results = GetActiveSelection();
size_t selected_count = selection_results.GetCount();
if (selected_count > 0)
{
HPS::CADModel cad_model = cview->GetDocument()->GetCADModel();
HPS::SelectionResultsIterator it = selection_results.GetIterator();
HPS::ComponentPath component_path = cad_model.GetComponentPath(it.GetItem());
if (!component_path.Empty())
{
// we check we did select a face and not an edge or something else
if (HPS::Exchange::Component::ComponentType::ExchangeTopoFace == component_path.Front().GetComponentType())
{
auto neighbours = GetNeighbours(component_path.Front());
for (int i = 0; i < neighbours.size(); i++)
{
auto face = neighbours[i];
auto keyPath = face.GetKeyPath(face);
auto facePath = cad_model.GetComponentPath(keyPath[0]);
facePath.Highlight(canvas, highlight_options);
}
canvas.Update();
}
}
}
}
You can see that now if you select a face (under cursor in orange), neighbour faces will be selected in orange.
Here is the source code if you want to quickly test it:
SandboxHighlightOp.cpp (7.3 KB)
SandboxHighlightOp.h (668 Bytes)
Go Beyond:
From there there are many things you can do:
- why not create your own rendering style to better distinguish selected face from neighbours?
- why not display edge normals for each selected face?
- why not add some clever restriction about selection (angle between faces, type of surface) to make concrete useful examples? Below I extend selection to faces that have angle less than 90 degrees.
I’m looking forward for some ideas you might have, some additional questions, please make this thread live, and let me know if these information were somehow useful and if you would like to see more topics like these on the forum.