Path.Area: support open path direction control

This commit is contained in:
Zheng, Lei
2017-04-08 12:30:59 +08:00
committed by Yorik van Havre
parent e8704891f4
commit 041c403f5d
2 changed files with 107 additions and 34 deletions

View File

@@ -434,6 +434,19 @@ void Area::addToBuild(CArea &area, const TopoDS_Shape &shape) {
}
}
static inline void getEndPoints(const TopoDS_Edge &e, gp_Pnt &p1, gp_Pnt &p2) {
p1 = BRep_Tool::Pnt(TopExp::FirstVertex(e));
p2 = BRep_Tool::Pnt(TopExp::LastVertex(e));
}
static inline void getEndPoints(const TopoDS_Wire &wire, gp_Pnt &p1, gp_Pnt &p2) {
BRepTools_WireExplorer xp(wire);
p1 = BRep_Tool::Pnt(TopoDS::Vertex(xp.CurrentVertex()));
for(;xp.More();xp.Next());
p2 = BRep_Tool::Pnt(TopoDS::Vertex(xp.CurrentVertex()));
}
struct WireJoiner {
typedef bg::model::box<gp_Pnt> Box;
@@ -453,15 +466,6 @@ struct WireJoiner {
return true;
}
static void getEndPoints(const TopoDS_Edge &e, gp_Pnt &p1, gp_Pnt &p2) {
p1 = BRep_Tool::Pnt(TopExp::FirstVertex((e)));
p2 = BRep_Tool::Pnt(TopExp::LastVertex((e)));
// TopExp_Explorer xp(e,TopAbs_VERTEX);
// p1 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current()));
// xp.Next();
// p2 = BRep_Tool::Pnt(TopoDS::Vertex(xp.Current()));
}
struct EdgeInfo {
TopoDS_Edge edge;
gp_Pnt p1;
@@ -1780,6 +1784,7 @@ struct ShapeParams {
double abscissa;
int k;
short orientation;
short direction;
#ifdef AREA_TIME_ENABLE
TIME_DURATION qd; //rtree query duration
TIME_DURATION bd; //rtree build duration
@@ -1787,8 +1792,8 @@ struct ShapeParams {
TIME_DURATION xd; //BRepExtrema_DistShapeShape duration
#endif
ShapeParams(double _a, int _k, short o)
:abscissa(_a),k(_k),orientation(o)
ShapeParams(double _a, int _k, short o, short d)
:abscissa(_a),k(_k),orientation(o),direction(d)
#ifdef AREA_TIME_ENABLE
,qd(0),bd(0),rd(0),xd(0)
#endif
@@ -1824,18 +1829,46 @@ struct GetWires {
}
TIME_INIT(t);
BRepTools_WireExplorer xp(info.wire);
if(params.abscissa<Precision::Confusion() || !info.isClosed) {
info.points.push_back(BRep_Tool::Pnt(xp.CurrentVertex()));
for(;xp.More();xp.Next());
gp_Pnt p1,p2;
getEndPoints(info.wire,p1,p2);
if(!info.isClosed && params.direction!=Area::DirectionNone) {
bool reverse = false;
switch(params.direction) {
case Area::DirectionXPositive:
reverse = p1.X()>p2.X();
break;
case Area::DirectionXNegative:
reverse = p1.X()<p2.X();
break;
case Area::DirectionYPositive:
reverse = p1.Y()>p2.Y();
break;
case Area::DirectionYNegative:
reverse = p1.Y()<p2.Y();
break;
case Area::DirectionZPositive:
reverse = p1.Z()>p2.Z();
break;
case Area::DirectionZNegative:
reverse = p1.Z()<p2.Z();
break;
}
if(reverse) {
info.wire.Reverse();
std::swap(p1,p2);
}
}
// We don't add in-between vertices of an open wire, because we
// haven't implemented open wire breaking yet.
info.points.push_back(BRep_Tool::Pnt(xp.CurrentVertex()));
info.points.push_back(p1);
if(params.direction!=Area::DirectionNone)
info.points.push_back(p2);
} else {
// For closed wires, we are can easily rebase the wire, so we
// discretize the wires to spatial index it in order to accelerate
// nearest point searching
for(;xp.More();xp.Next()) {
for(BRepTools_WireExplorer xp(info.wire);xp.More();xp.Next()) {
// push the head point
info.points.push_back(BRep_Tool::Pnt(xp.CurrentVertex()));
@@ -1940,15 +1973,21 @@ struct ShapeInfo{
}
if(!done){
double d1 = pt.SquareDistance(it->pstart());
double d2 = pt.SquareDistance(it->pend());
if(d1<d2) {
if(myParams.direction==Area::DirectionNone) {
d = d1;
p = it->pstart();
is_start = true;
}else{
d = d2;
p = it->pend();
is_start = false;
double d2 = pt.SquareDistance(it->pend());
if(d1<d2) {
d = d1;
p = it->pstart();
is_start = true;
}else{
d = d2;
p = it->pend();
is_start = false;
}
}
}
if(!first && d>=best_d) continue;
@@ -2049,9 +2088,9 @@ struct ShapeInfo{
pend = myBestPt;
estart = mySupport;
state = 1;
AREA_TRACE((reversed?"reversed ":"")<<"edge split "<<AREA_XYZ(pprev)<<", " <<
AREA_XYZ(myBestPt)<< ", "<<AREA_XYZ(pt)<<", "<<d1<<", "<<d2 <<", ("<<
first<<", " << myBestParameter << ", " << last<<')');
// AREA_TRACE((reversed?"reversed ":"")<<"edge split "<<AREA_XYZ(pprev)<<", " <<
// AREA_XYZ(myBestPt)<< ", "<<AREA_XYZ(pt)<<", "<<d1<<", "<<d2 <<", ("<<
// first<<", " << myBestParameter << ", " << last<<')');
continue;
}
AREA_WARN((reversed?"reversed ":"")<<"edge split failed "<<AREA_XYZ(pprev)<<", " <<
@@ -2220,9 +2259,10 @@ struct ShapeInfoBuilder {
struct WireOrienter {
std::list<TopoDS_Shape> &wires;
short orientation;
short direction;
WireOrienter(std::list<TopoDS_Shape> &ws, short o)
:wires(ws),orientation(o)
WireOrienter(std::list<TopoDS_Shape> &ws, short o, short d)
:wires(ws),orientation(o),direction(d)
{}
void operator()(const TopoDS_Shape &shape, int type) {
@@ -2230,11 +2270,42 @@ struct WireOrienter {
wires.push_back(shape);
else
wires.push_back(BRepBuilderAPI_MakeWire(TopoDS::Edge(shape)).Wire());
if(orientation!=Area::OrientationNone && BRep_Tool::IsClosed(wires.back())) {
int dir = Area::getWireDirection(wires.back());
if((dir>0&&orientation==Area::OrientationCW) ||
(dir<0&&orientation==Area::OrientationCCW))
wires.back().Reverse();
TopoDS_Shape &wire = wires.back();
if(BRep_Tool::IsClosed(wire)) {
if(orientation!=Area::OrientationNone) {
int dir = Area::getWireDirection(wire);
if((dir>0&&orientation==Area::OrientationCW) ||
(dir<0&&orientation==Area::OrientationCCW))
wire.Reverse();
}
}else if(direction!=Area::DirectionNone) {
gp_Pnt p1,p2;
getEndPoints(TopoDS::Wire(wire),p1,p2);
bool reverse = false;
switch(direction) {
case Area::DirectionXPositive:
reverse = p1.X()>p2.X();
break;
case Area::DirectionXNegative:
reverse = p1.X()<p2.X();
break;
case Area::DirectionYPositive:
reverse = p1.Y()>p2.Y();
break;
case Area::DirectionYNegative:
reverse = p1.Y()<p2.Y();
break;
case Area::DirectionZPositive:
reverse = p1.Z()>p2.Z();
break;
case Area::DirectionZNegative:
reverse = p1.Z()<p2.Z();
break;
}
if(reverse)
wire.Reverse();
}
}
};
@@ -2251,12 +2322,12 @@ std::list<TopoDS_Shape> Area::sortWires(const std::list<TopoDS_Shape> &shapes,
for(auto &shape : shapes) {
if(!shape.IsNull())
foreachSubshape(shape,
WireOrienter(wires,orientation), TopAbs_WIRE);
WireOrienter(wires,orientation,direction), TopAbs_WIRE);
}
return std::move(wires);
}
ShapeParams rparams(abscissa,nearest_k>0?nearest_k:1,orientation);
ShapeParams rparams(abscissa,nearest_k>0?nearest_k:1,orientation,direction);
std::list<ShapeInfo> shape_list;
TIME_INIT2(t,t1);

View File

@@ -199,7 +199,9 @@
((short, nearest_k, NearestK, 3, "Nearest k sampling vertices are considered during sorting"))\
((enum, orientation, Orientation, 0, "Enforce loop orientation\n"\
"Note the CW/CCW here specifies the outer wire orientation. For inner wires (holes), the\n"\
"enforced orientation is reversed", (None)(CW)(CCW)))
"enforced orientation is reversed", (None)(CW)(CCW)))\
((enum, direction, Direction, 0, "Enforce open path direction",\
(None)(XPositive)(XNegative)(YPositive)(YNegative)(ZPositive)(ZNegative)))
/** Area path generation parameters */
#define AREA_PARAMS_PATH \