X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchPlugin%2FSketchPlugin_Arc.cpp;h=04f2c922babe98d54245f40d28f4b9569af2c29f;hb=06e7f5859095193fc7f498bd89a7d28009794f53;hp=6295057977b2fc058736979d944cdfb1f3797114;hpb=8babac25037f2666dcb422dd68a66dd2ed1383d8;p=modules%2Fshaper.git diff --git a/src/SketchPlugin/SketchPlugin_Arc.cpp b/src/SketchPlugin/SketchPlugin_Arc.cpp index 629505797..0eb84450c 100644 --- a/src/SketchPlugin/SketchPlugin_Arc.cpp +++ b/src/SketchPlugin/SketchPlugin_Arc.cpp @@ -1,250 +1,297 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> - -// File: SketchPlugin_Arc.cpp -// Created: 26 Apr 2014 -// Author: Artem ZHIDKOV +// 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 "SketchPlugin_Arc.h" #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 +// for sqrt on Linux +#include + +static const double tolerance = 1e-7; +static const double paramTolerance = 1.e-4; +static const double PI = 3.141592653589793238463; -const double tolerance = 1e-7; SketchPlugin_Arc::SketchPlugin_Arc() - : SketchPlugin_Feature() +: SketchPlugin_SketchEntity() { - myStartUpdate = false; - myEndUpdate = false; + myParamBefore = 0.0; } -void SketchPlugin_Arc::initAttributes() +void SketchPlugin_Arc::initDerivedClassAttributes() { data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId()); data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId()); data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId()); ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID()); + + AttributeBooleanPtr isReversed = std::dynamic_pointer_cast( + data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId())); + + data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId()); + + // set after all to avoid in attributeChanged reference to not existing attributes + if (!isReversed->isInitialized()) { + isReversed->setValue(false); + } } void SketchPlugin_Arc::execute() { SketchPlugin_Sketch* aSketch = sketch(); - // result for the arc is set only when all obligatory attributes are initialized, - // otherwise AIS object is used to visualize the arc's preview - if (aSketch && isFeatureValid()) { - // compute a circle point in 3D view - std::shared_ptr aCenterAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(CENTER_ID())); - // compute the arc start point - std::shared_ptr aStartAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(START_ID())); - - std::shared_ptr aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y())); - // make a visible point - std::shared_ptr aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter); - std::shared_ptr aConstr1 = document()->createConstruction( - data(), 0); - aConstr1->setShape(aCenterPointShape); - aConstr1->setIsInHistory(false); - setResult(aConstr1, 0); - - // make a visible circle - std::shared_ptr aNDir = std::dynamic_pointer_cast( - aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); - std::shared_ptr aNormal = aNDir->dir(); - std::shared_ptr aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y())); - - // compute and change the arc end point - std::shared_ptr anEndAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(END_ID())); - /* must be automatically done in attributeChanged + if(!aSketch) { + return; + } + + std::shared_ptr aCenterAttr = + std::dynamic_pointer_cast(data()->attribute(CENTER_ID())); + std::shared_ptr aStartAttr = + std::dynamic_pointer_cast(data()->attribute(START_ID())); + std::shared_ptr anEndAttr = + std::dynamic_pointer_cast(data()->attribute(END_ID())); + if(!aCenterAttr->isInitialized() || !aStartAttr->isInitialized() || !anEndAttr->isInitialized()) { + return; + } + + // Make a visible point. + SketchPlugin_Sketch::createPoint2DResult(this, sketch(), CENTER_ID(), 0); + + // Make a visible arc. + std::shared_ptr aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y())); + std::shared_ptr aStart(aSketch->to3D(aStartAttr->x(), aStartAttr->y())); + std::shared_ptr anEnd(aSketch->to3D(anEndAttr->x(), anEndAttr->y())); + std::shared_ptr aNDir = std::dynamic_pointer_cast( + aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); + std::shared_ptr aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z())); + + if (myParamBefore == 0) { // parameter has not been calculate yet std::shared_ptr aCircleForArc( new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt())); - std::shared_ptr aProjection = aCircleForArc->project(anEndAttr->pnt()); - if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance) - anEndAttr->setValue(aProjection); - */ - std::shared_ptr aEndPoint(aSketch->to3D(anEndAttr->x(), anEndAttr->y())); - - std::shared_ptr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc( - aCenter, aStartPoint, aEndPoint, aNormal); - if (aCircleShape) { - std::shared_ptr aConstr2 = document()->createConstruction( - data(), 1); - aConstr2->setShape(aCircleShape); - aConstr2->setIsInHistory(false); - setResult(aConstr2, 1); - } + aCircleForArc->parameter(anEndAttr->pnt(), paramTolerance, myParamBefore); } -} -AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious) -{ - SketchPlugin_Sketch* aSketch = sketch(); - if (aSketch) { - // if the feature is valid, the execute() method should be performed, AIS object is empty - if (!isFeatureValid()) { - // compute a circle point in 3D view - std::shared_ptr aCenterAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(CENTER_ID())); - if (aCenterAttr->isInitialized()) { - std::shared_ptr aCenter(aSketch->to3D(aCenterAttr->x(), aCenterAttr->y())); - - std::shared_ptr aStartAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID())); - if (aStartAttr->isInitialized()) { - // make a visible circle - std::shared_ptr aNDir = std::dynamic_pointer_cast( - aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); - bool aHasPlane = aNDir && !(aNDir->x() == 0 && aNDir->y() == 0 && aNDir->z() == 0); - if (aHasPlane) { - std::shared_ptr aNormal = aNDir->dir(); - std::shared_ptr aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y())); - std::shared_ptr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc( - aCenter, aStartPoint, aStartPoint, aNormal); - if (aCircleShape) { - std::list > aShapes; - // make a visible point - std::shared_ptr aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter); - aShapes.push_back(aCenterPointShape); - - aShapes.push_back(aCircleShape); - if (!aShapes.empty()) - { - std::shared_ptr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes); - AISObjectPtr anAIS = thePrevious; - if (!anAIS) - anAIS = AISObjectPtr(new GeomAPI_AISObject); - anAIS->createShape(aCompound); - anAIS->setWidth(3); - return anAIS; - } - } - } - } + bool isReversed = boolean(REVERSED_ID())->value(); + + GeomEdgePtr anArcShape; + if (fabs(myParamBefore - 2.0 * PI) < paramTolerance) { + anArcShape = GeomAlgoAPI_EdgeBuilder::lineCircle(aCenter, aNormal, aStart->distance(aCenter)); + myParamBefore = 0; + } else { + anArcShape = isReversed ? + GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal) + : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal); + } + + // calculate tolerances for start and end points of the arc and set them to the result shape + // (this is done to fix gaps which appear because of inaccurate computation of arcs in PlaneGCS, + // which leads to difference in SketchPlugin_Arc attributes and boundary points of result shape) + if (anArcShape) { + for (int ind = 0; ind < 2; ++ind) { + bool isFirst = ind == 0; + GeomPointPtr anArcBndPoint = isFirst == isReversed ? anEnd : aStart; + GeomPointPtr aShapePoint = isFirst ? anArcShape->firstPoint() : anArcShape->lastPoint(); + double aDistance = anArcBndPoint->distance(aShapePoint); + // avoid setting too high tolerance because it may be caused by incomplete update of an arc + if (aDistance > tolerance && aDistance < 100. * tolerance) { + if (isFirst) + anArcShape->setFirstPointTolerance(aDistance); + else + anArcShape->setLastPointTolerance(aDistance); } } } - return AISObjectPtr(); -} - -void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY) -{ - std::shared_ptr aData = data(); - if (!aData->isValid()) - return; - std::shared_ptr aPoint1 = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Arc::CENTER_ID())); - aPoint1->move(theDeltaX, theDeltaY); - - myStartUpdate = true; - myEndUpdate = true; - std::shared_ptr aPoint2 = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Arc::START_ID())); - aPoint2->move(theDeltaX, theDeltaY); - - std::shared_ptr aPoint3 = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Arc::END_ID())); - aPoint3->move(theDeltaX, theDeltaY); - myStartUpdate = false; - myEndUpdate = false; + std::shared_ptr aResult = document()->createConstruction(data(), 1); + aResult->setShape(anArcShape); + aResult->setIsInHistory(false); + setResult(aResult, 1); } -double SketchPlugin_Arc::distanceToPoint(const std::shared_ptr& thePoint) +bool SketchPlugin_Arc::isFixed() { - double aDelta = 0; - std::shared_ptr aData = data(); - - std::shared_ptr aPoint1 = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Arc::CENTER_ID())); - aDelta = aPoint1->pnt()->distance(thePoint); - - std::shared_ptr aPoint2 = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Arc::START_ID())); - double aDistance = aPoint2->pnt()->distance(thePoint); - if (aDelta < aDistance) - aDelta = aDistance; - - std::shared_ptr aPoint3 = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Arc::END_ID())); - aDistance = aPoint3->pnt()->distance(thePoint); - if (aDelta < aDistance) - aDelta = aDistance; - - return aDelta; -} - -bool SketchPlugin_Arc::isFixed() { - return data()->selection(EXTERNAL_ID())->context().get(); -} - -bool SketchPlugin_Arc::isFeatureValid() -{ - std::shared_ptr aCenterAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::CENTER_ID())); - std::shared_ptr aStartAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr anEndAttr = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID())); - - return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized(); + return data()->selection(EXTERNAL_ID())->context().get() != NULL; } void SketchPlugin_Arc::attributeChanged(const std::string& theID) { std::shared_ptr aCenterAttr = std::dynamic_pointer_cast< GeomDataAPI_Point2D>(data()->attribute(CENTER_ID())); - if (!aCenterAttr->isInitialized()) - return; std::shared_ptr aStartAttr = std::dynamic_pointer_cast< GeomDataAPI_Point2D>(data()->attribute(START_ID())); - if (!aStartAttr->isInitialized()) - return; std::shared_ptr anEndAttr = std::dynamic_pointer_cast< GeomDataAPI_Point2D>(data()->attribute(END_ID())); - if (!anEndAttr->isInitialized()) - return; - // update the points in accordance to the changed point changes - if (theID == END_ID() && !myEndUpdate) { - myEndUpdate = true; - // compute and change the arc end point - std::shared_ptr aCircleForArc( - new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt())); - std::shared_ptr aProjection = aCircleForArc->project(anEndAttr->pnt()); - if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance) - anEndAttr->setValue(aProjection); - myEndUpdate = false; - } else if (theID == START_ID() && !myStartUpdate) { - myStartUpdate = true; - // compute and change the arc end point - std::shared_ptr aCircleForArc( - new GeomAPI_Circ2d(aCenterAttr->pnt(), anEndAttr->pnt())); - std::shared_ptr aProjection = aCircleForArc->project(aStartAttr->pnt()); - if (aProjection && aStartAttr->pnt()->distance(aProjection) > tolerance) - aStartAttr->setValue(aProjection); - myStartUpdate = false; - } else if (theID == CENTER_ID() && !myEndUpdate) { - myEndUpdate = true; - // compute and change the arc end point - std::shared_ptr aCircleForArc( - new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt())); - std::shared_ptr aProjection = aCircleForArc->project(anEndAttr->pnt()); - if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance) - anEndAttr->setValue(aProjection); - myEndUpdate = false; + // The second condition for unability to move external segments anywhere. + if(theID == EXTERNAL_ID() || isFixed()) { + std::shared_ptr aSelection = data()->selection(EXTERNAL_ID())->value(); + if(!aSelection) { + // empty shape in selection shows that the shape is equal to context + ResultPtr anExtRes = selection(EXTERNAL_ID())->context(); + if(anExtRes) { + aSelection = anExtRes->shape(); + } + } + // update arguments due to the selection value + if(aSelection && !aSelection->isNull() && aSelection->isEdge()) { + std::shared_ptr anEdge( new GeomAPI_Edge(aSelection)); + std::shared_ptr aCirc = anEdge->circle(); + if(aCirc.get()) { + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + aCenterAttr->setValue(sketch()->to2D(aCirc->center())); + aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint())); + anEndAttr->setValue(sketch()->to2D(anEdge->lastPoint())); + data()->blockSendAttributeUpdated(aWasBlocked, false); + + std::shared_ptr aCircle2d = + std::shared_ptr(new GeomAPI_Circ2d(aCenterAttr->pnt(), + aStartAttr->pnt())); + + double anEndParam = 0.0; + aCircle2d->parameter(anEndAttr->pnt(), paramTolerance, anEndParam); + myParamBefore = anEndParam; + + double aMidParam = anEndParam / 2.0; + std::shared_ptr aMidPnt2d; + aCircle2d->D0(aMidParam, aMidPnt2d); + std::shared_ptr aMinPnt = sketch()->to3D(aMidPnt2d->x(), aMidPnt2d->y()); + double aStartParam = 0.0; + aCirc->parameter(anEdge->firstPoint(), paramTolerance, aStartParam); + aCirc->parameter(aMinPnt, paramTolerance, aMidParam); + aCirc->parameter(anEdge->lastPoint(), paramTolerance, anEndParam); + + // adjust period + anEndParam -= aStartParam; + aMidParam -= aStartParam; + if (anEndParam < 0.0) + anEndParam += 2.0 * PI; + if (aMidParam < 0.0) + aMidParam += 2.0 * PI; + + aWasBlocked = data()->blockSendAttributeUpdated(true); + if(aMidParam < anEndParam) { + setReversed(false); + } else { + setReversed(true); + } + data()->blockSendAttributeUpdated(aWasBlocked, false); + } + } + } else if(theID == CENTER_ID() || theID == START_ID() || theID == END_ID()) { + if(!aCenterAttr->isInitialized() + || !aStartAttr->isInitialized() + || !anEndAttr->isInitialized()) { + return; + } + std::shared_ptr aCenter = aCenterAttr->pnt(); + std::shared_ptr aStart = aStartAttr->pnt(); + std::shared_ptr anEnd = anEndAttr->pnt(); + double aRadius = aCenter->distance(aStart); + if (aRadius < tolerance) + return; + std::shared_ptr aCircleForArc(new GeomAPI_Circ2d(aCenter, aStart)); + + // Do not recalculate REVERSED flag if the arc is not consistent + std::shared_ptr aProjection = aCircleForArc->project(anEnd); + if (aProjection && anEnd->distance(aProjection) <= tolerance) { + double aParameterNew = 0.0; + if(aCircleForArc->parameter(anEnd, paramTolerance, aParameterNew)) { + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) { + if(!boolean(REVERSED_ID())->value()) { + boolean(REVERSED_ID())->setValue(true); + } + } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) { + if(boolean(REVERSED_ID())->value()) { + boolean(REVERSED_ID())->setValue(false); + } + } + data()->blockSendAttributeUpdated(aWasBlocked, false); + } + if (fabs(aParameterNew) < paramTolerance || + fabs(aParameterNew - 2.0 * PI) < paramTolerance) + aParameterNew = 2.0 * PI; + myParamBefore = aParameterNew; + } + } + + double aRadius = 0; + double anAngle = 0; + if(aCenterAttr->isInitialized() && aStartAttr->isInitialized()) { + aRadius = aCenterAttr->pnt()->distance(aStartAttr->pnt()); + if(anEndAttr->isInitialized()) { + if(aStartAttr->pnt()->isEqual(anEndAttr->pnt())) { + anAngle = 360; + } else { + GeomAPI_Circ2d aCircleForArc(aCenterAttr->pnt(), aStartAttr->pnt()); + double aStartParam, anEndParam; + aCircleForArc.parameter(aStartAttr->pnt(), paramTolerance, aStartParam); + aCircleForArc.parameter(anEndAttr->pnt(), paramTolerance, anEndParam); + anAngle = (anEndParam - aStartParam) / PI * 180.0; + if(isReversed()) anAngle = 360.0 - anAngle; + } + } } + + bool aWasBlocked = data()->blockSendAttributeUpdated(true); + real(RADIUS_ID())->setValue(aRadius); + real(ANGLE_ID())->setValue(anAngle); + data()->blockSendAttributeUpdated(aWasBlocked, false); +} + +void SketchPlugin_Arc::setReversed(bool isReversed) +{ + boolean(REVERSED_ID())->setValue(isReversed); +} + +bool SketchPlugin_Arc::isReversed() +{ + return boolean(REVERSED_ID())->value(); }