I see there is no easy way to modify the whole shape and I am new to occ and could not understand your solution there. So I want to ask same but a bit more specific question. If I have only an edge and when I apply transform one of its vertices, how can I update the edge accordingly?
Thanks
I have a compound that has an edge in it and here is my algorithm that does not work:
I have oldCompound, oldEdge, oldVertex..
- Use BRepBuilderAPI_Transform to get newVertex from oldVertex
- Use BRepTools_ReShape :: Replace ( oldVertex, newVertex )
- Use BRepTools_ReShape :: Apply ( oldEdge ) to get newEdge
- Use BRepTools_ReShape :: Replace ( oldEdge, newEdge )
- Use BRepTools_ReShape :: Apply ( oldCompund ) to get newCompound
When I apply these , it only modifies the vertex
Thanks again
Maili,
Please explain in more details what you intend to achieve. If let's say you have a standalone vertical edge from vertex v1 (0,0,0) to v2 (0,0,1) lying on a 3D line and want the edge to become horizontal (from v1 to v2'(1,0,0)) then you can just use BRepBuilderAPI_Transform. No ReShape is necessary.
But if you have a box of side size 1 and want to move one of its vertex (say (0,0,0)) to some other point (say (-1,-1,-1)) and expect all the edges to connect it, this is wrong expectation. You have to do math on your own. This is also possible but is totally different concept.
Aren't both the same? Moving a vertex resulting its ancestors to be modified. I have an edge as in your first example but the only difference is that it is a subshape of a compound (I have just added the edge to a compound and compound has no other subshapes).
I have also tried it using only edge (without compound)--with/without ReShape and still no difference.
Dear Roman
It is first time to write to you, i am trying to subtract a series of solids stored in HSequenceOfShape from one big box.
It works fine for individual subtraction of one solid from the box but if i am trying to get the box after subtraction and try to subtract the second solid or third or ...., it crashes. Do you have any explaination for this case. How can i set the solid data correctly to do this operation. Boolean operation are working well as i do believe but i may have some wrong procedure.
Best
- Use BRepBuilderAPI_Transform to get newVertex from oldVertex
- Use BRepTools_ReShape :: Replace ( oldVertex, newVertex )
- Use BRepTools_ReShape :: Apply ( oldCompund ) to get newCompound
I suffered a lot trying to get that kind of replacements right. It took me some months, actually. You've put yourself into a task which is not easy for an OCC noob, and I can tell. I can also tell it's doable, just not the easiest way to get started with OCC.
I also tried this but same result, vertex moves but edge remains same. I was thinking to find all ancestors of vertex and replace them if this algorithm had worked but now I can't even handle a simple edge.
Thanks for reply
The problem might be that the curves and surfaces are not recomputed. Actually, I didn't play much with BRepTools_ReShape.
It's possible to write an algorithm that replaces and recomputes when necessary, but it's easier to write an algorithm that builds a copy of the shape with the replacements you want. If you have a well defined hierarchy, it becomes easier (for example, Compounds always contain CompSolids).
I wrote both algorithms with the condition that all faces are planar. Because of the application I'm developing I can make some assumptions, which ease the whole thing. I developed that code as part of my work, so I can't publish it.
Try writing an algorithm that duplicates your shape while making replacements. You start with your shape, then explore subshapes, then the subshapes of the subshapes and so on. You will end up with vertices in the deepest exploration. If you need to replace a vertex, you'll be able to take the decision right there. From the two newly copied vertices you create the edge, from the edges the wires and so on. Keep in mind shape orientation and normal of faces.
Let's take an edge for example. The most basic curve for an edge is a line that goes from point p1 to point p2 (each point represented by a vertex). If you translate any or both of those points, the line changes. OCC has an internal representation of that curve that won't get updated automatically if you just replace vertices and don't rebuild the edge, or force an update of it. In a similar way, faces have surfaces "attached" to it, the most basic one being a plane that contains all edges (and therefore all vertices) of its wires. If you translate a vertex, the new vertex may not even be contained in the previous surface. Also, curves and surfaces have boundaries, which change if you translate things here and there.
If you really want to check that, delve into BRepBuilderAPI_Make[Edge/Face], and check also BRep_Builder::Update*.
It's just easier to create a copy with all replacements you need, and let BRepBuilderAPI_Make* take care of everything.
below you will find a code sample reshaping a vertex provided that it is a single one or it belongs to a line.
I must say I was kind of "inspired" with Paul's fight with reshaping last year and so decided to try myself ;)
However, if you want to reshape faces (or even more complex curves) you will have to extend the code.
///
/// Sets the coordinates of the vertex.
///
/// The array containing the coordinates of the vertex.
void VertexProperty::Coordinates::set(array ^ value)
{
int i = 0;
TopoDS_Vertex vertex;
vertex = TopoDS::Vertex(theShapeMap->FindKey(objectIdentifier));
//=================================acquire entity
gp_Pnt point = BRep_Tool::Pnt(vertex);
//================== Check whether the vertex is shared by another entities
// if so and the other entities are linear edges
// add them to the 'update map of shapes'
ArrayList ^idList = gcnew ArrayList();
doc->GetDocumentEntities(idList);
///
/// Updates a single-vertex-shape.
///
/// The GeoEntity with the vertex to change.
/// The changed vertex.
void VertexProperty::UpdateVertex(GeoEntity * gE, TopoDS_Vertex & vertex)
{
Handle(ShapeBuild_ReShape) reshaper = new ShapeBuild_ReShape;
TopoDS_Vertex vertexToChange = TopoDS::Vertex(gE->GetTopoShape());
///
/// Updates all linear edges of the given shape
/// containing the vertex whose coordinates change.
///
/// The GeoEntity with the edge(s) to change.
/// The changed vertex.
void VertexProperty::UpdateEdge(GeoEntity * gE, TopoDS_Vertex & vertex)
{
TopoDS_Vertex first, last, unchangedVertex;
TopTools_IndexedMapOfShape edgesMap;
TopExp::MapShapes(gE->GetTopoShape(), TopAbs_EDGE, edgesMap);
Handle(ShapeBuild_ReShape) reshaper = new ShapeBuild_ReShape;
int edgesUpdates = 0;
///
/// Checks if an update/change of the given vertex is possible.
///
/// The shape with the vertex to change.
/// The changed vertex.
/// The new coordinates of the vertex.
/// If the shape is a 'VERTEX' or a linear 'EDGE'
/// and the change of the vertex coordinates does not
/// lead to reducing the the edge into a point
/// the method returns true. Otherwise false.
bool VertexProperty::CheckShapeToUpdateVertexOf(TopoDS_Shape & shape, TopoDS_Vertex & vertex, array ^ value)
{
if(shape.ShapeType() == TopAbs_VERTEX)
{
return true;
}
if(shape.ShapeType() != TopAbs_EDGE)
{
TraceWarning(" VertexProperty Warning. Only edges can be modified.");
return false;
}
Standard_Real f, l; //first and last parameter
Handle_Geom_Curve curve = BRep_Tool::Curve(TopoDS::Edge(shape), f, l);
if(GeomAdaptor_Curve(curve).GetType() != GeomAbs_Line)
{
TraceWarning(" VertexProperty Warning. Only linear edges can be modified.");
return false;
}
TopoDS_Vertex first, last, unchangedVertex;
TopTools_IndexedMapOfShape edgesMap;
TopExp::MapShapes(shape, TopAbs_EDGE, edgesMap);
Mon, 01/19/2009 - 16:51
You may want to check this thread: http://www.opencascade.org/org/forum/thread_14514/
ShapeBuild_ReShape may be all you need.
Mon, 01/19/2009 - 17:35
I see there is no easy way to modify the whole shape and I am new to occ and could not understand your solution there. So I want to ask same but a bit more specific question. If I have only an edge and when I apply transform one of its vertices, how can I update the edge accordingly?
Thanks
Mon, 01/19/2009 - 18:00
I have a compound that has an edge in it and here is my algorithm that does not work:
I have oldCompound, oldEdge, oldVertex..
- Use BRepBuilderAPI_Transform to get newVertex from oldVertex
- Use BRepTools_ReShape :: Replace ( oldVertex, newVertex )
- Use BRepTools_ReShape :: Apply ( oldEdge ) to get newEdge
- Use BRepTools_ReShape :: Replace ( oldEdge, newEdge )
- Use BRepTools_ReShape :: Apply ( oldCompund ) to get newCompound
When I apply these , it only modifies the vertex
Thanks again
Mon, 01/19/2009 - 18:05
offtopic: i had created new account when i thought i forgot the login name but then I found it so please dont let nick names confuse you
Mon, 01/19/2009 - 23:12
Maili,
Please explain in more details what you intend to achieve. If let's say you have a standalone vertical edge from vertex v1 (0,0,0) to v2 (0,0,1) lying on a 3D line and want the edge to become horizontal (from v1 to v2'(1,0,0)) then you can just use BRepBuilderAPI_Transform. No ReShape is necessary.
But if you have a box of side size 1 and want to move one of its vertex (say (0,0,0)) to some other point (say (-1,-1,-1)) and expect all the edges to connect it, this is wrong expectation. You have to do math on your own. This is also possible but is totally different concept.
Roman
---
opencascade.blogspot.com - blog on Open CASCADE
Join the Open CASCADE Group at LinkedIn
Tue, 01/20/2009 - 10:56
Aren't both the same? Moving a vertex resulting its ancestors to be modified. I have an edge as in your first example but the only difference is that it is a subshape of a compound (I have just added the edge to a compound and compound has no other subshapes).
I have also tried it using only edge (without compound)--with/without ReShape and still no difference.
Tue, 01/20/2009 - 11:06
My code is simply like this:
gp_Pnt pnt1(0,0,0);
gp_Pnt pnt2(0,0,300);
TopoDS_Edge aEdge = BRepBuilderAPI_MakeEdge(pnt1,pnt2);
TopoDS_Vertex aLastVertex = TopExp::LastVertex(aEdge, false);
gp_Trsf trans;
trans.SetTranslation(gp_Pnt(0,0,0), gp_Pnt(100,100,100));
BRepBuilder_Transform brepTrans(aLastVertex,trans);
TopoDS_Shape resultVert = brepTrans.Shape();
BRepTools_ReShape reshaper;
reshaper.Replace(aLastVertex, TopoDS::Vertex(resultVert));
TopoDS_Shape result = reshaper.Apply(aEdge);
Handle(AIS_Shape) aisShape = new AIS_Shape(result);
context->Display(aisShape, true);
Thanks for replies
Thu, 06/17/2010 - 08:22
Dear Roman
It is first time to write to you, i am trying to subtract a series of solids stored in HSequenceOfShape from one big box.
It works fine for individual subtraction of one solid from the box but if i am trying to get the box after subtraction and try to subtract the second solid or third or ...., it crashes. Do you have any explaination for this case. How can i set the solid data correctly to do this operation. Boolean operation are working well as i do believe but i may have some wrong procedure.
Best
Tue, 01/20/2009 - 09:43
Have you tried like this?
- Use BRepBuilderAPI_Transform to get newVertex from oldVertex
- Use BRepTools_ReShape :: Replace ( oldVertex, newVertex )
- Use BRepTools_ReShape :: Apply ( oldCompund ) to get newCompound
I suffered a lot trying to get that kind of replacements right. It took me some months, actually. You've put yourself into a task which is not easy for an OCC noob, and I can tell. I can also tell it's doable, just not the easiest way to get started with OCC.
Tue, 01/20/2009 - 10:25
I also tried this but same result, vertex moves but edge remains same. I was thinking to find all ancestors of vertex and replace them if this algorithm had worked but now I can't even handle a simple edge.
Thanks for reply
Tue, 01/20/2009 - 11:29
The problem might be that the curves and surfaces are not recomputed. Actually, I didn't play much with BRepTools_ReShape.
It's possible to write an algorithm that replaces and recomputes when necessary, but it's easier to write an algorithm that builds a copy of the shape with the replacements you want. If you have a well defined hierarchy, it becomes easier (for example, Compounds always contain CompSolids).
I wrote both algorithms with the condition that all faces are planar. Because of the application I'm developing I can make some assumptions, which ease the whole thing. I developed that code as part of my work, so I can't publish it.
Try writing an algorithm that duplicates your shape while making replacements. You start with your shape, then explore subshapes, then the subshapes of the subshapes and so on. You will end up with vertices in the deepest exploration. If you need to replace a vertex, you'll be able to take the decision right there. From the two newly copied vertices you create the edge, from the edges the wires and so on. Keep in mind shape orientation and normal of faces.
I hope you succeed.
Tue, 01/20/2009 - 15:53
Thanks for explanations, but what does "curves and surfaces are not recomputed" mean and how can I recompute them after translating the vertex?
Tue, 01/20/2009 - 16:13
Let's take an edge for example. The most basic curve for an edge is a line that goes from point p1 to point p2 (each point represented by a vertex). If you translate any or both of those points, the line changes. OCC has an internal representation of that curve that won't get updated automatically if you just replace vertices and don't rebuild the edge, or force an update of it. In a similar way, faces have surfaces "attached" to it, the most basic one being a plane that contains all edges (and therefore all vertices) of its wires. If you translate a vertex, the new vertex may not even be contained in the previous surface. Also, curves and surfaces have boundaries, which change if you translate things here and there.
If you really want to check that, delve into BRepBuilderAPI_Make[Edge/Face], and check also BRep_Builder::Update*.
It's just easier to create a copy with all replacements you need, and let BRepBuilderAPI_Make* take care of everything.
Wed, 01/21/2009 - 21:04
Hi Maili,
below you will find a code sample reshaping a vertex provided that it is a single one or it belongs to a line.
I must say I was kind of "inspired" with Paul's fight with reshaping last year and so decided to try myself ;)
However, if you want to reshape faces (or even more complex curves) you will have to extend the code.
///
/// Sets the coordinates of the vertex.
///
/// The array containing the coordinates of the vertex.
void VertexProperty::Coordinates::set(array ^ value)
{
int i = 0;
TopoDS_Vertex vertex;
vertex = TopoDS::Vertex(theShapeMap->FindKey(objectIdentifier));
//=================================acquire entity
gp_Pnt point = BRep_Tool::Pnt(vertex);
if( (value[0] != point.X()) || (value[1] != point.Y()) || (value[2] != point.Z()))
{
int nbAssemblies = doc->GetNbAssemblies();
if(nbAssemblies > 0 )
{
GeoAssembly *geoAssembly = doc->GetOCCDoc()->GetAssembly(nbAssemblies);
if(geoAssembly != NULL)
{
GeoEntity *gE = geoAssembly->GetEntityWithIdentifier(entityIdentifier);
if(gE != NULL)
{
if( ((shell::Enums::GeoEntityType)gE->GetGeoEntityType()) ==
shell::Enums::GeoEntityType::Topological)
{
CGeoEntityArray *geoEntities = new CGeoEntityArray;
//================== Check whether the vertex is shared by another entities
// if so and the other entities are linear edges
// add them to the 'update map of shapes'
ArrayList ^idList = gcnew ArrayList();
doc->GetDocumentEntities(idList);
for(i = 0; i < idList->Count; i++)
{
GeoEntity *entity = geoAssembly->GetEntityWithIdentifier(System::Int32::Parse(idList[i]->ToString()));
if( ((shell::Enums::GeoEntityType)entity->GetGeoEntityType()) ==
shell::Enums::GeoEntityType::Topological)
{
bool vertexFound = false;
for(TopExp_Explorer Ex(entity->GetTopoShape(), TopAbs_VERTEX); Ex.More(); Ex.Next())
{
if(TopoDS::Vertex(Ex.Current()).IsEqual(vertex))
{
vertexFound = true;
break;
}
}
if(vertexFound == true)
{
if(CheckShapeToUpdateVertexOf(entity->GetTopoShape(), vertex, value) == false)
{
if(geoEntities != NULL)
{
while(geoEntities->GetUpperBound() >= 0)
{
//zero-based index
GeoEntity *gE = geoEntities->GetAt(0);
gE = NULL;
geoEntities->RemoveAt(0);
}
delete geoEntities;
geoEntities = NULL;
}
return;
}
else
geoEntities->Add(entity);
}
}
}
//==================
if(geoEntities->GetCount() > 0)
{
BRep_Builder builder;
builder.UpdateVertex(vertex, gp_Pnt(value[0], value[1], value[2]), Precision::Confusion());
for(i = 0; i < geoEntities->GetCount(); i++)
{
if(geoEntities->ElementAt(i)->GetTopoShape().ShapeType() == TopAbs_VERTEX)
{
UpdateVertex(geoEntities->ElementAt(i), vertex);
}
else
{
UpdateEdge(geoEntities->ElementAt(i), vertex);
}
}
}
if(geoEntities != NULL)
{
while(geoEntities->GetUpperBound() >= 0)
{
//zero-based index
GeoEntity *gE = geoEntities->GetAt(0);
gE = NULL;
geoEntities->RemoveAt(0);
}
delete geoEntities;
geoEntities = NULL;
}
}
}
else
{
TraceError(" VertexProperty Error. GeoEntity pointer NULL.");
}
}
else
{
TraceError(" VertexProperty Error. GeoAssembly pointer NULL.");
}
}
else
{
TraceError(" VertexProperty Error. No assemblies.");
}
}
}
///
/// Updates a single-vertex-shape.
///
/// The GeoEntity with the vertex to change.
/// The changed vertex.
void VertexProperty::UpdateVertex(GeoEntity * gE, TopoDS_Vertex & vertex)
{
Handle(ShapeBuild_ReShape) reshaper = new ShapeBuild_ReShape;
TopoDS_Vertex vertexToChange = TopoDS::Vertex(gE->GetTopoShape());
reshaper->Replace(vertexToChange, vertex);
gE->GetTopoShape() = reshaper->Apply(gE->GetTopoShape());
reshaper->Clear();
gE->SetAISShapeChanged(true);
gE->UpdateAISShape();
view->GetOCCViewer()->UpdateView();
}
///
/// Updates all linear edges of the given shape
/// containing the vertex whose coordinates change.
///
/// The GeoEntity with the edge(s) to change.
/// The changed vertex.
void VertexProperty::UpdateEdge(GeoEntity * gE, TopoDS_Vertex & vertex)
{
TopoDS_Vertex first, last, unchangedVertex;
TopTools_IndexedMapOfShape edgesMap;
TopExp::MapShapes(gE->GetTopoShape(), TopAbs_EDGE, edgesMap);
Handle(ShapeBuild_ReShape) reshaper = new ShapeBuild_ReShape;
int edgesUpdates = 0;
for(int j = 1; j <= edgesMap.Extent(); j++)
{
TopExp::Vertices( TopoDS::Edge(edgesMap(j)), first, last);
if(first.IsEqual(vertex) || last.IsEqual(vertex))
{
if(first.IsEqual(vertex))
{
unchangedVertex = last;
reshaper->Replace(edgesMap(j), BRepBuilderAPI_MakeEdge(vertex, unchangedVertex));
}
else
{
unchangedVertex = first;
reshaper->Replace(edgesMap(j), BRepBuilderAPI_MakeEdge(unchangedVertex, vertex));
}
edgesUpdates++;
}
}
TraceDebugFormattedStr(" VertexProperty. Updated edges: ", "%i", ".", edgesUpdates);
if(edgesUpdates > 0)
{
gE->GetTopoShape() = reshaper->Apply(gE->GetTopoShape());
reshaper->Clear();
ShapeFix_Shape fixer(gE->GetTopoShape());
fixer.Perform();
gE->GetTopoShape() = fixer.Shape();
gE->SetAISShapeChanged(true);
gE->UpdateAISShape();
view->GetOCCViewer()->UpdateView();
}
edgesMap.Clear();
}
///
/// Checks if an update/change of the given vertex is possible.
///
/// The shape with the vertex to change.
/// The changed vertex.
/// The new coordinates of the vertex.
/// If the shape is a 'VERTEX' or a linear 'EDGE'
/// and the change of the vertex coordinates does not
/// lead to reducing the the edge into a point
/// the method returns true. Otherwise false.
bool VertexProperty::CheckShapeToUpdateVertexOf(TopoDS_Shape & shape, TopoDS_Vertex & vertex, array ^ value)
{
if(shape.ShapeType() == TopAbs_VERTEX)
{
return true;
}
if(shape.ShapeType() != TopAbs_EDGE)
{
TraceWarning(" VertexProperty Warning. Only edges can be modified.");
return false;
}
Standard_Real f, l; //first and last parameter
Handle_Geom_Curve curve = BRep_Tool::Curve(TopoDS::Edge(shape), f, l);
if(GeomAdaptor_Curve(curve).GetType() != GeomAbs_Line)
{
TraceWarning(" VertexProperty Warning. Only linear edges can be modified.");
return false;
}
TopoDS_Vertex first, last, unchangedVertex;
TopTools_IndexedMapOfShape edgesMap;
TopExp::MapShapes(shape, TopAbs_EDGE, edgesMap);
gp_Pnt changedPoint = BRep_Tool::Pnt(vertex);
for(int j = 1; j <= edgesMap.Extent(); j++)
{
TopExp::Vertices( TopoDS::Edge(edgesMap(j)), first, last);
if(first.IsEqual(vertex) || last.IsEqual(vertex))
{
if(first.IsEqual(vertex))
{
unchangedVertex = last;
}
else
{
unchangedVertex = first;
}
gp_Pnt unchangedPoint = BRep_Tool::Pnt(unchangedVertex);
if(unchangedPoint.IsEqual(gp_Pnt(value[0], value[1], value[2]), Precision::Confusion()) == Standard_True)
{
TraceWarning(" VertexProperty Warning. Vertices would be the same.");
return false;
}
}
}
return true;
}