X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_ConstraintSplit.cpp;h=9ff84a54232f270380c0109a62c09e52b7ae6111;hb=1c292b5bf95e18a6c8fbe407c532213e10c673c5;hp=2647f986b6bfc08789e697c636c7784776a704b2;hpb=7c26163aa1b2f3384ed0b3bd3fb12188478f6189;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp index 2647f986b..9ff84a542 100755 --- a/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp @@ -6,8 +6,12 @@ #include "SketchPlugin_ConstraintSplit.h" +#include #include +#include #include +#include + #include #include #include @@ -15,6 +19,7 @@ #include #include +#include #include #include @@ -23,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,11 +41,15 @@ #include #include -#define DEBUG_SPLIT +#include + +//#define DEBUG_SPLIT #ifdef DEBUG_SPLIT #include #endif +static const double PI = 3.141592653589793238463; + SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit() { } @@ -62,10 +72,12 @@ void SketchPlugin_ConstraintSplit::execute() setError("Error: Base object is not initialized."); return; } - AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B())); - if (!aFirstPointAttr.get() || !aFirstPointAttr->isInitialized() || - !aSecondPointAttr.get() || !aSecondPointAttr->isInitialized()) { + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B())); + if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() || + !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) { setError("Error: Sub-shape is not initialized."); return; } @@ -80,15 +92,14 @@ void SketchPlugin_ConstraintSplit::execute() // Find feature constraints FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature); - - std::set aFeaturesToDelete; + std::set aFeaturesToDelete, aFeaturesToUpdate; std::map aTangentFeatures; std::map aCoincidenceToFeature; - std::map aCoincidenceToPoint; - getConstraints(aFeaturesToDelete, aTangentFeatures, aCoincidenceToFeature, aCoincidenceToPoint); + getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature); std::map > aBaseRefAttributes; - getRefAttributes(aBaseFeature, aBaseRefAttributes); + std::list aRefsToFeature; + getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature); std::map aBasePointModifiedAttributes; @@ -104,12 +115,13 @@ void SketchPlugin_ConstraintSplit::execute() } std::cout << std::endl; - std::cout << "IN PARAMETERS" << std::endl; + std::cout << "---- IN PARAMETERS ----" << std::endl; std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl; std::cout << std::endl; if (!aCoincidenceToFeature.empty()) { - std::cout << "Coincidences to base feature[" << aCoincidenceToFeature.size() << "]: " << std::endl; + std::cout << "Coincidences to base feature[" << + aCoincidenceToFeature.size() << "]: " << std::endl; std::map::const_iterator anIt = aCoincidenceToFeature.begin(), aLast = aCoincidenceToFeature.end(); for (int i = 1; anIt != aLast; anIt++, i++) { @@ -119,7 +131,8 @@ void SketchPlugin_ConstraintSplit::execute() std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl; std::cout << " -Attribute to correct:" << anAttributeId << std::endl; - std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl; + std::cout << " -Point attribute:" << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl; } } @@ -135,28 +148,15 @@ void SketchPlugin_ConstraintSplit::execute() std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl; std::cout << " -Attribute to correct:" << anAttributeId << std::endl; - std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl; + std::cout << " -Point attribute:" << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl; } } - if (!aCoincidenceToPoint.empty()) { - std::cout << std::endl; - std::cout << "Coincidences to points on base feature[" << aCoincidenceToPoint.size() << "]: " << std::endl; - std::map::const_iterator anIt = aCoincidenceToPoint.begin(), - aLast = aCoincidenceToPoint.end(); - for (int i = 1; anIt != aLast; anIt++, i++) { - FeaturePtr aFeature = (*anIt).first; - std::string anAttributeId = (*anIt).second.first; - std::shared_ptr aPointAttr = (*anIt).second.second; - - std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl; - std::cout << " -Attribute to correct:" << anAttributeId << std::endl; - std::cout << " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl; - } - } - std::map >::const_iterator aRefIt = aBaseRefAttributes.begin(), - aRefLast = aBaseRefAttributes.end(); - std::cout << "References to bound point of feature [" << aBaseRefAttributes.size() << "]" < >::const_iterator + aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end(); + std::cout << std::endl << "References to attributes of base feature [" << + aBaseRefAttributes.size() << "]" << std::endl; for (; aRefIt != aRefLast; aRefIt++) { AttributePtr aBaseAttr = aRefIt->first; std::list aRefAttributes = aRefIt->second; @@ -164,16 +164,34 @@ void SketchPlugin_ConstraintSplit::execute() std::list::const_iterator aRefAttrIt = aRefAttributes.begin(), aRefAttrLast = aRefAttributes.end(); for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) { + if (!aRefsInfo.empty()) + aRefsInfo.append(","); AttributePtr aRAttr = *aRefAttrIt; aRefsInfo.append(aRAttr->id()); FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner()); aRefsInfo.append("(" + aRFeature->name() + ") "); } - - std::shared_ptr aPointAttr = std::dynamic_pointer_cast(aBaseAttr); - std::cout << " -Point attribute:" << aPointAttr->id().c_str() - << "[" << aRefAttributes.size() << "]" << aRefsInfo << std::endl; + std::shared_ptr aPointAttr = + std::dynamic_pointer_cast(aBaseAttr); + std::cout << aPointAttr->id().c_str() << + ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl; } + std::cout << std::endl; + std::cout << std::endl << "References to base feature [" << + aRefsToFeature.size() << "]" << std::endl; + std::list::const_iterator aRefAttrIt = aRefsToFeature.begin(), + aRefAttrLast = aRefsToFeature.end(); + std::string aRefsInfo; + for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) { + if (!aRefsInfo.empty()) + aRefsInfo.append(","); + AttributePtr aRAttr = *aRefAttrIt; + aRefsInfo.append(aRAttr->id()); + FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner()); + aRefsInfo.append("(" + aRFeature->name() + ") "); + } + std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl; + std::cout << std::endl; std::cout << "---- SPLIT ----" << std::endl; @@ -184,19 +202,27 @@ void SketchPlugin_ConstraintSplit::execute() FeaturePtr aSplitFeature, anAfterFeature; std::set aFurtherCoincidences; std::set aCreatedFeatures; + std::set> aModifiedAttributes; if (aFeatureKind == SketchPlugin_Line::ID()) - splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures); + splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures, + aModifiedAttributes); else if (aFeatureKind == SketchPlugin_Arc::ID()) - splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures); + splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures, + aModifiedAttributes); if (aFeatureKind == SketchPlugin_Circle::ID()) { FeaturePtr aCircleFeature = aBaseFeature; - splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures); + splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, + aCreatedFeatures, aModifiedAttributes); + + updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature); + aFeaturesToDelete.insert(aCircleFeature); - aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute + // as circle is removed, temporary fill this attribute*/ + aBaseObjectAttr->setObject(ResultPtr()); } #ifdef DEBUG_SPLIT - std::cout << "OUT PARAMETERS" << std::endl; + std::cout << "---- OUT PARAMETERS ----" << std::endl; std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl; std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl; std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl; @@ -219,6 +245,30 @@ void SketchPlugin_ConstraintSplit::execute() std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl; } + + std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl; + std::set >::const_iterator + aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end(); + std::string aResInfo; + for (; aPIt != aPLast; aPIt++) { + if (!aResInfo.empty()) + aResInfo += "\n"; + + std::pair aPair = *aPIt; + + AttributePtr anAttr = aPair.first; + aResInfo.append(anAttr->id()); + FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner()); + aResInfo.append("(" + aFeature->name() + ") "); + + aResInfo.append(" - is modified to - "); + + anAttr = aPair.second; + aResInfo.append(anAttr->id()); + aFeature = ModelAPI_Feature::feature(anAttr->owner()); + aResInfo.append("(" + aFeature->name() + ") "); + } + std::cout << aResInfo << std::endl; #endif std::set aFeatureResults; @@ -229,12 +279,11 @@ void SketchPlugin_ConstraintSplit::execute() // coincidence to feature updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences, aFeatureResults); - // coincidence to points - updateCoincidenceConstraintsToFeature(aCoincidenceToPoint, aFurtherCoincidences, - std::set()); // tangency updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences); + updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes); + // delete constraints #ifdef DEBUG_SPLIT std::cout << "remove features and references:" << std::endl; @@ -247,6 +296,17 @@ void SketchPlugin_ConstraintSplit::execute() #endif ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete); +#ifdef DEBUG_SPLIT + std::cout << "update features after split:" << std::endl; + std::set::const_iterator anUIt = aFeaturesToUpdate.begin(), + anULast = aFeaturesToUpdate.end(); + for (; anUIt != anULast; anUIt++) { + std::cout << getFeatureInfo(*anUIt, false) << std::endl; + std::cout << std::endl; + } +#endif + updateFeaturesAfterSplit(aFeaturesToUpdate); + // Send events to update the sub-features by the solver. if(isUpdateFlushed) { Events_Loop::loop()->setFlushed(anUpdateEvent, true); @@ -265,13 +325,64 @@ bool SketchPlugin_ConstraintSplit::isMacro() const return true; } +AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious) +{ + AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Constraint::VALUE())); + FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value()); + + AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr( + data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr( + data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + + if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() && + aFirstPointAttrOfSplit->isInitialized() && + aSecondPointAttrOfSplit->isInitialized()) { + + ResultPtr aResult = getFeatureResult(aBaseFeature); + GeomShapePtr aBaseShape = aResult->shape(); + std::list > aPoints; + + std::shared_ptr aStartPnt2d = aFirstPointAttrOfSplit->pnt(); + std::shared_ptr aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y()); + aPoints.push_back(aStartPoint); + + std::shared_ptr aSecondPnt2d = aSecondPointAttrOfSplit->pnt(); + std::shared_ptr aSecondPoint = + sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y()); + aPoints.push_back(aSecondPoint); + + std::set > aSplitShapes; + + GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes); + std::shared_ptr aShape = + GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes); + + AISObjectPtr anAIS = thePrevious; + if (aShape) { + if (!anAIS) + anAIS = AISObjectPtr(new GeomAPI_AISObject); + anAIS->createShape(aShape); + anAIS->setWidth(5); + std::vector aColor; + aColor = Config_PropManager::color("Visualization", "sketch_entity_color", + SKETCH_ENTITY_COLOR); + anAIS->setColor(aColor[0], aColor[1], aColor[2]); + } + return anAIS; + } + return AISObjectPtr(); +} + std::shared_ptr SketchPlugin_ConstraintSplit::getPointOfRefAttr( - const AttributePtr& theAttribute) + const AttributePtr& theAttribute) { AttributePoint2DPtr aPointAttribute; if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); if (aRefAttr.get() && aRefAttr->isInitialized()) { AttributePtr anAttribute = aRefAttr->attr(); if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId()) @@ -302,16 +413,16 @@ void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStar } if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) { theStartPointAttr = std::dynamic_pointer_cast( - aBaseFeature->attribute(aStartAttributeName)); + aBaseFeature->attribute(aStartAttributeName)); theEndPointAttr = std::dynamic_pointer_cast( - aBaseFeature->attribute(anEndAttributeName)); + aBaseFeature->attribute(anEndAttributeName)); } } void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeaturesToDelete, + std::set& theFeaturesToUpdate, std::map& theTangentFeatures, - std::map& theCoincidenceToFeature, - std::map& theCoincidenceToPoint) + std::map& theCoincidenceToFeature) { std::shared_ptr aData = data(); @@ -334,19 +445,36 @@ void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeatu aRefFeatureKind == SketchPlugin_MultiRotation::ID() || aRefFeatureKind == SketchPlugin_MultiTranslation::ID()) theFeaturesToDelete.insert(aRefFeature); + else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) + theFeaturesToUpdate.insert(aRefFeature); else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) { if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion - theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented + /// until tangency between arc and line is implemented + theFeaturesToDelete.insert(aRefFeature); else { std::string anAttributeToBeModified; AttributePoint2DPtr aTangentPoint; ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object(); ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object(); if (aResult1.get() && aResult2.get()) { - FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature - (ModelAPI_Feature::feature(aResult1), - ModelAPI_Feature::feature(aResult2)); - aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature); + FeaturePtr aCoincidenceFeature = + SketchPlugin_ConstraintCoincidence::findCoincidenceFeature + (ModelAPI_Feature::feature(aResult1), + ModelAPI_Feature::feature(aResult2)); + // get the point not lying on the splitting feature + for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { + AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i)); + if (!aRefAttr || aRefAttr->isObject()) + continue; + AttributePoint2DPtr aPoint = + std::dynamic_pointer_cast(aRefAttr->attr()); + if (!aPoint) + continue; + if (aPoint->owner() != aBaseFeature) { + aTangentPoint = aPoint; + break; + } + } } if (aTangentPoint.get()) { FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1); @@ -354,8 +482,8 @@ void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeatu ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B(); theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint); } - else - theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint + else /// there is not coincident point between tangent constraint + theFeaturesToDelete.insert(aRefFeature); } } else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) { @@ -404,33 +532,32 @@ void SketchPlugin_ConstraintSplit::getConstraints(std::set& theFeatu if (anAttribute.get()) aCoincidentPoint = std::dynamic_pointer_cast(anAttribute); } - if (aCoincidentPoint.get()) { - if (isToFeature) - theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified, - aCoincidentPoint); - else - theCoincidenceToPoint[aRefFeature] = std::make_pair(anAttributeToBeModified, + if (aCoincidentPoint.get() && isToFeature) + theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified, aCoincidentPoint); - } - else - theFeaturesToDelete.insert(aRefFeature); /// this case should not happen } } } void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature, - std::map >& theRefs) + std::map >& theRefs, + std::list& theRefsToFeature) { theRefs.clear(); - std::list aPointAttributes = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list aPointAttributes = + theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); std::set aPointAttributesSet; - std::list::const_iterator aPIt = aPointAttributes.begin(), aPLast = aPointAttributes.end(); + std::list::const_iterator aPIt = + aPointAttributes.begin(), aPLast = aPointAttributes.end(); for (; aPIt != aPLast; aPIt++) aPointAttributesSet.insert(*aPIt); - const std::set& aRefsAttributes = theFeature->data()->refsToMe(); + std::set aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe(); + std::set aFRefsList = theFeature->data()->refsToMe(); + aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end()); + std::set::const_iterator aIt; for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) { AttributePtr anAttr = (*aIt); @@ -438,9 +565,10 @@ void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature if (anAttrFeature.get() != this && anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) { AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttr); - if (!aRefAttr->isObject()) { + if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes AttributePtr anAttrInRef = aRefAttr->attr(); - if (anAttrInRef.get() && aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) { + if (anAttrInRef.get() && + aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) { if (theRefs.find(anAttrInRef) != theRefs.end()) theRefs[anAttrInRef].push_back(aRefAttr); else { @@ -450,6 +578,9 @@ void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature } } } + else { /// find attributes referenced to feature itself + theRefsToFeature.push_back(anAttr); + } } } } @@ -482,6 +613,7 @@ void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature( aFeaturePointAttribute = aFCAttribute; } if (aFeaturePointAttribute.get()) { + aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr()); aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute); } else { @@ -535,7 +667,8 @@ void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature( aFeaturePointAttribute = aFCAttribute; } if (aFeaturePointAttribute.get()) { - FeaturePtr aFeature = std::dynamic_pointer_cast(aFeaturePointAttribute->owner()); + FeaturePtr aFeature = + std::dynamic_pointer_cast(aFeaturePointAttribute->owner()); aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature)); } #ifdef DEBUG_SPLIT @@ -544,11 +677,59 @@ void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature( } } +void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints( + const ResultPtr& theFeatureBaseResult, + const std::list& theRefsToFeature) +{ + std::list::const_iterator anIt = theRefsToFeature.begin(), + aLast = theRefsToFeature.end(); + for (; anIt != aLast; anIt++) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIt); + if (aRefAttr.get()) + aRefAttr->setObject(theFeatureBaseResult); + } +} + +void SketchPlugin_ConstraintSplit::updateRefAttConstraints( + const std::map >& theBaseRefAttributes, + const std::set >& theModifiedAttributes) +{ +#ifdef DEBUG_SPLIT + std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl; +#endif + + std::set >::const_iterator + anIt = theModifiedAttributes.begin(), aLast = theModifiedAttributes.end(); + for (; anIt != aLast; anIt++) { + AttributePtr anAttribute = anIt->first; + + /// not found in references + if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end()) + continue; + std::list aRefAttributes = theBaseRefAttributes.at(anAttribute); + std::list::const_iterator aRefIt = aRefAttributes.begin(), + aRLast = aRefAttributes.end(); + + AttributePtr aNewAttribute = anIt->second; + for (; aRefIt != aRLast; aRefIt++) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*aRefIt); + if (aRefAttr.get()) { + aRefAttr->setAttr(aNewAttribute); +#ifdef DEBUG_SPLIT + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner()); + std::cout << " -" << getFeatureInfo(aFeature) << std::endl; +#endif + } + } + } +} + void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature, FeaturePtr& theBaseFeatureModified, FeaturePtr& theAfterFeature, std::set& thePoints, - std::set& theCreatedFeatures) + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) { std::set aCreatedFeatures; FeaturePtr aConstraintFeature; @@ -565,38 +746,60 @@ void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature, if (aFeatureKind != SketchPlugin_Line::ID()) return; - AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); - AttributePoint2DPtr aStartPointAttr, anEndPointAttr; - getFeaturePoints(aStartPointAttr, anEndPointAttr); - if (!aStartPointAttr.get() && !anEndPointAttr.get()) { + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase); + if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) { setError("Error: Feature has no start and end points."); return; } - arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr); + arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase, + aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); - /// split feature - theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr); +#ifdef DEBUG_SPLIT + std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl; + std::cout << "Start point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl; + std::cout << "1st point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl; + std::cout << "2nd point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl; + std::cout << "End point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl; +#endif + + /// create a split feature + theSplitFeature = + createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); theCreatedFeatures.insert(theSplitFeature); // before split feature - if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { + if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_Line::START_ID()))); + } + else { theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here /// move end arc point to start of split } // after split feature - if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) { + if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) { FeaturePtr aFeature; if (!theBaseFeatureModified.get()) { aFeature = aBaseFeature; ///< use base feature to store all constraints here - fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttr); + fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit); aFeature->execute(); // to update result } else { - aFeature = createLineFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr); + aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase); theCreatedFeatures.insert(aFeature); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + aFeature->attribute(SketchPlugin_Line::END_ID()))); } aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), theSplitFeature->attribute(SketchPlugin_Line::END_ID()), @@ -613,16 +816,19 @@ void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature, else theAfterFeature = aFeature; } - else + else { thePoints.insert(std::dynamic_pointer_cast (theSplitFeature->attribute(SketchPlugin_Line::END_ID()))); - + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_Line::END_ID()))); + } // base split, that is defined before split feature should be changed at end // (after the after feature creation). Otherwise modified value will be used in after feature // before split feature - if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { + if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { /// move end arc point to start of split - fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttr); + fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), + aFirstPointAttrOfSplit); theBaseFeatureModified->execute(); // to update result aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), @@ -655,7 +861,8 @@ void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature, FeaturePtr& theBaseFeatureModified, FeaturePtr& theAfterFeature, std::set& thePoints, - std::set& theCreatedFeatures) + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) { std::set aCreatedFeatures; FeaturePtr aConstraintFeature; @@ -672,38 +879,62 @@ void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature, if (aFeatureKind != SketchPlugin_Arc::ID()) return; - AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); - AttributePoint2DPtr aStartPointAttr, anEndPointAttr; - getFeaturePoints(aStartPointAttr, anEndPointAttr); - if (!aStartPointAttr.get() && !anEndPointAttr.get()) { + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase; + getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase); + if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) { setError("Error: Feature has no start and end points."); return; } - arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr); + // manually change type of arc to avoid incorrect self-constrainting of the tangent arc + aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue( + SketchPlugin_Arc::ARC_TYPE_CENTER_START_END()); + + arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase, + aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); +#ifdef DEBUG_SPLIT + std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl; + std::cout << "Start point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl; + std::cout << "1st point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl; + std::cout << "2nd point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl; + std::cout << "End point: " << + ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl; +#endif /// split feature - theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr); + theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); theCreatedFeatures.insert(theSplitFeature); // before split feature - if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { + if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { + theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_Arc::START_ID()))); + } + else { theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here /// move end arc point to start of split } // after split feature - if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) { + if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) { FeaturePtr aFeature; if (!theBaseFeatureModified.get()) { aFeature = aBaseFeature; ///< use base feature to store all constraints here - fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr); + fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit); aFeature->execute(); // to update result } else { - aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr); + aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase); theCreatedFeatures.insert(aFeature); + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + aFeature->attribute(SketchPlugin_Arc::END_ID()))); } aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), theSplitFeature->attribute(SketchPlugin_Arc::END_ID()), @@ -720,16 +951,19 @@ void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature, else theAfterFeature = aFeature; } - else + else { thePoints.insert(std::dynamic_pointer_cast (theSplitFeature->attribute(SketchPlugin_Arc::END_ID()))); - + theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase, + theSplitFeature->attribute(SketchPlugin_Arc::END_ID()))); + } // base split, that is defined before split feature should be changed at end // (after the after feature creation). Otherwise modified value will be used in after feature // before split feature - if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) { + if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) { /// move end arc point to start of split - fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr); + fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), + aFirstPointAttrOfSplit); theBaseFeatureModified->execute(); // to update result aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(), theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), @@ -770,7 +1004,8 @@ void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature, FeaturePtr& theBaseFeatureModified, FeaturePtr& theAfterFeature, std::set& thePoints, - std::set& theCreatedFeatures) + std::set& theCreatedFeatures, + std::set>& theModifiedAttributes) { std::set aCreatedFeatures; FeaturePtr aConstraintFeature; @@ -787,18 +1022,28 @@ void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature, if (aFeatureKind != SketchPlugin_Circle::ID()) return; - AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributePoint2DPtr aFirstPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributePoint2DPtr aSecondPointAttrOfSplit = + getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B())); /// split feature - theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr); + theSplitFeature = + createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); bool aSplitReversed = std::dynamic_pointer_cast(theSplitFeature)->isReversed(); theCreatedFeatures.insert(theSplitFeature); /// base feature is a left part of the circle - theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr); - std::dynamic_pointer_cast(theBaseFeatureModified)->setReversed(!aSplitReversed); + theBaseFeatureModified = createArcFeature(aBaseFeature, + aFirstPointAttrOfSplit, aSecondPointAttrOfSplit); + std::dynamic_pointer_cast( + theBaseFeatureModified)->setReversed(!aSplitReversed); theBaseFeatureModified->execute(); + + theModifiedAttributes.insert( + std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()), + theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID()))); + theCreatedFeatures.insert(theBaseFeatureModified); thePoints.insert(std::dynamic_pointer_cast @@ -822,12 +1067,13 @@ void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature, theCreatedFeatures.insert(aConstraintFeature); } -void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theStartPointAttr, - const AttributePoint2DPtr& theEndPointAttr, - AttributePoint2DPtr& theFirstPointAttr, - AttributePoint2DPtr& theLastPointAttr) +void SketchPlugin_ConstraintSplit::arrangePointsOnLine( + const AttributePoint2DPtr& theStartPointAttr, + const AttributePoint2DPtr& theEndPointAttr, + AttributePoint2DPtr& theFirstPointAttr, + AttributePoint2DPtr& theLastPointAttr) const { - /// if first point is closer to last point, wrap first and last values + // if first point is closer to last point, swap first and last values if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) > theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) { AttributePoint2DPtr aTmpPoint = theFirstPointAttr; @@ -836,6 +1082,43 @@ void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theS } } +void SketchPlugin_ConstraintSplit::arrangePointsOnArc( + const FeaturePtr& theArc, + const std::shared_ptr& theStartPointAttr, + const std::shared_ptr& theEndPointAttr, + std::shared_ptr& theFirstPointAttr, + std::shared_ptr& theSecondPointAttr) const +{ + static const double anAngleTol = 1.e-12; + + std::shared_ptr aCenter = std::dynamic_pointer_cast( + theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); + bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value(); + + // collect directions to each point + std::shared_ptr aStartDir( + new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy()))); + std::shared_ptr aFirstPtDir( + new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy()))); + std::shared_ptr aSecondPtDir( + new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy()))); + + // sort points by their angular values + double aFirstPtAngle = aStartDir->angle(aFirstPtDir); + double aSecondPtAngle = aStartDir->angle(aSecondPtDir); + double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI; + if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.)) + aFirstPtAngle += aPeriod; + if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.)) + aSecondPtAngle += aPeriod; + + if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) { + AttributePoint2DPtr aTmpPoint = theFirstPointAttr; + theFirstPointAttr = theSecondPointAttr; + theSecondPointAttr = aTmpPoint; + } +} + void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute, const AttributePtr& theSourceAttribute) { @@ -885,7 +1168,8 @@ FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theB return aFeature; aFeature = aSketch->addFeature(SketchPlugin_Arc::ID()); - // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated" + // update fillet arc: make the arc correct for sure, so, it is not needed to process + // the "attribute updated" // by arc; moreover, it may cause cyclicity in hte mechanism of updater aFeature->data()->blockSendAttributeUpdated(true); @@ -896,6 +1180,12 @@ FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theB theBaseFeature->attribute(aCenterAttributeId)); fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr); fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr); + + /// fill referersed state of created arc as it is on the base arc + if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) { + bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value(); + aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed); + } aFeature->data()->blockSendAttributeUpdated(false); aFeature->execute(); // to obtain result @@ -918,7 +1208,8 @@ FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& the return aConstraint; } -FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId, +FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects( + const std::string& theConstraintId, const ObjectPtr& theFirstObject, const ObjectPtr& theSecondObject) { @@ -934,6 +1225,28 @@ FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::s return aConstraint; } +void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit( + const std::set& theFeaturesToUpdate) +{ + std::set::const_iterator anIt = theFeaturesToUpdate.begin(), + aLast = theFeaturesToUpdate.end(); + for (; anIt != aLast; anIt++) { + FeaturePtr aRefFeature = std::dynamic_pointer_cast(*anIt); + std::string aRefFeatureKind = aRefFeature->getKind(); + if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) { + std::shared_ptr aLenghtFeature = + std::dynamic_pointer_cast(*anIt); + if (aLenghtFeature.get()) { + std::shared_ptr aValueAttr = std::dynamic_pointer_cast< + ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE())); + double aValue; + if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get()) + aValueAttr->setValue(aValue); + } + } + } +} + std::shared_ptr SketchPlugin_ConstraintSplit::getFeatureResult( const std::shared_ptr& theFeature) { @@ -986,14 +1299,15 @@ std::string SketchPlugin_ConstraintSplit::getFeatureInfo( if (isUseAttributesInfo) { std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature, getEdgeAttributes(theFeature)); - if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle + /// processing of feature with point 2d attributes, like line, arc, circle + if (!aPointsInfo.empty()) { anInfo += ": "; anInfo += "\n"; anInfo += aPointsInfo; } else { /// process constraint coincidence, find points in ref attr attributes std::list anAttrs = theFeature->data()->attributes( - ModelAPI_AttributeRefAttr::typeId()); + ModelAPI_AttributeRefAttr::typeId()); std::list::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end(); std::string anAttributesInfo; for(; anIt != aLast; anIt++) { @@ -1006,7 +1320,7 @@ std::string SketchPlugin_ConstraintSplit::getFeatureInfo( std::string aType = anAttr->attributeType(); if (aType == ModelAPI_AttributeRefAttr::typeId()) { std::shared_ptr aRefAttr = - std::dynamic_pointer_cast(anAttr); + std::dynamic_pointer_cast(anAttr); if (aRefAttr.get()) { if (aRefAttr->isObject()) { FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());