From: azv Date: Wed, 3 Feb 2016 08:36:11 +0000 (+0300) Subject: Creating an arc by 3 points and a tangent arc X-Git-Tag: V_2.2.0~158 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=4507796772cdf8f63bc0bdb452b5013094fe7036;p=modules%2Fshaper.git Creating an arc by 3 points and a tangent arc --- diff --git a/src/GeomAPI/GeomAPI_Dir.cpp b/src/GeomAPI/GeomAPI_Dir.cpp index 3174cea0e..6f57e7681 100644 --- a/src/GeomAPI/GeomAPI_Dir.cpp +++ b/src/GeomAPI/GeomAPI_Dir.cpp @@ -41,6 +41,11 @@ const std::shared_ptr GeomAPI_Dir::xyz() return std::shared_ptr(new GeomAPI_XYZ(MY_DIR->X(), MY_DIR->Y(), MY_DIR->Z())); } +void GeomAPI_Dir::reverse() +{ + MY_DIR->Reverse(); +} + double GeomAPI_Dir::dot(const std::shared_ptr& theArg) const { return MY_DIR->Dot(theArg->impl()); diff --git a/src/GeomAPI/GeomAPI_Dir.h b/src/GeomAPI/GeomAPI_Dir.h index 4c4c007af..a3e49f907 100644 --- a/src/GeomAPI/GeomAPI_Dir.h +++ b/src/GeomAPI/GeomAPI_Dir.h @@ -41,6 +41,9 @@ class GeomAPI_Dir : public GeomAPI_Interface GEOMAPI_EXPORT const std::shared_ptr xyz(); + /// inverses the direction + GEOMAPI_EXPORT void reverse(); + /// result is a scalar product of directions GEOMAPI_EXPORT double dot(const std::shared_ptr& theArg) const; diff --git a/src/GeomAPI/GeomAPI_Dir2d.cpp b/src/GeomAPI/GeomAPI_Dir2d.cpp index 4cb8149a3..1e5332d31 100644 --- a/src/GeomAPI/GeomAPI_Dir2d.cpp +++ b/src/GeomAPI/GeomAPI_Dir2d.cpp @@ -36,6 +36,11 @@ const std::shared_ptr GeomAPI_Dir2d::xy() return std::shared_ptr(new GeomAPI_XY(MY_DIR->X(), MY_DIR->Y())); } +void GeomAPI_Dir2d::reverse() +{ + MY_DIR->Reverse(); +} + double GeomAPI_Dir2d::dot(const std::shared_ptr& theArg) const { return MY_DIR->Dot(theArg->impl()); diff --git a/src/GeomAPI/GeomAPI_Dir2d.h b/src/GeomAPI/GeomAPI_Dir2d.h index aafe267ce..2e8cc227e 100644 --- a/src/GeomAPI/GeomAPI_Dir2d.h +++ b/src/GeomAPI/GeomAPI_Dir2d.h @@ -38,6 +38,9 @@ class GeomAPI_Dir2d : public GeomAPI_Interface GEOMAPI_EXPORT const std::shared_ptr xy(); + /// inverses the direction + GEOMAPI_EXPORT void reverse(); + /// result is a scalar product of directions GEOMAPI_EXPORT double dot(const std::shared_ptr& theArg) const; diff --git a/src/GeomAPI/GeomAPI_Lin.cpp b/src/GeomAPI/GeomAPI_Lin.cpp index dba5834ab..a9fe074d0 100644 --- a/src/GeomAPI/GeomAPI_Lin.cpp +++ b/src/GeomAPI/GeomAPI_Lin.cpp @@ -43,6 +43,15 @@ GeomAPI_Lin::GeomAPI_Lin(const std::shared_ptr& theStart, { } +GeomAPI_Lin::GeomAPI_Lin(const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirection) + : GeomAPI_Interface(newLine(theOrigin->x(), theOrigin->y(), theOrigin->z(), + theOrigin->x() + theDirection->x(), + theOrigin->y() + theDirection->y(), + theOrigin->z() + theDirection->z())) +{ +} + std::shared_ptr GeomAPI_Lin::location() { gp_Pnt aLoc = impl().Location(); diff --git a/src/GeomAPI/GeomAPI_Lin.h b/src/GeomAPI/GeomAPI_Lin.h index b9323c856..6f6710984 100644 --- a/src/GeomAPI/GeomAPI_Lin.h +++ b/src/GeomAPI/GeomAPI_Lin.h @@ -29,6 +29,10 @@ class GeomAPI_Lin : public GeomAPI_Interface GEOMAPI_EXPORT GeomAPI_Lin(const std::shared_ptr& theStart, const std::shared_ptr& theEnd); + /// Creation of line defined by origin and direction + GEOMAPI_EXPORT + GeomAPI_Lin(const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirection); /// Returns point on the line (first point) GEOMAPI_EXPORT diff --git a/src/GeomAPI/GeomAPI_Lin2d.cpp b/src/GeomAPI/GeomAPI_Lin2d.cpp index 6b53b8fdc..2d97bd6c8 100644 --- a/src/GeomAPI/GeomAPI_Lin2d.cpp +++ b/src/GeomAPI/GeomAPI_Lin2d.cpp @@ -25,6 +25,7 @@ static gp_Lin2d* newLine2d(const double theStartX, const double theStartY, const return new gp_Lin2d(aStart, gp_Dir2d(aDir)); } + GeomAPI_Lin2d::GeomAPI_Lin2d(const double theStartX, const double theStartY, const double theEndX, const double theEndY) : GeomAPI_Interface(newLine2d(theStartX, theStartY, theEndX, theEndY)) @@ -37,6 +38,14 @@ GeomAPI_Lin2d::GeomAPI_Lin2d(const std::shared_ptr& theStart, { } +GeomAPI_Lin2d::GeomAPI_Lin2d(const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirection) + : GeomAPI_Interface(newLine2d(theOrigin->x(), theOrigin->y(), + theOrigin->x() + theDirection->x(), theOrigin->y() + theDirection->y())) +{ +} + + std::shared_ptr GeomAPI_Lin2d::location() { gp_Pnt2d aLoc = impl().Location(); diff --git a/src/GeomAPI/GeomAPI_Lin2d.h b/src/GeomAPI/GeomAPI_Lin2d.h index e5556ec9f..7aef47937 100644 --- a/src/GeomAPI/GeomAPI_Lin2d.h +++ b/src/GeomAPI/GeomAPI_Lin2d.h @@ -29,6 +29,10 @@ class GeomAPI_Lin2d : public GeomAPI_Interface GEOMAPI_EXPORT GeomAPI_Lin2d(const std::shared_ptr& theStart, const std::shared_ptr& theEnd); + /// Creation of line defined by origin and direction + GEOMAPI_EXPORT + GeomAPI_Lin2d(const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirection); /// Returns point on the line (first point) GEOMAPI_EXPORT diff --git a/src/PartSet/PartSet_icons.qrc b/src/PartSet/PartSet_icons.qrc index c6e632420..368893c2b 100644 --- a/src/PartSet/PartSet_icons.qrc +++ b/src/PartSet/PartSet_icons.qrc @@ -5,6 +5,9 @@ icons/angle_up.png icons/angle_down.png icons/arc.png + icons/arc_base_32x32.png + icons/arc_3pt_32x32.png + icons/arc_tang_32x32.png icons/circle.png icons/circle_pt_rad_32x32.png icons/circle_3pt_32x32.png diff --git a/src/PartSet/icons/arc_3pt_32x32.png b/src/PartSet/icons/arc_3pt_32x32.png new file mode 100644 index 000000000..584fa594a Binary files /dev/null and b/src/PartSet/icons/arc_3pt_32x32.png differ diff --git a/src/PartSet/icons/arc_base_32x32.png b/src/PartSet/icons/arc_base_32x32.png new file mode 100644 index 000000000..c36df3056 Binary files /dev/null and b/src/PartSet/icons/arc_base_32x32.png differ diff --git a/src/PartSet/icons/arc_tang_32x32.png b/src/PartSet/icons/arc_tang_32x32.png new file mode 100644 index 000000000..cfec981e7 Binary files /dev/null and b/src/PartSet/icons/arc_tang_32x32.png differ diff --git a/src/SketchPlugin/SketchPlugin_Arc.cpp b/src/SketchPlugin/SketchPlugin_Arc.cpp index 9ec13a320..b9c73ef85 100644 --- a/src/SketchPlugin/SketchPlugin_Arc.cpp +++ b/src/SketchPlugin/SketchPlugin_Arc.cpp @@ -6,16 +6,29 @@ #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 @@ -28,6 +41,63 @@ const double tolerance = 1e-7; const double paramTolerance = 1.e-4; const double PI =3.141592653589793238463; +namespace { + static const std::string& ARC_TYPE() + { + static const std::string TYPE("ArcType"); + return TYPE; + } + static const std::string& ARC_TYPE_CENTER_START_END() + { + static const std::string TYPE("CenterStartEnd"); + return TYPE; + } + static const std::string& ARC_TYPE_THREE_POINTS() + { + static const std::string TYPE("ThreePoints"); + return TYPE; + } + static const std::string& ARC_TYPE_TANGENT() + { + static const std::string TYPE("Tangent"); + return TYPE; + } + + static const std::string& PASSED_POINT_ID() + { + static const std::string PASSED_PNT("ArcPassedPoint"); + return PASSED_PNT; + } + static const std::string& TANGENT_POINT_ID() + { + static const std::string TANGENT_PNT("ArcTangentPoint"); + return TANGENT_PNT; + } + static const std::string& RADIUS_ID() + { + static const std::string RADIUS("ArcRadius"); + return RADIUS; + } + static const std::string& ANGLE_ID() + { + static const std::string ANGLE("ArcAngle"); + return ANGLE; + } + + static const std::string& POINT_ID(int theIndex) + { + switch (theIndex) { + case 1: return SketchPlugin_Arc::START_ID(); + case 2: return SketchPlugin_Arc::END_ID(); + case 3: return PASSED_POINT_ID(); + } + + static const std::string DUMMY; + return DUMMY; + } +} + + SketchPlugin_Arc::SketchPlugin_Arc() : SketchPlugin_SketchEntity() @@ -61,6 +131,15 @@ void SketchPlugin_Arc::initDerivedClassAttributes() myXEndBefore = anEndAttr->x(); myYEndBefore = anEndAttr->y(); } + + data()->addAttribute(ARC_TYPE(), ModelAPI_AttributeString::typeId()); + std::dynamic_pointer_cast( + data()->attribute(ARC_TYPE()))->setValue(ARC_TYPE_CENTER_START_END()); + + data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId()); + data()->addAttribute(TANGENT_POINT_ID(), ModelAPI_AttributeRefAttr::typeId()); + data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId()); + data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId()); } void SketchPlugin_Arc::execute() @@ -69,6 +148,9 @@ void SketchPlugin_Arc::execute() // 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()) { + ResultPtr aLastResult = lastResult(); + bool hasResult = aLastResult && aLastResult.get(); + // compute a circle point in 3D view std::shared_ptr aCenterAttr = std::dynamic_pointer_cast< GeomDataAPI_Point2D>(data()->attribute(CENTER_ID())); @@ -132,6 +214,11 @@ void SketchPlugin_Arc::execute() aConstr2->setIsInHistory(false); setResult(aConstr2, 1); } + + AttributeRefAttrPtr aTangentPoint = std::dynamic_pointer_cast( + attribute(TANGENT_POINT_ID())); + if (!hasResult && aTangentPoint->attr()) + tangencyArcConstraints(); } } @@ -149,6 +236,11 @@ AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious) std::shared_ptr aStartAttr = std::dynamic_pointer_cast< GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::START_ID())); + std::shared_ptr aEndAttr = std::dynamic_pointer_cast< + GeomDataAPI_Point2D>(data()->attribute(SketchPlugin_Arc::END_ID())); + AttributeStringPtr aTypeAttr = std::dynamic_pointer_cast( + data()->attribute(ARC_TYPE())); + if (aStartAttr->isInitialized()) { // make a visible circle std::shared_ptr aNDir = std::dynamic_pointer_cast( @@ -157,8 +249,12 @@ AISObjectPtr SketchPlugin_Arc::getAISObject(AISObjectPtr thePrevious) if (aHasPlane) { std::shared_ptr aNormal = aNDir->dir(); std::shared_ptr aStartPoint(aSketch->to3D(aStartAttr->x(), aStartAttr->y())); + std::shared_ptr aEndPoint = aStartPoint; + if (aTypeAttr && aTypeAttr->isInitialized() && + aTypeAttr->value() == ARC_TYPE_THREE_POINTS() && aEndAttr->isInitialized()) + aEndPoint = aSketch->to3D(aEndAttr->x(), aEndAttr->y()); std::shared_ptr aCircleShape = GeomAlgoAPI_EdgeBuilder::lineCircleArc( - aCenter, aStartPoint, aStartPoint, aNormal); + aCenter, aStartPoint, aEndPoint, aNormal); if (aCircleShape) { std::list > aShapes; // make a visible point @@ -191,6 +287,8 @@ void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY) if (!aData->isValid()) return; + aData->blockSendAttributeUpdated(true); + myStartUpdate = true; myEndUpdate = true; std::shared_ptr aPoint2 = std::dynamic_pointer_cast( @@ -206,6 +304,11 @@ void SketchPlugin_Arc::move(double theDeltaX, double theDeltaY) std::shared_ptr aPoint1 = std::dynamic_pointer_cast( aData->attribute(SketchPlugin_Arc::CENTER_ID())); aPoint1->move(theDeltaX, theDeltaY); + + std::shared_ptr aPassedPoint = + std::dynamic_pointer_cast(aData->attribute(PASSED_POINT_ID())); + aPassedPoint->move(theDeltaX, theDeltaY); + aData->blockSendAttributeUpdated(false); } bool SketchPlugin_Arc::isFixed() { @@ -214,16 +317,108 @@ bool SketchPlugin_Arc::isFixed() { bool SketchPlugin_Arc::isFeatureValid() { + AttributeStringPtr anArcTypeAttr = + std::dynamic_pointer_cast(data()->attribute(ARC_TYPE())); + if (!anArcTypeAttr) + return false; + std::string anArcType = anArcTypeAttr->value(); + 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())); + std::shared_ptr aPassedAttr = std::dynamic_pointer_cast< + GeomDataAPI_Point2D>(data()->attribute(PASSED_POINT_ID())); - return aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized(); + bool isValid = false; + if (anArcType == ARC_TYPE_THREE_POINTS()) + isValid = aStartAttr->isInitialized() && anEndAttr->isInitialized() && aPassedAttr->isInitialized(); + else + isValid = aCenterAttr->isInitialized() && aStartAttr->isInitialized() && anEndAttr->isInitialized(); + + return isValid; } +static inline void adjustPeriod(double& theParam) +{ + static const double PERIOD = 2.0 * PI; + while (theParam < 0.0) theParam += PERIOD; + while (theParam >= PERIOD) theParam -= PERIOD; +} + +static inline void calculateArcAngleRadius( + const std::shared_ptr& theCircle, + const std::shared_ptr& theStartPoint, + const std::shared_ptr& theEndPoint, + const std::shared_ptr& thePassedPoint, + AttributeDoublePtr theAngleAttr, + AttributeDoublePtr theRadiusAttr) +{ + double aStartParam, aEndParam, aPassedParam; + theCircle->parameter(theStartPoint, paramTolerance, aStartParam); + theCircle->parameter(theEndPoint, paramTolerance, aEndParam); + theCircle->parameter(thePassedPoint, paramTolerance, aPassedParam); + adjustPeriod(aStartParam); + adjustPeriod(aEndParam); + adjustPeriod(aPassedParam); + + if (aPassedParam >= aStartParam && aPassedParam <= aEndParam) + theAngleAttr->setValue((aEndParam - aStartParam) * 180.0 / PI); + else + theAngleAttr->setValue((aEndParam - aStartParam - 2.0 * PI) * 180.0 / PI); + theRadiusAttr->setValue(theCircle->radius()); +} + +static inline void calculatePassedPoint( + const std::shared_ptr& theCenter, + const std::shared_ptr& theStartPoint, + const std::shared_ptr& theEndPoint, + bool theArcReversed, + std::shared_ptr thePassedPoint) +{ + std::shared_ptr aStartDir(new GeomAPI_Dir2d( + theStartPoint->xy()->decreased(theCenter->xy()))); + std::shared_ptr aEndDir(new GeomAPI_Dir2d( + theEndPoint->xy()->decreased(theCenter->xy()))); + std::shared_ptr aMidDir(new GeomAPI_Dir2d( + aStartDir->xy()->added(aEndDir->xy()))); + if ((aStartDir->cross(aMidDir) > 0) ^ !theArcReversed) + aMidDir->reverse(); + + double aRadius = theCenter->distance(theStartPoint); + std::shared_ptr aPassedPnt = theCenter->xy()->added( aMidDir->xy()->multiplied(aRadius) ); + thePassedPoint->setValue(aPassedPnt->x(), aPassedPnt->y()); +} + +void SketchPlugin_Arc::updateDependentAttributes() +{ + data()->blockSendAttributeUpdated(true); + + std::shared_ptr aCenterAttr = std::dynamic_pointer_cast< + GeomDataAPI_Point2D>(data()->attribute(CENTER_ID())); + std::shared_ptr aStartAttr = std::dynamic_pointer_cast< + GeomDataAPI_Point2D>(data()->attribute(START_ID())); + std::shared_ptr anEndAttr = std::dynamic_pointer_cast< + GeomDataAPI_Point2D>(data()->attribute(END_ID())); + std::shared_ptr aPassedPoint = + std::dynamic_pointer_cast(attribute(PASSED_POINT_ID())); + AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast( + data()->attribute(RADIUS_ID())); + AttributeDoublePtr anAngleAttr = std::dynamic_pointer_cast( + data()->attribute(ANGLE_ID())); + + calculatePassedPoint(aCenterAttr->pnt(), aStartAttr->pnt(), anEndAttr->pnt(), + isReversed(), aPassedPoint); + std::shared_ptr aCircle( + new GeomAPI_Circ2d(aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt())); + calculateArcAngleRadius(aCircle, aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt(), + anAngleAttr, aRadiusAttr); + data()->blockSendAttributeUpdated(false); +} + + void SketchPlugin_Arc::attributeChanged(const std::string& theID) { std::shared_ptr aCenterAttr = std::dynamic_pointer_cast< @@ -247,19 +442,199 @@ void SketchPlugin_Arc::attributeChanged(const std::string& theID) } return; } - if (!isFeatureValid()) + + AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast( + data()->attribute(RADIUS_ID())); + AttributeDoublePtr anAngleAttr = std::dynamic_pointer_cast( + data()->attribute(ANGLE_ID())); + + if (theID == RADIUS_ID()) { + if (!aStartAttr->isInitialized() || !anEndAttr->isInitialized()) + return; + // move center and passed point + std::shared_ptr aStartPnt = aStartAttr->pnt(); + std::shared_ptr aEndPnt = anEndAttr->pnt(); + double aDist = aStartPnt->distance(aEndPnt); + if (fabs(aDist) < tolerance) + return; + std::shared_ptr aDir = aEndPnt->xy()->decreased(aStartPnt->xy()); + std::shared_ptr aMidPerpDir(new GeomAPI_Dir2d(-aDir->y(), aDir->x())); + std::shared_ptr aMidPnt = aStartPnt->xy()->added(aEndPnt->xy())->multiplied(0.5); + + double anAngle = anAngleAttr->value() * PI / 180.0; + adjustPeriod(anAngle); + if (anAngle > PI) + aMidPerpDir->reverse(); + + double aRadius = aRadiusAttr->value(); + aDist = sqrt(aRadius * aRadius - aDist * aDist / 4.0); + + std::shared_ptr aCenter = aMidPnt->added(aMidPerpDir->xy()->multiplied(aDist)); + + data()->blockSendAttributeUpdated(true); + aCenterAttr->setValue(aCenter->x(), aCenter->y()); + updateDependentAttributes(); + data()->blockSendAttributeUpdated(false); return; + } + if (theID == ANGLE_ID()) { + if (!aStartAttr->isInitialized() || !aCenterAttr->isInitialized()) + return; + data()->blockSendAttributeUpdated(true); + // move end point and passed point + std::shared_ptr aCenter = aCenterAttr->pnt()->xy(); + double anAngle = anAngleAttr->value() * PI / 180.0; + double sinA = sin(anAngle); + double cosA = cos(anAngle); + std::shared_ptr aStartDir = aStartAttr->pnt()->xy()->decreased(aCenter); + std::shared_ptr aDir(new GeomAPI_XY( + aStartDir->x() * cosA - aStartDir->y() * sinA, + aStartDir->x() * sinA + aStartDir->y() * cosA)); + anEndAttr->setValue(aCenter->x() + aDir->x(), aCenter->y() + aDir->y()); - // update the points in accordance to the changed point changes - if (theID == CENTER_ID() && !myEndUpdate) { - myEndUpdate = true; + anAngle /= 2.0; + sinA = sin(anAngle); + cosA = cos(anAngle); + aDir = std::shared_ptr(new GeomAPI_XY( + aStartDir->x() * cosA - aStartDir->y() * sinA, + aStartDir->x() * sinA + aStartDir->y() * cosA)); + std::shared_ptr aPassedPoint = + std::dynamic_pointer_cast(attribute(PASSED_POINT_ID())); + aPassedPoint->setValue(aCenter->x() + aDir->x(), aCenter->y() + aDir->y()); + + std::shared_ptr aCircle( + new GeomAPI_Circ2d(aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt())); + calculateArcAngleRadius(aCircle, aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt(), + anAngleAttr, aRadiusAttr); + data()->blockSendAttributeUpdated(false); + return; + } + + if (theID == CENTER_ID()) { + if (!isFeatureValid()) + return; + data()->blockSendAttributeUpdated(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; + updateDependentAttributes(); + data()->blockSendAttributeUpdated(false); + return; + } + + AttributeStringPtr aTypeAttr = + std::dynamic_pointer_cast(attribute(ARC_TYPE())); + if (!aTypeAttr) + return; + std::string anArcType = aTypeAttr->value(); + + // update the points in accordance to the changed point changes + if (anArcType == ARC_TYPE_CENTER_START_END()) { + if (!isFeatureValid()) + return; + updateDependentAttributes(); + } + else if (anArcType == ARC_TYPE_THREE_POINTS() && + (theID == START_ID() || theID == END_ID() || theID == PASSED_POINT_ID())) { + data()->blockSendAttributeUpdated(true); + + std::shared_ptr aPoints[3]; + int aNbInitialized = 0; + for (int i = 1; i <= 3; ++i) { + std::shared_ptr aCurPnt = + std::dynamic_pointer_cast(attribute(POINT_ID(i))); + if (aCurPnt->isInitialized()) + aPoints[aNbInitialized++] = aCurPnt->pnt(); + } + + if (aNbInitialized == 1) + aCenterAttr->setValue(aPoints[0]->x(), aPoints[0]->y()); + else if (aNbInitialized == 2) { + // calculate center point, which gives a quarter of circle for the given start and end points + std::shared_ptr aStartPnt = aPoints[0]; + std::shared_ptr aEndPnt = aPoints[1]; + std::shared_ptr aDir = aEndPnt->xy()->decreased(aStartPnt->xy())->multiplied(0.5); + double x = aDir->x(); + double y = aDir->y(); + aDir->setX(x - y); + aDir->setY(y + x); + std::shared_ptr aCenter = aStartPnt->xy()->added(aDir); + double aRadius = sqrt(aDir->dot(aDir)); + + aCenterAttr->setValue(aCenter->x(), aCenter->y()); + aRadiusAttr->setValue(aRadius); + anAngleAttr->setValue(90.0); + } + else { + std::shared_ptr aCircle( + new GeomAPI_Circ2d(aPoints[0], aPoints[1], aPoints[2])); + + std::shared_ptr aCenter = aCircle->center(); + if (aCenter) { + aCenterAttr->setValue(aCenter); + if (theID == START_ID() || theID == END_ID()) + updateDependentAttributes(); + else + calculateArcAngleRadius(aCircle, aPoints[0], aPoints[1], aPoints[2], + anAngleAttr, aRadiusAttr); + } + } + + data()->blockSendAttributeUpdated(false); + } + else if (anArcType == ARC_TYPE_TANGENT() && (theID == TANGENT_POINT_ID() || theID == END_ID())) { + SketchPlugin_Sketch* aSketch = sketch(); + AttributeRefAttrPtr aTangPtAttr = std::dynamic_pointer_cast( + data()->attribute(TANGENT_POINT_ID())); + + if (aTangPtAttr->isInitialized() && anEndAttr->isInitialized()) { + data()->blockSendAttributeUpdated(true); + // compute orthogonal direction + std::shared_ptr anOrthoDir; + std::shared_ptr aTangentPoint = + std::dynamic_pointer_cast(aTangPtAttr->attr()); + std::shared_ptr aTangPnt2d = aTangentPoint->pnt(); + FeaturePtr aTangFeature = ModelAPI_Feature::feature(aTangentPoint->owner()); + std::shared_ptr aTangEdge = std::dynamic_pointer_cast( + aTangFeature->lastResult()->shape()); + if (aTangEdge->isLine()) { + std::shared_ptr aDir = aTangEdge->line()->direction(); + std::shared_ptr aPnt(new GeomAPI_Pnt(aDir->x(), aDir->y(), aDir->z())); + std::shared_ptr aPnt2d = aSketch->to2D(aPnt); + anOrthoDir = std::shared_ptr(new GeomAPI_Dir2d(-aPnt2d->y(), aPnt2d->x())); + } + else if (aTangEdge->isArc()) { + std::shared_ptr aCenter = aTangEdge->circle()->center(); + std::shared_ptr aCenter2d = aSketch->to2D(aCenter); + anOrthoDir = std::shared_ptr( + new GeomAPI_Dir2d(aTangPnt2d->xy()->decreased(aCenter2d->xy()))); + } + + // compute parameters of the middle perpendicular + std::shared_ptr aEndPntCoord = anEndAttr->pnt()->xy(); + std::shared_ptr aTempDir = aEndPntCoord->decreased(aTangPnt2d->xy()); + std::shared_ptr aMidDir(new GeomAPI_Dir2d(-aTempDir->y(), aTempDir->x())); + std::shared_ptr aMidPnt( + new GeomAPI_Pnt2d(aEndPntCoord->added(aTangPnt2d->xy())->multiplied(0.5))); + + // compute center of arc by calculating intersection of orthogonal line and middle perpendicular + std::shared_ptr anOrthoLine(new GeomAPI_Lin2d(aTangPnt2d, anOrthoDir)); + std::shared_ptr aMiddleLine(new GeomAPI_Lin2d(aMidPnt, aMidDir)); + std::shared_ptr aCenter = anOrthoLine->intersect(aMiddleLine); + if (aCenter) { + aCenterAttr->setValue(aCenter); + aStartAttr->setValue(aTangPnt2d); + updateDependentAttributes(); + } + + data()->blockSendAttributeUpdated(false); + + if (theID == TANGENT_POINT_ID()) + tangencyArcConstraints(); + } } } @@ -273,3 +648,147 @@ bool SketchPlugin_Arc::isReversed() { return std::dynamic_pointer_cast(attribute(INVERSED_ID()))->value(); } + +void SketchPlugin_Arc::tangencyArcConstraints() +{ + if (!lastResult()) + return; + + std::shared_ptr aStartAttr = + std::dynamic_pointer_cast(attribute(START_ID())); + AttributeRefAttrPtr aTangPtAttr = std::dynamic_pointer_cast( + attribute(TANGENT_POINT_ID())); + if (!aTangPtAttr->attr()) + return; + + FeaturePtr aFeature = ModelAPI_Feature::feature(aStartAttr->owner()); + ObjectPtr aThisArc = aFeature->lastResult(); + aFeature = ModelAPI_Feature::feature(aTangPtAttr->attr()->owner()); + ObjectPtr aTangFeature = aFeature->lastResult(); + + // trying to find constraints to fix the tangency of the arc + std::set aCoincidence; + std::set aTangency; + + AttributeRefAttrPtr aRefAttrA, aRefAttrB; + std::set aRefs = data()->refsToMe(); + const std::set& aRefsToResult = lastResult()->data()->refsToMe(); + aRefs.insert(aRefsToResult.begin(), aRefsToResult.end()); + std::set::const_iterator aRefIt = aRefs.begin(); + for (; aRefIt != aRefs.end(); ++aRefIt) { + FeaturePtr aConstrFeature = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + aRefAttrA = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B())); + if ((aRefAttrA && aRefAttrA->attr() == aStartAttr) || + (aRefAttrB && aRefAttrB->attr() == aStartAttr)) + aCoincidence.insert(aConstrFeature); + } + else if (aConstrFeature->getKind() == SketchPlugin_ConstraintTangent::ID()) { + aRefAttrA = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B())); + if ((aRefAttrA && aRefAttrA->object() == aThisArc) || + (aRefAttrB && aRefAttrB->object() == aThisArc)) + aTangency.insert(aConstrFeature); + } + } + // search applicable pair of constraints + bool isFound = false; + FeaturePtr aPrevCoincidence, aPrevTangency; + std::set::const_iterator aCIt, aTIt; + for (aCIt = aCoincidence.begin(); aCIt != aCoincidence.end() && !isFound; ++aCIt) { + aRefAttrA = std::dynamic_pointer_cast( + (*aCIt)->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + (*aCIt)->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributePtr anOtherPoint = + aRefAttrA->attr() == aStartAttr ? aRefAttrB->attr() : aRefAttrA->attr(); + for (aTIt = aTangency.begin(); aTIt != aTangency.end() && !isFound; ++aTIt) { + aRefAttrA = std::dynamic_pointer_cast( + (*aTIt)->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + (*aTIt)->attribute(SketchPlugin_Constraint::ENTITY_B())); + ObjectPtr anOtherObject = aRefAttrA->object() == aThisArc ? + aRefAttrB->object() : aRefAttrA->object(); + if (anOtherPoint->owner() == anOtherObject) { + isFound = true; + aPrevCoincidence = *aCIt; + aPrevTangency = *aTIt; + } + } + } + + if (isFound) { + // update previous constraints + aRefAttrA = std::dynamic_pointer_cast( + aPrevCoincidence->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + aPrevCoincidence->attribute(SketchPlugin_Constraint::ENTITY_B())); + if (aRefAttrA->attr() == aStartAttr) + aRefAttrB->setAttr(aTangPtAttr->attr()); + else + aRefAttrA->setAttr(aTangPtAttr->attr()); + + aRefAttrA = std::dynamic_pointer_cast( + aPrevTangency->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + aPrevTangency->attribute(SketchPlugin_Constraint::ENTITY_B())); + if (aRefAttrA->object() == aThisArc) + aRefAttrB->setObject(aTangFeature); + else + aRefAttrA->setObject(aTangFeature); + } else { + // Wait all constraints being removed, then send update events + static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED); + bool isDeleteFlushed = Events_Loop::loop()->isFlushed(aDeleteEvent); + if (isDeleteFlushed) + Events_Loop::loop()->setFlushed(aDeleteEvent, false); + // Remove all obtained constraints which use current arc, because + // there is no information which of them were used to build tangency arc. + DocumentPtr aDoc = sketch()->document(); + for (aCIt = aCoincidence.begin(); aCIt != aCoincidence.end(); ++aCIt) + aDoc->removeFeature(*aCIt); + for (aTIt = aTangency.begin(); aTIt != aTangency.end(); ++aTIt) + aDoc->removeFeature(*aTIt); + // Send events to update the sub-features by the solver. + if (isDeleteFlushed) + Events_Loop::loop()->setFlushed(aDeleteEvent, true); + else + Events_Loop::loop()->flush(aDeleteEvent); + + // Wait all constraints being created, then send update events + static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); + if (isUpdateFlushed) + Events_Loop::loop()->setFlushed(anUpdateEvent, false); + + // Create new constraints + FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID()); + aRefAttrA = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttrA->setAttr(aStartAttr); + aRefAttrB->setAttr(aTangPtAttr->attr()); + aConstraint->execute(); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + + aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID()); + aRefAttrA = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + aRefAttrB = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + aRefAttrA->setObject(aThisArc); + aRefAttrB->setObject(aTangFeature); + aConstraint->execute(); + ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent); + + // Send events to update the sub-features by the solver. + if(isUpdateFlushed) + Events_Loop::loop()->setFlushed(anUpdateEvent, true); + } +} diff --git a/src/SketchPlugin/SketchPlugin_Arc.h b/src/SketchPlugin/SketchPlugin_Arc.h index 296b849bc..2bd7c0c44 100644 --- a/src/SketchPlugin/SketchPlugin_Arc.h +++ b/src/SketchPlugin/SketchPlugin_Arc.h @@ -105,6 +105,12 @@ protected: private: /// Returns true if all obligatory attributes are initialized bool isFeatureValid(); + + /// Update attributes like passed point, radius and angle of the arc + void updateDependentAttributes(); + + /// Compose constraints to build tangency arc + void tangencyArcConstraints(); }; #endif diff --git a/src/SketchPlugin/SketchPlugin_Circle.cpp b/src/SketchPlugin/SketchPlugin_Circle.cpp index ea819628e..f252df658 100644 --- a/src/SketchPlugin/SketchPlugin_Circle.cpp +++ b/src/SketchPlugin/SketchPlugin_Circle.cpp @@ -30,12 +30,12 @@ namespace { static const std::string TYPE("CircleType"); return TYPE; } - static const std::string CIRCLE_TYPE_CENTER_AND_RADIUS() + static const std::string& CIRCLE_TYPE_CENTER_AND_RADIUS() { static const std::string TYPE("CenterRadius"); return TYPE; } - static const std::string CIRCLE_TYPE_THREE_POINTS() + static const std::string& CIRCLE_TYPE_THREE_POINTS() { static const std::string TYPE("ThreePoints"); return TYPE; diff --git a/src/SketchPlugin/SketchPlugin_Validators.cpp b/src/SketchPlugin/SketchPlugin_Validators.cpp index 46bbf6a66..9ac7fec38 100755 --- a/src/SketchPlugin/SketchPlugin_Validators.cpp +++ b/src/SketchPlugin/SketchPlugin_Validators.cpp @@ -125,6 +125,8 @@ static bool hasCoincidentPoint(FeaturePtr theFeature1, FeaturePtr theFeature2) anAttr = aConstrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()); aRefAttr = std::dynamic_pointer_cast(anAttr); + if (!aRefAttr) + continue; anAttr = aRefAttr->attr(); for (std::list::const_iterator anIt = anAttrList.begin(); anIt != anAttrList.end(); ++anIt) diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index 98d339bc8..68e7e32f0 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -40,23 +40,54 @@ + - + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp index 96fa9ea2f..404c5df7f 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include void SketchSolver_ConstraintMulti::getEntities(std::list& theEntities) { @@ -155,8 +157,10 @@ void SketchSolver_ConstraintMulti::adjustConstraint() } else if (aFeature->getKind() == SketchPlugin_Line::ID()) { aPoints.push_back(aFeature->attribute(SketchPlugin_Line::START_ID())); aPoints.push_back(aFeature->attribute(SketchPlugin_Line::END_ID())); - } else - aPoints = aFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) + aPoints.push_back(aFeature->attribute(SketchPlugin_Circle::CENTER_ID())); + else if (aFeature->getKind() == SketchPlugin_Point::ID()) + aPoints.push_back(aFeature->attribute(SketchPlugin_Point::COORD_ID())); std::list::iterator aPtIt = aPoints.begin(); for (aXIt = aX.begin(), aYIt = aY.begin(); aPtIt != aPoints.end(); ++aXIt, ++aYIt, ++aPtIt) { diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index 837054917..e149fe03d 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include @@ -80,6 +82,25 @@ void SketchSolver_Storage::addConstraint( theConstraint->data()->blockSendAttributeUpdated(myEventsBlocked); } +static std::list pointAttributes(FeaturePtr theFeature) +{ + std::list aPoints; + if (theFeature->getKind() == SketchPlugin_Arc::ID()) { + aPoints.push_back(theFeature->attribute(SketchPlugin_Arc::CENTER_ID())); + aPoints.push_back(theFeature->attribute(SketchPlugin_Arc::START_ID())); + aPoints.push_back(theFeature->attribute(SketchPlugin_Arc::END_ID())); + } + else if (theFeature->getKind() == SketchPlugin_Circle::ID()) + aPoints.push_back(theFeature->attribute(SketchPlugin_Circle::CENTER_ID())); + else if (theFeature->getKind() == SketchPlugin_Line::ID()) { + aPoints.push_back(theFeature->attribute(SketchPlugin_Line::START_ID())); + aPoints.push_back(theFeature->attribute(SketchPlugin_Line::END_ID())); + } + else if (theFeature->getKind() == SketchPlugin_Point::ID()) + aPoints.push_back(theFeature->attribute(SketchPlugin_Point::ID())); + return aPoints; +} + void SketchSolver_Storage::addEntity(FeaturePtr theFeature, EntityWrapperPtr theSolverEntity) { @@ -90,8 +111,7 @@ void SketchSolver_Storage::addEntity(FeaturePtr theFeature, if (!theSolverEntity) { // feature links to the empty entity, add its attributes - std::list aPntAttrs = - theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list aPntAttrs = pointAttributes(theFeature); std::list::const_iterator anAttrIt = aPntAttrs.begin(); for (; anAttrIt != aPntAttrs.end(); ++anAttrIt) addEntity(*anAttrIt, EntityWrapperPtr()); @@ -131,8 +151,7 @@ bool SketchSolver_Storage::update(FeaturePtr theFeature, const GroupID& theGroup // Reserve the feature in the map of features (do not want to add several copies of it) myFeatureMap[theFeature] = aRelated; // Firstly, create/update its attributes - std::list anAttrs = - theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list anAttrs = pointAttributes(theFeature); std::list::const_iterator anIt = anAttrs.begin(); for (; anIt != anAttrs.end(); ++anIt) { isUpdated = update(*anIt, theGroup) || isUpdated; @@ -335,7 +354,7 @@ bool SketchSolver_Storage::isUsed(FeaturePtr theFeature) const if (::isUsed(*aCWIt, theFeature)) return true; // check attributes - std::list anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list anAttrList = pointAttributes(theFeature); std::list::const_iterator anIt = anAttrList.begin(); for (; anIt != anAttrList.end(); ++anIt) if (isUsed(*anIt))