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");
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");
bool theArcReversed,
std::shared_ptr<GeomDataAPI_Point2D> thePassedPoint)
{
+ if (theCenter->distance(theStartPoint) < tolerance ||
+ theCenter->distance(theEndPoint) < tolerance)
+ return;
+
std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(
theStartPoint->xy()->decreased(theCenter->xy())));
std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(
if (aRadiusAttr && anAngleAttr) {
std::shared_ptr<GeomAPI_Circ2d> aCircle(
new GeomAPI_Circ2d(aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt()));
- calculateArcAngleRadius(aCircle, aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt(),
- anAngleAttr, aRadiusAttr);
+ if (aCircle->implPtr<void*>())
+ calculateArcAngleRadius(aCircle, aStartAttr->pnt(), anEndAttr->pnt(), aPassedPoint->pnt(),
+ anAngleAttr, aRadiusAttr);
}
data()->blockSendAttributeUpdated(false);
}
if (!aStartAttr->isInitialized() || !anEndAttr->isInitialized())
return;
// move center and passed point
- std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aStartAttr->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = anEndAttr->pnt();
+ std::shared_ptr<GeomAPI_XY> aStartPnt = aStartAttr->pnt()->xy();
+ std::shared_ptr<GeomAPI_XY> aEndPnt = anEndAttr->pnt()->xy();
double aDist = aStartPnt->distance(aEndPnt);
if (fabs(aDist) < tolerance)
return;
- std::shared_ptr<GeomAPI_XY> aDir = aEndPnt->xy()->decreased(aStartPnt->xy());
+ std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
std::shared_ptr<GeomAPI_Dir2d> aMidPerpDir(new GeomAPI_Dir2d(-aDir->y(), aDir->x()));
- std::shared_ptr<GeomAPI_XY> aMidPnt = aStartPnt->xy()->added(aEndPnt->xy())->multiplied(0.5);
+ std::shared_ptr<GeomAPI_XY> aMidPnt = aStartPnt->added(aEndPnt)->multiplied(0.5);
double anAngle = anAngleAttr->value() * PI / 180.0;
adjustPeriod(anAngle);
aMidPerpDir->reverse();
double aRadius = aRadiusAttr->value();
- aDist = sqrt(aRadius * aRadius - aDist * aDist / 4.0);
+ // The center is placed on a perpendicular bisector of a start-end points segment.
+ // If the radius is smaller that necessary, start and end points are moved too.
+ double aDist2 = aRadius * aRadius - aDist * aDist / 4.0;
+ aDist = aDist2 > 0.0 ? sqrt(aDist2) : 0.0;
+ // distance between middle point and start point (does not changed if the arc diameter is greater than start-end distance)
+ aDist2 = sqrt(aRadius * aRadius - aDist * aDist);
std::shared_ptr<GeomAPI_XY> aCenter = aMidPnt->added(aMidPerpDir->xy()->multiplied(aDist));
+ aStartPnt = aMidPnt->added(aDir->xy()->multiplied(-aDist2));
+ aEndPnt = aMidPnt->added(aDir->xy()->multiplied(aDist2));
data()->blockSendAttributeUpdated(true);
aCenterAttr->setValue(aCenter->x(), aCenter->y());
+ aStartAttr->setValue(aStartPnt->x(), aStartPnt->y());
+ anEndAttr->setValue(aEndPnt->x(), aEndPnt->y());
updateDependentAttributes();
data()->blockSendAttributeUpdated(false);
return;
}
if (theID == CENTER_ID()) {
- if (!isFeatureValid())
- return;
- if (aCenterAttr->pnt()->distance(aStartAttr->pnt()) < tolerance)
- return;
- data()->blockSendAttributeUpdated(true);
- // compute and change the arc end point
- std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
- new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
- std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
- if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
- anEndAttr->setValue(aProjection);
- updateDependentAttributes();
- data()->blockSendAttributeUpdated(false);
+ if (isFeatureValid())
+ projectEndPoint();
return;
}
if (anArcType == ARC_TYPE_CENTER_START_END()) {
if (!isFeatureValid())
return;
+ if (theID == END_ID() && isStable()) {
+ // The arc is under construction, so its end point projected
+ // on the circle formed by center and start points
+ projectEndPoint();
+ }
updateDependentAttributes();
}
else if (anArcType == ARC_TYPE_THREE_POINTS() &&
Events_Loop::loop()->setFlushed(anUpdateEvent, true);
}
}
+
+void SketchPlugin_Arc::projectEndPoint()
+{
+ std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<
+ GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<
+ GeomDataAPI_Point2D>(data()->attribute(START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> anEndAttr = std::dynamic_pointer_cast<
+ GeomDataAPI_Point2D>(data()->attribute(END_ID()));
+
+ if (aCenterAttr->pnt()->distance(aStartAttr->pnt()) < tolerance)
+ return;
+ data()->blockSendAttributeUpdated(true);
+ // compute and change the arc end point
+ std::shared_ptr<GeomAPI_Circ2d> aCircleForArc(
+ new GeomAPI_Circ2d(aCenterAttr->pnt(), aStartAttr->pnt()));
+ std::shared_ptr<GeomAPI_Pnt2d> aProjection = aCircleForArc->project(anEndAttr->pnt());
+ if (aProjection && anEndAttr->pnt()->distance(aProjection) > tolerance)
+ anEndAttr->setValue(aProjection);
+ updateDependentAttributes();
+ data()->blockSendAttributeUpdated(false);
+}