X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_Sketch.cpp;h=692ac5d0ed2be3377aad617f6744f1ca75773a5d;hb=b090c94333e03c317704ea05cba728154b7c492e;hp=256ba9d5e5057573512dfde8770fe3bb6569fac1;hpb=b2a34ee4bab2fe2d97f900cbdafcaf122344c46c;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_Sketch.cpp b/src/SketchPlugin/SketchPlugin_Sketch.cpp index 256ba9d5e..692ac5d0e 100644 --- a/src/SketchPlugin/SketchPlugin_Sketch.cpp +++ b/src/SketchPlugin/SketchPlugin_Sketch.cpp @@ -1,22 +1,62 @@ -// File: SketchPlugin_Sketch.cxx -// Created: 27 Mar 2014 -// Author: Mikhail PONIKAROV +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// 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 "SketchPlugin_Sketch.h" -#include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include #include +#include +#include +#include -#include +#include +#include +#include +#include +#include +#include -using namespace std; +#include +#include + +#include + +#include +#include SketchPlugin_Sketch::SketchPlugin_Sketch() { @@ -24,47 +64,74 @@ SketchPlugin_Sketch::SketchPlugin_Sketch() void SketchPlugin_Sketch::initAttributes() { - data()->addAttribute(SketchPlugin_Sketch::ORIGIN_ID(), GeomDataAPI_Point::type()); - data()->addAttribute(SketchPlugin_Sketch::DIRX_ID(), GeomDataAPI_Dir::type()); - data()->addAttribute(SketchPlugin_Sketch::DIRY_ID(), GeomDataAPI_Dir::type()); - data()->addAttribute(SketchPlugin_Sketch::NORM_ID(), GeomDataAPI_Dir::type()); - data()->addAttribute(SketchPlugin_Sketch::FEATURES_ID(), ModelAPI_AttributeRefList::type()); + data()->addAttribute(SketchPlugin_Sketch::ORIGIN_ID(), GeomDataAPI_Point::typeId()); + data()->addAttribute(SketchPlugin_Sketch::DIRX_ID(), GeomDataAPI_Dir::typeId()); + 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()); + 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() { if (!data()->isValid()) return; - boost::shared_ptr aRefList = boost::dynamic_pointer_cast< + std::shared_ptr aRefList = std::dynamic_pointer_cast< ModelAPI_AttributeRefList>(data()->attribute(SketchPlugin_Sketch::FEATURES_ID())); - boost::shared_ptr anOrigin = boost::dynamic_pointer_cast( + std::shared_ptr anOrigin = std::dynamic_pointer_cast( data()->attribute(SketchPlugin_Sketch::ORIGIN_ID())); - boost::shared_ptr aDirX = boost::dynamic_pointer_cast( + std::shared_ptr aDirX = std::dynamic_pointer_cast( data()->attribute(SketchPlugin_Sketch::DIRX_ID())); - boost::shared_ptr aDirY = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::DIRY_ID())); - boost::shared_ptr aNorm = boost::dynamic_pointer_cast( + std::shared_ptr aNorm = std::dynamic_pointer_cast( 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(); - boost::shared_ptr aFeature; - std::list > aFeaturesPreview; + std::shared_ptr aFeature; + std::list > aFeaturesPreview; for (; anIt != aLast; anIt++) { - aFeature = boost::dynamic_pointer_cast(*anIt); + aFeature = std::dynamic_pointer_cast(*anIt); if (aFeature) { + if (!aFeature->sketch()) // on load document the back references are missed + aFeature->setSketch(this); + // 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())->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())) { + if (aFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()) + continue; + } - const std::list >& aRes = aFeature->results(); - std::list >::const_iterator aResIter = aRes.cbegin(); + const std::list >& aRes = aFeature->results(); + std::list >::const_iterator aResIter = aRes.cbegin(); for (; aResIter != aRes.cend(); aResIter++) { - boost::shared_ptr aConstr = boost::dynamic_pointer_cast< + std::shared_ptr aConstr = std::dynamic_pointer_cast< ModelAPI_ResultConstruction>(*aResIter); if (aConstr) { - boost::shared_ptr aShape = aConstr->shape(); + std::shared_ptr aShape = aConstr->shape(); if (aShape) aFeaturesPreview.push_back(aShape); } @@ -72,112 +139,464 @@ void SketchPlugin_Sketch::execute() } } - if (aFeaturesPreview.empty()) - return; - std::list > aLoops; - std::list > aWires; - GeomAlgoAPI_SketchBuilder::createFaces(anOrigin->pnt(), aDirX->dir(), aDirY->dir(), aNorm->dir(), - aFeaturesPreview, aLoops, aWires); - - aLoops.insert(aLoops.end(), aWires.begin(), aWires.end()); - boost::shared_ptr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aLoops); - boost::shared_ptr aConstr = document()->createConstruction(data()); - aConstr->setShape(aCompound); + // Collect all edges as one big wire + std::shared_ptr aBigWire(new GeomAPI_PlanarEdges); + std::list >::const_iterator aShapeIt = aFeaturesPreview.begin(); + for (; aShapeIt != aFeaturesPreview.end(); ++aShapeIt) { + aBigWire->addEdge(*aShapeIt); + } + aBigWire->setPlane(anOrigin->pnt(), aDirX->dir(), aNorm->dir()); + std::shared_ptr aConstr = document()->createConstruction(data()); + aConstr->setShape(aBigWire); setResult(aConstr); } -const void SketchPlugin_Sketch::addSub(const FeaturePtr& theFeature) +std::shared_ptr SketchPlugin_Sketch::addFeature(std::string theID) { - boost::dynamic_pointer_cast(theFeature)->setSketch(this); - data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->append(theFeature); + // 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) { + // 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); + + return aNew; } -boost::shared_ptr SketchPlugin_Sketch::to3D(const double theX, const double theY) +void SketchPlugin_Sketch::removeFeature(std::shared_ptr theFeature) { - boost::shared_ptr aC = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::ORIGIN_ID())); - boost::shared_ptr aX = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::DIRX_ID())); - boost::shared_ptr aY = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::DIRY_ID())); + if (!data()->isValid()) // sketch is already removed (case on undo of sketch), sync is not needed + return; + 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()); + } +} - boost::shared_ptr aSum = aC->pnt()->xyz()->added(aX->dir()->xyz()->multiplied(theX)) - ->added(aY->dir()->xyz()->multiplied(theY)); +int SketchPlugin_Sketch::numberOfSubs(bool forTree) const +{ + if (forTree) + return 0; + return data()->reflist(FEATURES_ID())->size(false); +} - return boost::shared_ptr(new GeomAPI_Pnt(aSum)); +std::shared_ptr SketchPlugin_Sketch::subFeature( + const int theIndex, bool forTree) +{ + if (forTree) + return FeaturePtr(); + + ObjectPtr anObj = data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->object(theIndex, false); + FeaturePtr aRes = std::dynamic_pointer_cast(anObj); + return aRes; } -bool SketchPlugin_Sketch::isPlaneSet() +int SketchPlugin_Sketch::subFeatureId(const int theIndex) const { - boost::shared_ptr aNormal = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::NORM_ID())); + 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; +} - return aNormal && !(aNormal->x() == 0 && aNormal->y() == 0 && aNormal->z() == 0); +bool SketchPlugin_Sketch::isSub(ObjectPtr theObject) const +{ + // check is this feature of result + FeaturePtr aFeature = std::dynamic_pointer_cast(theObject); + if (!aFeature) { + ResultPtr aRes = std::dynamic_pointer_cast(theObject); + if (aRes) + aFeature = document()->feature(aRes); + } + if (aFeature) { + return data()->reflist(SketchPlugin_Sketch::FEATURES_ID())->isInList(aFeature); + } + return false; } -boost::shared_ptr SketchPlugin_Sketch::plane() + +static bool isOrigin(const GeomPointPtr& thePoint, const double theTolerance) { - boost::shared_ptr anOrigin = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::ORIGIN_ID())); - boost::shared_ptr aNorm = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::NORM_ID())); + 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()) { + 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 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 == 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); + } - if (!anOrigin || !aNorm) - return boost::shared_ptr(); + // 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++) { + if (aSub->get()) { + if (areCoordPlanes) + updateCoordinateAxis(*aSub, aCurPlane); - return boost::shared_ptr(new GeomAPI_Pln(anOrigin->pnt(), aNorm->dir())); + ModelAPI_EventCreator::get()->sendUpdated(*aSub, anUpdateEvent); + } + } + if (aCurPlane) + myPlane = aCurPlane; + } } -void addPlane(double theX, double theY, double theZ, - std::list >& theShapes) +void SketchPlugin_Sketch::createPoint2DResult(ModelAPI_Feature* theFeature, + SketchPlugin_Sketch* theSketch, + const std::string& theAttributeID, const int theIndex) { - boost::shared_ptr anOrigin(new GeomAPI_Pnt(0, 0, 0)); - boost::shared_ptr aNormal(new GeomAPI_Dir(theX, theY, theZ)); - double aSize = Config_PropManager::integer("Sketch planes", "Size of planes", PLANE_SIZE); - boost::shared_ptr aFace = GeomAlgoAPI_FaceBuilder::square(anOrigin, aNormal, - aSize); - theShapes.push_back(aFace); + std::shared_ptr aPoint = std::dynamic_pointer_cast( + theFeature->attribute(theAttributeID)); + + if (!aPoint || !aPoint->isInitialized()) + return; + + std::shared_ptr aCenter(theSketch->to3D(aPoint->x(), aPoint->y())); + //std::cout<<"Execute circle "<x()<<" "<y()<<" "<z()< aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter); + std::shared_ptr aResult = theFeature->document()->createConstruction( + theFeature->data(), theIndex); + aResult->setShape(aCenterPointShape); + aResult->setIsInHistory(false); + + theFeature->setResult(aResult, theIndex); } -AISObjectPtr SketchPlugin_Sketch::getAISObject(AISObjectPtr thePrevious) +void SketchPlugin_Sketch::createLine2DResult(ModelAPI_Feature* theFeature, + SketchPlugin_Sketch* theSketch, + const std::string& theStartAttrID, + const std::string& theEndAttrID, + const int theIndex) { - boost::shared_ptr aNorm = boost::dynamic_pointer_cast( - data()->attribute(SketchPlugin_Sketch::NORM_ID())); + 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); +} - if (!aNorm || (aNorm->x() == 0 && aNorm->y() == 0 && aNorm->z() == 0)) { - AISObjectPtr aAIS = thePrevious; - if (!aAIS) { - std::list > aFaces; +FeaturePtr SketchPlugin_Sketch::addUniqueNamedCopiedFeature(FeaturePtr theFeature, + 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(); + // all attribute values are copied\pasted to the new feature, name is not an exception + theFeature->data()->copyTo(aNewFeature->data()); + // 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; +} - addPlane(1, 0, 0, aFaces); // YZ plane - addPlane(0, 1, 0, aFaces); // XZ plane - addPlane(0, 0, 1, aFaces); // XY plane - boost::shared_ptr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aFaces); - aAIS = AISObjectPtr(new GeomAPI_AISObject()); - aAIS->createShape(aCompound); +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())); - std::vector aRGB = Config_PropManager::color("Sketch planes", "planes_color", - SKETCH_PLANE_COLOR); - aAIS->setColor(aRGB[0], aRGB[1], aRGB[2]); + return std::shared_ptr(new GeomAPI_Ax3(anOrigin->pnt(), aDirX->dir(), aNorm->dir())); +} - aAIS->setWidth(Config_PropManager::integer("Sketch planes", "planes_thikness", - SKETCH_WIDTH)); +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); + } + } } - return aAIS; } - return AISObjectPtr(); + for (std::list::iterator anIt = aRemove.begin(); anIt != aRemove.end(); ++anIt) + document()->removeFeature(*anIt); + return true; } -void SketchPlugin_Sketch::erase() + +static ObjectPtr findAxis(GeomShapePtr theAxisToCompare, + ObjectPtr theOX, + ObjectPtr theOY, + ObjectPtr theOZ) { - boost::shared_ptr aRefList = boost::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 = boost::dynamic_pointer_cast(*anIt); - if (aFeature) - document()->removeFeature(aFeature); + 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(), "OX"); + ObjectPtr anOY = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), "OY"); + ObjectPtr anOZ = aRootDoc->objectByName(ModelAPI_ResultConstruction::group(), "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); } - SketchPlugin_Feature::erase(); }