Skip to content

Commit

Permalink
Part: add API TopoShape::linearize()
Browse files Browse the repository at this point in the history
Used by Part::Extrude and PartDesign::Pad/Pocket for convert
planar BSplineSurface face to plane when drafting.

Related realthunder/FreeCAD_assembly3#627
  • Loading branch information
realthunder committed May 26, 2021
1 parent 284b14c commit dd9023e
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 16 deletions.
21 changes: 21 additions & 0 deletions src/Mod/Part/App/FeatureExtrusion.cpp
Expand Up @@ -88,6 +88,8 @@ Extrusion::Extrusion()
ADD_PROPERTY_TYPE(InnerTaperAngle,(0.0), "Extrude", App::Prop_None, "Taper angle of inner holes.");
ADD_PROPERTY_TYPE(InnerTaperAngleRev,(0.0), "Extrude", App::Prop_None, "Taper angle of the reverse part for inner holes.");
ADD_PROPERTY_TYPE(UsePipeForDraft,(false), "Extrude", App::Prop_None, "Use pipe (i.e. sweep) operation to create draft angles.");
ADD_PROPERTY_TYPE(Linearize,(false), "Extrude", App::Prop_None,
"Linearize the resut shape by simplify linear edge and planar face into line and plane");
ADD_PROPERTY_TYPE(FaceMakerClass,("Part::FaceMakerExtrusion"), "Extrude", App::Prop_None, "If Solid is true, this sets the facemaker class to use when converting wires to faces. Otherwise, ignored."); //default for old documents. See setupObject for default for new extrusions.
}

Expand Down Expand Up @@ -147,6 +149,7 @@ Extrusion::ExtrusionParameters Extrusion::computeFinalParameters()
{
Extrusion::ExtrusionParameters result;
result.usepipe = this->UsePipeForDraft.getValue();
result.linearize = this->Linearize.getValue();
Base::Vector3d dir;
switch(this->DirMode.getValue()){
case dmCustom:
Expand Down Expand Up @@ -533,6 +536,8 @@ void Extrusion::makeDraft(const ExtrusionParameters& params, const TopoShape& _s
#endif
if (params.usepipe) {
drafts.push_back(makeDraftUsingPipe(list_of_sections, hasher));
if (params.linearize)
drafts.back().linearize(true, false);
return;
}

Expand All @@ -544,6 +549,8 @@ void Extrusion::makeDraft(const ExtrusionParameters& params, const TopoShape& _s

mkGenerator.Build();
drafts.push_back(TopoShape(0,hasher).makEShape(mkGenerator,list_of_sections));
if (params.linearize)
drafts.back().linearize(true, false);
}
catch (Standard_Failure &){
throw;
Expand Down Expand Up @@ -629,5 +636,19 @@ void Part::Extrusion::setupObject()
{
Part::Feature::setupObject();
UsePipeForDraft.setValue(PartParams::UsePipeForExtrusionDraft());
Linearize.setValue(Part::PartParams::LinearizeExtrusionDraft());
this->FaceMakerClass.setValue("Part::FaceMakerBullseye"); //default for newly created features
}

Part::Extrusion::ExtrusionParameters::ExtrusionParameters()
: lengthFwd(0)
, lengthRev(0)
, solid(false)
, innertaper(false)
, usepipe(false)
, linearize(PartParams::LinearizeExtrusionDraft())
, taperAngleFwd(0)
, taperAngleRev(0)
, innerTaperAngleFwd(0)
, innerTaperAngleRev(0)
{}// constructor to keep garbage out
16 changes: 4 additions & 12 deletions src/Mod/Part/App/FeatureExtrusion.h
Expand Up @@ -56,35 +56,27 @@ class PartExport Extrusion : public Part::Feature
App::PropertyAngle InnerTaperAngleRev;
App::PropertyString FaceMakerClass;
App::PropertyBool UsePipeForDraft;
App::PropertyBool Linearize;

/**
* @brief The ExtrusionParameters struct is supposed to be filled with final
* extrusion parameters, after resolving links, applying mode logic,
* reversing, etc., and be passed to extrudeShape.
*/
struct ExtrusionParameters {
struct PartExport ExtrusionParameters {
gp_Dir dir;
double lengthFwd;
double lengthRev;
bool solid;
bool innertaper;
bool usepipe;
bool linearize;
double taperAngleFwd; //in radians
double taperAngleRev;
double innerTaperAngleFwd; //in radians
double innerTaperAngleRev;
std::string faceMakerClass;
ExtrusionParameters()
: lengthFwd(0)
, lengthRev(0)
, solid(false)
, innertaper(false)
, usepipe(false)
, taperAngleFwd(0)
, taperAngleRev(0)
, innerTaperAngleFwd(0)
, innerTaperAngleRev(0)
{}// constructor to keep garbage out
ExtrusionParameters();
};

/** @name methods override feature */
Expand Down
32 changes: 28 additions & 4 deletions src/Mod/Part/App/Geometry.cpp
Expand Up @@ -1809,8 +1809,14 @@ PyObject *GeomBSplineCurve::getPyObject(void)

bool GeomBSplineCurve::isSame(const Geometry &_other, double tol, double atol) const
{
if(_other.getTypeId() != getTypeId())
if(_other.getTypeId() != getTypeId()) {
if (isLinear() && _other.isDerivedFrom(GeomCurve::getClassTypeId())) {
std::unique_ptr<Geometry> geo(toLineSegment());
if (geo)
return geo->isSame(_other, tol, atol);
}
return false;
}

auto &other = static_cast<const GeomBSplineCurve &>(_other);
(void)atol;
Expand Down Expand Up @@ -4167,8 +4173,14 @@ PyObject *GeomLine::getPyObject(void)

bool GeomLine::isSame(const Geometry &_other, double tol, double atol) const
{
if(_other.getTypeId() != getTypeId())
if(_other.getTypeId() != getTypeId()) {
if (_other.isDerivedFrom(GeomCurve::getClassTypeId())) {
std::unique_ptr<Geometry> geo(static_cast<const GeomCurve&>(_other).toLine());
if (geo)
return isSame(*geo, tol, atol);
}
return false;
}

auto &other = static_cast<const GeomLine &>(_other);

Expand Down Expand Up @@ -4766,8 +4778,14 @@ PyObject *GeomBSplineSurface::getPyObject(void)

bool GeomBSplineSurface::isSame(const Geometry &_other, double tol, double atol) const
{
if(_other.getTypeId() != getTypeId())
if(_other.getTypeId() != getTypeId()) {
if (_other.isDerivedFrom(GeomSurface::getClassTypeId()) && isPlanar()) {
std::unique_ptr<Geometry> geo(toPlane());
if (geo)
return geo->isSame(_other, tol, atol);
}
return false;
}

auto &other = static_cast<const GeomBSplineSurface &>(_other);
Standard_Integer uc = mySurface->NbUPoles();
Expand Down Expand Up @@ -5194,8 +5212,14 @@ PyObject *GeomPlane::getPyObject(void)

bool GeomPlane::isSame(const Geometry &_other, double tol, double atol) const
{
if(_other.getTypeId() != getTypeId())
if(_other.getTypeId() != getTypeId()) {
if (_other.isDerivedFrom(GeomSurface::getClassTypeId())) {
std::unique_ptr<Geometry> geo(static_cast<const GeomSurface&>(_other).toPlane());
if (geo)
return isSame(*geo, tol, atol);
}
return false;
}

auto &other = static_cast<const GeomPlane &>(_other);
return GeomElementarySurface::isSame(other,tol,atol);
Expand Down
1 change: 1 addition & 0 deletions src/Mod/Part/App/PartParams.h
Expand Up @@ -68,6 +68,7 @@ class PartExport PartParams: public ParameterGrp::ObserverType
FC_APP_PART_PARAM(AutoGroupSolids,bool,Bool,false) \
FC_APP_PART_PARAM(SingleSolid,bool,Bool,false) \
FC_APP_PART_PARAM(UsePipeForExtrusionDraft,bool,Bool,false) \
FC_APP_PART_PARAM(LinearizeExtrusionDraft,bool,Bool,true) \
FC_APP_PART_PARAM(AutoCorrectLink,bool,Bool,false) \

#undef FC_APP_PART_PARAM
Expand Down
6 changes: 6 additions & 0 deletions src/Mod/Part/App/TopoShape.h
Expand Up @@ -668,6 +668,12 @@ class PartExport TopoShape : public Data::ComplexGeoData
return TopoShape(0,Hasher).makECut({*this,shape},op,tol);
}

/** Try to simplify geometry of any linear/planar subshape to line/plane
*
* @return Return true if the shape is modified
*/
bool linearize(bool face, bool edge);

static const std::string &modPostfix();
static const std::string &genPostfix();
static const std::string &modgenPostfix();
Expand Down
45 changes: 45 additions & 0 deletions src/Mod/Part/App/TopoShapeEx.cpp
Expand Up @@ -4579,3 +4579,48 @@ bool TopoShape::isPlanarFace(double tol) const
return GeomSurface::isPlanar(
BRepAdaptor_Surface(TopoDS::Face(getShape())).Surface().Surface(), nullptr, tol);
}

bool TopoShape::linearize(bool face, bool edge)
{
bool touched = false;
BRep_Builder builder;
// Note: changing edge geometry seems to mess up with face (or shell, or solid)
// Probably need to do some fix afterwards.
if (edge) {
for (auto & edge : getSubTopoShapes(TopAbs_EDGE)) {
TopoDS_Edge e = TopoDS::Edge(edge.getShape());
BRepAdaptor_Curve curve(e);
if (curve.GetType() == GeomAbs_Line || !edge.isLinearEdge())
continue;
std::unique_ptr<Geometry> geo(
Geometry::fromShape(e.Located(TopLoc_Location()).Oriented(TopAbs_FORWARD)));
std::unique_ptr<Geometry> gline(static_cast<GeomCurve*>(geo.get())->toLine());
if (gline) {
touched = true;
builder.UpdateEdge(e,
Handle(Geom_Curve)::DownCast(gline->handle()),
e.Location(),
BRep_Tool::Tolerance(e));
}
}
}
if (face) {
for (auto & face : getSubTopoShapes(TopAbs_FACE)) {
TopoDS_Face f = TopoDS::Face(face.getShape());
BRepAdaptor_Surface surf(f);
if (surf.GetType() == GeomAbs_Plane || !face.isPlanarFace())
continue;
std::unique_ptr<Geometry> geo(
Geometry::fromShape(f.Located(TopLoc_Location()).Oriented(TopAbs_FORWARD)));
std::unique_ptr<Geometry> gplane(static_cast<GeomSurface*>(geo.get())->toPlane());
if (gplane) {
touched = true;
builder.UpdateFace(f,
Handle(Geom_Surface)::DownCast(gplane->handle()),
f.Location(),
BRep_Tool::Tolerance(f));
}
}
}
return touched;
}
4 changes: 4 additions & 0 deletions src/Mod/PartDesign/App/FeaturePad.cpp
Expand Up @@ -91,6 +91,8 @@ Pad::Pad()
ADD_PROPERTY_TYPE(InnerTaperAngleRev,(0.0), "Pad", App::Prop_None, "Taper angle of the reverse part for inner holes.");

ADD_PROPERTY_TYPE(UsePipeForDraft,(false), "Pad", App::Prop_None, "Use pipe (i.e. sweep) operation to create draft angles.");
ADD_PROPERTY_TYPE(Linearize,(false), "Pad", App::Prop_None,
"Linearize the resut shape by simplify linear edge and planar face into line and plane");
}

short Pad::mustExecute() const
Expand All @@ -117,6 +119,7 @@ void Pad::setupObject()
{
ProfileBased::setupObject();
UsePipeForDraft.setValue(Part::PartParams::UsePipeForExtrusionDraft());
Linearize.setValue(Part::PartParams::LinearizeExtrusionDraft());
}

App::DocumentObjectExecReturn *Pad::_execute(bool makeface, bool fuse)
Expand Down Expand Up @@ -367,6 +370,7 @@ App::DocumentObjectExecReturn *Pad::_execute(bool makeface, bool fuse)
params.taperAngleRev = this->TaperAngleRev.getValue() * M_PI / 180.0;
params.innerTaperAngleFwd = this->InnerTaperAngle.getValue() * M_PI / 180.0;
params.innerTaperAngleRev = this->InnerTaperAngleRev.getValue() * M_PI / 180.0;
params.linearize = this->Linearize.getValue();
if (L2 == 0.0 && Midplane.getValue()) {
params.lengthFwd = L/2;
params.lengthRev = L/2;
Expand Down
1 change: 1 addition & 0 deletions src/Mod/PartDesign/App/FeaturePad.h
Expand Up @@ -51,6 +51,7 @@ class PartDesignExport Pad : public ProfileBased
App::PropertyAngle InnerTaperAngle;
App::PropertyAngle InnerTaperAngleRev;
App::PropertyBool UsePipeForDraft;
App::PropertyBool Linearize;

/** @name methods override feature */
//@{
Expand Down
7 changes: 7 additions & 0 deletions src/Mod/PartDesign/App/FeaturePocket.cpp
Expand Up @@ -83,6 +83,10 @@ Pocket::Pocket()
ADD_PROPERTY_TYPE(TaperAngleRev,(0.0), "Pocket", App::Prop_None, "Taper angle of reverse part of pocketing.");
ADD_PROPERTY_TYPE(InnerTaperAngle,(0.0), "Pocket", App::Prop_None, "Taper angle of inner holes.");
ADD_PROPERTY_TYPE(InnerTaperAngleRev,(0.0), "Pocket", App::Prop_None, "Taper angle of the reverse part for inner holes.");

ADD_PROPERTY_TYPE(UsePipeForDraft,(false), "Pocket", App::Prop_None, "Use pipe (i.e. sweep) operation to create draft angles.");
ADD_PROPERTY_TYPE(Linearize,(false), "Pocket", App::Prop_None,
"Linearize the resut shape by simplify linear edge and planar face into line and plane");
}

short Pocket::mustExecute() const
Expand Down Expand Up @@ -246,6 +250,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
params.dir.Reverse();
std::vector<TopoShape> drafts;
params.usepipe = this->UsePipeForDraft.getValue();
params.linearize = this->Linearize.getValue();
Part::Extrusion::makeDraft(params, profileshape, drafts, getDocument()->getStringHasher());
if (drafts.empty())
return new App::DocumentObjectExecReturn("Pocket with draft angle failed");
Expand Down Expand Up @@ -303,5 +308,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void)
void Pocket::setupObject()
{
ProfileBased::setupObject();
UsePipeForDraft.setValue(Part::PartParams::UsePipeForExtrusionDraft());
Linearize.setValue(Part::PartParams::LinearizeExtrusionDraft());
}

1 change: 1 addition & 0 deletions src/Mod/PartDesign/App/FeaturePocket.h
Expand Up @@ -46,6 +46,7 @@ class PartDesignExport Pocket : public ProfileBased
App::PropertyAngle InnerTaperAngle;
App::PropertyAngle InnerTaperAngleRev;
App::PropertyBool UsePipeForDraft;
App::PropertyBool Linearize;

/** @name methods override feature */
//@{
Expand Down

0 comments on commit dd9023e

Please sign in to comment.