X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_Sketch.cpp;h=1d3c560da11b39cb0ebb9142304dbea018821520;hb=06e7f5859095193fc7f498bd89a7d28009794f53;hp=1b97f5634a0bd4a3c1db14989ac38030bc4f80cb;hpb=00074cfd3880c016908daac0e8eb8667fba19c1d;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index 1b97f5634..1d3c560da 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -1,24 +1,39 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> - -// File: SketchPlugin_Sketch.cxx -// Created: 27 Mar 2014 -// Author: Mikhail PONIKAROV +// Copyright (C) 2014-2023 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include #include +#include #include -#include #include +#include #include - -#include +#include +#include #include #include #include +#include #include #include #include @@ -30,8 +45,12 @@ #include #include +#include +#include #include +#include +#include #include #include @@ -39,8 +58,6 @@ #include #include -using namespace std; - SketchPlugin_Sketch::SketchPlugin_Sketch() { } @@ -52,9 +69,16 @@ void SketchPlugin_Sketch::initAttributes() data()->addAttribute(SketchPlugin_Sketch::NORM_ID(), GeomDataAPI_Dir::typeId()); data()->addAttribute(SketchPlugin_Sketch::FEATURES_ID(), ModelAPI_AttributeRefList::typeId()); // the selected face, base for the sketcher plane, not obligatory - data()->addAttribute(SketchPlugin_SketchEntity::EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId()); + data()->addAttribute(SketchPlugin_SketchEntity::EXTERNAL_ID(), + ModelAPI_AttributeSelection::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory( getKind(), SketchPlugin_SketchEntity::EXTERNAL_ID()); + data()->addAttribute(SketchPlugin_Sketch::SOLVER_ERROR(), ModelAPI_AttributeString::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory( + getKind(), SketchPlugin_Sketch::SOLVER_ERROR()); + data()->addAttribute(SketchPlugin_Sketch::SOLVER_DOF(), ModelAPI_AttributeString::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory( + getKind(), SketchPlugin_Sketch::SOLVER_DOF()); } void SketchPlugin_Sketch::execute() @@ -72,7 +96,7 @@ void SketchPlugin_Sketch::execute() data()->attribute(SketchPlugin_Sketch::NORM_ID())); std::list aFeatures = aRefList->list(); - if (aFeatures.empty()) + if (aFeatures.empty()) // actually, this must be avoided by the validators return; std::list::const_iterator anIt = aFeatures.begin(), aLast = aFeatures.end(); @@ -83,10 +107,17 @@ void SketchPlugin_Sketch::execute() if (aFeature) { if (!aFeature->sketch()) // on load document the back references are missed aFeature->setSketch(this); - // do not include the external edges into the result + // do not include into the result the external edges with disabled flag "Include into result" if (aFeature->data()->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID())) { - if (aFeature->data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->value()) - continue; + if (aFeature->data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->context()) { + const std::string& anAttrName = + aFeature->getKind() == SketchPlugin_Projection::ID() ? + SketchPlugin_Projection::INCLUDE_INTO_RESULT() : + SketchPlugin_IntersectionPoint::INCLUDE_INTO_RESULT(); + AttributeBooleanPtr aKeepResult = aFeature->boolean(anAttrName); + if (!aKeepResult || !aKeepResult->value()) + continue; + } } // do not include the construction entities in the result if (aFeature->data()->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID())) { @@ -108,9 +139,6 @@ void SketchPlugin_Sketch::execute() } } - if (aFeaturesPreview.empty()) - return; - // Collect all edges as one big wire std::shared_ptr aBigWire(new GeomAPI_PlanarEdges); std::list >::const_iterator aShapeIt = aFeaturesPreview.begin(); @@ -125,13 +153,48 @@ void SketchPlugin_Sketch::execute() std::shared_ptr SketchPlugin_Sketch::addFeature(std::string theID) { + // It is necessary to keep and restore the current feature in the document, + // if the sketch is updated from Python API. Because in that case, the current feature + // may be a non-sketch feature, so it is required to set it back, after adding a sketch feature, + // to keep the sequence of non-sketch features within the document. + FeaturePtr aCurFeature = document()->currentFeature(false); + std::shared_ptr aCurSketchFeature = + std::dynamic_pointer_cast(aCurFeature); + std::shared_ptr aCurSketch = + std::dynamic_pointer_cast(aCurFeature); + if ((aCurSketch && aCurSketch.get() == this) || + (aCurSketchFeature && aCurSketchFeature->sketch() == this)) + aCurFeature = FeaturePtr(); // no need to restore feature if it is from the current sketch + + // Set last feature of the sketch as current feature. + // Reason: Changing of parameter through Python API may lead to creation of new features + // (e.g. changing number of copies in MultiRotation). If the sketch is not the last + // feature in the Object Browser, then new features will be added to the end feature. + // Therefore, setting any feature below the sketch as a current feature will disable + // these newly created features. + std::shared_ptr aRefList = std::dynamic_pointer_cast< + ModelAPI_AttributeRefList>(data()->attribute(SketchPlugin_Sketch::FEATURES_ID())); + int aSize = aRefList->size(false); + ObjectPtr aLastObject = aSize == 0 ? data()->owner() : aRefList->object(aSize - 1, false); + FeaturePtr aLastFeature = std::dynamic_pointer_cast(aLastObject); + document()->setCurrentFeature(aLastFeature, false); + + // add new feature std::shared_ptr aNew = document()->addFeature(theID, false); if (aNew) { - std::dynamic_pointer_cast(aNew)->setSketch(this); + // the sketch cannot be specified for the macro-features defined in python + // like SketchRectangle, so we need to check the type of new feature + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(aNew); + if (aSketchFeature) + aSketchFeature->setSketch(this); data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->append(aNew); } - // set as current also after it becomes sub to set correctly enabled for other sketch subs - document()->setCurrentFeature(aNew, false); + + // set as current also after it becomes sub to set correctly enabled for other sketch subs + // or restore the previous current feature + document()->setCurrentFeature(aCurFeature ? aCurFeature : aNew, false); + return aNew; } @@ -139,39 +202,52 @@ void SketchPlugin_Sketch::removeFeature(std::shared_ptr theFea { if (!data()->isValid()) // sketch is already removed (case on undo of sketch), sync is not needed return; - list aSubs = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->list(); - list::iterator aSubIt = aSubs.begin(), aLastIt = aSubs.end(); - bool isRemoved = false; - bool aHasEmtpyFeature = false; - for(; aSubIt != aLastIt && !isRemoved; aSubIt++) { - std::shared_ptr aFeature = std::dynamic_pointer_cast(*aSubIt); - if (aFeature.get() != NULL && aFeature == theFeature) { - data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->remove(aFeature); - isRemoved = true; - } - else if (aFeature.get() == NULL) - aHasEmtpyFeature = true; + AttributeRefListPtr aList = reflist(SketchPlugin_Sketch::FEATURES_ID()); + // if the object is last, remove it from the list + // (needed to skip empty transaction on edit of sketch feature) + if (aList->object(aList->size(true) - 1, true) == theFeature) { + aList->remove(theFeature); + } else { + // to keep the persistent sub-elements indexing, do not remove elements from list, + // but substitute by nulls + aList->substitute(theFeature, ObjectPtr()); } - // if the object is not found in the sketch sub-elements, that means that the object is removed already. - // Find the first empty element and remove it - if (!isRemoved && aHasEmtpyFeature) - data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->remove(ObjectPtr()); } -int SketchPlugin_Sketch::numberOfSubs() const +int SketchPlugin_Sketch::numberOfSubs(bool forTree) const { - return data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->size(); + if (forTree) + return 0; + return data()->reflist(FEATURES_ID())->size(false); } -std::shared_ptr SketchPlugin_Sketch::subFeature(const int theIndex) const +std::shared_ptr SketchPlugin_Sketch::subFeature( + const int theIndex, bool forTree) { - ObjectPtr anObj = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->object(theIndex); - return std::dynamic_pointer_cast(anObj); + if (forTree) + return FeaturePtr(); + + ObjectPtr anObj = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->object(theIndex, false); + FeaturePtr aRes = std::dynamic_pointer_cast(anObj); + return aRes; } int SketchPlugin_Sketch::subFeatureId(const int theIndex) const { - return subFeature(theIndex)->data()->featureId(); + std::shared_ptr aRefList = std::dynamic_pointer_cast< + ModelAPI_AttributeRefList>(data()->attribute(SketchPlugin_Sketch::FEATURES_ID())); + std::list aFeatures = aRefList->list(); + std::list::const_iterator anIt = aFeatures.begin(); + int aResultIndex = 1; // number of the counted (created) features, started from 1 + int aFeatureIndex = -1; // number of the not-empty features in the list + for (; anIt != aFeatures.end(); anIt++) { + if (anIt->get()) + aFeatureIndex++; + if (aFeatureIndex == theIndex) + break; + aResultIndex++; + } + return aResultIndex; } bool SketchPlugin_Sketch::isSub(ObjectPtr theObject) const @@ -184,78 +260,114 @@ bool SketchPlugin_Sketch::isSub(ObjectPtr theObject) const aFeature = document()->feature(aRes); } if (aFeature) { - list aSubs = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->list(); - for(list::iterator aSubIt = aSubs.begin(); aSubIt != aSubs.end(); aSubIt++) { - if (*aSubIt == aFeature) - return true; - } + return data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->isInList(aFeature); } return false; } -void SketchPlugin_Sketch::erase() +static bool isOrigin(const GeomPointPtr& thePoint, const double theTolerance) { - std::shared_ptr aRefList = std::dynamic_pointer_cast< - ModelAPI_AttributeRefList>(data()->attribute(SketchPlugin_Sketch::FEATURES_ID())); - std::list aFeatures = aRefList->list(); - std::list::const_iterator anIt = aFeatures.begin(); - for (; anIt != aFeatures.end(); anIt++) { - FeaturePtr aFeature = std::dynamic_pointer_cast(*anIt); - if (aFeature) { - // subs are referenced from sketch, but must be removed for sure, so not checkings - document()->removeFeature(aFeature); - } - } - ModelAPI_CompositeFeature::erase(); + return fabs(thePoint->x()) < theTolerance && + fabs(thePoint->y()) < theTolerance && + fabs(thePoint->z()) < theTolerance; +} + +static bool isCoordinateAxis(const GeomDirPtr& theDir, const double theTolerance) +{ + return fabs(theDir->x() - 1.0) < theTolerance || fabs(theDir->x() + 1.0) < theTolerance || + fabs(theDir->y() - 1.0) < theTolerance || fabs(theDir->y() + 1.0) < theTolerance || + fabs(theDir->z() - 1.0) < theTolerance || fabs(theDir->z() + 1.0) < theTolerance; +} + +static bool isCoordinatePlane(const GeomAx3Ptr& thePlane) +{ + static const double THE_TOLERANCE = 1.e-7; + if (!thePlane) + return false; + + GeomPointPtr anOrigin = thePlane->origin(); + GeomDirPtr aNormal = thePlane->normal(); + GeomDirPtr aDirX = thePlane->dirX(); + + return isOrigin(anOrigin, THE_TOLERANCE) && + isCoordinateAxis(aNormal, THE_TOLERANCE) && + isCoordinateAxis(aDirX, THE_TOLERANCE); } void SketchPlugin_Sketch::attributeChanged(const std::string& theID) { if (theID == SketchPlugin_SketchEntity::EXTERNAL_ID()) { - std::shared_ptr aSelection = - data()->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->value(); - if (aSelection) { // update arguments due to the selection value + AttributeSelectionPtr aSelAttr = selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); + if (aSelAttr->context().get()) { // update arguments due to the selection value + std::shared_ptr aSelection = aSelAttr->value(); + if (!aSelection.get()) aSelection = aSelAttr->context()->shape(); // update the sketch plane - std::shared_ptr aPlane = GeomAlgoAPI_FaceBuilder::plane(aSelection); - if (aPlane) { - double anA, aB, aC, aD; - aPlane->coefficients(anA, aB, aC, aD); - - // calculate attributes of the sketch - std::shared_ptr aNormDir(new GeomAPI_Dir(anA, aB, aC)); - std::shared_ptr aCoords = aNormDir->xyz(); - std::shared_ptr aZero(new GeomAPI_XYZ(0, 0, 0)); - aCoords = aCoords->multiplied(-aD * aCoords->distance(aZero)); - std::shared_ptr anOrigPnt(new GeomAPI_Pnt(aCoords)); - // X axis is preferable to be dirX on the sketch - static const double tol = 0.1; // here can not be very small value to avoid very close to X normal axis (issue 595) - bool isX = fabs(anA) - 1.0 < tol && fabs(aB) < tol && fabs(aC) < tol; - std::shared_ptr aTempDir( - isX ? new GeomAPI_Dir(0, 1, 0) : new GeomAPI_Dir(1, 0, 0)); - std::shared_ptr aYDir(new GeomAPI_Dir(aNormDir->cross(aTempDir))); - std::shared_ptr aXDir(new GeomAPI_Dir(aYDir->cross(aNormDir))); - - // update position of the sketch - std::shared_ptr anOrigin = std::dynamic_pointer_cast - (data()->attribute(SketchPlugin_Sketch::ORIGIN_ID())); - anOrigin->setValue(anOrigPnt); - std::shared_ptr aNormal = std::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::NORM_ID())); - aNormal->setValue(aNormDir); - std::shared_ptr aDirX = std::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::DIRX_ID())); - aDirX->setValue(aXDir); - std::shared_ptr aDir = aPlane->direction(); + std::shared_ptr aFace; + if (aSelection->isFace()) { + aFace = aSelection->face(); + } else if (aSelection->isCompound()) { + GeomAPI_ShapeIterator anIt(aSelection); + aFace = anIt.current()->face(); + } + if (aFace.get()) { + std::shared_ptr aPlane = aFace->getPlane(); + if (aPlane.get()) { + double anA, aB, aC, aD; + aPlane->coefficients(anA, aB, aC, aD); + + // calculate attributes of the sketch + std::shared_ptr aNormDir(new GeomAPI_Dir(anA, aB, aC)); + std::shared_ptr aCoords = aNormDir->xyz(); + std::shared_ptr aZero(new GeomAPI_XYZ(0, 0, 0)); + aCoords = aCoords->multiplied(-aD * aCoords->distance(aZero)); + std::shared_ptr anOrigPnt(new GeomAPI_Pnt(aCoords)); + // X axis is preferable to be dirX on the sketch + // here can not be very small value to avoid very close to X normal axis (issue 595) + static const double tol = 0.1; + bool isX = fabs(anA) - 1.0 < tol && fabs(aB) < tol && fabs(aC) < tol; + std::shared_ptr aTempDir( + isX ? new GeomAPI_Dir(0, 1, 0) : new GeomAPI_Dir(1, 0, 0)); + std::shared_ptr aYDir(new GeomAPI_Dir(aNormDir->cross(aTempDir))); + std::shared_ptr aXDir(new GeomAPI_Dir(aYDir->cross(aNormDir))); + + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + // update position of the sketch + std::shared_ptr anOrigin = std::dynamic_pointer_cast + (data()->attribute(SketchPlugin_Sketch::ORIGIN_ID())); + anOrigin->setValue(anOrigPnt); + std::shared_ptr aNormal = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Sketch::NORM_ID())); + aNormal->setValue(aNormDir); + std::shared_ptr aDirX = std::dynamic_pointer_cast( + data()->attribute(SketchPlugin_Sketch::DIRX_ID())); + aDirX->setValue(aXDir); + data()->blockSendAttributeUpdated(aWasBlocked, true); + } } } - } else if (theID == SketchPlugin_Sketch::NORM_ID() || theID == SketchPlugin_Sketch::DIRX_ID()) { + } else if (theID == NORM_ID() || theID == DIRX_ID() || theID == ORIGIN_ID()) { + // check if current and previous sketch planes are coordinate planes and they are different + GeomAx3Ptr aCurPlane; + bool areCoordPlanes = false; + if (isPlaneSet()) { + aCurPlane = coordinatePlane(); + areCoordPlanes = isCoordinatePlane(aCurPlane) && isCoordinatePlane(myPlane); + } + // send all sub-elements are also updated: all entities become created on different plane static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); std::list aSubs = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->list(); std::list::iterator aSub = aSubs.begin(); for(; aSub != aSubs.end(); aSub++) { - ModelAPI_EventCreator::get()->sendUpdated(*aSub, anUpdateEvent); + if (aSub->get()) { + if (areCoordPlanes) + updateCoordinateAxis(*aSub, aCurPlane); + + ModelAPI_EventCreator::get()->sendUpdated(*aSub, anUpdateEvent); + } } + if (aCurPlane) + myPlane = aCurPlane; } } @@ -272,7 +384,7 @@ void SketchPlugin_Sketch::createPoint2DResult(ModelAPI_Feature* theFeature, std::shared_ptr aCenter(theSketch->to3D(aPoint->x(), aPoint->y())); //std::cout<<"Execute circle "<x()<<" "<y()<<" "<z()< aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter); + std::shared_ptr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter); std::shared_ptr aResult = theFeature->document()->createConstruction( theFeature->data(), theIndex); aResult->setShape(aCenterPointShape); @@ -281,16 +393,229 @@ void SketchPlugin_Sketch::createPoint2DResult(ModelAPI_Feature* theFeature, theFeature->setResult(aResult, theIndex); } +void SketchPlugin_Sketch::createLine2DResult(ModelAPI_Feature* theFeature, + SketchPlugin_Sketch* theSketch, + const std::string& theStartAttrID, + const std::string& theEndAttrID, + const int theIndex) +{ + std::shared_ptr aStartAttr = + std::dynamic_pointer_cast(theFeature->attribute(theStartAttrID)); + std::shared_ptr anEndAttr = + std::dynamic_pointer_cast(theFeature->attribute(theEndAttrID)); + + if (!aStartAttr || !aStartAttr->isInitialized() || + !anEndAttr || !anEndAttr->isInitialized()) + return; + + std::shared_ptr aStart(theSketch->to3D(aStartAttr->x(), aStartAttr->y())); + std::shared_ptr anEnd(theSketch->to3D(anEndAttr->x(), anEndAttr->y())); + //std::cout<<"Execute line "<x()<<" "<y()<<" "<z()<<" - " + // <x()<<" "<y()<<" "<z()< anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd); + // store the result + std::shared_ptr aResult = + theFeature->document()->createConstruction(theFeature->data(), theIndex); + aResult->setShape(anEdge); + aResult->setIsInHistory(false); + theFeature->setResult(aResult, theIndex); +} + FeaturePtr SketchPlugin_Sketch::addUniqueNamedCopiedFeature(FeaturePtr theFeature, - SketchPlugin_Sketch* theSketch) + SketchPlugin_Sketch* theSketch, + const bool theIsCopy) { FeaturePtr aNewFeature = theSketch->addFeature(theFeature->getKind()); // addFeature generates a unique name for the feature, it caches the name - std::string aUniqueFeatureName = aNewFeature->data()->name(); + std::wstring aUniqueFeatureName = aNewFeature->data()->name(); // all attribute values are copied\pasted to the new feature, name is not an exception theFeature->data()->copyTo(aNewFeature->data()); - // as a name for the feature, the generated unique name is set + // external state should not be copied as a new object is an object of the current sketch + if (theFeature->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()).get()) + aNewFeature->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->setValue(ResultPtr(), + GeomShapePtr()); aNewFeature->data()->setName(aUniqueFeatureName); + // text expressions could block setValue of some attributes + SketchPlugin_Tools::clearExpressions(aNewFeature); + // Set copy attribute + AttributeBooleanPtr anAttr = aNewFeature->data()->boolean(SketchPlugin_SketchEntity::COPY_ID()); + if(anAttr.get()) { + anAttr->setValue(theIsCopy); + } return aNewFeature; } + +std::shared_ptr SketchPlugin_Sketch::plane(SketchPlugin_Sketch* theSketch) +{ + std::shared_ptr aData = theSketch->data(); + + std::shared_ptr anOrigin = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::ORIGIN_ID())); + std::shared_ptr aDirX = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::DIRX_ID())); + std::shared_ptr aNorm = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Sketch::NORM_ID())); + + if (aNorm.get() && aNorm->isInitialized() && anOrigin.get() && anOrigin->isInitialized()) + return std::shared_ptr( + new GeomAPI_Ax3(anOrigin->pnt(), aDirX->dir(), aNorm->dir())); + + return std::shared_ptr(); +} + +bool SketchPlugin_Sketch::customAction(const std::string& theActionId) +{ + bool isOk = false; + if (theActionId == ACTION_REMOVE_EXTERNAL()) + isOk = removeLinksToExternal(); + else { + std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\"."; + Events_InfoMessage("SketchPlugin_Sketch", aMsg).arg(getKind()).arg(theActionId).send(); + } + return isOk; +} + +static bool isExternalBased(const FeaturePtr theFeature) +{ + return theFeature->getKind() == SketchPlugin_Projection::ID() || + theFeature->getKind() == SketchPlugin_IntersectionPoint::ID(); +} + +bool SketchPlugin_Sketch::removeLinksToExternal() +{ + std::list aRemove; + std::list aSubs = reflist(FEATURES_ID())->list(); + for (std::list::iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); + if (!aFeature) + continue; + if (isExternalBased(aFeature)) { + // mark feature as to be removed + aRemove.push_back(aFeature); + } + else { + AttributeSelectionPtr anExtAttr = + aFeature->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); + ResultPtr anExternal = anExtAttr ? anExtAttr->context() : ResultPtr(); + if (anExternal) { + FeaturePtr anExtFeature = ModelAPI_Feature::feature(anExternal); + if (anExtFeature && isExternalBased(anExtFeature)) { + // make result of projection/intersection as non-external, + aFeature->selection(SketchPlugin_SketchEntity::EXTERNAL_ID())->setValue( + ObjectPtr(), GeomShapePtr()); + // set feature auxiliary if the parent is not included into sketch result + bool isIncludedToSketchResult = false; + if (anExtFeature->getKind() == SketchPlugin_Projection::ID()) { + isIncludedToSketchResult = anExtFeature->boolean( + SketchPlugin_Projection::INCLUDE_INTO_RESULT())->value(); + } + if (anExtFeature->getKind() == SketchPlugin_IntersectionPoint::ID()) { + isIncludedToSketchResult = anExtFeature->boolean( + SketchPlugin_IntersectionPoint::INCLUDE_INTO_RESULT())->value(); + } + + aFeature->boolean(SketchPlugin_SketchEntity::COPY_ID())->setValue(false); + aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue( + !isIncludedToSketchResult); + } + } + } + } + for (std::list::iterator anIt = aRemove.begin(); anIt != aRemove.end(); ++anIt) + document()->removeFeature(*anIt); + return true; +} + + +static ObjectPtr findAxis(GeomShapePtr theAxisToCompare, + ObjectPtr theOX, + ObjectPtr theOY, + ObjectPtr theOZ) +{ + if (theAxisToCompare) { + ObjectPtr anAxes[] = { theOX, theOY, theOZ }; + for (int i = 0; i < 3; ++i) { + ResultPtr anAx = std::dynamic_pointer_cast(anAxes[i]); + if (anAx && theAxisToCompare->isEqual(anAx->shape())) + return anAxes[i]; + } + } + return ObjectPtr(); +} + +static ObjectPtr findAxis(ObjectPtr theAxisToCompare, + ObjectPtr theOX, + ObjectPtr theOY, + ObjectPtr theOZ) +{ + if (theAxisToCompare == theOX) + return theOX; + else if (theAxisToCompare == theOY) + return theOY; + else if (theAxisToCompare == theOZ) + return theOZ; + // nothing helped, search by shape + ResultPtr anAxis = std::dynamic_pointer_cast(theAxisToCompare); + return findAxis(anAxis ? anAxis->shape() : GeomShapePtr(), theOX, theOY, theOZ); +} + +GeomShapePtr axisOnNewPlane(ObjectPtr theAxis, GeomAx3Ptr theOldPlane, GeomAx3Ptr theNewPlane) +{ + ResultPtr anAxis = std::dynamic_pointer_cast(theAxis); + if (!anAxis) + return GeomShapePtr(); + + GeomEdgePtr anAxisEdge = anAxis->shape()->edge(); + GeomLinePtr anAxisLine = anAxisEdge->line(); + GeomDirPtr anAxisDir = anAxisLine->direction(); + + double aFirstParam, aLastParam; + anAxisEdge->getRange(aFirstParam, aLastParam); + + if (theOldPlane->dirX()->isParallel(anAxisDir)) + anAxisDir = theNewPlane->dirX(); + else if (theOldPlane->dirY()->isParallel(anAxisDir)) + anAxisDir = theNewPlane->dirY(); + else if (theOldPlane->normal()->isParallel(anAxisDir)) + anAxisDir = theNewPlane->normal(); + + GeomPointPtr aFirstPoint(new GeomAPI_Pnt(aFirstParam * anAxisDir->x(), + aFirstParam * anAxisDir->y(), + aFirstParam * anAxisDir->z())); + GeomPointPtr aLastPoint(new GeomAPI_Pnt(aLastParam * anAxisDir->x(), + aLastParam * anAxisDir->y(), + aLastParam * anAxisDir->z())); + return GeomAlgoAPI_EdgeBuilder::line(aFirstPoint, aLastPoint); +} + +void SketchPlugin_Sketch::updateCoordinateAxis(ObjectPtr theSub, GeomAx3Ptr thePlane) +{ + FeaturePtr aFeature = ModelAPI_Feature::feature(theSub); + if (!aFeature) + return; + + DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument(); + ObjectPtr anOX = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), L"OX"); + ObjectPtr anOY = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), L"OY"); + ObjectPtr anOZ = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), L"OZ"); + + AttributeSelectionPtr anExtFeature; + if (aFeature->getKind() == SketchPlugin_Projection::ID()) + anExtFeature = aFeature->selection(SketchPlugin_Projection::EXTERNAL_FEATURE_ID()); + else if (aFeature->getKind() == SketchPlugin_IntersectionPoint::ID()) + anExtFeature = aFeature->selection(SketchPlugin_IntersectionPoint::EXTERNAL_FEATURE_ID()); + else + return; + + ObjectPtr aContext = anExtFeature->context(); + GeomShapePtr aShape = anExtFeature->value(); + if (!aShape) { // selected object is a construction + ObjectPtr anAxis = findAxis(aContext, anOX, anOY, anOZ); + GeomShapePtr aNewAxis = axisOnNewPlane(anAxis, myPlane, thePlane); + anAxis = findAxis(aNewAxis, anOX, anOY, anOZ); + if (anAxis) + anExtFeature->setValue(anAxis, aShape); + } +}