PartDesign: Make Base Feature compatible with GeoFeatureGroup. fixes #0003080

The Original BaseFeature implementation had some serious issues with scoped links. It failed completely for e.g. sketches on the BaseFeature as it made a local link to refere to a out of body object. The only solution to make this work correctly is to add a proxy object into the body which is alloed to exactly that, to link outside oof the body. Something like shapebinder.
This commit is contained in:
Stefan Tröger
2017-09-16 15:47:07 +02:00
committed by wmayer
parent 30f930404c
commit de31528dda
15 changed files with 820 additions and 47 deletions

View File

@@ -58,6 +58,7 @@
#include "FeaturePipe.h"
#include "FeatureLoft.h"
#include "ShapeBinder.h"
#include "FeatureBase.h"
namespace PartDesign {
extern PyObject* initModule();
@@ -146,6 +147,7 @@ PyMOD_INIT_FUNC(_PartDesign)
PartDesign::Wedge ::init();
PartDesign::AdditiveWedge ::init();
PartDesign::SubtractiveWedge ::init();
PartDesign::FeatureBase ::init();
PyMOD_Return(mod);
}

View File

@@ -47,6 +47,7 @@
#include "ShapeBinder.h"
#include "Body.h"
#include "FeatureBase.h"
#include "BodyPy.h"
using namespace PartDesign;
@@ -109,8 +110,7 @@ void Body::onChanged(const App::Property *prop)
short Body::mustExecute() const
{
if ( Tip.isTouched() ||
BaseFeature.isTouched() ) {
if ( Tip.isTouched() ) {
return 1;
}
return Part::BodyBase::mustExecute();
@@ -133,18 +133,13 @@ App::DocumentObject* Body::getPrevFeature(App::DocumentObject *start) const
App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start)
{
App::DocumentObject* baseFeature = BaseFeature.getValue();
if ( !start ) { // default to tip
start = Tip.getValue();
}
if ( !start ) { // No Tip
return nullptr;
} else if ( start == baseFeature ) { // The base feature always considered as the first solid
return nullptr;
}
if (!hasObject(start))
return nullptr;
@@ -156,15 +151,13 @@ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start)
if (rvIt != features.rend()) { // the solid found in model list
return *rvIt;
} else { // if solid is not present in the list the previous one is baseFeature
return baseFeature; // return it either it's set or nullptr
}
return nullptr;
}
App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start)
{
App::DocumentObject* baseFeature = BaseFeature.getValue();
if ( !start ) { // default to tip
start = Tip.getValue();
}
@@ -178,14 +171,9 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start)
const std::vector<App::DocumentObject*> & features = Group.getValues();
std::vector<App::DocumentObject*>::const_iterator startIt;
if ( start == baseFeature ) {
// Handle the base feature, it's always considered to be solid
startIt = features.begin();
} else {
startIt = std::find ( features.begin(), features.end(), start );
assert ( startIt != features.end() );
startIt++;
}
startIt = std::find ( features.begin(), features.end(), start );
assert ( startIt != features.end() );
startIt++;
if (startIt == features.end() ) { // features list is empty
return nullptr;
@@ -195,9 +183,9 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start)
if (rvIt != features.end()) { // the solid found in model list
return *rvIt;
} else {
return nullptr;
}
return nullptr;
}
bool Body::isAfterInsertPoint(App::DocumentObject* feature) {
@@ -299,18 +287,8 @@ std::vector< App::DocumentObject* > Body::addObjects(std::vector< App::DocumentO
void Body::insertObject(App::DocumentObject* feature, App::DocumentObject* target, bool after)
{
if (target) {
if (target == BaseFeature.getValue()) {
// Handle the insertion relative to the base feature in a special way
if (after) {
target = nullptr;
} else {
throw Base::Exception("Body: impossible to insert before the base object");
}
} else if (!hasObject (target)) {
// Check if the target feature belongs to the body
throw Base::Exception("Body: the feature we should insert relative to is not part of that body");
}
if (target && !hasObject (target)) {
throw Base::Exception("Body: the feature we should insert relative to is not part of that body");
}
//ensure that all origin links are ok
@@ -420,8 +398,7 @@ App::DocumentObjectExecReturn *Body::execute(void)
Part::TopoShape tipShape;
if ( tip ) {
if ( !tip->getTypeId().isDerivedFrom ( PartDesign::Feature::getClassTypeId() )
&& tip != BaseFeature.getValue () ) {
if ( !tip->getTypeId().isDerivedFrom ( PartDesign::Feature::getClassTypeId() ) ) {
return new App::DocumentObjectExecReturn ( "Linked object is not a PartDesign feature" );
}
@@ -454,11 +431,32 @@ void Body::onSettingDocument() {
void Body::onChanged (const App::Property* prop) {
if ( prop == &BaseFeature ) {
App::DocumentObject *baseFeature = BaseFeature.getValue();
App::DocumentObject *nextSolid = getNextSolidFeature ( baseFeature );
if ( nextSolid ) {
assert ( nextSolid->isDerivedFrom ( PartDesign::Feature::getClassTypeId () ) );
static_cast<PartDesign::Feature*>(nextSolid)->BaseFeature.setValue( baseFeature );
FeatureBase* bf = nullptr;
auto first = Group.getValues().empty() ? nullptr : Group.getValues().front();
if(BaseFeature.getValue()) {
//setup the FeatureBase if needed
if(!first || !first->isDerivedFrom(FeatureBase::getClassTypeId())) {
bf = static_cast<FeatureBase*>(getDocument()->addObject("PartDesign::FeatureBase", "BaseFeature"));
insertObject(bf, first, false);
if(!Tip.getValue())
Tip.setValue(bf);
}
else
bf = static_cast<FeatureBase*>(first);
}
if(bf && (bf->BaseFeature.getValue() != BaseFeature.getValue()))
bf->BaseFeature.setValue(BaseFeature.getValue());
}
else if( prop == &Group ) {
//if the FeatureBase was deleted we set the BaseFeature link to nullptr
if(BaseFeature.getValue() &&
(Group.getValues().empty() || !Group.getValues().front()->isDerivedFrom(FeatureBase::getClassTypeId()))) {
BaseFeature.setValue(nullptr);
}
}

View File

@@ -37,6 +37,8 @@ SET(Features_SRCS
FeatureSolid.h
Body.cpp
Body.h
FeatureBase.h
FeatureBase.cpp
)
SOURCE_GROUP("Features" FILES ${Features_SRCS})

View File

@@ -55,6 +55,7 @@ Feature::Feature()
{
ADD_PROPERTY(BaseFeature,(0));
Placement.setStatus(App::Property::Hidden, true);
BaseFeature.setStatus(App::Property::Hidden, true);
}
short Feature::mustExecute() const
@@ -176,6 +177,20 @@ TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj)
return builder.Shape();
}
Body* Feature::getFeatureBody() {
auto list = getInList();
for (auto in : list) {
if(in->isDerivedFrom(Body::getClassTypeId()) && //is Body?
static_cast<Body*>(in)->hasObject(this)) { //is part of this Body?
return static_cast<Body*>(in);
}
}
return nullptr;
};
}//namespace PartDesign
namespace App {

View File

@@ -56,6 +56,9 @@ public:
/// Check whether the given feature is a datum feature
static bool isDatum(const App::DocumentObject* feature);
/// Returns the body the feature is in, or none
Body* getFeatureBody();
/**
* Returns the BaseFeature property's object (if any)
* @param silent if couldn't determine the base feature and silent == true,

View File

@@ -0,0 +1,97 @@
/***************************************************************************
* Copyright (c) 2017 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 <Standard_Failure.hxx>
#endif
#include <Base/Exception.h>
#include <App/FeaturePythonPyImp.h>
#include "Body.h"
#include "FeatureBase.h"
#include "FeaturePy.h"
namespace PartDesign {
PROPERTY_SOURCE(PartDesign::FeatureBase,PartDesign::Feature)
FeatureBase::FeatureBase()
{
BaseFeature.setScope(App::LinkScope::Global);
BaseFeature.setStatus(App::Property::Hidden, false);
}
Part::Feature* FeatureBase::getBaseObject(bool) const {
return nullptr;
}
short int FeatureBase::mustExecute(void) const {
if(BaseFeature.isTouched())
return 1;
return Part::Feature::mustExecute();
}
App::DocumentObjectExecReturn* FeatureBase::execute(void) {
if(!BaseFeature.getValue())
return new App::DocumentObjectExecReturn("BaseFeature link is not set");
if(!BaseFeature.getValue()->isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("BaseFeature must be a Part::Feature");
auto shape = static_cast<Part::Feature*>(BaseFeature.getValue())->Shape.getValue();
if(shape.IsNull())
return new App::DocumentObjectExecReturn("BaseFeature has a empty shape");
Shape.setValue(shape);
return StdReturn;
}
void FeatureBase::onChanged(const App::Property* prop) {
// the BaseFeature property should track the Body BaseFeature and vice-versa
if (prop == &BaseFeature) {
auto body = getFeatureBody();
if(!body)
return;
if (BaseFeature.getValue() && body->BaseFeature.getValue() != BaseFeature.getValue()) {
body->BaseFeature.setValue(BaseFeature.getValue());
}
}
Part::Feature::onChanged(prop);
}
}//namespace PartDesign

View File

@@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (c) 2017 Stefan Tröger <stefantroeger@gmx.net> *
* *
* 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 PARTDESIGN_FeatureBase_H
#define PARTDESIGN_FeatureBase_H
#include <App/PropertyStandard.h>
#include "Feature.h"
/// Base class of all additive features in PartDesign
namespace PartDesign
{
class PartDesignExport FeatureBase : public PartDesign::Feature
{
PROPERTY_HEADER(PartDesign::FeatureBase);
public:
FeatureBase();
virtual short int mustExecute(void) const;
virtual Part::Feature* getBaseObject(bool silent=false) const;
virtual const char* getViewProviderName() const {
return "PartDesignGui::ViewProviderBase";
}
virtual void onChanged(const App::Property* prop);
virtual App::DocumentObjectExecReturn* execute(void);
};
} //namespace PartDesign
#endif // PARTDESIGN_FeatureBase_H