diff --git a/src/Gui/SoDatumLabel.cpp b/src/Gui/SoDatumLabel.cpp index 2e2b44b3c4..52f1823317 100644 --- a/src/Gui/SoDatumLabel.cpp +++ b/src/Gui/SoDatumLabel.cpp @@ -93,6 +93,9 @@ SoDatumLabel::SoDatumLabel() SO_NODE_ADD_FIELD(param2, (0.f)); SO_NODE_ADD_FIELD(param4, (0.f)); SO_NODE_ADD_FIELD(param5, (0.f)); + SO_NODE_ADD_FIELD(param6, (0.f)); + SO_NODE_ADD_FIELD(param7, (0.f)); + SO_NODE_ADD_FIELD(param8, (0.f)); useAntialiasing = true; @@ -989,6 +992,43 @@ void SoDatumLabel::GLRender(SoGLRenderAction * action) glVertex2f(ar3[0], ar3[1]); glVertex2f(ar4[0], ar4[1]); glEnd(); + + + if (this->datumtype.getValue() == DISTANCE) { + // Draw arc helpers if needed + float range1 = this->param4.getValue(); + if (range1 != 0.0) { + float startangle1 = this->param3.getValue(); + float radius1 = this->param5.getValue(); + SbVec3f center = points[2]; + int countSegments = std::max(6, abs(int(50.0 * range1 / (2 * M_PI)))); + double segment = range1 / (countSegments - 1); + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < countSegments; i++) { + double theta = startangle1 + segment * i; + SbVec3f v1 = center + SbVec3f(radius1 * cos(theta), radius1 * sin(theta), 0); + glVertex2f(v1[0], v1[1]); + } + glEnd(); + } + float range2 = this->param7.getValue(); + if (range2 != 0.0) { + float startangle2 = this->param6.getValue(); + float radius2 = this->param8.getValue(); + SbVec3f center = points[3]; + int countSegments = std::max(6, abs(int(50.0 * range2 / (2 * M_PI)))); + double segment = range2 / (countSegments - 1); + + glBegin(GL_LINE_STRIP); + for (int i = 0; i < countSegments; i++) { + double theta = startangle2 + segment * i; + SbVec3f v1 = center + SbVec3f(radius2 * cos(theta), radius2 * sin(theta), 0); + glVertex2f(v1[0], v1[1]); + } + glEnd(); + } + } } else if (this->datumtype.getValue() == RADIUS || this->datumtype.getValue() == DIAMETER) { // Get the Points diff --git a/src/Gui/SoDatumLabel.h b/src/Gui/SoDatumLabel.h index 077069236a..2e55ffeb8e 100644 --- a/src/Gui/SoDatumLabel.h +++ b/src/Gui/SoDatumLabel.h @@ -77,6 +77,9 @@ public: SoSFFloat param3; SoSFFloat param4; SoSFFloat param5; + SoSFFloat param6; + SoSFFloat param7; + SoSFFloat param8; SoMFVec3f pnts; SoSFVec3f norm; SoSFImage image; diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp index c8a38dd933..0af1df62e6 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.cpp @@ -814,6 +814,17 @@ Restart: case DistanceY: { assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); + double helperStartAngle1 = 0.; // for arc helpers + double helperStartAngle2 = 0.; + double helperRange1 = 0.; + double helperRange2 = 0.; + double radius1 = 0.; + double radius2 = 0.; + Base::Vector3d center1(0., 0., 0.); + Base::Vector3d center2(0., 0., 0.); + + int numPoints = 2; + // pnt1 will be initialized to (0,0,0) if only one point is given auto pnt1 = geolistfacade.getPoint(Constr->First, Constr->FirstPos); @@ -838,17 +849,15 @@ Restart: pnt2.ProjectToLine(pnt1 - l2p1, l2p2 - l2p1); pnt2 += pnt1; } - else { - if (isCircleOrArc(*geo1)) { - // circular to line distance - auto [radius, ct] = getRadiusCenterCircleArc(geo1); - // project the center on the line (translated to origin) - pnt1.ProjectToLine(ct - l2p1, l2p2 - l2p1); - Base::Vector3d dir = pnt1; - dir.Normalize(); - pnt1 += ct; - pnt2 = ct + dir * radius; - } + else if (isCircleOrArc(*geo1)) { + // circular to line distance + auto [radius, ct] = getRadiusCenterCircleArc(geo1); + // project the center on the line (translated to origin) + pnt1.ProjectToLine(ct - l2p1, l2p2 - l2p1); + Base::Vector3d dir = pnt1; + dir.Normalize(); + pnt1 += ct; + pnt2 = ct + dir * radius; } } else if (isCircleOrArc(*geo2)) { @@ -890,10 +899,8 @@ Restart: break; } - // NOLINTBEGIN - SoDatumLabel* asciiText = static_cast( - sep->getChild(static_cast(ConstraintNodePosition::DatumLabelIndex))); - // NOLINTEND + int index = static_cast(ConstraintNodePosition::DatumLabelIndex); + auto* asciiText = static_cast(sep->getChild(index)); // NOLINT // Get presentation string (w/o units if option is set) asciiText->string = @@ -909,13 +916,102 @@ Restart: asciiText->datumtype = SoDatumLabel::DISTANCEY; } + // Check if arc helpers are needed + if (Constr->Second != GeoEnum::GeoUndef + && Constr->SecondPos == Sketcher::PointPos::none) { + auto geo1 = geolistfacade.getGeometryFromGeoId(Constr->First); + auto geo2 = geolistfacade.getGeometryFromGeoId(Constr->Second); + + if (isArcOfCircle(*geo1)) { + auto arc = static_cast(geo1); // NOLINT + radius1 = arc->getRadius(); + center1 = arc->getCenter(); + + double angle = + toVector2d(isLineSegment(*geo2) ? pnt2 - center1 : pnt1 - center1) + .Angle(); + double startAngle, endAngle; + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + findHelperAngles(helperStartAngle1, + helperRange1, + angle, + startAngle, + endAngle); + + if (helperRange1 != 0.) { + // We override to draw the full helper as it does not look good + // otherwise We still use findHelperAngles before to find if helper + // is needed. + helperStartAngle1 = endAngle; + helperRange1 = 2 * M_PI - (endAngle - startAngle); + + numPoints++; + } + } + if (isArcOfCircle(*geo2)) { + auto arc = static_cast(geo2); // NOLINT + radius2 = arc->getRadius(); + center2 = arc->getCenter(); + + double angle = + toVector2d(pnt2 - center2).Angle(); // between -pi and pi + double startAngle, endAngle; // between 0 and 2*pi + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + findHelperAngles(helperStartAngle2, + helperRange2, + angle, + startAngle, + endAngle); + + if (helperRange2 != 0.) { + helperStartAngle2 = endAngle; + helperRange2 = 2 * M_PI - (endAngle - startAngle); + + numPoints++; + } + } + } + // Assign the Datum Points - asciiText->pnts.setNum(2); + asciiText->pnts.setNum(numPoints); SbVec3f* verts = asciiText->pnts.startEditing(); verts[0] = SbVec3f(pnt1.x, pnt1.y, zConstrH); verts[1] = SbVec3f(pnt2.x, pnt2.y, zConstrH); + if (numPoints > 2) { + if (helperRange1 != 0.) { + verts[2] = SbVec3f(center1.x, center1.y, zConstrH); + asciiText->param3 = helperStartAngle1; + asciiText->param4 = helperRange1; + asciiText->param5 = radius1; + } + else { + verts[2] = SbVec3f(center2.x, center2.y, zConstrH); + asciiText->param3 = helperStartAngle2; + asciiText->param4 = helperRange2; + asciiText->param5 = radius2; + } + if (numPoints > 3) { + verts[3] = SbVec3f(center2.x, center2.y, zConstrH); + asciiText->param6 = helperStartAngle2; + asciiText->param7 = helperRange2; + asciiText->param8 = radius2; + } + else { + asciiText->param6 = 0.; + asciiText->param7 = 0.; + asciiText->param8 = 0.; + } + } + else { + asciiText->param3 = 0.; + asciiText->param4 = 0.; + asciiText->param5 = 0.; + } + asciiText->pnts.finishEditing(); // Assign the Label Distance @@ -1281,20 +1377,25 @@ Restart: const Part::Geometry* geo = geolistfacade.getGeometryFromGeoId(Constr->First); if (geo->is()) { - const Part::GeomLineSegment* lineSeg = - static_cast(geo); + auto* lineSeg = static_cast(geo); p0 = Base::convertTo( (lineSeg->getEndPoint() + lineSeg->getStartPoint()) / 2); + double l1 = 2 * distance + - (lineSeg->getEndPoint() - lineSeg->getStartPoint()).Length() / 2; + endLineLength1 = 2 * distance; + endLineLength2 = l1 > 0. ? l1 : 0.; Base::Vector3d dir = lineSeg->getEndPoint() - lineSeg->getStartPoint(); startangle = 0.; range = atan2(dir.y, dir.x); } else if (geo->is()) { - const Part::GeomArcOfCircle* arc = - static_cast(geo); + auto* arc = static_cast(geo); p0 = Base::convertTo(arc->getCenter()); + endLineLength1 = 2 * distance - arc->getRadius(); + endLineLength2 = endLineLength1; + double endangle; arc->getRange(startangle, endangle, /*emulateCCWXY=*/true); range = endangle - startangle; @@ -1333,51 +1434,43 @@ Restart: double helperStartAngle = 0.; double helperRange = 0.; - if (Constr->First != GeoEnum::GeoUndef) { - const Part::Geometry* geo = - geolistfacade.getGeometryFromGeoId(Constr->First); + if (Constr->First == GeoEnum::GeoUndef) { + break; + } - if (geo->is()) { - auto* arc = static_cast(geo); - double radius = arc->getRadius(); - double angle = (double)Constr->LabelPosition; - double startAngle, endAngle; - arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); - if (angle == 10) { - angle = (startAngle + endAngle) / 2; - } - if (!(angle > startAngle && angle < endAngle)) { - if (angle < startAngle - && startAngle - angle < angle + 2 * M_PI - endAngle) { - helperStartAngle = angle; - helperRange = startAngle - angle; - } - else { - if (angle < endAngle) { - angle += 2 * M_PI; - } - helperStartAngle = endAngle; - helperRange = angle - endAngle; - } - } - Base::Vector3d center = arc->getCenter(); - pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); - pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + const Part::Geometry* geo = geolistfacade.getGeometryFromGeoId(Constr->First); + + if (geo->is()) { + auto* arc = static_cast(geo); + double radius = arc->getRadius(); + double angle = (double)Constr->LabelPosition; // between -pi and pi + double startAngle, endAngle; // between 0 and 2*pi + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + if (angle == 10) { + angle = (startAngle + endAngle) / 2; } - else if (geo->is()) { - auto* circle = static_cast(geo); - double radius = circle->getRadius(); - double angle = (double)Constr->LabelPosition; - if (angle == 10) { - angle = 0; - } - Base::Vector3d center = circle->getCenter(); - pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); - pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); - } - else { - break; + + findHelperAngles(helperStartAngle, + helperRange, + angle, + startAngle, + endAngle); + + Base::Vector3d center = arc->getCenter(); + pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); + pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + } + else if (geo->is()) { + auto* circle = static_cast(geo); + double radius = circle->getRadius(); + double angle = (double)Constr->LabelPosition; + if (angle == 10) { + angle = 0; } + Base::Vector3d center = circle->getCenter(); + pnt1 = center - radius * Base::Vector3d(cos(angle), sin(angle), 0.); + pnt2 = center + radius * Base::Vector3d(cos(angle), sin(angle), 0.); } else { break; @@ -1415,54 +1508,45 @@ Restart: double helperStartAngle = 0.; double helperRange = 0.; - if (Constr->First != GeoEnum::GeoUndef) { - const Part::Geometry* geo = - geolistfacade.getGeometryFromGeoId(Constr->First); + if (Constr->First == GeoEnum::GeoUndef) { + break; + } + const Part::Geometry* geo = geolistfacade.getGeometryFromGeoId(Constr->First); - if (geo->is()) { - auto* arc = static_cast(geo); - double radius = arc->getRadius(); - double angle = (double)Constr->LabelPosition; - double startAngle, endAngle; - arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); - if (angle == 10) { - angle = (startAngle + endAngle) / 2; - } - if (!(angle > startAngle && angle < endAngle)) { - if (angle < startAngle - && startAngle - angle < angle + 2 * M_PI - endAngle) { - helperStartAngle = angle; - helperRange = startAngle - angle; - } - else { - if (angle < endAngle) { - angle += 2 * M_PI; - } - helperStartAngle = endAngle; - helperRange = angle - endAngle; - } - } - pnt1 = arc->getCenter(); - pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + if (geo->is()) { + auto* arc = static_cast(geo); + double radius = arc->getRadius(); + double angle = (double)Constr->LabelPosition; // between -pi and pi + double startAngle, endAngle; // between 0 and 2*pi + arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + + if (angle == 10) { + angle = (startAngle + endAngle) / 2; } - else if (geo->is()) { - auto* circle = static_cast(geo); - auto gf = GeometryFacade::getFacade(geo); - double radius; + findHelperAngles(helperStartAngle, + helperRange, + angle, + startAngle, + endAngle); - radius = circle->getRadius(); + pnt1 = arc->getCenter(); + pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); + } + else if (geo->is()) { + auto* circle = static_cast(geo); + auto gf = GeometryFacade::getFacade(geo); - double angle = (double)Constr->LabelPosition; - if (angle == 10) { - angle = 0; - } - pnt1 = circle->getCenter(); - pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); - } - else { - break; + double radius; + + radius = circle->getRadius(); + + double angle = (double)Constr->LabelPosition; + if (angle == 10) { + angle = 0; } + pnt1 = circle->getCenter(); + pnt2 = pnt1 + radius * Base::Vector3d(cos(angle), sin(angle), 0.); } else { break; @@ -1518,6 +1602,39 @@ Restart: } } +void EditModeConstraintCoinManager::findHelperAngles(double& helperStartAngle, + double& helperRange, + double angle, + double startAngle, + double endAngle) +{ + double margin = 0.2; // about 10deg + if (angle < 0) { + angle = angle + 2 * M_PI; + } + // endAngle can be more than 2*pi as its startAngle + arcAngle + if (endAngle > 2 * M_PI && angle < endAngle - 2 * M_PI) { + angle = angle + 2 * M_PI; + } + if (!(angle > startAngle && angle < endAngle)) { + if ((angle < startAngle && startAngle - angle < angle + 2 * M_PI - endAngle) + || (angle > endAngle && startAngle + 2 * M_PI - angle < angle - endAngle)) { + if (angle > startAngle) { + angle -= 2 * M_PI; + } + helperStartAngle = angle - margin; + helperRange = startAngle - angle + margin; + } + else { + if (angle < endAngle) { + angle += 2 * M_PI; + } + helperStartAngle = endAngle; + helperRange = angle - endAngle + margin; + } + } +} + Base::Vector3d EditModeConstraintCoinManager::seekConstraintPosition(const Base::Vector3d& origPos, const Base::Vector3d& norm, const Base::Vector3d& dir, diff --git a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h index 657bd6adbb..8db7b6d798 100644 --- a/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h +++ b/src/Mod/Sketcher/Gui/EditModeConstraintCoinManager.h @@ -250,6 +250,13 @@ private: /// Essentially a version of sendConstraintIconToCoin, with a blank icon void clearCoinImage(SoImage* soImagePtr); + + /// Find helper angle for radius/diameter constraint + void findHelperAngles(double& helperStartAngle, + double& helperAngle, + double angle, + double startAngle, + double endAngle); //@} private: