Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
// ConversionTools.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.
#include "stdafx.h"
#include "ConversionTools.h"
#include "MarkedList.h"
#include "HEllipse.h"
#include "HSpline.h"
#include "Wire.h"
#include "Face.h"
#include "Edge.h"
#include "Shape.h"
#include "strconv.h"
#include "Curve.h"
#include "ShapeBuild_ReShape.hxx"
#include <sstream>
#include <vector>
#include <algorithm>
#include <functional>
static gp_Pnt GetStart(const TopoDS_Edge &edge)
{
BRepAdaptor_Curve curve(edge);
double uStart = curve.FirstParameter();
gp_Pnt PS;
gp_Vec VS;
curve.D1(uStart, PS, VS);
return(PS);
}
static gp_Pnt GetEnd(const TopoDS_Edge &edge)
{
BRepAdaptor_Curve curve(edge);
double uEnd = curve.LastParameter();
gp_Pnt PE;
gp_Vec VE;
curve.D1(uEnd, PE, VE);
return(PE);
}
struct EdgeComparison : public std::binary_function<const TopoDS_Edge &, const TopoDS_Edge &, bool >
{
EdgeComparison( const TopoDS_Edge & edge )
{
m_reference_edge = edge;
}
bool operator()( const TopoDS_Edge & lhs, const TopoDS_Edge & rhs ) const
{
std::vector<double> lhs_distances;
lhs_distances.push_back( GetStart(m_reference_edge).Distance( GetStart(lhs) ) );
lhs_distances.push_back( GetStart(m_reference_edge).Distance( GetEnd(lhs) ) );
lhs_distances.push_back( GetEnd(m_reference_edge).Distance( GetStart(lhs) ) );
lhs_distances.push_back( GetEnd(m_reference_edge).Distance( GetEnd(lhs) ) );
std::sort(lhs_distances.begin(), lhs_distances.end());
std::vector<double> rhs_distances;
rhs_distances.push_back( GetStart(m_reference_edge).Distance( GetStart(rhs) ) );
rhs_distances.push_back( GetStart(m_reference_edge).Distance( GetEnd(rhs) ) );
rhs_distances.push_back( GetEnd(m_reference_edge).Distance( GetStart(rhs) ) );
rhs_distances.push_back( GetEnd(m_reference_edge).Distance( GetEnd(rhs) ) );
std::sort(rhs_distances.begin(), rhs_distances.end());
return(*(lhs_distances.begin()) < *(rhs_distances.begin()));
}
TopoDS_Edge m_reference_edge;
};
void SortEdges( std::vector<TopoDS_Edge> & edges )
{
for (std::vector<TopoDS_Edge>::iterator l_itEdge = edges.begin(); l_itEdge != edges.end(); l_itEdge++)
{
// We've already begun. Just sort based on the previous point's location.
std::vector<TopoDS_Edge>::iterator l_itNextEdge = l_itEdge;
l_itNextEdge++;
if (l_itNextEdge != edges.end())
{
EdgeComparison compare( *l_itEdge );
std::sort( l_itNextEdge, edges.end(), compare );
} // End if - then
} // End for
} // End SortEdges() method
static gp_Circ HArcGetCircle(HeeksObj* object)
{
Point3d c, a;
object->GetCentrePoint(c);
object->GetAxis(a);
gp_Ax2 axis(P2G(c), P2D(a));
double r;
object->GetRadius(r);
return gp_Circ(axis, r);
}
bool ConvertLineArcsToWire2(const std::list<HeeksObj *> &list, TopoDS_Wire &wire)
{
std::vector<TopoDS_Edge> edges;
std::list<HeeksObj*> list2;
std::list<HeeksObj*>::const_iterator It;
for(It = list.begin(); It != list.end(); It++){
HeeksObj* object = *It;
if(object->GetType() == SketchType){
for(HeeksObj* child = object->GetFirstChild(); child; child = object->GetNextChild())
{
list2.push_back(child);
}
}
else{
list2.push_back(object);
}
}
for(std::list<HeeksObj*>::iterator It = list2.begin(); It != list2.end(); It++){
HeeksObj* object = *It;
int t = object->GetType();
if (t == LineType)
{
Point3d s, e;
object->GetStartPoint(s);
object->GetEndPoint(e);
edges.push_back(BRepBuilderAPI_MakeEdge(P2G(s), P2G(e)));
}
else if (t == ArcType)
{
Point3d s, e, c, a;
object->GetStartPoint(s);
object->GetEndPoint(e);
edges.push_back(BRepBuilderAPI_MakeEdge(HArcGetCircle(object), P2G(s), P2G(e)));
}
else if (t == HSpline::m_type)
{
HSpline* spline = (HSpline*)object;
edges.push_back(BRepBuilderAPI_MakeEdge(spline->m_spline));
}
}
if(edges.size() > 0){
wire = EdgesToWire(edges);
return true;
}
return false;
}
bool ConvertSketchToEdges(HeeksObj *object, std::list< std::vector<TopoDS_Edge> > &edges)
{
std::list<HeeksObj*> line_arc_list;
if(object->GetType() == SketchType)
{
std::list<HeeksObj*> new_separate_sketches;
theApp->SketchSplit(object, new_separate_sketches);
if(new_separate_sketches.size() > 1)
{
// call again with each separate sketch
for(std::list<HeeksObj*>::iterator It = new_separate_sketches.begin(); It != new_separate_sketches.end(); It++)
{
HeeksObj* sketch = *It;
if(!ConvertSketchToEdges(sketch, edges))return false;
}
return true;
}
else
{
for(HeeksObj* child = object->GetFirstChild(); child; child = object->GetNextChild())
{
line_arc_list.push_back(child);
}
std::vector<TopoDS_Edge> empty_list;
edges.push_back(empty_list);
}
}
else
{
line_arc_list.push_back(object);
}
if(edges.size() == 0)
{
std::vector<TopoDS_Edge> empty_list;
edges.push_back(empty_list);
}
const double max_tolerance = 10.0;
for(std::list<HeeksObj*>::const_iterator It = line_arc_list.begin(); It != line_arc_list.end(); It++){
try {
HeeksObj* object = *It;
if (object->GetType() == LineType){
bool done = false;
double tolerance = TOLERANCE;
while ((!done) && (tolerance < max_tolerance))
{
Point3d s, e;
object->GetStartPoint(s);
object->GetEndPoint(e);
if (!(s == e))
{
BRep_Builder aBuilder;
TopoDS_Vertex start, end;
aBuilder.MakeVertex(start, P2G(s), TOLERANCE);
start.Orientation(TopAbs_REVERSED);
aBuilder.MakeVertex(end, P2G(e), TOLERANCE);
end.Orientation(TopAbs_FORWARD);
BRepBuilderAPI_MakeEdge edge(start, end);
if (!edge.IsDone())
{ // return(false);
tolerance *= 10.0;
}
else
{
edges.back().push_back(edge.Edge());
done = true;
}
}
else
{
break;
}
if (!done)
{
return(false);
}
} // End while
}
else if (object->GetType() == ArcType)
{
bool done = false;
double tolerance = TOLERANCE;
while ((!done) && (tolerance < max_tolerance))
{
Point3d s, e;
object->GetStartPoint(s);
object->GetEndPoint(e);
BRep_Builder aBuilder;
TopoDS_Vertex start, end;
aBuilder.MakeVertex(start, P2G(s), TOLERANCE);
start.Orientation(TopAbs_REVERSED);
aBuilder.MakeVertex(end, P2G(e), TOLERANCE);
end.Orientation(TopAbs_FORWARD);
BRepBuilderAPI_MakeEdge edge(HArcGetCircle(object), start, end);
if (!edge.IsDone())
{
// return(false);
tolerance *= 10.0;
}
else
{
edges.back().push_back(edge.Edge());
done = true;
}
} // End while
if (!done)
{
return(false);
}
}
else if (object->GetType() == CircleType)
{
edges.back().push_back(BRepBuilderAPI_MakeEdge(HArcGetCircle(object)));
}
else if (object->GetType() == HEllipse::m_type)
{
HEllipse* ellipse = (HEllipse*)object;
edges.back().push_back(BRepBuilderAPI_MakeEdge(ellipse->GetEllipse()));
}
else if (object->GetType() == HSpline::m_type)
{
HSpline* spline = (HSpline*)object;
edges.back().push_back(BRepBuilderAPI_MakeEdge(spline->m_spline));
}
else
{
std::wstring message;
message.append(L"Cannot convert object type ");
message.append(object->GetTypeString());
message.append(L" to edge");
theApp->DoMessageBox(message.c_str());
return(false);
}
} // End try
catch(Standard_Failure)
{
Handle_Standard_Failure e = Standard_Failure::Caught();
theApp->DoMessageBox((std::wstring(L"Error converting sketch to face: ") + Ctt(e->GetMessageString())).c_str());
return false;
}
}
return(true);
}
TopoDS_Wire EdgesToWire(const std::vector<TopoDS_Edge> &edges)
{
BRepBuilderAPI_MakeWire wire_maker;
for(std::vector<TopoDS_Edge>::const_iterator It = edges.begin(); It != edges.end(); It++)
{
const TopoDS_Edge &edge = *It;
wire_maker.Add(edge);
}
return wire_maker.Wire();
}
bool SketchToWires(HeeksObj* sketch, std::list<TopoDS_Wire> &wire_list)
{
std::list< std::vector<TopoDS_Edge> > edges_list;
if (!ConvertSketchToEdges(sketch, edges_list))
return false;
for(std::list< std::vector<TopoDS_Edge> >::iterator It = edges_list.begin(); It != edges_list.end(); It++)
{
std::vector<TopoDS_Edge> &edges = *It;
wire_list.push_back(EdgesToWire(edges));
}
return true;
}
bool ConvertEdgesToFaceOrWire(const std::vector<TopoDS_Edge> &edges, std::list<TopoDS_Shape> &face_or_wire, bool face_not_wire)
{
// It's not enough to add the edges to the wire in an arbitrary order. If the adjacent edges
// don't connect then the wire ends up losing one of the edges. We must sort the edge objects
// so that they're connected (or best we can) before constructing the TopoDS_Wire object from
// them.
// So, please call SortEdges before getting to here.
try
{
TopoDS_Wire wire = EdgesToWire(edges);
if(face_not_wire)
{
BRepBuilderAPI_MakeFace make_face(wire);
if(make_face.IsDone() == Standard_False)face_or_wire.push_back(wire);
else face_or_wire.push_back(make_face.Face());
}
else
{
face_or_wire.push_back(wire);
}
}
catch (Standard_Failure) {
Handle_Standard_Failure e = Standard_Failure::Caught();
std::wstring message(L"Error converting sketch to face: ");
message.append(Ctt(e->GetMessageString()));
theApp->DoMessageBox(message.c_str());
return false;
}
catch(...)
{
theApp->DoMessageBox(L"Fatal Error converting sketch to face");
return false;
}
return true;
}
bool ConvertSketchToFaceOrWire(HeeksObj* object, std::list<TopoDS_Shape> &face_or_wire, bool face_not_wire)
{
std::list< std::vector<TopoDS_Edge> > edges;
if (! ConvertSketchToEdges(object, edges))
{
return(false);
}
for(std::list< std::vector<TopoDS_Edge> >::iterator It = edges.begin(); It != edges.end(); It++)
{
std::vector<TopoDS_Edge> &list = *It;
if(list.size() > 0)
{
SortEdges(list);
if(!ConvertEdgesToFaceOrWire(list, face_or_wire, face_not_wire))return false;
}
}
return true;
}
void SketchToFace()
{
std::list< std::vector<TopoDS_Edge> > individual_edges;
std::list<HeeksObj*> objects;
theApp->GetSelection(objects);
std::list<HeeksObj*>::const_iterator It;
for (std::list<HeeksObj*>::iterator It = objects.begin(); It != objects.end(); It++){
HeeksObj* object = *It;
int t = object->GetType();
if (t == SketchType)
{
std::list<TopoDS_Shape> faces;
if (ConvertSketchToFaceOrWire(object, faces, true))
{
for (std::list<TopoDS_Shape>::iterator It2 = faces.begin(); It2 != faces.end(); It2++)
{
TopoDS_Shape& face = *It2;
theApp->AddUndoably(new CFace(TopoDS::Face(face)), NULL, NULL);
}
}
}
if (t == LineType || t == ArcType || t == CircleType || t == HEllipse::m_type || t == HSpline::m_type)
{
if (!ConvertSketchToEdges(object, individual_edges))return;
}
}
for (std::list< std::vector<TopoDS_Edge> >::iterator It = individual_edges.begin(); It != individual_edges.end(); It++)
{
std::vector<TopoDS_Edge> &edges = *It;
if (edges.size() > 0)
{
SortEdges(edges);
std::list<TopoDS_Shape> faces;
if (ConvertEdgesToFaceOrWire(edges, faces, true))
{
for (std::list<TopoDS_Shape>::iterator It2 = faces.begin(); It2 != faces.end(); It2++)
{
TopoDS_Shape& face = *It2;
theApp->AddUndoably(new CFace(TopoDS::Face(face)), NULL, NULL);
}
}
}
}
}
bool ConvertFaceToSketch2(const TopoDS_Face& face, HeeksObj* sketch, double deviation)
{
// given a face, this adds lines and arcs to the given sketch
// loop through all the loops
TopoDS_Wire outerWire=BRepTools::OuterWire(face);
for (TopExp_Explorer expWire(face, TopAbs_WIRE); expWire.More(); expWire.Next())
{
const TopoDS_Shape &W = expWire.Current();
for(BRepTools_WireExplorer expEdge(TopoDS::Wire(W)); expEdge.More(); expEdge.Next())
{
const TopoDS_Shape &E = expEdge.Current();
if(!ConvertEdgeToSketch2(TopoDS::Edge(E), sketch, deviation))return false;
}
}
return true; // success
}
void ChangeFaceRadius(const TopoDS_Face& face, double new_radius)
{
TopoDS_Shape cmpnd; // already exists
TopoDS_Shape theNewFace = face.Complemented();
Handle_ShapeBuild_ReShape rebuild = new ShapeBuild_ReShape;
// remove it: rebuild->Remove(theOldFace);
// or replace it:
rebuild->Replace(face, theNewFace, Standard_False);
TopoDS_Shape shcmpnd = rebuild->Apply(cmpnd, TopAbs_SHAPE, 1);
}
bool ConvertWireToSketch(const TopoDS_Wire& wire, HeeksObj* sketch, double deviation)
{
const TopoDS_Shape &W = wire;
for(BRepTools_WireExplorer expEdge(TopoDS::Wire(W)); expEdge.More(); expEdge.Next())
{
const TopoDS_Shape &E = expEdge.Current();
if(!ConvertEdgeToSketch2(TopoDS::Edge(E), sketch, deviation))return false;
}
return true; // success
}
static void AddLineOrArcToSketch(HeeksObj* sketch, HeeksObj* line_or_arc)
{
Point3d sketch_end;
if (sketch->GetEndPoint(sketch_end))
{
Point3d start;
if (line_or_arc->GetStartPoint(start))
{
if (start.Dist(sketch_end) <= 0.001)
{
line_or_arc->SetStartPoint(sketch_end);
}
}
}
sketch->Add(line_or_arc, NULL);
}
bool ConvertEdgeToSketch2(const TopoDS_Edge& edge, HeeksObj* sketch, double deviation, bool reverse)
{
// enum GeomAbs_CurveType
// 0 - GeomAbs_Line
// 1 - GeomAbs_Circle
// 2 - GeomAbs_Ellipse
// 3 - GeomAbs_Hyperbola
// 4 - GeomAbs_Parabola
// 5 - GeomAbs_BezierCurve
// 6 - GeomAbs_BSplineCurve
// 7 - GeomAbs_OtherCurve
BRepAdaptor_Curve curve(edge);
GeomAbs_CurveType curve_type = curve.GetType();
bool sense = (edge.Orientation() == TopAbs_FORWARD);
if(reverse)sense = !sense;
switch(curve_type)
{
case GeomAbs_Line:
// make a line
{
double uStart = curve.FirstParameter();
double uEnd = curve.LastParameter();
gp_Pnt PS;
gp_Vec VS;
curve.D1(uStart, PS, VS);
gp_Pnt PE;
gp_Vec VE;
curve.D1(uEnd, PE, VE);
HeeksObj* new_object = theApp->CreateNewLine(G2P(sense ? PS : PE), G2P(sense ? PE : PS));
AddLineOrArcToSketch(sketch, new_object);
}
break;
case GeomAbs_Circle:
// make an arc
{
double uStart = curve.FirstParameter();
double uEnd = curve.LastParameter();
gp_Pnt PS;
gp_Vec VS;
curve.D1(uStart, PS, VS);
gp_Pnt PE;
gp_Vec VE;
curve.D1(uEnd, PE, VE);
gp_Circ circle = curve.Circle();
gp_Ax1 axis = circle.Axis();
if(!sense)
{
axis.SetDirection(-axis.Direction());
circle.SetAxis(axis);
}
if(curve.IsPeriodic())
{
double period = curve.Period();
double uHalf = uStart + period/2;
gp_Pnt PH;
gp_Vec VH;
curve.D1(uHalf, PH, VH);
{
HeeksObj* new_object = theApp->CreateNewArc(G2P(PS), G2P(PH), D2P(circle.Axis().Direction()), G2P(circle.Location()));
AddLineOrArcToSketch(sketch, new_object);
}
{
HeeksObj* new_object = theApp->CreateNewArc(G2P(PH), G2P(PE), D2P(circle.Axis().Direction()), G2P(circle.Location()));
AddLineOrArcToSketch(sketch, new_object);
}
}
else
{
HeeksObj* new_object = theApp->CreateNewArc(G2P(sense ? PS : PE), G2P(sense ? PE : PS), D2P(circle.Axis().Direction()), G2P(circle.Location()));
AddLineOrArcToSketch(sketch, new_object);
}
}
break;
case GeomAbs_BSplineCurve:
{
std::list<HeeksObj*> new_spans;
#if 0
// to do
HSpline::ToBiarcs(curve.BSpline(), new_spans, deviation, curve.FirstParameter(), curve.LastParameter());
#endif
if(sense)
{
for(std::list<HeeksObj*>::iterator It = new_spans.begin(); It != new_spans.end(); It++)
AddLineOrArcToSketch(sketch, *It);
}
else
{
for(std::list<HeeksObj*>::reverse_iterator It = new_spans.rbegin(); It != new_spans.rend(); It++)
{
HeeksObj* object = *It;
object->Reverse();
AddLineOrArcToSketch(sketch, object);
}
}
}
break;
default:
{
// make lots of small lines
BRepTools::Clean(edge);
BRepMesh_IncrementalMesh(edge, deviation);
TopLoc_Location L;
Handle(Poly_Polygon3D) Polyg = BRep_Tool::Polygon3D(edge, L);
if (!Polyg.IsNull()) {
const TColgp_Array1OfPnt& Points = Polyg->Nodes();
Standard_Integer po;
gp_Pnt prev_p;
int i = 0;
for (po = sense ? Points.Lower():Points.Upper(); (sense && (po <= Points.Upper())) || (!sense && (po >= Points.Lower())); i++) {
gp_Pnt p = (Points.Value(po)).Transformed(L);
if(i != 0)
{
HeeksObj* new_object = theApp->CreateNewLine(G2P(prev_p), G2P(p));
AddLineOrArcToSketch(sketch, new_object);
}
prev_p = p;
if(sense)po++;
else po--;
}
}
}
break;
}
return true;
}
static void AddLineOrArc(HeeksObj* sketch, Span &span)
{
if(span.m_v.m_type == 0)
{
HeeksObj* new_object = theApp->CreateNewLine(Point3d(span.m_p.x, span.m_p.y, 0), Point3d(span.m_v.m_p.x, span.m_v.m_p.y, 0));
AddLineOrArcToSketch(sketch, new_object);
}
else
{
Point3d axis = (span.m_v.m_type > 0) ? Point3d(0, 0, 1) : Point3d(0, 0, -1);
Point3d c(span.m_v.m_c);
HeeksObj* new_object = theApp->CreateNewArc(Point3d(span.m_p.x, span.m_p.y, 0), Point3d(span.m_v.m_p.x, span.m_v.m_p.y, 0), axis, c);
AddLineOrArcToSketch(sketch, new_object);
}
}
c5721c306This file is pinned to the selected release. Download the original to open it in your design tool.