Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A general class to implement smart making faces from wires (e.g. making a face from sketch prior to extruding)
- Loading branch information
Showing
3 changed files
with
327 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -282,6 +282,8 @@ SET(Part_SRCS | |
OCCError.h | ||
FT2FC.cpp | ||
FT2FC.h | ||
FaceMaker.cpp | ||
FaceMaker.h | ||
) | ||
|
||
SET(Part_Scripts | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
/*************************************************************************** | ||
* Copyright (c) 2016 Victor Titov (DeepSOIC) <vv.titov@gmail.com> * | ||
* * | ||
* This file is part of the FreeCAD CAx development system. * | ||
* * | ||
* This library is free software; you can redistribute it and/or * | ||
* modify it under the terms of the GNU Library General Public * | ||
* License as published by the Free Software Foundation; either * | ||
* version 2 of the License, or (at your option) any later version. * | ||
* * | ||
* This library is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU Library General Public License for more details. * | ||
* * | ||
* You should have received a copy of the GNU Library General Public * | ||
* License along with this library; see the file COPYING.LIB. If not, * | ||
* write to the Free Software Foundation, Inc., 59 Temple Place, * | ||
* Suite 330, Boston, MA 02111-1307, USA * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "PreCompiled.h" | ||
#ifndef _PreComp_ | ||
# include <TopoDS.hxx> | ||
# include <TopoDS_Iterator.hxx> | ||
# include <BRep_Builder.hxx> | ||
# include <BRepBuilderAPI_MakeWire.hxx> | ||
# include <BRepBuilderAPI_MakeFace.hxx> | ||
# include <BRep_Tool.hxx> | ||
#endif | ||
|
||
#include "FaceMaker.h" | ||
|
||
#include <Base/Exception.h> | ||
#include <memory> | ||
|
||
#include <QtGlobal> | ||
|
||
TYPESYSTEM_SOURCE_ABSTRACT(Part::FaceMaker, Base::BaseClass); | ||
TYPESYSTEM_SOURCE_ABSTRACT(Part::FaceMakerPublic, Part::FaceMaker); | ||
|
||
void Part::FaceMaker::addWire(const TopoDS_Wire& w) | ||
{ | ||
this->addShape(w); | ||
} | ||
|
||
void Part::FaceMaker::addShape(const TopoDS_Shape& sh) | ||
{ | ||
if(sh.IsNull()) | ||
throw Base::ValueError("Input shape is null."); | ||
switch(sh.ShapeType()){ | ||
case TopAbs_COMPOUND: | ||
this->myCompounds.push_back(TopoDS::Compound(sh)); | ||
break; | ||
case TopAbs_WIRE: | ||
this->myWires.push_back(TopoDS::Wire(sh)); | ||
break; | ||
case TopAbs_EDGE: | ||
this->myWires.push_back(BRepBuilderAPI_MakeWire(TopoDS::Edge(sh)).Wire()); | ||
break; | ||
default: | ||
throw Base::TypeError("Shape must be a wire, edge or compound. Something else was supplied."); | ||
break; | ||
} | ||
this->mySourceShapes.push_back(sh); | ||
} | ||
|
||
void Part::FaceMaker::useCompound(const TopoDS_Compound& comp) | ||
{ | ||
TopoDS_Iterator it(comp); | ||
for(; it.More(); it.Next()){ | ||
this->addShape(it.Value()); | ||
} | ||
} | ||
|
||
const TopoDS_Face& Part::FaceMaker::Face() | ||
{ | ||
const TopoDS_Shape &sh = this->Shape(); | ||
if(sh.IsNull()) | ||
throw Base::Exception("Part::FaceMaker: result shape is null."); | ||
if (sh.ShapeType() != TopAbs_FACE) | ||
throw Base::TypeError("Part::FaceMaker: return shape is not a single face."); | ||
return TopoDS::Face(sh); | ||
} | ||
|
||
void Part::FaceMaker::Build() | ||
{ | ||
this->NotDone(); | ||
this->myShapesToReturn.clear(); | ||
this->myGenerated.Clear(); | ||
|
||
this->Build_Essence();//adds stuff to myShapesToReturn | ||
|
||
for(const TopoDS_Compound& cmp : this->myCompounds){ | ||
std::unique_ptr<FaceMaker> facemaker_instance = Part::FaceMaker::ConstructFromType(this->getTypeId()); | ||
FaceMaker* facemaker = &(*facemaker_instance); //handy to have plain pointer for intellisense to work =) | ||
|
||
facemaker->useCompound(cmp); | ||
|
||
facemaker->Build(); | ||
const TopoDS_Shape &subfaces = facemaker->Shape(); | ||
if (subfaces.IsNull()) | ||
continue; | ||
if (subfaces.ShapeType() == TopAbs_COMPOUND){ | ||
this->myShapesToReturn.push_back(subfaces); | ||
} else { | ||
//result is not a compound (probably, a face)... but we want to follow compounding structure of input, so wrap it into compound. | ||
TopoDS_Builder builder; | ||
TopoDS_Compound cmp_res; | ||
builder.MakeCompound(cmp_res); | ||
builder.Add(cmp_res,subfaces); | ||
this->myShapesToReturn.push_back(cmp_res); | ||
} | ||
} | ||
|
||
if(this->myShapesToReturn.empty()){ | ||
//nothing to do, null shape will be returned. | ||
} else if (this->myShapesToReturn.size() == 1){ | ||
this->myShape = this->myShapesToReturn[0]; | ||
} else { | ||
TopoDS_Builder builder; | ||
TopoDS_Compound cmp_res; | ||
builder.MakeCompound(cmp_res); | ||
for(TopoDS_Shape &sh: this->myShapesToReturn){ | ||
builder.Add(cmp_res,sh); | ||
} | ||
this->myShape = cmp_res; | ||
} | ||
this->Done(); | ||
} | ||
|
||
std::unique_ptr<Part::FaceMaker> Part::FaceMaker::ConstructFromType(const char* className) | ||
{ | ||
Base::Type fmType = Base::Type::fromName(className); | ||
if (fmType.isBad()){ | ||
std::stringstream ss; | ||
ss << "Class '"<< className <<"' not found."; | ||
throw Base::Exception(ss.str().c_str()); | ||
} | ||
return Part::FaceMaker::ConstructFromType(fmType); | ||
} | ||
|
||
std::unique_ptr<Part::FaceMaker> Part::FaceMaker::ConstructFromType(Base::Type type) | ||
{ | ||
if (!type.isDerivedFrom(Part::FaceMaker::getClassTypeId())){ | ||
std::stringstream ss; | ||
ss << "Class '" << type.getName() << "' is not derived from Part::FaceMaker."; | ||
throw Base::TypeError(ss.str().c_str()); | ||
} | ||
return std::unique_ptr<FaceMaker>(static_cast<Part::FaceMaker*>(type.createInstance())); | ||
} | ||
|
||
void Part::FaceMaker::throwNotImplemented() | ||
{ | ||
throw Base::NotImplementedError("Not implemente yet..."); | ||
} | ||
|
||
|
||
//---------------------------------------------------------------------------------------- | ||
|
||
TYPESYSTEM_SOURCE(Part::FaceMakerSimple, Part::FaceMakerPublic); | ||
|
||
|
||
std::string Part::FaceMakerSimple::getUserFriendlyName() const | ||
{ | ||
return std::string(QT_TRANSLATE_NOOP("Part_FaceMaker","Simple")); | ||
} | ||
|
||
std::string Part::FaceMakerSimple::getBriefExplanation() const | ||
{ | ||
return std::string(QT_TRANSLATE_NOOP("Part_FaceMaker","Makes separate plane face from every wire independently. No support for holes; wires can be on different planes.")); | ||
} | ||
|
||
void Part::FaceMakerSimple::Build_Essence() | ||
{ | ||
for(TopoDS_Wire &w: myWires){ | ||
this->myShapesToReturn.push_back(BRepBuilderAPI_MakeFace(w).Shape()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
/*************************************************************************** | ||
* Copyright (c) 2016 Victor Titov (DeepSOIC) <vv.titov@gmail.com> * | ||
* * | ||
* This file is part of the FreeCAD CAx development system. * | ||
* * | ||
* This library is free software; you can redistribute it and/or * | ||
* modify it under the terms of the GNU Library General Public * | ||
* License as published by the Free Software Foundation; either * | ||
* version 2 of the License, or (at your option) any later version. * | ||
* * | ||
* This library is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU Library General Public License for more details. * | ||
* * | ||
* You should have received a copy of the GNU Library General Public * | ||
* License along with this library; see the file COPYING.LIB. If not, * | ||
* write to the Free Software Foundation, Inc., 59 Temple Place, * | ||
* Suite 330, Boston, MA 02111-1307, USA * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef PART_FACEMAKER_H | ||
#define PART_FACEMAKER_H | ||
|
||
#include <BRepBuilderAPI_MakeShape.hxx> | ||
#include <Base/BaseClass.h> | ||
#include <TopoDS_Wire.hxx> | ||
#include <TopoDS_Compound.hxx> | ||
#include <TopoDS_Face.hxx> | ||
|
||
#include <memory> | ||
|
||
namespace Part | ||
{ | ||
|
||
/** | ||
* @brief FaceMaker class is the base class for implementing various "smart" | ||
* face making routines. This was created to address the problem of multiple | ||
* private implementations of making faces with holes, which are quite complex. | ||
* The two most important facemaking routines then was: one in Part Extrude, | ||
* and one in PartDesign (there, it is used in every sketch-based feature). | ||
* Plus, another one (new) was needed for filling 2D offset. | ||
*/ | ||
class PartExport FaceMaker: public BRepBuilderAPI_MakeShape, public Base::BaseClass | ||
{ | ||
TYPESYSTEM_HEADER(); | ||
|
||
public: | ||
FaceMaker() {}; | ||
virtual ~FaceMaker() {}; | ||
|
||
virtual void addWire(const TopoDS_Wire& w); | ||
/** | ||
* @brief addShape: add another wire, edge, or compound. If compound is | ||
* added, its internals will be treated as isolated from the rest, and the | ||
* compounding structure of result will follow. | ||
* @param sh | ||
*/ | ||
virtual void addShape(const TopoDS_Shape& sh); | ||
/** | ||
* @brief useCompound: add children of compound to the FaceMaker. Note that | ||
* this is different from addShape(comp) - structure is lost. The compound | ||
* is NOT expanded recursively. | ||
* @param comp | ||
*/ | ||
virtual void useCompound(const TopoDS_Compound &comp); | ||
|
||
/** | ||
* @brief Face: returns the face (result). If result is not a single face, | ||
* throws Base::TypeError. (hint: use .Shape() instead) | ||
* @return | ||
*/ | ||
virtual const TopoDS_Face& Face(); | ||
|
||
virtual void Build(); | ||
|
||
//fails to compile, huh! | ||
//virtual const TopTools_ListOfShape& Generated(const TopoDS_Shape &S) override {throwNotImplemented();} | ||
//virtual const TopTools_ListOfShape& Modified(const TopoDS_Shape &S) override {throwNotImplemented();} | ||
//virtual Standard_Boolean IsDeleted(const TopoDS_Shape &S) override {throwNotImplemented();} | ||
|
||
static std::unique_ptr<FaceMaker> ConstructFromType(const char* className); | ||
static std::unique_ptr<FaceMaker> ConstructFromType(Base::Type type); | ||
|
||
protected: | ||
std::vector<TopoDS_Shape> mySourceShapes; //wire or compound | ||
std::vector<TopoDS_Wire> myWires; //wires from mySourceShapes | ||
std::vector<TopoDS_Compound> myCompounds; //compounds, for recursive processing | ||
std::vector<TopoDS_Shape> myShapesToReturn; | ||
|
||
/** | ||
* @brief Build_Essence: build routine that can assume there is no nesting. | ||
* | ||
* Implementing instructions: | ||
* Add new faces (or whatever) to myShapesToReturn. The rest is done by | ||
* base class's Build(). Please ignore contents of myCompounds in | ||
* implementation. If special handling of nesting is required, override | ||
* whole Build(). | ||
*/ | ||
virtual void Build_Essence() = 0; | ||
|
||
static void throwNotImplemented(); | ||
}; | ||
|
||
/** | ||
* @brief The FaceMakerPublic class: derive from it if you want the face maker to be listed in tools that allow choosing one. | ||
*/ | ||
class PartExport FaceMakerPublic : public FaceMaker | ||
{ | ||
TYPESYSTEM_HEADER(); | ||
public: | ||
virtual std::string getUserFriendlyName() const = 0; | ||
virtual std::string getBriefExplanation() const = 0; | ||
}; | ||
|
||
|
||
|
||
/** | ||
* @brief The FaceMakerSimple class: make plane faces from all closed wires | ||
* supplied, ignoring overlaps. | ||
* | ||
* Strengths: can work with non-coplanar sets of wires. Will not make broken | ||
* faces if wires overlap*. | ||
* | ||
* Limitations: can't make faces with holes (will generate overlapping faces | ||
* instead). Can't make faces from nonplanar wires. | ||
* | ||
* * Compound of valid but overlapping faces is created. The compound is invalid | ||
* for BOPs, but the faces themselves are valid, provided that the source wires | ||
* are valid. | ||
*/ | ||
class PartExport FaceMakerSimple : public FaceMakerPublic | ||
{ | ||
TYPESYSTEM_HEADER(); | ||
public: | ||
virtual std::string getUserFriendlyName() const override; | ||
virtual std::string getBriefExplanation() const override; | ||
protected: | ||
virtual void Build_Essence() override; | ||
}; | ||
|
||
|
||
}//namespace Part | ||
#endif // PART_FACEMAKER_H |