#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_Circ.h>
+#include <GeomAPI_Circ2d.h>
+#include <GeomAPI_Vertex.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
#include <GeomDataAPI_Dir.h>
#include <GeomAlgoAPI_EdgeBuilder.h>
#include <GeomAlgoAPI_CompoundBuilder.h>
-namespace {
- static const std::string& CIRCLE_TYPE()
- {
- static const std::string TYPE("CircleType");
- return TYPE;
- }
- 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 TYPE("ThreePoints");
- return TYPE;
- }
+#include <cmath>
- static const std::string& FIRST_POINT_ID()
- {
- static const std::string FIRST_PNT("FirstPoint");
- return FIRST_PNT;
- }
- static const std::string& SECOND_POINT_ID()
- {
- static const std::string SECOND_PNT("SecondPoint");
- return SECOND_PNT;
- }
- static const std::string& THIRD_POINT_ID()
- {
- static const std::string THIRD_PNT("ThirdPoint");
- return THIRD_PNT;
- }
+const double tolerance = 1e-7;
+
+namespace {
static const std::string& POINT_ID(int theIndex)
{
switch (theIndex) {
- case 1: return FIRST_POINT_ID();
- case 2: return SECOND_POINT_ID();
- case 3: return THIRD_POINT_ID();
+ case 1: return SketchPlugin_Circle::FIRST_POINT_ID();
+ case 2: return SketchPlugin_Circle::SECOND_POINT_ID();
+ case 3: return SketchPlugin_Circle::THIRD_POINT_ID();
}
static const std::string DUMMY;
}
}
-static void calculateCircleOnThreePoints(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPnt,
- const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPnt,
- const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPnt,
- std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
- double& theRadius);
-
SketchPlugin_Circle::SketchPlugin_Circle()
: SketchPlugin_SketchEntity()
AISObjectPtr SketchPlugin_Circle::getAISObject(AISObjectPtr thePrevious)
{
SketchPlugin_Sketch* aSketch = sketch();
- if (aSketch) {
+ if (aSketch && !isFeatureValid()) {
// compute a circle point in 3D view
std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
if (aCircleShape && aRadius != 0) {
std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
// make a visible point
- std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::point(aCenter);
+ std::shared_ptr<GeomAPI_Shape> aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
aShapes.push_back(aCenterPointShape);
aShapes.push_back(aCircleShape);
return AISObjectPtr();
}
+bool SketchPlugin_Circle::isFeatureValid()
+{
+ std::shared_ptr<GeomDataAPI_Point2D> aCenter =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+ bool aValid = aCenter->isInitialized();
+
+ std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
+ data()->attribute(CIRCLE_TYPE()))->value();
+ if (aType == CIRCLE_TYPE_THREE_POINTS()) {
+ std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
+ aValid = aValid &&
+ aFirstPnt->isInitialized() &&
+ aSecondPnt->isInitialized() &&
+ aThirdPnt->isInitialized();
+ }
+ return aValid;
+}
+
void SketchPlugin_Circle::move(double theDeltaX, double theDeltaY)
{
std::shared_ptr<ModelAPI_Data> aData = data();
if (!aData->isValid())
return;
- std::shared_ptr<GeomDataAPI_Point2D> aPoint1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
aData->attribute(CENTER_ID()));
- aPoint1->move(theDeltaX, theDeltaY);
+ aPoint->move(theDeltaX, theDeltaY);
+
+ aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(FIRST_POINT_ID()));
+ aPoint->move(theDeltaX, theDeltaY);
+ aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(SECOND_POINT_ID()));
+ aPoint->move(theDeltaX, theDeltaY);
+ aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(THIRD_POINT_ID()));
+ aPoint->move(theDeltaX, theDeltaY);
}
bool SketchPlugin_Circle::isFixed() {
// the second condition for unability to move external segments anywhere
if (theID == EXTERNAL_ID() || isFixed()) {
std::shared_ptr<GeomAPI_Shape> 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<GeomAPI_Edge> anEdge( new GeomAPI_Edge(aSelection));
else if (theID == CENTER_ID() || theID == RADIUS_ID()) {
std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
data()->attribute(CIRCLE_TYPE()))->value();
- if (aType == CIRCLE_TYPE_THREE_POINTS())
- return;
-
- std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
- if (!aCenterAttr->isInitialized())
- return;
- AttributeDoublePtr aRadiusAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(attribute(RADIUS_ID()));
- if (!aRadiusAttr->isInitialized())
- return;
-
- // check the execute() was called and the shape was built
- if (!lastResult())
- return;
-
- data()->blockSendAttributeUpdated(true);
- std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
- double aRadius = aRadiusAttr->value();
- aFirstPnt->setValue(aCenterAttr->x() + aRadius, aCenterAttr->y());
- aSecondPnt->setValue(aCenterAttr->x(), aCenterAttr->y() + aRadius);
- aThirdPnt->setValue(aCenterAttr->x() - aRadius, aCenterAttr->y());
- data()->blockSendAttributeUpdated(false);
- }
- else if (theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
+ if (aType == CIRCLE_TYPE_THREE_POINTS() && lastResult()) // adjust data from the solver
+ adjustThreePoints();
+ } else if (theID == FIRST_POINT_ID() || theID == SECOND_POINT_ID() || theID == THIRD_POINT_ID()) {
+ // support the center and radius attributes enev in other mode: solver uses them
std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
data()->attribute(CIRCLE_TYPE()))->value();
if (aType == CIRCLE_TYPE_CENTER_AND_RADIUS())
return;
-
- data()->blockSendAttributeUpdated(true);
-
+ data()->blockSendAttributeUpdated(true); // to modify two attributes at once
std::shared_ptr<GeomAPI_Pnt2d> aPoints[3];
int aNbInitialized = 0;
for (int i = 1; i <= 3; ++i) {
aCenterAttr->setValue(aCoord->x(), aCoord->y());
aRadiusAttr->setValue(aRadius);
} else {
- std::shared_ptr<GeomAPI_Pnt2d> aCenter;
- double aRadius;
- calculateCircleOnThreePoints(aPoints[0], aPoints[1], aPoints[2], aCenter, aRadius);
+ std::shared_ptr<GeomAPI_Circ2d> aCircle(
+ new GeomAPI_Circ2d(aPoints[0], aPoints[1], aPoints[2]));
+
+ std::shared_ptr<GeomAPI_Pnt2d> aCenter = aCircle->center();
if (aCenter) {
+ double aRadius = aCircle->radius();
aCenterAttr->setValue(aCenter->x(), aCenter->y());
aRadiusAttr->setValue(aRadius);
}
}
+ data()->blockSendAttributeUpdated(false, false);
- data()->blockSendAttributeUpdated(false);
+ } else if (theID == CIRCLE_TYPE()) { // if switched to 3 points mode, adjust the needed attributes
+ std::string aType = std::dynamic_pointer_cast<ModelAPI_AttributeString>(
+ data()->attribute(CIRCLE_TYPE()))->value();
+ if (aType == CIRCLE_TYPE_THREE_POINTS()) {
+ adjustThreePoints();
+ }
}
}
-
-
-
-// ========== Auxiliary functions =========================
-void calculateCircleOnThreePoints(const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPnt,
- const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPnt,
- const std::shared_ptr<GeomAPI_Pnt2d>& theThirdPnt,
- std::shared_ptr<GeomAPI_Pnt2d>& theCenter,
- double& theRadius)
+void SketchPlugin_Circle::adjustThreePoints()
{
- std::shared_ptr<GeomAPI_XY> aVec12 = theSecondPnt->xy()->decreased(theFirstPnt->xy());
- std::shared_ptr<GeomAPI_XY> aVec23 = theThirdPnt->xy()->decreased(theSecondPnt->xy());
- std::shared_ptr<GeomAPI_XY> aVec31 = theFirstPnt->xy()->decreased(theThirdPnt->xy());
- // square of parallelogram
- double aSquare2 = aVec12->cross(aVec23);
- aSquare2 *= aSquare2 * 2.0;
- if (aSquare2 < 1.e-20)
+ std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+ if (!aCenterAttr->isInitialized())
+ return;
+ AttributeDoublePtr aRadiusAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(attribute(RADIUS_ID()));
+ if (!aRadiusAttr->isInitialized())
return;
- // coefficients to calculate center
- double aCoeff1 = aVec23->dot(aVec23) / aSquare2 * aVec12->dot(aVec31->multiplied(-1.0));
- double aCoeff2 = aVec31->dot(aVec31) / aSquare2 * aVec23->dot(aVec12->multiplied(-1.0));
- double aCoeff3 = aVec12->dot(aVec12) / aSquare2 * aVec31->dot(aVec23->multiplied(-1.0));
- // center
- std::shared_ptr<GeomAPI_XY> aCenter = theFirstPnt->xy()->multiplied(aCoeff1)->added(
- theSecondPnt->xy()->multiplied(aCoeff2))->added(theThirdPnt->xy()->multiplied(aCoeff3));
- theCenter = std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCenter));
- // radius
- theRadius = theFirstPnt->distance(theCenter);
+
+ data()->blockSendAttributeUpdated(true);
+ std::shared_ptr<GeomDataAPI_Point2D> aFirstPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_POINT_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aSecondPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(SECOND_POINT_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aThirdPnt =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(THIRD_POINT_ID()));
+ double aRadius = aRadiusAttr->value();
+
+ if (fabs(aFirstPnt->pnt()->distance(aCenterAttr->pnt()) - aRadius) > tolerance ||
+ fabs(aSecondPnt->pnt()->distance(aCenterAttr->pnt()) - aRadius) > tolerance ||
+ fabs(aThirdPnt->pnt()->distance(aCenterAttr->pnt()) - aRadius) > tolerance) {
+ aFirstPnt->setValue(aCenterAttr->x() + aRadius, aCenterAttr->y());
+ aSecondPnt->setValue(aCenterAttr->x(), aCenterAttr->y() + aRadius);
+ aThirdPnt->setValue(aCenterAttr->x() - aRadius, aCenterAttr->y());
+ }
+ data()->blockSendAttributeUpdated(false, false);
}