Skip to content

Commit

Permalink
PartDesign: add SubShapeBinder
Browse files Browse the repository at this point in the history
The SubShapeBinder utilize the newly added
DocumentObject::getSubObject() api to obtain any sub-object exposed by
the parent object, e.g. children of group objects, internal geometry of
sketches, etc.

Because of its usefulness, the SubShapeBinder creation command allows
to create the binder object without an active body, meaning that it can
be freely used outside of PartDesign.
  • Loading branch information
realthunder committed Feb 18, 2018
1 parent a2f057a commit 73035a6
Show file tree
Hide file tree
Showing 13 changed files with 724 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/Mod/PartDesign/App/AppPartDesign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ PyMOD_INIT_FUNC(_PartDesign)
PartDesign::AdditiveLoft ::init();
PartDesign::SubtractiveLoft ::init();
PartDesign::ShapeBinder ::init();
PartDesign::SubShapeBinder ::init();
PartDesign::Plane ::init();
PartDesign::Line ::init();
PartDesign::Point ::init();
Expand Down
1 change: 1 addition & 0 deletions src/Mod/PartDesign/App/FeatureSketchBased.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ PROPERTY_SOURCE(PartDesign::ProfileBased, PartDesign::FeatureAddSub)
ProfileBased::ProfileBased()
{
ADD_PROPERTY_TYPE(Profile,(0),"SketchBased", App::Prop_None, "Reference to sketch");
ADD_PROPERTY_TYPE(ClaimChildren, (false), "Base",App::Prop_Output,"Claim linked object as children");
ADD_PROPERTY_TYPE(Midplane,(0),"SketchBased", App::Prop_None, "Extrude symmetric to sketch face");
ADD_PROPERTY_TYPE(Reversed, (0),"SketchBased", App::Prop_None, "Reverse extrusion direction");
ADD_PROPERTY_TYPE(UpToFace,(0),"SketchBased",(App::PropertyType)(App::Prop_None),"Face where feature will end");
Expand Down
2 changes: 2 additions & 0 deletions src/Mod/PartDesign/App/FeatureSketchBased.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class PartDesignExport ProfileBased : public PartDesign::FeatureAddSub
App::PropertyBool Midplane;
/// Face to extrude up to
App::PropertyLinkSub UpToFace;
/// Force claim linked profile as children
App::PropertyBool ClaimChildren;

App::PropertyBool Refine;

Expand Down
162 changes: 161 additions & 1 deletion src/Mod/PartDesign/App/ShapeBinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,19 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cfloat>
#include <BRepBuilderAPI_MakeFace.hxx>
# include <BRepBuilderAPI_MakeFace.hxx>
# include <BRepBuilderAPI_MakeWire.hxx>
# include <BRep_Builder.hxx>
# include <BRep_Tool.hxx>
# include <TopExp_Explorer.hxx>
# include <TopoDS.hxx>
# include <Precision.hxx>
#endif

#include <App/Document.h>
#include "ShapeBinder.h"
#include <Mod/Part/App/TopoShape.h>
#include <Mod/Part/App/FaceMakerBullseye.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846
Expand Down Expand Up @@ -159,3 +167,155 @@ void ShapeBinder::handleChangedPropertyType(Base::XMLReader &reader, const char
Support.Restore(reader);
}
}

// ============================================================================

namespace Part {
PartExport std::list<TopoDS_Edge> sort_Edges(double tol3d, std::list<TopoDS_Edge>& edges);
}

// ============================================================================

PROPERTY_SOURCE(PartDesign::SubShapeBinder, PartDesign::ShapeBinder)

SubShapeBinder::SubShapeBinder()
{
ADD_PROPERTY_TYPE(Fuse, (true), "Base",App::Prop_None,"Fused linked solid shapes");
ADD_PROPERTY_TYPE(MakeFace, (true), "Base",App::Prop_None,"Create face for linked wires");
ADD_PROPERTY_TYPE(ClaimChildren, (false), "Base",App::Prop_Output,"Claim linked object as children");
ADD_PROPERTY_TYPE(Relative, (false), "Base",App::Prop_None,"Enable relative sub-object linking");
Placement.setStatus(App::Property::Hidden, true);
}

App::DocumentObjectExecReturn* SubShapeBinder::execute(void) {
if(this->isRestoring())
return Part::Feature::execute();

BRep_Builder builder;
TopoDS_Compound comp;
builder.MakeCompound(comp);

int count = 0;
auto subset = Support.getSubListValues();
for(auto &info : subset) {
auto obj = info.first;
if(!obj || !obj->getNameInDocument())
continue;
static std::string none("");
std::set<std::string> subs(info.second.begin(),info.second.end());
if(subs.empty())
subs.insert(none);
else if(subs.size()>1)
subs.erase(none);
for(const auto &sub : subs) {
auto shape = Part::Feature::getShape(obj,sub.c_str(),true);
if(!shape.IsNull()){
builder.Add(comp,shape);
++count;
}
}
}
if(!count)
return new App::DocumentObjectExecReturn("No shapes");

if(Fuse.getValue()) {
// If the compound has solid, fuse them together, and ignore other type of
// shapes
count = 0;
Part::TopoShape base;
std::vector<TopoDS_Shape> operators;
for(TopExp_Explorer it(comp, TopAbs_SOLID); it.More(); it.Next(),++count) {
if(!count)
base = it.Current();
else
operators.push_back(it.Current());
}
if(count) {
if(operators.empty())
Shape.setValue(base.getShape());
else
Shape.setValue(base.fuse(operators));
return Part::Feature::execute();
}
}

if(MakeFace.getValue() && !TopExp_Explorer(comp, TopAbs_FACE).More()) {
if(!TopExp_Explorer(comp, TopAbs_SHELL).More()) {
std::list<TopoDS_Edge> edges;
for(TopExp_Explorer it(comp,TopAbs_EDGE);it.More();it.Next())
edges.push_back(TopoDS::Edge(it.Current()));
if(edges.size()) {
Part::FaceMakerBullseye mkFace;
do {
BRepBuilderAPI_MakeWire mkWire;
for(auto &edge : Part::sort_Edges(Precision::Confusion(),edges))
mkWire.Add(edge);
mkFace.addWire(mkWire.Wire());
}while(edges.size());
try {
mkFace.Build();
const TopoDS_Shape &shape = mkFace.Shape();
if(!shape.IsNull()) {
Shape.setValue(shape);
return Part::Feature::execute();
}
}catch (Base::Exception &){}
}
}
}
Shape.setValue(comp);
return Part::Feature::execute();
}

void SubShapeBinder::setLinks(
const std::vector<std::pair<App::DocumentObject*,std::string> > &subs,
bool reset)
{
std::map<App::DocumentObject*, std::set<std::string> > values;
if(!reset) {
const auto &objs = Support.getValues();
const auto &subs = Support.getSubValues();
for(size_t i=0;i<objs.size();++i) {
auto obj = objs[i];
if(!obj || !obj->getNameInDocument())
continue;
values[obj].insert(subs[i]);
}
}
for(auto &info : subs) {
auto obj = info.first;
if(!obj || !obj->getNameInDocument())
continue;
if(obj->getDocument()!=getDocument())
throw Base::RuntimeError("Direct external linking is not allowed");
if(Relative.getValue())
values[obj].insert(info.second);
else {
auto &sub = info.second;
auto idx = sub.rfind('.');
if(idx == std::string::npos) {
values[obj].insert(sub);
continue;
}
auto sobj = obj->getSubObject(sub.c_str());
if(!sobj)
throw Base::RuntimeError("Cannot find sub object");
if(sobj->getDocument()!=getDocument())
values[obj].insert(info.second);
else
values[sobj].insert(sub.c_str()+idx+1);
}
}
auto inSet = getInListEx(true);
inSet.insert(this);
std::vector<App::PropertyLinkSubList::SubSet> newValues;
for(auto &value : values) {
newValues.emplace_back();
auto &newSub = newValues.back();
newSub.first = value.first;
if(inSet.find(value.first)!=inSet.end())
throw Base::RuntimeError("Cyclic dependency");
newSub.second.insert(newSub.second.end(),value.second.begin(),value.second.end());
}
Support.setSubListValues(newValues);
}
20 changes: 20 additions & 0 deletions src/Mod/PartDesign/App/ShapeBinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@ class PartDesignExport ShapeBinder : public Part::Feature
virtual App::DocumentObjectExecReturn* execute(void);
};

class PartDesignExport SubShapeBinder : public ShapeBinder {
PROPERTY_HEADER(PartDesign::SubShapeBinder);
public:
SubShapeBinder();
const char* getViewProviderName(void) const {
return "PartDesignGui::ViewProviderSubShapeBinder";
}

void setLinks(const std::vector<std::pair<App::DocumentObject*,std::string> > &subs,
bool reset=false);

App::PropertyBool ClaimChildren;
App::PropertyBool Relative;
App::PropertyBool Fuse;
App::PropertyBool MakeFace;

protected:
virtual App::DocumentObjectExecReturn* execute(void);
};

} //namespace PartDesign


Expand Down
1 change: 1 addition & 0 deletions src/Mod/PartDesign/Gui/AppPartDesignGui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ PyMOD_INIT_FUNC(PartDesignGui)
PartDesignGui::ViewProviderDatumPlane ::init();
PartDesignGui::ViewProviderDatumCoordinateSystem::init();
PartDesignGui::ViewProviderShapeBinder ::init();
PartDesignGui::ViewProviderSubShapeBinder::init();
PartDesignGui::ViewProviderBoolean ::init();
PartDesignGui::ViewProviderAddSub ::init();
PartDesignGui::ViewProviderPrimitive ::init();
Expand Down
71 changes: 71 additions & 0 deletions src/Mod/PartDesign/Gui/Command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,76 @@ bool CmdPartDesignShapeBinder::isActive(void)
return hasActiveDocument ();
}

//===========================================================================
// PartDesign_SubShapeBinder
//===========================================================================

DEF_STD_CMD_A(CmdPartDesignSubShapeBinder);

CmdPartDesignSubShapeBinder::CmdPartDesignSubShapeBinder()
:Command("PartDesign_SubShapeBinder")
{
sAppModule = "PartDesign";
sGroup = QT_TR_NOOP("PartDesign");
sMenuText = QT_TR_NOOP("Create a sub-object(s) shape binder");
sToolTipText = QT_TR_NOOP("Create a sub-object(s) shape binder");
sWhatsThis = "PartDesign_SubShapeBinder";
sStatusTip = sToolTipText;
sPixmap = "PartDesign_SubShapeBinder";
}

void CmdPartDesignSubShapeBinder::activated(int iMsg)
{
Q_UNUSED(iMsg);

PartDesign::SubShapeBinder *obj = 0;
std::vector<std::pair<App::DocumentObject*,std::string> > subs;
for(auto &sel : Gui::Selection().getSelection("",false)) {
if(!sel.pObject) continue;
if(!obj) {
const char *dot = sel.SubName?strrchr(sel.SubName,'.'):0;
if(!dot || dot[1]==0) {
auto sobj = sel.pObject->getSubObject(sel.SubName);
if(!sobj) continue;
obj = dynamic_cast<PartDesign::SubShapeBinder*>(sobj->getLinkedObject(true));
if(obj) continue;
}
}
subs.push_back(std::make_pair(sel.pObject,std::string(sel.SubName?sel.SubName:"")));
}

try {
if (obj)
openCommand("Change SubShapeBinder");
else {
PartDesign::Body *pcActiveBody = PartDesignGui::getBody(false);
std::string FeatName = getUniqueObjectName("Binder",pcActiveBody);

openCommand("Create SubShapeBinder");
if(pcActiveBody) {
FCMD_OBJ_CMD(pcActiveBody,"newObject('PartDesign::SubShapeBinder','" << FeatName << "')");
}else
doCommand(Command::Doc,"App.ActiveDocument.addObject('PartDesign::SubShapeBinder','%s')",FeatName.c_str());
if(pcActiveBody)
obj = dynamic_cast<PartDesign::SubShapeBinder*>(pcActiveBody->getObject(FeatName.c_str()));
else
obj = dynamic_cast<PartDesign::SubShapeBinder*>(
App::GetApplication().getActiveDocument()->getObject(FeatName.c_str()));
if(!obj) return;
}
obj->setLinks(subs,true);
updateActive();
commitCommand();
}catch(Base::Exception &e) {
e.ReportException();
abortCommand();
}
}

bool CmdPartDesignSubShapeBinder::isActive(void)
{
return hasActiveDocument();
}
//===========================================================================
// PartDesign_Clone
//===========================================================================
Expand Down Expand Up @@ -2213,6 +2283,7 @@ void CreatePartDesignCommands(void)
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();

rcCmdMgr.addCommand(new CmdPartDesignShapeBinder());
rcCmdMgr.addCommand(new CmdPartDesignSubShapeBinder());
rcCmdMgr.addCommand(new CmdPartDesignClone());
rcCmdMgr.addCommand(new CmdPartDesignPlane());
rcCmdMgr.addCommand(new CmdPartDesignLine());
Expand Down
1 change: 1 addition & 0 deletions src/Mod/PartDesign/Gui/Resources/PartDesign.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<file>icons/PartDesign_Body.svg</file>
<file>icons/PartDesign_Boolean.svg</file>
<file>icons/PartDesign_ShapeBinder.svg</file>
<file>icons/PartDesign_SubShapeBinder.svg</file>
<file>icons/PartDesign_Clone.svg</file>
<file>icons/PartDesign_Plane.svg</file>
<file>icons/PartDesign_Line.svg</file>
Expand Down
Loading

0 comments on commit 73035a6

Please sign in to comment.