Path.Area: fix path orientation setting

This commit is contained in:
Zheng, Lei
2017-05-08 04:07:23 +08:00
committed by wmayer
parent 2d23673dd5
commit 9120d6db77
3 changed files with 88 additions and 70 deletions

View File

@@ -530,8 +530,9 @@ struct WireJoiner {
BRep_Builder builder;
TopoDS_Compound comp;
gp_Dir dir;
WireJoiner() {
WireJoiner(const gp_Dir &dir = gp_Dir()):dir(dir) {
builder.MakeCompound(comp);
}
@@ -554,11 +555,10 @@ struct WireJoiner {
if(BRep_Tool::IsClosed(e)){
BRepBuilderAPI_MakeWire mkWire;
mkWire.Add(e);
const TopoDS_Wire &wire = mkWire.Wire();
if(bbox && Area::getWireDirection(wire)>0)
builder.Add(comp,wire.Reversed());
else
builder.Add(comp,wire);
TopoDS_Wire wire = mkWire.Wire();
if(bbox)
Area::setWireOrientation(wire,dir,true);
builder.Add(comp,wire);
return;
}
gp_Pnt p1,p2;
@@ -795,11 +795,9 @@ struct WireJoiner {
else
mkWire.Add(TopoDS::Edge(info.edge.Reversed()));
}
const TopoDS_Wire &wire = mkWire.Wire();
if(Area::getWireDirection(wire)>0)
builder.Add(comp,wire.Reversed());
else
builder.Add(comp,wire);
TopoDS_Wire wire = mkWire.Wire();
Area::setWireOrientation(wire,dir,true);
builder.Add(comp,wire);
break;
}
}
@@ -932,10 +930,11 @@ std::list<TopoDS_Wire> Area::project(const TopoDS_Shape &solid)
{
TIME_INIT2(t,t1);
Handle_HLRBRep_Algo brep_hlr = NULL;
gp_Dir dir(0,0,1);
try {
brep_hlr = new HLRBRep_Algo();
brep_hlr->Add(solid, 0);
HLRAlgo_Projector projector(gp_Ax2(gp_Pnt(),gp_Dir(0,0,1)));
HLRAlgo_Projector projector(gp_Ax2(gp_Pnt(),dir));
brep_hlr->Projector(projector);
brep_hlr->Update();
brep_hlr->Hide();
@@ -943,7 +942,7 @@ std::list<TopoDS_Wire> Area::project(const TopoDS_Shape &solid)
AREA_ERR("error occurred while projecting shape");
}
TIME_PRINT(t1,"HLRBrep_Algo");
WireJoiner joiner;
WireJoiner joiner(dir);
try {
#define ADD_HLR_SHAPE(_name) \
shape = hlrToShape._name##Compound();\
@@ -1173,22 +1172,32 @@ std::vector<shared_ptr<Area> > Area::makeSections(
continue;
}
if(myParams.Fill != FillNone) {
Part::FaceMakerBullseye mkFace;
mkFace.setPlane(pln);
for(const TopoDS_Wire &wire : wires)
// always try to make face to normalize wire orientation
Part::FaceMakerBullseye mkFace;
mkFace.setPlane(pln);
for(const TopoDS_Wire &wire : wires) {
if(BRep_Tool::IsClosed(wire))
mkFace.addWire(wire);
try {
mkFace.Build();
if (mkFace.Shape().IsNull())
AREA_WARN("FaceMakerBullseye return null shape on section");
else {
builder.Add(comp,mkFace.Shape());
continue;
}
try {
mkFace.Build();
const TopoDS_Shape &shape = mkFace.Shape();
if (shape.IsNull())
AREA_WARN("FaceMakerBullseye return null shape on section");
else {
for(auto it=wires.begin(),itNext=it;it!=wires.end();it=itNext) {
++itNext;
if(BRep_Tool::IsClosed(*it))
wires.erase(it);
}
for(TopExp_Explorer xp(shape,myParams.Fill==FillNone?TopAbs_WIRE:TopAbs_FACE);
xp.More();xp.Next())
{
builder.Add(comp,xp.Current());
}
}catch (Base::Exception &e){
AREA_WARN("FaceMakerBullseye failed on section: " << e.what());
}
}catch (Base::Exception &e){
AREA_WARN("FaceMakerBullseye failed on section: " << e.what());
}
for(const TopoDS_Wire &wire : wires)
builder.Add(comp,wire);
@@ -1903,12 +1912,8 @@ struct GetWires {
info.wire = BRepBuilderAPI_MakeWire(TopoDS::Edge(shape)).Wire();
info.isClosed = BRep_Tool::IsClosed(info.wire);
if(info.isClosed && params.orientation != Area::OrientationNone){
int dir =Area::getWireDirection(info.wire);
if((dir>0&&params.orientation==Area::OrientationCW) ||
(dir<0&&params.orientation==Area::OrientationCCW))
info.wire.Reverse();
}
if(info.isClosed && params.orientation == Area::OrientationReversed)
info.wire.Reverse();
TIME_INIT(t);
if(params.abscissa<Precision::Confusion() || !info.isClosed) {
@@ -2252,11 +2257,11 @@ struct ShapeInfo{
struct ShapeInfoBuilder {
std::list<ShapeInfo> &myList;
gp_Trsf &myTrsf;
short *myArcPlane;
short &myArcPlane;
bool &myArcPlaneFound;
ShapeParams &myParams;
ShapeInfoBuilder(bool &plane_found, short *arc_plane, gp_Trsf &trsf,
ShapeInfoBuilder(bool &plane_found, short &arc_plane, gp_Trsf &trsf,
std::list<ShapeInfo> &list, ShapeParams &params)
:myList(list) ,myTrsf(trsf) ,myArcPlane(arc_plane)
,myArcPlaneFound(plane_found), myParams(params)
@@ -2269,9 +2274,9 @@ struct ShapeInfoBuilder {
return;
}
myList.push_back(ShapeInfo(finder,shape,myParams));
if(myArcPlane==NULL || myArcPlaneFound ||
*myArcPlane==Area::ArcPlaneNone ||
*myArcPlane==Area::ArcPlaneVariable)
if(myArcPlaneFound ||
myArcPlane==Area::ArcPlaneNone ||
myArcPlane==Area::ArcPlaneVariable)
return;
if(type == TopAbs_EDGE) {
@@ -2295,19 +2300,19 @@ struct ShapeInfoBuilder {
bool x0 = fabs(dir.X())<Precision::Confusion();
bool y0 = fabs(dir.Y())<Precision::Confusion();
bool z0 = fabs(dir.Z())<Precision::Confusion();
switch(*myArcPlane) {
switch(myArcPlane) {
case Area::ArcPlaneAuto: {
if(x0&&y0){
AREA_TRACE("found arc plane XY");
*myArcPlane = Area::ArcPlaneXY;
myArcPlane = Area::ArcPlaneXY;
} else if(x0&&z0) {
AREA_TRACE("found arc plane ZX");
*myArcPlane = Area::ArcPlaneZX;
myArcPlane = Area::ArcPlaneZX;
} else if(z0&&y0) {
AREA_TRACE("found arc plane YZ");
*myArcPlane = Area::ArcPlaneYZ;
myArcPlane = Area::ArcPlaneYZ;
} else {
*myArcPlane = Area::ArcPlaneXY;
myArcPlane = Area::ArcPlaneXY;
dstPos = gp_Ax3(pos.Location(),gp_Dir(0,0,1));
break;
}
@@ -2340,11 +2345,12 @@ struct ShapeInfoBuilder {
struct WireOrienter {
std::list<TopoDS_Shape> &wires;
const gp_Dir &dir;
short orientation;
short direction;
WireOrienter(std::list<TopoDS_Shape> &ws, short o, short d)
:wires(ws),orientation(o),direction(d)
WireOrienter(std::list<TopoDS_Shape> &ws, const gp_Dir &dir, short o, short d)
:wires(ws),dir(dir),orientation(o),direction(d)
{}
void operator()(const TopoDS_Shape &shape, int type) {
@@ -2356,12 +2362,8 @@ struct WireOrienter {
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();
}
if(orientation==Area::OrientationReversed)
wire.Reverse();
}else if(direction!=Area::DirectionNone) {
gp_Pnt p1,p2;
getEndPoints(TopoDS::Wire(wire),p1,p2);
@@ -2393,18 +2395,36 @@ struct WireOrienter {
};
std::list<TopoDS_Shape> Area::sortWires(const std::list<TopoDS_Shape> &shapes,
const gp_Pnt *_pstart, gp_Pnt *_pend, short *arc_plane,
const gp_Pnt *_pstart, gp_Pnt *_pend, short *_parc_plane,
PARAM_ARGS(PARAM_FARG,AREA_PARAMS_SORT))
{
std::list<TopoDS_Shape> wires;
if(shapes.empty()) return wires;
short _arc_plane = ArcPlaneNone;
short &arc_plane = _parc_plane?*_parc_plane:_arc_plane;
if(sort_mode == SortModeNone) {
gp_Dir dir;
switch(arc_plane) {
case ArcPlaneYZ:
dir = gp_Dir(1,0,0);
break;
case ArcPlaneZX:
dir = gp_Dir(0,1,0);
break;
default:
if(arc_plane != ArcPlaneXY)
AREA_WARN("Sort mode 'None' without a given arc plane, using XY plane");
arc_plane = ArcPlaneXY;
dir = gp_Dir(0,0,1);
break;
}
for(auto &shape : shapes) {
if(!shape.IsNull())
foreachSubshape(shape,
WireOrienter(wires,orientation,direction), TopAbs_WIRE);
WireOrienter(wires,dir,orientation,direction), TopAbs_WIRE);
}
return std::move(wires);
}
@@ -2627,29 +2647,24 @@ static inline void addGCode(Toolpath &path, const char *name) {
path.addCommand(cmd);
}
int Area::getWireDirection(const TopoDS_Shape &shape, const gp_Pln *pln) {
gp_Dir dir;
if(pln)
dir = pln->Axis().Direction();
else{
BRepLib_FindSurface finder(shape,-1,Standard_True);
if(!finder.Found()) return 0;
dir = GeomAdaptor_Surface(finder.Surface()).Plane().Axis().Direction();
}
const TopoDS_Wire &wire = TopoDS::Wire(shape);
void Area::setWireOrientation(TopoDS_Wire &wire, const gp_Dir &dir, bool wire_ccw) {
//make a test face
BRepBuilderAPI_MakeFace mkFace(wire, /*onlyplane=*/Standard_True);
if(!mkFace.IsDone()) return 0;
if(!mkFace.IsDone()) {
AREA_WARN("setWireOrientation: failed to make test face");
return;
}
TopoDS_Face tmpFace = mkFace.Face();
//compare face surface normal with our plane's one
BRepAdaptor_Surface surf(tmpFace);
bool normal_co = surf.Plane().Axis().Direction().Dot(dir) > 0;
bool ccw = surf.Plane().Axis().Direction().Dot(dir) > 0;
//unlikely, but just in case OCC decided to reverse our wire for the face... take that into account!
TopoDS_Iterator it(tmpFace, /*CumOri=*/Standard_False);
normal_co ^= it.Value().Orientation() != wire.Orientation();
ccw ^= it.Value().Orientation() != wire.Orientation();
return normal_co ? 1 : -1;
if(ccw != wire_ccw)
wire.Reverse();
}
void Area::toPath(Toolpath &path, const std::list<TopoDS_Shape> &shapes,

View File

@@ -446,7 +446,7 @@ public:
const gp_Pnt *pstart=NULL, gp_Pnt *pend=NULL,
PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_PATH));
static int getWireDirection(const TopoDS_Shape& wire, const gp_Pln *plane=0);
static void setWireOrientation(TopoDS_Wire& wire, const gp_Dir &dir, bool ccw);
PARAM_ENUM_DECLARE(AREA_PARAMS_PATH)

View File

@@ -190,6 +190,11 @@
"arc encountered.",\
(None)(Auto)(XY)(ZX)(YZ)(Variable)))
#define AREA_PARAMS_ORIENTATION \
((enum, orientation, Orientation, 0, "Enforce loop orientation\n"\
"'Normal' means CCW for outer wires when looking against the positive axis direction, \n"\
"and CW for inner wires. 'Reversed' means the other way round", (Normal)(Reversed)))
/** Area wire sorting parameters */
#define AREA_PARAMS_SORT \
((enum, sort_mode, SortMode, 1, "Wire sorting mode to optimize travel distance.\n"\
@@ -202,9 +207,7 @@
((double, abscissa, SortAbscissa, 3.0, "Controls vertex sampling on wire for nearest point searching\n"\
"The sampling is dong using OCC GCPnts_UniformAbscissa",App::PropertyLength))\
((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)))\
AREA_PARAMS_ORIENTATION \
((enum, direction, Direction, 0, "Enforce open path direction",\
(None)(XPositive)(XNegative)(YPositive)(YNegative)(ZPositive)(ZNegative)))