diff --git a/src/Mod/Path/App/Area.cpp b/src/Mod/Path/App/Area.cpp index 976520d368..5017d8aed5 100644 --- a/src/Mod/Path/App/Area.cpp +++ b/src/Mod/Path/App/Area.cpp @@ -558,43 +558,65 @@ std::vector > Area::makeSections( Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax); - bool hit_bottom = false; std::vector heights; if(_heights.empty()) { - if(mode != SectionModeAbsolute && myParams.SectionOffset<0) - throw Base::ValueError("only positive section offset is allowed in non-absolute mode"); - if(myParams.SectionCount>1 && myParams.Stepdown1 && d 0.0) + z = zMax-myParams.SectionOffset; + else + z = zMin+myParams.SectionOffset; + }else if(mode == SectionModeWorkplane){ + // Because we've transformed the shapes using the work plane so + // that the work plane is aligned with xy0 plane, the starting Z + // value shall be 0 minus the given section offset. Note the + // section offset is relative to the starting Z + if(myParams.Stepdown > 0.0) + z = -myParams.SectionOffset; + else + z = myParams.SectionOffset; + } else { gp_Pnt pt(0,0,myParams.SectionOffset); - double z = pt.Transformed(loc).Z(); - if(z < zMax) - zMax = z; + z = pt.Transformed(loc).Z(); } - if(zMax <= zMin) - throw Base::ValueError("section offset too big"); + if(z > zMax) + z = zMax; + else if(z < zMin) + z = zMin; + double dz; + if(myParams.Stepdown>0.0) + dz = z - zMin; + else + dz = zMax - z; int count = myParams.SectionCount; - if(count<0 || count*myParams.Stepdown > zMax-zMin) { - count = ceil((zMax-zMin)/myParams.Stepdown); - if((count-1)*myParams.Stepdown < zMax-zMin) - ++count; - } + if(count<0 || count*d > dz) + count = floor(dz/d)+1; heights.reserve(count); - for(int i=0;i0.0) { + if(z-zMin > Area::makeSections( default: throw Base::ValueError("invalid section mode"); } - if((zMin-z)>Precision::Confusion()) { - hit_bottom = true; - continue; - }else if ((z-zMax)>Precision::Confusion()) - continue; + if(z-zMin > sections; sections.reserve(heights.size()); diff --git a/src/Mod/Path/App/Area.h b/src/Mod/Path/App/Area.h index 2799e8e612..fc97ff9a50 100644 --- a/src/Mod/Path/App/Area.h +++ b/src/Mod/Path/App/Area.h @@ -303,10 +303,21 @@ public: */ TopoDS_Shape makePocket(int index=-1, PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_POCKET)); - + /** Make a pocket of the combined shape + * + * \arg \c heights: optional customized heights of each section. The + * meaning of each height depends on section mode. If none is given, + * the section heights is determined by the section settings in this + * Area object (configured through setParams()). + * \arg \c plane: the section plane if the section mode is + * SectionModeWorkplane, otherwise ignored + * + * See #AREA_PARAMS_EXTRA for description of the arguments. Currently, there + * is only one argument, namely \c mode for section mode. + */ std::vector > makeSections( PARAM_ARGS_DEF(PARAM_FARG,AREA_PARAMS_SECTION_EXTRA), - const std::vector &_heights = std::vector(), + const std::vector &heights = std::vector(), const TopoDS_Shape &plane = TopoDS_Shape()); /** Config this Area object */ diff --git a/src/Mod/Path/App/AreaParams.h b/src/Mod/Path/App/AreaParams.h index d440b08679..42880b6865 100644 --- a/src/Mod/Path/App/AreaParams.h +++ b/src/Mod/Path/App/AreaParams.h @@ -120,18 +120,19 @@ #define AREA_PARAMS_SECTION_EXTRA \ ((enum,mode,SectionMode,2,"Section offset coordinate mode.\n"\ - "'Absolute' means the absolute Z height to start section.\n"\ - "'BoundBox' means relative Z height to the bounding box of all the children shape. Only\n"\ - "positive value is allowed, which specifies the offset below the top Z of the bounding box.\n"\ - "Note that OCC has trouble getting the minimumi bounding box of some solids, particularly\n"\ - "those with non-planar surface.\n"\ - "'Workplane' means relative to workplane.",\ + "'Absolute' means the absolute Z height (given in SectionOffset) to start slicing.\n"\ + "'BoundBox' means relative Z height to the bounding box of all the children shape.\n"\ + "'Workplane' means relative to workplane, minus SectionOffset.\n"\ + "Note that OCC has trouble getting the minimum bounding box of some solids, particularly\n"\ + "those with non-planar surface. It is recommended to use Workplane to specifiy the intended\n"\ + "starting z height.",\ (Absolute)(BoundBox)(Workplane))) /** Section parameters */ #define AREA_PARAMS_SECTION \ ((long,count,SectionCount,0,"Number of sections to generate. -1 means full sections."))\ - ((double,stepdown,Stepdown,1.0,"Step down distance for each section"))\ + ((double,stepdown,Stepdown,1.0,"Step down distance for each section.\n"\ + "Positive value means going from top down, and negative the other way round"))\ ((double,offset,SectionOffset,0.0,"Offset for the first section"))\ AREA_PARAMS_SECTION_EXTRA diff --git a/src/Mod/Path/App/AreaPyImp.cpp b/src/Mod/Path/App/AreaPyImp.cpp index 2c22e456b8..a28cdf2211 100644 --- a/src/Mod/Path/App/AreaPyImp.cpp +++ b/src/Mod/Path/App/AreaPyImp.cpp @@ -126,7 +126,7 @@ static const PyMethodDef areaOverrides[] = { "\n* heights ([]): a list of section heights, the meaning of the value is determined by 'mode'.\n" "If not specified, the current SectionCount, and SectionOffset of this Area is used.\n" "\n* plane (None): optional shape to specify a section plane. If not give, the current workplane\n" - "of this Area is used.", + "of this Area is used if section mode is 'Workplane'.", }, { "sortWires",NULL,0, diff --git a/src/Mod/Path/App/FeatureArea.cpp b/src/Mod/Path/App/FeatureArea.cpp index ed8fd1a230..be19b0a46d 100644 --- a/src/Mod/Path/App/FeatureArea.cpp +++ b/src/Mod/Path/App/FeatureArea.cpp @@ -41,7 +41,7 @@ PROPERTY_SOURCE(Path::FeatureArea, Part::Feature) PARAM_ENUM_STRING_DECLARE(static const char *Enums,AREA_PARAMS_ALL) FeatureArea::FeatureArea() - :myBuild(false) + :myInited(false) { ADD_PROPERTY(Sources,(0)); ADD_PROPERTY(WorkPlane,(TopoDS_Shape())); @@ -64,13 +64,14 @@ FeatureArea::~FeatureArea() } Area &FeatureArea::getArea() { - if(!myBuild) - execute(); + if(!myInited) execute(); return myArea; } App::DocumentObjectExecReturn *FeatureArea::execute(void) { + myInited = true; + std::vector links = Sources.getValues(); if (links.empty()) return new App::DocumentObjectExecReturn("No shapes linked"); @@ -85,7 +86,6 @@ App::DocumentObjectExecReturn *FeatureArea::execute(void) TIME_INIT(t); - myBuild = true; AreaParams params; #define AREA_PROP_GET(_param) \ @@ -112,6 +112,7 @@ App::DocumentObjectExecReturn *FeatureArea::execute(void) myShapes.push_back(myArea.getShape(i)); } + bool hasShape = false; if(myShapes.empty()) Shape.setValue(TopoDS_Shape()); else{ @@ -120,13 +121,20 @@ App::DocumentObjectExecReturn *FeatureArea::execute(void) BRep_Builder builder; TopoDS_Compound compound; builder.MakeCompound(compound); - for(auto &shape : myShapes) + for(auto &shape : myShapes) { + if(shape.IsNull()) continue; + hasShape = true; builder.Add(compound,shape); + } Shape.setValue(compound); } TIME_PRINT(t,"feature execute"); - return Part::Feature::execute(); + + if(!hasShape) + return new App::DocumentObjectExecReturn("no output shape"); + + return DocumentObject::StdReturn; } const std::vector &FeatureArea::getShapes() { @@ -136,7 +144,9 @@ const std::vector &FeatureArea::getShapes() { short FeatureArea::mustExecute(void) const { - return !myArea.isBuilt() || Part::Feature::mustExecute(); + if(!myArea.isBuilt()) + return 1; + return Part::Feature::mustExecute(); } PyObject *FeatureArea::getPyObject() @@ -202,21 +212,26 @@ App::DocumentObjectExecReturn *FeatureAreaView::execute(void) if(!pObj->isDerivedFrom(FeatureArea::getClassTypeId())) return new App::DocumentObjectExecReturn("Linked object is not a FeatureArea"); + bool hasShape = false; std::list shapes = getShapes(); if(shapes.empty()) Shape.setValue(TopoDS_Shape()); - else if(shapes.size()==1) { - Shape.setValue(shapes.front()); - }else{ + else{ BRep_Builder builder; TopoDS_Compound compound; builder.MakeCompound(compound); - for(auto &shape : shapes) + for(auto &shape : shapes) { + if(shape.IsNull()) continue; + hasShape = true; builder.Add(compound,shape); + } Shape.setValue(compound); } - return Part::Feature::execute(); + if(!hasShape) + return new App::DocumentObjectExecReturn("no output shape"); + + return DocumentObject::StdReturn; } // Python feature --------------------------------------------------------- diff --git a/src/Mod/Path/App/FeatureArea.h b/src/Mod/Path/App/FeatureArea.h index 6e2f087c88..a6ad65edd6 100644 --- a/src/Mod/Path/App/FeatureArea.h +++ b/src/Mod/Path/App/FeatureArea.h @@ -66,9 +66,9 @@ public: } private: - bool myBuild; Area myArea; std::vector myShapes; + bool myInited; }; typedef App::FeaturePythonT FeatureAreaPython;