From ba0e9ac5a8b32efc8726a60f13a2b6fdef96cc72 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Tue, 10 Jun 2025 23:50:33 +0200 Subject: [PATCH] Sketcher: Make symmetric constraint more interactable --- src/Gui/SoDatumLabel.cpp | 152 +++++++++++++++++++++------------------ src/Gui/SoDatumLabel.h | 9 +++ 2 files changed, 91 insertions(+), 70 deletions(-) diff --git a/src/Gui/SoDatumLabel.cpp b/src/Gui/SoDatumLabel.cpp index 20cc683751..5149ae2d82 100644 --- a/src/Gui/SoDatumLabel.cpp +++ b/src/Gui/SoDatumLabel.cpp @@ -446,19 +446,31 @@ private: std::vector computeSymmetricBBox() const { - // Get the points stored in the pnt field + // get the points stored in the pnt field const SbVec3f *points = label->pnts.getValues(0); if (label->pnts.getNum() < 2) { return {}; } - SbVec3f p1 = points[0]; - SbVec3f p2 = points[1]; + // use shared geometry calculation + SoDatumLabel::SymmetricGeometry geom = label->calculateSymmetricGeometry(points); - // Finds the mins and maxes + // include all visual elements in bounding box std::vector corners; - corners.push_back(p1); - corners.push_back(p2); + + // main points (existing) + corners.push_back(geom.p1); + corners.push_back(geom.p2); + + // first arrow triangle points + corners.push_back(geom.ar0); // arrow tip + corners.push_back(geom.ar1); // arrow base point 1 + corners.push_back(geom.ar2); // arrow base point 2 + + // second arrow triangle points + corners.push_back(geom.ar3); // arrow tip + corners.push_back(geom.ar4); // arrow base point 1 + corners.push_back(geom.ar5); // arrow base point 2 return corners; } @@ -904,49 +916,37 @@ void SoDatumLabel::generateAnglePrimitives(SoAction * action, const SbVec3f& p0) void SoDatumLabel::generateSymmetricPrimitives(SoAction * action, const SbVec3f& p1, const SbVec3f& p2) { - SbVec3f dir = (p2-p1); - dir.normalize(); - SbVec3f normal (-dir[1],dir[0],0); + // use shared geometry calculation + SbVec3f points[2] = {p1, p2}; + SymmetricGeometry geom = calculateSymmetricGeometry(points); - float margin = this->imgHeight / 4.0F; + // generate selectable primitives for lines + float lineWidth = geom.margin * 0.8f; - // Calculate coordinates for the first arrow - SbVec3f ar0 = p1 + dir * 5 * margin ; - SbVec3f ar1 = ar0 - dir * 0.866F * 2 * margin; // Base Point of Arrow - SbVec3f ar2 = ar1 + normal * margin; // Triangular corners - ar1 -= normal * margin; - - // Calculate coordinates for the second arrow - SbVec3f ar3 = p2 - dir * 5 * margin ; - SbVec3f ar4 = ar3 + dir * 0.866F * 2 * margin; // Base Point of 2nd Arrow - - SbVec3f ar5 = ar4 + normal * margin; // Triangular corners - ar4 -= normal * margin; + // lines from endpoints to arrow tips + generateLineSelectionPrimitive(action, geom.p1, geom.ar0, lineWidth); + generateLineSelectionPrimitive(action, geom.p2, geom.ar3, lineWidth); + // generate selectable primitives for arrow heads as triangles SoPrimitiveVertex pv; + pv.setNormal(SbVec3f(0.F, 0.F, 1.F)); this->beginShape(action, TRIANGLES); - pv.setNormal( SbVec3f(0.F, 0.F, 1.F) ); - - // Set coordinates - pv.setPoint( ar0 ); + // first arrow + pv.setPoint(geom.ar0); + shapeVertex(&pv); + pv.setPoint(geom.ar1); + shapeVertex(&pv); + pv.setPoint(geom.ar2); shapeVertex(&pv); - pv.setPoint( ar1 ); + // second arrow + pv.setPoint(geom.ar3); shapeVertex(&pv); - - pv.setPoint( ar2 ); + pv.setPoint(geom.ar4); shapeVertex(&pv); - - // Set coordinates - pv.setPoint( ar3 ); - shapeVertex(&pv); - - pv.setPoint( ar4 ); - shapeVertex(&pv); - - pv.setPoint( ar5 ); + pv.setPoint(geom.ar5); shapeVertex(&pv); this->endShape(); @@ -1340,43 +1340,27 @@ void SoDatumLabel::drawAngle(const SbVec3f* points, float& angle, SbVec3f& textO void SoDatumLabel::drawSymmetric(const SbVec3f* points) { - SbVec3f p1 = points[0]; - SbVec3f p2 = points[1]; - - SbVec3f dir = (p2-p1); - dir.normalize(); - SbVec3f normal (-dir[1],dir[0],0); - - float margin = this->imgHeight / 4.0F; - - // Calculate coordinates for the first arrow - SbVec3f ar0 = p1 + dir * 4 * margin; // Tip of Arrow - SbVec3f ar1 = ar0 - dir * 0.866F * 2 * margin; - SbVec3f ar2 = ar1 + normal * margin; - ar1 -= normal * margin; + // use shared geometry calculation + SymmetricGeometry geom = calculateSymmetricGeometry(points); + // draw first arrow glBegin(GL_LINES); - glVertex3f(p1[0], p1[1], ZCONSTR); - glVertex3f(ar0[0], ar0[1], ZCONSTR); - glVertex3f(ar0[0], ar0[1], ZCONSTR); - glVertex3f(ar1[0], ar1[1], ZCONSTR); - glVertex3f(ar0[0], ar0[1], ZCONSTR); - glVertex3f(ar2[0], ar2[1], ZCONSTR); + glVertex3f(geom.p1[0], geom.p1[1], ZCONSTR); + glVertex3f(geom.ar0[0], geom.ar0[1], ZCONSTR); + glVertex3f(geom.ar0[0], geom.ar0[1], ZCONSTR); + glVertex3f(geom.ar1[0], geom.ar1[1], ZCONSTR); + glVertex3f(geom.ar0[0], geom.ar0[1], ZCONSTR); + glVertex3f(geom.ar2[0], geom.ar2[1], ZCONSTR); glEnd(); - // Calculate coordinates for the second arrow - SbVec3f ar3 = p2 - dir * 4 * margin; // Tip of 2nd Arrow - SbVec3f ar4 = ar3 + dir * 0.866F * 2 * margin; - SbVec3f ar5 = ar4 + normal * margin; - ar4 -= normal * margin; - + // draw second arrow glBegin(GL_LINES); - glVertex3f(p2[0], p2[1], ZCONSTR); - glVertex3f(ar3[0], ar3[1], ZCONSTR); - glVertex3f(ar3[0], ar3[1], ZCONSTR); - glVertex3f(ar4[0], ar4[1], ZCONSTR); - glVertex3f(ar3[0], ar3[1], ZCONSTR); - glVertex3f(ar5[0], ar5[1], ZCONSTR); + glVertex3f(geom.p2[0], geom.p2[1], ZCONSTR); + glVertex3f(geom.ar3[0], geom.ar3[1], ZCONSTR); + glVertex3f(geom.ar3[0], geom.ar3[1], ZCONSTR); + glVertex3f(geom.ar4[0], geom.ar4[1], ZCONSTR); + glVertex3f(geom.ar3[0], geom.ar3[1], ZCONSTR); + glVertex3f(geom.ar5[0], geom.ar5[1], ZCONSTR); glEnd(); } @@ -1793,6 +1777,34 @@ SoDatumLabel::AngleGeometry SoDatumLabel::calculateAngleGeometry(const SbVec3f* return geom; } +SoDatumLabel::SymmetricGeometry SoDatumLabel::calculateSymmetricGeometry(const SbVec3f* points) const +{ + SymmetricGeometry geom; + + geom.p1 = points[0]; + geom.p2 = points[1]; + + geom.dir = (geom.p2 - geom.p1); + geom.dir.normalize(); + geom.normal = SbVec3f(-geom.dir[1], geom.dir[0], 0); + + geom.margin = this->imgHeight / 4.0F; + + // calculate coordinates for the first arrow + geom.ar0 = geom.p1 + geom.dir * 4 * geom.margin; // tip of arrow + geom.ar1 = geom.ar0 - geom.dir * 0.866F * 2 * geom.margin; + geom.ar2 = geom.ar1 + geom.normal * geom.margin; + geom.ar1 -= geom.normal * geom.margin; + + // calculate coordinates for the second arrow + geom.ar3 = geom.p2 - geom.dir * 4 * geom.margin; // tip of 2nd arrow + geom.ar4 = geom.ar3 + geom.dir * 0.866F * 2 * geom.margin; + geom.ar5 = geom.ar4 + geom.normal * geom.margin; + geom.ar4 -= geom.normal * geom.margin; + + return geom; +} + void SoDatumLabel::generateLineSelectionPrimitive(SoAction* action, const SbVec3f& start, const SbVec3f& end, float width) { // create a thicker line used for selection diff --git a/src/Gui/SoDatumLabel.h b/src/Gui/SoDatumLabel.h index 780a32b935..c6115cb18d 100644 --- a/src/Gui/SoDatumLabel.h +++ b/src/Gui/SoDatumLabel.h @@ -151,6 +151,14 @@ private: float endLineLength12, endLineLength22; // extension line lengths (other side) }; + struct SymmetricGeometry { + SbVec3f p1, p2; // main points + SbVec3f dir, normal; // direction and normal vectors + SbVec3f ar0, ar1, ar2; // first arrow triangle points (tip, base1, base2) + SbVec3f ar3, ar4, ar5; // second arrow triangle points (tip, base1, base2) + float margin; // margin for calculations + }; + float getScaleFactor(SoState*) const; void generateDistancePrimitives(SoAction * action, const SbVec3f&, const SbVec3f&); void generateDiameterPrimitives(SoAction * action, const SbVec3f&, const SbVec3f&); @@ -166,6 +174,7 @@ private: DistanceGeometry calculateDistanceGeometry(const SbVec3f* points, float scale, int srch) const; DiameterGeometry calculateDiameterGeometry(const SbVec3f* points) const; AngleGeometry calculateAngleGeometry(const SbVec3f* points) const; + SymmetricGeometry calculateSymmetricGeometry(const SbVec3f* points) const; void generateLineSelectionPrimitive(SoAction* action, const SbVec3f& start, const SbVec3f& end, float width); void generateArcSelectionPrimitive(SoAction* action, const SbVec3f& center, float radius, float startAngle, float endAngle, float width); void generateArrowSelectionPrimitive(SoAction* action, const SbVec3f& base, const SbVec3f& dir, float width, float length);