From 4cd563b5c25cca5d3135a408347c54237b549cb4 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Fri, 23 Mar 2018 15:00:53 -0400 Subject: [PATCH] Remove duplicate code/save Dim line geom --- src/Mod/TechDraw/App/DrawViewDimension.cpp | 471 ++++++------ src/Mod/TechDraw/App/DrawViewDimension.h | 34 +- src/Mod/TechDraw/App/DrawViewDimensionPy.xml | 20 + .../TechDraw/App/DrawViewDimensionPyImp.cpp | 83 +++ src/Mod/TechDraw/Gui/QGIViewDimension.cpp | 672 ++++++------------ 5 files changed, 606 insertions(+), 674 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index a7d45d5ba1..4695f63c4e 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #endif #include @@ -114,6 +117,10 @@ DrawViewDimension::DrawViewDimension(void) measurement = new Measure::Measurement(); //TODO: should have better initial datumLabel position than (0,0) in the DVP?? something closer to the object being measured? + + //start/end point for linear measures + m_linearPoints.first = Base::Vector3d(0,0,0); + m_linearPoints.second = Base::Vector3d(0,0,0); } DrawViewDimension::~DrawViewDimension() @@ -167,6 +174,15 @@ short DrawViewDimension::mustExecute() const if (result) { return result; } + + auto dvp = getViewPart(); + if (dvp != nullptr) { + result = dvp->isTouched(); + } + if (result) { + return result; + } + return DrawView::mustExecute(); } @@ -179,11 +195,139 @@ App::DocumentObjectExecReturn *DrawViewDimension::execute(void) if (!has2DReferences()) { //too soon return App::DocumentObject::StdReturn; } + + if (!getViewPart()->hasGeometry()) { //happens when loading saved document + Base::Console().Log("INFO - DVD::getDimValue ViewPart has no Geometry yet\n"); + return App::DocumentObject::StdReturn; + } + + if (!checkReferences2D()) { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return App::DocumentObject::StdReturn; + } + + const std::vector &subElements = References2D.getSubValues(); + + if ( Type.isValue("Distance") || + Type.isValue("DistanceX") || + Type.isValue("DistanceY") ) { + + if (getRefType() == oneEdge) { + m_linearPoints = getPointsOneEdge(); + }else if (getRefType() == twoEdge) { + m_linearPoints = getPointsTwoEdges(); + } else if (getRefType() == twoVertex) { + m_linearPoints = getPointsTwoVerts(); + } else if (getRefType() == vertexEdge) { + m_linearPoints = getPointsEdgeVert(); + } //else tarfu + } else if(Type.isValue("Radius")){ + int idx = DrawUtil::getIndexFromName(subElements[0]); + TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); + TechDrawGeometry::Circle* circle; + arcPoints pts; + if( (base && base->geomType == TechDrawGeometry::GeomType::CIRCLE) || + (base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE)) { + circle = static_cast (base); + pts.center = Base::Vector3d(circle->center.x,circle->center.y,0.0); + pts.radius = circle->radius; + if (base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE) { + TechDrawGeometry::AOC* aoc = static_cast (circle); + pts.isArc = true; + pts.onCurve.first = Base::Vector3d(aoc->midPnt.x,aoc->midPnt.y,0.0); + pts.midArc = Base::Vector3d(aoc->midPnt.x,aoc->midPnt.y,0.0); + pts.arcEnds.first = Base::Vector3d(aoc->startPnt.x,aoc->startPnt.y,0.0); + pts.arcEnds.second = Base::Vector3d(aoc->endPnt.x,aoc->endPnt.y,0.0); + pts.arcCW = aoc->cw; + } else { + pts.isArc = false; + pts.onCurve.first = pts.center + Base::Vector3d(1,0,0) * circle->radius; //arbitrary point on edge + pts.onCurve.second = pts.center + Base::Vector3d(-1,0,0) * circle->radius; //arbitrary point on edge + } + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return App::DocumentObject::StdReturn; + } + m_arcPoints = pts; + } else if(Type.isValue("Diameter")){ + int idx = DrawUtil::getIndexFromName(subElements[0]); + TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); + TechDrawGeometry::Circle* circle; + arcPoints pts; + if ((base && base->geomType == TechDrawGeometry::GeomType::CIRCLE) || + (base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE)) { + circle = static_cast (base); + pts.center = Base::Vector3d(circle->center.x,circle->center.y,0.0); + pts.center = Base::Vector3d(circle->center.x,circle->center.y,0.0); + pts.radius = circle->radius; + if (base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE) { + TechDrawGeometry::AOC* aoc = static_cast (circle); + pts.isArc = true; + pts.onCurve.first = Base::Vector3d(aoc->midPnt.x,aoc->midPnt.y,0.0); + pts.midArc = Base::Vector3d(aoc->midPnt.x,aoc->midPnt.y,0.0); + pts.arcEnds.first = Base::Vector3d(aoc->startPnt.x,aoc->startPnt.y,0.0); + pts.arcEnds.second = Base::Vector3d(aoc->endPnt.x,aoc->endPnt.y,0.0); + pts.arcCW = aoc->cw; + } else { + pts.isArc = false; + pts.onCurve.first = pts.center + Base::Vector3d(1,0,0) * circle->radius; //arbitrary point on edge + pts.onCurve.second = pts.center + Base::Vector3d(-1,0,0) * circle->radius; //arbitrary point on edge + } + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return App::DocumentObject::StdReturn; + } + m_arcPoints = pts; + } else if(Type.isValue("Angle")){ + //TODO: do we need to distinguish inner vs outer angle? -wf + if (getRefType() != twoEdge) { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return App::DocumentObject::StdReturn; + } + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + TechDrawGeometry::BaseGeom* edge0 = getViewPart()->getProjEdgeByIndex(idx0); + TechDrawGeometry::BaseGeom* edge1 = getViewPart()->getProjEdgeByIndex(idx1); + TechDrawGeometry::Generic *gen0; + TechDrawGeometry::Generic *gen1; + if (edge0 && edge0->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen0 = static_cast(edge0); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return App::DocumentObject::StdReturn; + } + if (edge1 && edge1->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen1 = static_cast(edge1); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return App::DocumentObject::StdReturn; + } + + anglePoints pts; + Base::Vector3d apex = DrawUtil::vector23(gen0->apparentInter(gen1)); + Base::Vector3d extPoint0,extPoint1; + if ((DrawUtil::vector23(gen0->getStartPoint()) - apex).Length() > + (DrawUtil::vector23(gen0->getEndPoint()) - apex).Length()) { + extPoint0 = DrawUtil::vector23(gen0->getStartPoint()); + } else { + extPoint0 = DrawUtil::vector23(gen0->getEndPoint()); + } + if ((DrawUtil::vector23(gen1->getStartPoint()) - apex).Length() > + (DrawUtil::vector23(gen1->getEndPoint()) - apex).Length()) { + extPoint1 = DrawUtil::vector23(gen1->getStartPoint()); + } else { + extPoint1 = DrawUtil::vector23(gen1->getEndPoint()); + } + pts.ends.first = extPoint0; + pts.ends.second = extPoint1; + pts.vertex = apex; + m_anglePoints = pts; + } //TODO: if MeasureType = Projected and the Projected shape changes, the Dimension may become invalid (see tilted Cube example) requestPaint(); - return App::DocumentObject::execute();; + return App::DocumentObject::execute(); } std::string DrawViewDimension::getFormatedValue() @@ -293,224 +437,117 @@ double DrawViewDimension::getDimValue() } } else { // Projected Values - const std::vector &objects = References2D.getValues(); - const std::vector &subElements = References2D.getSubValues(); - if (!checkReferences2D()) { Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); return result; } if ( Type.isValue("Distance") || Type.isValue("DistanceX") || Type.isValue("DistanceY") ) { - if (getRefType() == oneEdge) { - //TODO: Check for straight line Edge? - int idx = DrawUtil::getIndexFromName(subElements[0]); - TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); - TechDrawGeometry::Generic* gen; - if (geom && geom->geomType == TechDrawGeometry::GeomType::GENERIC) { - gen = static_cast(geom); - } else { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - Base::Vector2d start = gen->points[0]; - Base::Vector2d end = gen->points[1]; - Base::Vector2d line = end - start; - if (Type.isValue("Distance")) { - result = line.Length() / getViewPart()->getScale(); - } else if (Type.isValue("DistanceX")) { - return fabs(line.x) / getViewPart()->getScale(); - } else { - result = fabs(line.y) / getViewPart()->getScale(); - } - }else if (getRefType() == twoEdge) { - //only works for straight line edges - int idx0 = DrawUtil::getIndexFromName(subElements[0]); - int idx1 = DrawUtil::getIndexFromName(subElements[1]); - TechDrawGeometry::BaseGeom* geom0 = getViewPart()->getProjEdgeByIndex(idx0); - TechDrawGeometry::Generic* gen0; - if (geom0 && geom0->geomType == TechDrawGeometry::GeomType::GENERIC) { - gen0 = static_cast(geom0); - } else { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - TechDrawGeometry::BaseGeom* geom1 = getViewPart()->getProjEdgeByIndex(idx1); - TechDrawGeometry::Generic* gen1; - if (geom1 && geom1->geomType == TechDrawGeometry::GeomType::GENERIC) { - gen1 = static_cast(geom1); - } else { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - Base::Vector2d s0 = gen0->points[0]; - Base::Vector2d e0 = gen0->points[1]; - Base::Vector2d s1 = gen1->points[0]; - Base::Vector2d e1 = gen1->points[1]; - if (Type.isValue("Distance")) { - result = dist2Segs(s0,e0,s1,e1) / getViewPart()->getScale(); - } else if (Type.isValue("DistanceX")) { - Base::Vector2d p1 = geom0->nearPoint(geom1); - Base::Vector2d p2 = geom1->nearPoint(geom0); - result = fabs(p1.x - p2.x) / getViewPart()->getScale(); - } else if (Type.isValue("DistanceY")) { - Base::Vector2d p1 = geom0->nearPoint(geom1); - Base::Vector2d p2 = geom1->nearPoint(geom0); - result = fabs(p1.y - p2.y) / getViewPart()->getScale(); - } - } else if (getRefType() == twoVertex) { - int idx0 = DrawUtil::getIndexFromName(subElements[0]); - int idx1 = DrawUtil::getIndexFromName(subElements[1]); - TechDrawGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0); - TechDrawGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1); - if ((v0 == nullptr) || - (v1 == nullptr) ) { - Base::Console().Error("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - Base::Vector2d start = v0->pnt; //v0 != nullptr, but v0->pnt is invalid - Base::Vector2d end = v1->pnt; - Base::Vector2d line = end - start; - if (Type.isValue("Distance")) { - result = line.Length() / getViewPart()->getScale(); - } else if (Type.isValue("DistanceX")) { - result = fabs(line.x) / getViewPart()->getScale(); - } else { - result = fabs(line.y) / getViewPart()->getScale(); - } - } else if (getRefType() == vertexEdge) { - int idx0 = DrawUtil::getIndexFromName(subElements[0]); - int idx1 = DrawUtil::getIndexFromName(subElements[1]); - TechDrawGeometry::BaseGeom* e; - TechDrawGeometry::Vertex* v; - if (DrawUtil::getGeomTypeFromName(subElements[0]) == "Edge") { - e = getViewPart()->getProjEdgeByIndex(idx0); - v = getViewPart()->getProjVertexByIndex(idx1); - } else { - e = getViewPart()->getProjEdgeByIndex(idx1); - v = getViewPart()->getProjVertexByIndex(idx0); - } - if ((v == nullptr) || - (e == nullptr) ) { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - Base::Vector2d nearPoint = e->nearPoint(v->pnt); - Base::Vector2d line = nearPoint - v->pnt; - if (Type.isValue("Distance")) { - result = e->minDist(v->pnt) / getViewPart()->getScale(); - } else if (Type.isValue("DistanceX")) { - result = fabs(line.x) / getViewPart()->getScale(); - } else { - result = fabs(line.y) / getViewPart()->getScale(); - } - } //else tarfu + pointPair pts = m_linearPoints; + Base::Vector3d dimVec = pts.first - pts.second; + if (Type.isValue("Distance")) { + result = dimVec.Length() / getViewPart()->getScale(); + } else if (Type.isValue("DistanceX")) { + result = fabs(dimVec.x) / getViewPart()->getScale(); + } else { + result = fabs(dimVec.y) / getViewPart()->getScale(); + } + } else if(Type.isValue("Radius")){ - //only 1 reference for a Radius - int idx = DrawUtil::getIndexFromName(subElements[0]); - TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); - TechDrawGeometry::Circle* circle; - if( (base && base->geomType == TechDrawGeometry::GeomType::CIRCLE) || - (base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE)) { - circle = static_cast (base); - } else { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - result = circle->radius / getViewPart()->getScale(); //Projected BaseGeom is scaled for drawing + arcPoints pts = m_arcPoints; + result = pts.radius / getViewPart()->getScale(); //Projected BaseGeom is scaled for drawing } else if(Type.isValue("Diameter")){ - //only 1 reference for a Diameter - int idx = DrawUtil::getIndexFromName(subElements[0]); - TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); - TechDrawGeometry::Circle* circle; - if ((base && base->geomType == TechDrawGeometry::GeomType::CIRCLE) || - (base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE)) { - circle = static_cast (base); - } else { - return result; - } - result = (circle->radius * 2.0) / getViewPart()->getScale(); //Projected BaseGeom is scaled for drawing + arcPoints pts = m_arcPoints; + result = (pts.radius * 2.0) / getViewPart()->getScale(); //Projected BaseGeom is scaled for drawing + } else if(Type.isValue("Angle")){ - // Must project lines to 2D so cannot use measurement framework this time - //Relcalculate the measurement based on references stored. - //WF: why not use projected geom in GeomObject and Vector2d.GetAngle? intersection pt & direction issues? - //TODO: do we need to distinguish inner vs outer angle? -wf - if (getRefType() != twoEdge) { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - int idx0 = DrawUtil::getIndexFromName(subElements[0]); - int idx1 = DrawUtil::getIndexFromName(subElements[1]); - auto viewPart( dynamic_cast(objects[0]) ); - if( viewPart == nullptr ) { - Base::Console().Log("INFO - DVD::getDimValue - References2D not DrawViewPart\n"); - return result; - } - TechDrawGeometry::BaseGeom* edge0 = viewPart->getProjEdgeByIndex(idx0); - TechDrawGeometry::BaseGeom* edge1 = viewPart->getProjEdgeByIndex(idx1); - TechDrawGeometry::Generic *gen1; - TechDrawGeometry::Generic *gen2; - if (edge0 && edge0->geomType == TechDrawGeometry::GeomType::GENERIC) { - gen1 = static_cast(edge0); - } else { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } - if (edge1 && edge1->geomType == TechDrawGeometry::GeomType::GENERIC) { - gen2 = static_cast(edge1); - } else { - Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); - References2D.setValue(nullptr,""); - return result; - } + anglePoints pts = m_anglePoints; + Base::Vector3d vertex = pts.vertex; + Base::Vector3d leg0 = pts.ends.first - vertex; + Base::Vector3d leg1 = pts.ends.second - vertex; + double legAngle = leg0.GetAngle(leg1) * 180.0 / M_PI; + result = legAngle; + } + } + return result; +} - Base::Vector3d p1S(gen1->points.at(0).x, gen1->points.at(0).y, 0.); - Base::Vector3d p1E(gen1->points.at(1).x, gen1->points.at(1).y, 0.); +pointPair DrawViewDimension::getPointsOneEdge() +{ + pointPair result; + const std::vector &subElements = References2D.getSubValues(); - Base::Vector3d p2S(gen2->points.at(0).x, gen2->points.at(0).y, 0.); - Base::Vector3d p2E(gen2->points.at(1).x, gen2->points.at(1).y, 0.); + //TODO: Check for straight line Edge? + int idx = DrawUtil::getIndexFromName(subElements[0]); + TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); + TechDrawGeometry::Generic* gen; + if (geom && geom->geomType == TechDrawGeometry::GeomType::GENERIC) { + gen = static_cast(geom); + } else { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return result; + } + result.first = DrawUtil::vector23(gen->points[0]); + result.second = DrawUtil::vector23(gen->points[1]); + return result; +} - Base::Vector3d dir1 = p1E - p1S; - Base::Vector3d dir2 = p2E - p2S; +pointPair DrawViewDimension::getPointsTwoEdges() +{ + pointPair result; + const std::vector &subElements = References2D.getSubValues(); - // Line Intersetion (taken from ViewProviderSketch.cpp) - double det = dir1.x*dir2.y - dir1.y*dir2.x; - if ((det > 0 ? det : -det) < 1e-10) - throw Base::Exception("Invalid selection - Det = 0"); + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + TechDrawGeometry::BaseGeom* geom0 = getViewPart()->getProjEdgeByIndex(idx0); + TechDrawGeometry::BaseGeom* geom1 = getViewPart()->getProjEdgeByIndex(idx1); + result = closestPoints(geom0->occEdge,geom1->occEdge); + return result; +} - double c1 = dir1.y*gen1->points.at(0).x - dir1.x*gen1->points.at(0).y; - double c2 = dir2.y*gen2->points.at(1).x - dir2.x*gen2->points.at(1).y; - double x = (dir1.x*c2 - dir2.x*c1)/det; - double y = (dir1.y*c2 - dir2.y*c1)/det; +pointPair DrawViewDimension::getPointsTwoVerts() +{ + pointPair result; + const std::vector &subElements = References2D.getSubValues(); - // Intersection point - Base::Vector3d p0 = Base::Vector3d(x,y,0); + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + TechDrawGeometry::Vertex* v0 = getViewPart()->getProjVertexByIndex(idx0); + TechDrawGeometry::Vertex* v1 = getViewPart()->getProjVertexByIndex(idx1); + if ((v0 == nullptr) || + (v1 == nullptr) ) { + Base::Console().Error("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return result; + } + result.first = DrawUtil::vector23(v0->pnt); + result.second = DrawUtil::vector23(v1->pnt); + return result; +} - Base::Vector3d lPos((double) X.getValue(), (double) Y.getValue(), 0.); - //Base::Vector3d delta = lPos - p0; +pointPair DrawViewDimension::getPointsEdgeVert() +{ + pointPair result; + const std::vector &subElements = References2D.getSubValues(); - // Create vectors point towards intersection always - Base::Vector3d a = -p0, b = -p0; - a += ((p1S - p0).Length() < FLT_EPSILON) ? p1E : p1S; - b += ((p2S - p0).Length() < FLT_EPSILON) ? p2E : p2S; - - double angle2 = atan2( a.x*b.y - a.y*b.x, a.x*b.x + a.y*b.y ); - result = angle2 * 180. / M_PI; - } else { - throw Base::Exception("getDimValue() - Unknown Dimension Type (2)"); - } //endif Angle - } //endif Projected + int idx0 = DrawUtil::getIndexFromName(subElements[0]); + int idx1 = DrawUtil::getIndexFromName(subElements[1]); + TechDrawGeometry::BaseGeom* e; + TechDrawGeometry::Vertex* v; + if (DrawUtil::getGeomTypeFromName(subElements[0]) == "Edge") { + e = getViewPart()->getProjEdgeByIndex(idx0); + v = getViewPart()->getProjVertexByIndex(idx1); + } else { + e = getViewPart()->getProjEdgeByIndex(idx1); + v = getViewPart()->getProjVertexByIndex(idx0); + } + if ((v == nullptr) || + (e == nullptr) ) { + Base::Console().Log("Error: DVD - %s - 2D references are corrupt\n",getNameInDocument()); + return result; + } + result = closestPoints(e->occEdge,v->occVertex); return result; } @@ -591,6 +628,24 @@ bool DrawViewDimension::checkReferences2D() const return result; } +pointPair DrawViewDimension::closestPoints(TopoDS_Shape s1, + TopoDS_Shape s2) const +{ + pointPair result; + BRepExtrema_DistShapeShape extss(s1, s2); + if (!extss.IsDone()) { + throw Base::Exception("DVD::closestPoints - BRepExtrema_DistShapeShape failed"); + } + int count = extss.NbSolution(); + if (count != 0) { + gp_Pnt p = extss.PointOnShape1(1); + result.first = Base::Vector3d(p.X(),p.Y(),p.Z()); + p = extss.PointOnShape2(1); + result.second = Base::Vector3d(p.X(),p.Y(),p.Z()); + } //TODO: else { explode } + + return result; +} //!add Dimension 3D references to measurement void DrawViewDimension::setAll3DMeasurement() @@ -646,7 +701,7 @@ double DrawViewDimension::dist2Segs(Base::Vector2d s1, BRepExtrema_DistShapeShape extss(edge1, edge2); if (!extss.IsDone()) { - throw Base::Exception("DVD - BRepExtrema_DistShapeShape failed"); + throw Base::Exception("DVD::dist2Segs - BRepExtrema_DistShapeShape failed"); } int count = extss.NbSolution(); double minDist = 0.0; @@ -657,6 +712,20 @@ double DrawViewDimension::dist2Segs(Base::Vector2d s1, return minDist; } +bool DrawViewDimension::leaderIntersectsArc(Base::Vector3d s, Base::Vector3d pointOnCircle) { + bool result = false; + const std::vector &subElements = References2D.getSubValues(); + int idx = DrawUtil::getIndexFromName(subElements[0]); + TechDrawGeometry::BaseGeom* base = getViewPart()->getProjEdgeByIndex(idx); + if( base && base->geomType == TechDrawGeometry::GeomType::ARCOFCIRCLE ) { + TechDrawGeometry::AOC* aoc = static_cast (base); + if (aoc->intersectsArc(s,pointOnCircle)) { + result = true; + } + } + return result; +} + bool DrawViewDimension::has2DReferences(void) const { bool result = false; diff --git a/src/Mod/TechDraw/App/DrawViewDimension.h b/src/Mod/TechDraw/App/DrawViewDimension.h index a47513743a..dea7a36d50 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.h +++ b/src/Mod/TechDraw/App/DrawViewDimension.h @@ -30,6 +30,8 @@ #include "DrawView.h" +class TopoDS_Shape; + namespace Measure { class Measurement; } @@ -42,7 +44,22 @@ struct DimRef { std::string sub; }; -class DrawViewPart; +typedef std::pair pointPair; + +struct anglePoints { + pointPair ends; + Base::Vector3d vertex; +}; + +struct arcPoints { + bool isArc; + double radius; + Base::Vector3d center; + pointPair onCurve; + pointPair arcEnds; + Base::Vector3d midArc; + bool arcCW; +}; class TechDrawExport DrawViewDimension : public TechDraw::DrawView { @@ -86,6 +103,10 @@ public: void setAll3DMeasurement(); void clear3DMeasurements(void); bool checkReferences2D(void) const; + pointPair getLinearPoints(void) {return m_linearPoints; } + arcPoints getArcPoints(void) {return m_arcPoints; } + anglePoints getAnglePoints(void) {return m_anglePoints; } + bool leaderIntersectsArc(Base::Vector3d s, Base::Vector3d pointOnCircle); protected: void onChanged(const App::Property* prop); @@ -94,6 +115,10 @@ protected: bool useDecimals() const; std::string getPrefix() const; std::string getDefaultFormatSpec() const; + pointPair getPointsOneEdge(); + pointPair getPointsTwoEdges(); + pointPair getPointsTwoVerts(); + pointPair getPointsEdgeVert(); protected: Measure::Measurement *measurement; @@ -101,10 +126,17 @@ protected: Base::Vector2d e1, Base::Vector2d s2, Base::Vector2d e2) const; + pointPair closestPoints(TopoDS_Shape s1, + TopoDS_Shape s2) const; + private: static const char* TypeEnums[]; static const char* MeasureTypeEnums[]; void dumpRefs2D(char* text) const; + //Dimension "geometry" + pointPair m_linearPoints; + arcPoints m_arcPoints; + anglePoints m_anglePoints; }; } //namespace TechDraw diff --git a/src/Mod/TechDraw/App/DrawViewDimensionPy.xml b/src/Mod/TechDraw/App/DrawViewDimensionPy.xml index f6b84ecaee..48dfad36b0 100644 --- a/src/Mod/TechDraw/App/DrawViewDimensionPy.xml +++ b/src/Mod/TechDraw/App/DrawViewDimensionPy.xml @@ -13,6 +13,26 @@ Feature for creating and manipulating Technical Drawing Dimensions + + + getText() - returns Dimension text. + + + + + getLinearPoints() - returns list of points for linear Dimension + + + + + getArcPoints() - returns list of points for circle/arc Dimension + + + + + getAnglePoints() - returns list of points for angle Dimension + + diff --git a/src/Mod/TechDraw/App/DrawViewDimensionPyImp.cpp b/src/Mod/TechDraw/App/DrawViewDimensionPyImp.cpp index e5db566e3e..28bf85b421 100644 --- a/src/Mod/TechDraw/App/DrawViewDimensionPyImp.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimensionPyImp.cpp @@ -1,9 +1,37 @@ +/*************************************************************************** + * Copyright (c) WandererFan (wandererfan@gmail.com) 2018 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ #include "PreCompiled.h" +#ifndef _PreComp_ +#endif + +#include +#include +#include #include "DrawViewDimension.h" // inclusion of the generated files (generated out of DrawViewDimensionPy.xml) +#include #include #include @@ -14,7 +42,62 @@ std::string DrawViewDimensionPy::representation(void) const { return std::string(""); } +PyObject* DrawViewDimensionPy::getText(PyObject* args) +{ + (void) args; +// PyObject* asShape = Py_False; +// PyObject* pagePos = Py_False; +// if (!PyArg_ParseTuple(args, "|OO", &asShape, &pagePos)) { +// return 0; +// } + DrawViewDimension* dvd = getDrawViewDimensionPtr(); + std::string textString = dvd->getFormatedValue(); +//TODO: check multiversion code! +#if PY_MAJOR_VERSION >= 3 + PyObject* pyText = Base::PyAsUnicodeObject(textString); +#else + PyObject *pyText = PyString_FromString(textString.c_str()); +#endif + return pyText; +} +PyObject* DrawViewDimensionPy::getLinearPoints(PyObject* args) +{ + (void) args; + DrawViewDimension* dvd = getDrawViewDimensionPtr(); + pointPair pts = dvd->getLinearPoints(); + PyObject* ret = PyList_New(0); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.first))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.second))); + return ret; +} + +PyObject* DrawViewDimensionPy::getArcPoints(PyObject* args) +{ + (void) args; + DrawViewDimension* dvd = getDrawViewDimensionPtr(); + arcPoints pts = dvd->getArcPoints(); + PyObject* ret = PyList_New(0); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.center))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.onCurve.first))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.onCurve.second))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.arcEnds.first))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.arcEnds.second))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.midArc))); + return ret; +} + +PyObject* DrawViewDimensionPy::getAnglePoints(PyObject* args) +{ + (void) args; + DrawViewDimension* dvd = getDrawViewDimensionPtr(); + anglePoints pts = dvd->getAnglePoints(); + PyObject* ret = PyList_New(0); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.ends.first))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.ends.second))); + PyList_Append(ret,new Base::VectorPy(new Base::Vector3d(pts.vertex))); + return ret; +} PyObject *DrawViewDimensionPy::getCustomAttributes(const char* /*attr*/) const { diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index fff8364e78..ec7da5be92 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -340,152 +340,17 @@ void QGIViewDimension::draw() Base::Vector3d lblCenter(datumLabel->X(), datumLabel->Y(), 0); //already gui coords //const std::vector &objects = dim->References2D.getValues(); - const std::vector &SubNames = dim->References2D.getSubValues(); + //const std::vector &SubNames = dim->References2D.getSubValues(); const char *dimType = dim->Type.getValueAsString(); - if(strcmp(dimType, "Distance") == 0 || - strcmp(dimType, "DistanceX") == 0 || - strcmp(dimType, "DistanceY") == 0) { - Base::Vector3d distStart, distEnd; //start/end points of distance to dimension - if((dim->References2D.getValues().size() == 1) && - (TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Edge")) { - int idx = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - TechDrawGeometry::BaseGeom* geom = refObj->getProjEdgeByIndex(idx); - if (!geom) { - Base::Console().Log("INFO - qgivd::draw - no geom for projected edge: %d of %d\n", - idx,refObj->getEdgeGeometry().size()); - return; - } - if (geom->geomType == TechDrawGeometry::GENERIC) { - TechDrawGeometry::Generic *gen = static_cast(geom); - Base::Vector2d pnt1 = gen->points.at(0); - Base::Vector2d pnt2 = gen->points.at(1); - distStart = Base::Vector3d(pnt1.x, pnt1.y, 0.); - distStart = Rez::guiX(distStart); - distEnd = Base::Vector3d(pnt2.x, pnt2.y, 0.); - distEnd = Rez::guiX(distEnd); - } else { - Base::Console().Log("INFO - QGIVD::draw - Original edge not found or is invalid type (1)\n"); - datumLabel->hide(); - hide(); - return; - } - } else if(dim->References2D.getValues().size() == 2 && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Vertex" && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[1]) == "Vertex") { - int idx0 = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - int idx1 = TechDraw::DrawUtil::getIndexFromName(SubNames[1]); - TechDrawGeometry::Vertex *v0 = refObj->getProjVertexByIndex(idx0); - TechDrawGeometry::Vertex *v1 = refObj->getProjVertexByIndex(idx1); - if (!v0 || !v1) { - //Ugh. this is probably because the document is restoring. check log. - Base::Console().Log("INFO - qgivd::draw - no geom for projected edge: %d or %d of %d\n", - idx0,idx1,refObj->getEdgeGeometry().size()); - return; - } - distStart = Base::Vector3d (v0->pnt.x, v0->pnt.y, 0.); - distStart = Rez::guiX(distStart); - distEnd = Base::Vector3d (v1->pnt.x, v1->pnt.y, 0.); - distEnd = Rez::guiX(distEnd); - } else if(dim->References2D.getValues().size() == 2 && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Edge" && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[1]) == "Edge") { - int idx0 = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - int idx1 = TechDraw::DrawUtil::getIndexFromName(SubNames[1]); - TechDrawGeometry::BaseGeom* geom0 = refObj->getProjEdgeByIndex(idx0); - TechDrawGeometry::BaseGeom* geom1 = refObj->getProjEdgeByIndex(idx1); - if (!geom0 || !geom1) { - Base::Console().Log("INFO - qgivd::draw - no geom for projected edge: %d or %d of %d\n", - idx0,idx1,refObj->getEdgeGeometry().size()); - return; - } - if (strcmp(dimType, "DistanceX") == 0 || - strcmp(dimType, "DistanceY") == 0) { - Base::Vector2d p1,p2; - p1 = geom0->nearPoint(geom1); - p2 = geom1->nearPoint(geom0); - distStart = Base::Vector3d(p1.x,p1.y,0.0); - distStart = Rez::guiX(distStart); - distEnd = Base::Vector3d(p2.x,p2.y,0.0); - distEnd = Rez::guiX(distEnd); - } else if ( (geom0->geomType == TechDrawGeometry::GENERIC) && - (geom1->geomType == TechDrawGeometry::GENERIC) ){ - TechDrawGeometry::Generic *gen0 = static_cast(geom0); - TechDrawGeometry::Generic *gen1 = static_cast(geom1); - Base::Vector2d pnt1, pnt2; - Base::Vector3d edge1Start, edge1End, edge2Start, edge2End; - pnt1 = gen0->points.at(0); - pnt2 = gen0->points.at(1); - edge1Start = Base::Vector3d(pnt1.x, pnt1.y, 0); - edge1Start = Rez::guiX(edge1Start); - edge1End = Base::Vector3d(pnt2.x, pnt2.y, 0); - edge1End = Rez::guiX(edge1End); - pnt1 = gen1->points.at(0); - pnt2 = gen1->points.at(1); - edge2Start = Base::Vector3d(pnt1.x, pnt1.y, 0); - edge2Start = Rez::guiX(edge2Start); - edge2End = Base::Vector3d(pnt2.x, pnt2.y, 0); - edge2End = Rez::guiX(edge2End); - - // figure out which end of each edge to use for drawing - Base::Vector3d lin1 = edge1End - edge1Start; //vector from edge1Start to edge2End - Base::Vector3d lin2 = edge2End - edge2Start; - - Base::Vector3d labelV1 = lblCenter - edge1Start; //vector from edge1Start to lblCenter - Base::Vector3d labelV2 = lblCenter - edge2Start; - - if(lin1.x * labelV1.x + lin1.y * labelV1.y > 0.) //dotprod > 0 ==> angle(lin1,labelV1) < PI/2?? - distStart = edge1End; - else - distStart = edge1Start; - - if(lin2.x * labelV2.x + lin2.y * labelV2.y > 0.) - distEnd = edge2End; - else - distEnd = edge2Start; - } else { - Base::Console().Log("INFO - QGIVD::draw - Invalid reference for dimension type (1)\n"); - datumLabel->hide(); - hide(); - return; - } - } else if(dim->References2D.getValues().size() == 2) { - int vx,ex; - TechDrawGeometry::BaseGeom* e; - TechDrawGeometry::Vertex* v; - if ((TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Edge") && - (TechDraw::DrawUtil::getGeomTypeFromName(SubNames[1]) == "Vertex")) { - ex = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - vx = TechDraw::DrawUtil::getIndexFromName(SubNames[1]); - } else if ((TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Vertex") && - (TechDraw::DrawUtil::getGeomTypeFromName(SubNames[1]) == "Edge")) { - ex = TechDraw::DrawUtil::getIndexFromName(SubNames[1]); - vx = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - } else { - Base::Console().Log("INFO - qgivd::draw - vertexEdge dim is not vertexEdge!\n"); - return; - } - e = refObj->getProjEdgeByIndex(ex); - v = refObj->getProjVertexByIndex(vx); - if (!e || !v) { - Base::Console().Log("INFO - qgivd::draw - no geom for projected edge: %d or %d of %d\n", - ex,vx,refObj->getEdgeGeometry().size()); - return; - } - Base::Vector3d pnt(v->pnt.x,v->pnt.y, 0.0); - Base::Vector3d edgeStart(e->getStartPoint().x,e->getStartPoint().y,0.0); - Base::Vector3d edgeEnd(e->getEndPoint().x,e->getEndPoint().y,0.0); - Base::Vector3d displace; - displace.ProjectToLine(pnt - edgeStart, edgeEnd - edgeStart); - Base::Vector3d ptOnLine = pnt + displace; - - distStart = Rez::guiX(pnt); - distEnd = Rez::guiX(ptOnLine); - //need to figure out Distance? from slope of distEnd-distStart? - } else { - Base::Console().Message("TARFU - invalid references for Dimension!!"); - } + if (strcmp(dimType, "Distance") == 0 || + strcmp(dimType, "DistanceX") == 0 || + strcmp(dimType, "DistanceY") == 0) { + pointPair pts = dim->getLinearPoints(); + Base::Vector3d distStart, distEnd; //start/end points of distance to measure + distStart = Rez::guiX(pts.first); + distEnd = Rez::guiX(pts.second); // +/- aligned method // dimension text legible from bottom or right @@ -663,46 +528,13 @@ void QGIViewDimension::draw() Base::Vector3d arrow1Tip, arrow2Tip, dirDimLine; //was p1,p2,dir double radius; Base::Vector3d pointOnCurve,curveCenter; - TechDrawGeometry::AOC* geomArc = 0; - bool isArc = false; - if(dim->References2D.getValues().size() == 1 && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Edge") { - int idx = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - TechDrawGeometry::BaseGeom *geom = refObj->getProjEdgeByIndex(idx); - if(!geom) { - Base::Console().Log("INFO - qgivd::draw - no geom for projected edge: %d of %d\n", - idx,refObj->getEdgeGeometry().size()); - return; - } - if (geom->geomType == TechDrawGeometry::CIRCLE) { - TechDrawGeometry::Circle *circ = static_cast(geom); - radius = Rez::guiX(circ->radius); - curveCenter = Base::Vector3d(circ->center.x,circ->center.y,0.0); - curveCenter = Rez::guiX(curveCenter); - pointOnCurve = Base::Vector3d(curveCenter.x + radius, curveCenter.y,0.0); - pointOnCurve = Rez::guiX(pointOnCurve); - } else if (geom->geomType == TechDrawGeometry::ARCOFCIRCLE) { - isArc = true; - TechDrawGeometry::AOC *circ = static_cast(geom); - geomArc = circ; - radius = Rez::guiX(circ->radius); - curveCenter = Base::Vector3d(circ->center.x,circ->center.y,0.0); - curveCenter = Rez::guiX(curveCenter); - pointOnCurve = Base::Vector3d(circ->midPnt.x, circ->midPnt.y,0.0); - pointOnCurve = Rez::guiX(pointOnCurve); - } else { - Base::Console().Log("INFO - QGIVD::draw - Original edge not found or is invalid type (2)\n"); - datumLabel->hide(); - hide(); - return; - } - } else { - Base::Console().Log("INFO - QGIVD::draw - Invalid reference for dimension type (2)\n"); - datumLabel->hide(); - hide(); - return; - } + arcPoints pts = dim->getArcPoints(); + bool isArc = pts.isArc; + radius = Rez::guiX(pts.radius); + curveCenter = Rez::guiX(pts.center); + pointOnCurve = Rez::guiX(pts.onCurve.first); + // Note Bounding Box size is not the same width or height as text (only used for finding center) float bbX = datumLabel->boundingRect().width(); float bbY = datumLabel->boundingRect().height(); @@ -872,43 +704,39 @@ void QGIViewDimension::draw() margin = Rez::guiX(5.f); //space around label double kinkLength = Rez::guiX(5.0); //sb % of horizontal dist(lblCenter,curveCenter)??? if (isArc) { + aHead2->hide(); aHead1->flip(true); aHead1->draw(); - Base::Vector3d midPt(geomArc->midPnt.x, geomArc->midPnt.y,0.0); - midPt = Rez::guiX(midPt); - Base::Vector3d startPt(geomArc->startPnt.x, geomArc->startPnt.y,0.0); - startPt = Rez::guiX(startPt); - Base::Vector3d endPt(geomArc->endPnt.x, geomArc->endPnt.y,0.0); - endPt = Rez::guiX(endPt); + Base::Vector3d startPt = Rez::guiX(pts.arcEnds.first); + Base::Vector3d endPt = Rez::guiX(pts.arcEnds.second); kinkLength = (lblCenter.x < curveCenter.x) ? kinkLength : -kinkLength; dirDimLine = lblCenter - curveCenter; dirDimLine.Normalize(); - Base::Vector3d labelEndDir(1.0,0.0,0.0); - if (lblCenter.x > pointOnCurve.x) { //label is to right of point - labelEndDir = -1.0 * labelEndDir; - } - dLineStart = lblCenter + labelEndDir * (margin + w / 2); - kinkPoint.y = dLineStart.y; - kinkPoint.x = dLineStart.x + kinkLength; - - pointOnCurve = curveCenter + dirDimLine * radius; - if (!geomArc->intersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc - if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) { - if (!geomArc->cw ) { - pointOnCurve = endPt; - } else { - pointOnCurve = startPt; - } + Base::Vector3d labelEndDir(1.0,0.0,0.0); + if (lblCenter.x > pointOnCurve.x) { //label is to right of point + labelEndDir = -1.0 * labelEndDir; + } + dLineStart = lblCenter + labelEndDir * (margin + w / 2); + kinkPoint.y = dLineStart.y; + kinkPoint.x = dLineStart.x + kinkLength; + pointOnCurve = curveCenter + dirDimLine * radius; + if (!dim->leaderIntersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc + if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) { + if (!pts.arcCW ) { + pointOnCurve = endPt; } else { - if (!geomArc->cw) { - pointOnCurve = startPt; - } else { - pointOnCurve = endPt; - } + pointOnCurve = startPt; + } + } else { + if (!pts.arcCW) { + pointOnCurve = startPt; + } else { + pointOnCurve = endPt; } } + } Base::Vector3d arVector = (kinkPoint - pointOnCurve); arVector.Normalize(); arAngle = atan2(arVector.y, arVector.x) * 180 / M_PI; @@ -920,7 +748,7 @@ void QGIViewDimension::draw() } dimLines->setPath(path); - + if (isArc) { aHead1->setPos(pointOnCurve.x, pointOnCurve.y); aHead1->setRotation(arAngle); @@ -955,52 +783,18 @@ void QGIViewDimension::draw() } else if(strcmp(dimType, "Radius") == 0) { // preferred terminology: Dimension Text, Dimension Line(s), Extension Lines, Arrowheads // radius gets 1 dimension line from the dimension text to a point on the curve -// Base::Vector3d lblCenter(datumLabel->X(), datumLabel->Y(),0.0); Base::Vector3d pointOnCurve,curveCenter; double radius; - TechDrawGeometry::AOC* geomArc = 0; - bool isArc = false; - if(dim->References2D.getValues().size() == 1 && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Edge") { - int idx = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - TechDrawGeometry::BaseGeom* geom = refObj->getProjEdgeByIndex(idx); - if(!geom) { - Base::Console().Log("INFO - qgivd::draw - no geom for projected edge: %d of %d\n", - idx,refObj->getEdgeGeometry().size()); - return; - } - if (geom->geomType == TechDrawGeometry::CIRCLE) { - TechDrawGeometry::Circle *circ = static_cast(geom); - radius = Rez::guiX(circ->radius); - curveCenter = Base::Vector3d(circ->center.x,circ->center.y,0.0); - curveCenter = Rez::guiX(curveCenter); - pointOnCurve = Base::Vector3d(curveCenter.x + radius, curveCenter.y,0.0); - pointOnCurve = Rez::guiX(pointOnCurve); - } else if (geom->geomType == TechDrawGeometry::ARCOFCIRCLE) { - isArc = true; - TechDrawGeometry::AOC *circ = static_cast(geom); - geomArc = circ; - radius = Rez::guiX(circ->radius); - curveCenter = Base::Vector3d(circ->center.x,circ->center.y,0.0); - curveCenter = Rez::guiX(curveCenter); - pointOnCurve = Base::Vector3d(circ->midPnt.x, circ->midPnt.y,0.0); - pointOnCurve = Rez::guiX(pointOnCurve); - } else { - Base::Console().Log("INFO - QGIVD::draw - Original edge not found or is invalid type (3)\n"); - datumLabel->hide(); - hide(); - return; - } - } else { - Base::Console().Log("INFO - QGIVD::draw - Invalid reference for dimension type (3)\n"); - datumLabel->hide(); - hide(); - return; - } + arcPoints pts = dim->getArcPoints(); + bool isArc = pts.isArc; + radius = Rez::guiX(pts.radius); + curveCenter = Rez::guiX(pts.center); + pointOnCurve = Rez::guiX(pts.onCurve.first); QFontMetrics fm(datumLabel->font()); int w = fm.width(labelText); + // Note Bounding Box size is not the same width or height as text (only used for finding center) float bbX = datumLabel->boundingRect().width(); float bbY = datumLabel->boundingRect().height(); @@ -1045,14 +839,11 @@ void QGIViewDimension::draw() //handle partial arc weird cases if (isArc) { - Base::Vector3d midPt(geomArc->midPnt.x, geomArc->midPnt.y,0.0); - midPt = Rez::guiX(midPt); - Base::Vector3d startPt(geomArc->startPnt.x, geomArc->startPnt.y,0.0); - startPt = Rez::guiX(startPt); - Base::Vector3d endPt(geomArc->endPnt.x, geomArc->endPnt.y,0.0); - endPt = Rez::guiX(endPt); + Base::Vector3d midPt = Rez::guiX(pts.midArc); + Base::Vector3d startPt = Rez::guiX(pts.arcEnds.first); + Base::Vector3d endPt = Rez::guiX(pts.arcEnds.second); if (outerPlacement && - !geomArc->intersectsArc(Rez::appX(curveCenter),Rez::appX(kinkPoint))) { + !dim->leaderIntersectsArc(Rez::appX(curveCenter),Rez::appX(kinkPoint))) { //keep pathological case within arc pointOnCurve = midPt; } else if (!outerPlacement) { if ((midPt - lblCenter).Length() > (midPt - curveCenter).Length()) { //label is farther than center @@ -1061,15 +852,15 @@ void QGIViewDimension::draw() dLineStart = curveCenter + dirDimLine * margin; pointOnCurve = curveCenter + dirDimLine * radius; kinkPoint = dLineStart; - if (!geomArc->intersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc + if (!dim->leaderIntersectsArc(Rez::appX(dLineStart),Rez::appX(pointOnCurve))) { //keep pathological case within arc if ((pointOnCurve - endPt).Length() < (pointOnCurve - startPt).Length()) { - if (!geomArc->cw ) { + if (!pts.arcCW ) { pointOnCurve = endPt; } else { pointOnCurve = startPt; } } else { - if (!geomArc->cw) { + if (!pts.arcCW ) { pointOnCurve = startPt; } else { pointOnCurve = endPt; @@ -1107,237 +898,176 @@ void QGIViewDimension::draw() // } } else if(strcmp(dimType, "Angle") == 0) { // Only use two straight line edeges for angle - if(dim->References2D.getValues().size() == 2 && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]) == "Edge" && - TechDraw::DrawUtil::getGeomTypeFromName(SubNames[1]) == "Edge") { - int idx0 = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); - int idx1 = TechDraw::DrawUtil::getIndexFromName(SubNames[1]); - TechDrawGeometry::BaseGeom* geom0 = refObj->getProjEdgeByIndex(idx0); - TechDrawGeometry::BaseGeom* geom1 = refObj->getProjEdgeByIndex(idx1); - if (!geom0 || !geom1) { - Base::Console().Log("INFO - qgivd::draw - no geom for projected edge: %d or %d of %d\n", - idx0,idx1,refObj->getEdgeGeometry().size()); - return; - } - if ( (geom0->geomType == TechDrawGeometry::GENERIC) && - (geom1->geomType == TechDrawGeometry::GENERIC) ) { - TechDrawGeometry::Generic *gen0 = static_cast(geom0); - TechDrawGeometry::Generic *gen1 = static_cast(geom1); + anglePoints pts = dim->getAnglePoints(); + Base::Vector3d vertex = Rez::guiX(pts.vertex); + Base::Vector3d legEnd0 = Rez::guiX(pts.ends.first); + Base::Vector3d legEnd1 = Rez::guiX(pts.ends.second); + Base::Vector3d p0 = vertex; + Base::Vector3d dir1 = legEnd0 - vertex; + Base::Vector3d dir2 = legEnd1 - vertex; + // Qt y coordinates are flipped + dir1.y *= -1.; + dir2.y *= -1.; -// Base::Vector3d lblCenter(datumLabel->X(), datumLabel->Y(), 0); - // Get Points for line - Base::Vector2d pnt1, pnt2; - Base::Vector3d p1S, p1E, p2S, p2E; - pnt1 = gen0->points.at(0); - pnt2 = gen0->points.at(1); + Base::Vector3d labelVec = (lblCenter - p0); - p1S = Base::Vector3d(pnt1.x, pnt1.y, 0); - p1S = Rez::guiX(p1S); - p1E = Base::Vector3d(pnt2.x, pnt2.y, 0); - p1E = Rez::guiX(p1E); + double labelangle = atan2(-labelVec.y, labelVec.x); //angle with +X axis on [-PI,+PI] - pnt1 = gen1->points.at(0); - pnt2 = gen1->points.at(1); + double startangle = atan2(dir1.y,dir1.x); + double range = atan2(-dir1.y*dir2.x+dir1.x*dir2.y, + dir1.x*dir2.x+dir1.y*dir2.y); - p2S = Base::Vector3d(pnt1.x, pnt1.y, 0); - p2S = Rez::guiX(p2S); - p2E = Base::Vector3d(pnt2.x, pnt2.y, 0); - p2E = Rez::guiX(p2E); + double endangle = startangle + range; - Base::Vector3d dir1 = p1E - p1S; - Base::Vector3d dir2 = p2E - p2S; + float bbX = datumLabel->boundingRect().width(); + float bbY = datumLabel->boundingRect().height(); - double det = dir1.x*dir2.y - dir1.y*dir2.x; - if ((det > 0 ? det : -det) < 1e-10) - return; - double c1 = dir1.y*p1S.x - dir1.x*p1S.y; - double c2 = dir2.y*p2S.x - dir2.x*p2S.y; - double x = (dir1.x*c2 - dir2.x*c1)/det; - double y = (dir1.y*c2 - dir2.y*c1)/det; + // Get font height + QFontMetrics fm(datumLabel->font()); - Base::Vector3d p0(x,y,0); + int h = fm.height(); + double length = labelVec.Length(); + length -= h * 0.6; // Adjust the length so the label isn't over the line - // Get directions with outwards orientation and check if coincident - dir1 = ((p1E - p0).Length() > (p1S - p0).Length()) ? p1E - p0 : p1S - p0; - dir2 = ((p2E - p0).Length() > (p2S - p0).Length()) ? p2E - p0 : p2S - p0; + Base::Vector3d p1 = legEnd0; + Base::Vector3d p2 = legEnd1; - // Qt y coordinates are flipped - dir1.y *= -1.; - dir2.y *= -1.; + // add an offset from the ends + p1 += (p1-p0).Normalize() * 5.; + p2 += (p2-p0).Normalize() * 5.; - Base::Vector3d labelVec = (lblCenter - p0); + Base::Vector3d ar1Pos = p0; + Base::Vector3d ar2Pos = p0; - double labelangle = atan2(-labelVec.y, labelVec.x); + ar1Pos += Base::Vector3d(cos(startangle) * length, -sin(startangle) * length, 0.); + ar2Pos += Base::Vector3d(cos(endangle) * length , -sin(endangle) * length, 0.); - double startangle = atan2(dir1.y,dir1.x); - double range = atan2(-dir1.y*dir2.x+dir1.x*dir2.y, - dir1.x*dir2.x+dir1.y*dir2.y); + // Draw the path + QPainterPath path; - double endangle = startangle + range; + // Only draw extension lines if outside arc + if(length > (p1-p0).Length()) { + path.moveTo(p1.x, p1.y); + p1 = ar1Pos + (p1-p0).Normalize() * Rez::guiX(5.); //a bit past arrow head on leg 1 + path.lineTo(p1.x, p1.y); + } - // Obtain the Label Position and measure the length between intersection -// Base::Vector3d lblCenter(datumLabel->X(), datumLabel->Y(), 0); - - float bbX = datumLabel->boundingRect().width(); - float bbY = datumLabel->boundingRect().height(); - - // Get font height - QFontMetrics fm(datumLabel->font()); - - int h = fm.height(); - double length = labelVec.Length(); - length -= h * 0.6; // Adjust the length so the label isn't over the line - - // Find the end points for dim lines - Base::Vector3d p1 = ((p1E - p0).Length() > (p1S - p0).Length()) ? p1E : p1S; - Base::Vector3d p2 = ((p2E - p0).Length() > (p2S - p0).Length()) ? p2E : p2S; - - // add an offset from the ends (add 1mm from end) - p1 += (p1-p0).Normalize() * 5.; //apply Rez here??? unitVector * 5 = 1/mm? - p2 += (p2-p0).Normalize() * 5.; - - Base::Vector3d ar1Pos = p0; - Base::Vector3d ar2Pos = p0; - - ar1Pos += Base::Vector3d(cos(startangle) * length, -sin(startangle) * length, 0.); - ar2Pos += Base::Vector3d(cos(endangle) * length , -sin(endangle) * length, 0.); - - // Draw the path - QPainterPath path; - - // Only draw extension lines if outside arc - if(length > (p1-p0).Length()) { - path.moveTo(p1.x, p1.y); - p1 = ar1Pos + (p1-p0).Normalize() * Rez::guiX(5.); //a bit past arrow head on leg 1 - path.lineTo(p1.x, p1.y); - } - - if(length > (p2-p0).Length()) { - path.moveTo(p2.x, p2.y); - p2 = ar2Pos + (p2-p0).Normalize() * Rez::guiX(5.); //a bit past leg 2 arrow head on leg 2 - path.lineTo(p2.x, p2.y); - } + if(length > (p2-p0).Length()) { + path.moveTo(p2.x, p2.y); + p2 = ar2Pos + (p2-p0).Normalize() * Rez::guiX(5.); //a bit past leg 2 arrow head on leg 2 + path.lineTo(p2.x, p2.y); + } - bool isOutside = true; + bool isOutside = true; //label is outside angle end-vertex-end? - // TODO find a better solution for this. Addmitedely not tidy - // ############### - // Treat zero as positive to be consistent for horizontal lines - if(std::abs(startangle) < FLT_EPSILON) - startangle = 0; + // TODO find a better solution for this. Addmitedely not tidy + // ############### + // Treat zero as positive to be consistent for horizontal lines + if(std::abs(startangle) < FLT_EPSILON) + startangle = 0; - if(std::abs(endangle) < FLT_EPSILON) - endangle = 0; - - if(startangle >= 0 && endangle >= 0) { //Both are in positive side - double langle = labelangle; - if(labelangle < 0) - langle += M_PI * 2; - if(endangle - startangle > 0) { - if(langle > startangle && langle < endangle) - isOutside = false; - } else { - if(langle < startangle && langle > endangle) - isOutside = false; - } - } else if(startangle < 0 && endangle < 0) { //both are in negative side - double langle = labelangle; - if(labelangle > 0) - langle -= M_PI * 2; - if(endangle - startangle < 0) { - if(langle > endangle && langle < startangle) //clockwise - isOutside = false; - } else { - if(langle < endangle && langle > startangle) //anticlockwise - isOutside = false; - } - } else if(startangle >= 0 && endangle < 0) { - if(labelangle < startangle && labelangle > endangle) //clockwise - isOutside = false; - - } else if(startangle < 0 && endangle >= 0) { - //Both are in positive side - - if(labelangle > startangle && labelangle < endangle) //clockwise - isOutside = false; - } - - QRectF arcRect(p0.x - length, p0.y - length, 2. * length, 2. * length); - path.arcMoveTo(arcRect, endangle * 180 / M_PI); - - if(isOutside) { - if(labelangle > endangle) - { - path.arcTo(arcRect, endangle * 180 / M_PI, (labelangle - endangle) * 180 / M_PI); //CCW from endangle - path.arcMoveTo(arcRect,startangle * 180 / M_PI); - path.arcTo(arcRect, startangle * 180 / M_PI, -10); //cw10 from start - } else { - path.arcTo(arcRect, endangle * 180 / M_PI, 10); // chosen a nominal value for 10 degrees - path.arcMoveTo(arcRect,startangle * 180 / M_PI); - path.arcTo(arcRect, startangle * 180 / M_PI, (labelangle - startangle) * 180 / M_PI); //unknown dir - } - - - } else { - path.arcTo(arcRect, endangle * 180 / M_PI, -range * 180 / M_PI); - } - - dimLines->setPath(path); - - aHead1->flip(true); - aHead1->setStyle(QGIArrow::getPrefArrowStyle()); - aHead1->setSize(QGIArrow::getPrefArrowSize()); - aHead1->draw(); - aHead2->setStyle(QGIArrow::getPrefArrowStyle()); - aHead2->setSize(QGIArrow::getPrefArrowSize()); - aHead2->draw(); - - Base::Vector3d norm1 = p1-p0; //(-dir1.y, dir1.x, 0.); - Base::Vector3d norm2 = p2-p0; //(-dir2.y, dir2.x, 0.); - - Base::Vector3d avg = (norm1 + norm2) / 2.; - - norm1 = norm1.ProjectToLine(avg, norm1); - norm2 = norm2.ProjectToLine(avg, norm2); - - aHead1->setPos(ar1Pos.x,ar1Pos.y ); - aHead2->setPos(ar2Pos.x,ar2Pos.y ); - - float ar1angle = atan2(-norm1.y, -norm1.x) * 180 / M_PI; - float ar2angle = atan2(norm2.y, norm2.x) * 180 / M_PI; - - if(isOutside) { - aHead1->setRotation(ar1angle + 180.); - aHead2->setRotation(ar2angle + 180.); - } else { - aHead1->setRotation(ar1angle); - aHead2->setRotation(ar2angle); - } - - // Set the angle of the dimension text - - Base::Vector3d labelNorm(-labelVec.y, labelVec.x, 0.); - double lAngle = atan2(labelNorm.y, labelNorm.x); - - //if label is more/less vertical, make it vertical - if (lAngle > M_PI_2+M_PI/12) { // label norm angle > 90 + 15 = 105 - lAngle -= M_PI; // lAngle - 180 Flip - } else if (lAngle <= -M_PI_2+M_PI/12) { // < -90 + 15 = - 85 - lAngle += M_PI; // langle + 180 Flip - } - - datumLabel->setTransformOriginPoint(bbX / 2., bbY /2.); - - datumLabel->setRotation(lAngle * 180 / M_PI); + if(std::abs(endangle) < FLT_EPSILON) + endangle = 0; + if(startangle >= 0 && endangle >= 0) { //Both are in positive side + double langle = labelangle; + if(labelangle < 0) + langle += M_PI * 2; + if(endangle - startangle > 0) { + if(langle > startangle && langle < endangle) + isOutside = false; + } else { + if(langle < startangle && langle > endangle) + isOutside = false; + } + } else if(startangle < 0 && endangle < 0) { //both are in negative side + double langle = labelangle; + if(labelangle > 0) + langle -= M_PI * 2; + if(endangle - startangle < 0) { + if(langle > endangle && langle < startangle) //clockwise + isOutside = false; } else { - Base::Console().Log("INFO - QGIVD::draw - Invalid reference for dimension type (4)\n"); - datumLabel->hide(); - hide(); - return; + if(langle < endangle && langle > startangle) //anticlockwise + isOutside = false; } - } //endif 2 Edges + } else if(startangle >= 0 && endangle < 0) { + if(labelangle < startangle && labelangle > endangle) //clockwise + isOutside = false; + + } else if(startangle < 0 && endangle >= 0) { + //Both are in positive side + + if(labelangle > startangle && labelangle < endangle) //clockwise + isOutside = false; + } + + QRectF arcRect(p0.x - length, p0.y - length, 2. * length, 2. * length); + path.arcMoveTo(arcRect, endangle * 180 / M_PI); + if(isOutside) { + if(labelangle > endangle) + { + path.arcTo(arcRect, endangle * 180 / M_PI, (labelangle - endangle) * 180 / M_PI); //CCW from endangle + path.arcMoveTo(arcRect,startangle * 180 / M_PI); + path.arcTo(arcRect, startangle * 180 / M_PI, -10); //cw10 from start + } else { + path.arcTo(arcRect, endangle * 180 / M_PI, 10); // chosen a nominal value for 10 degrees + path.arcMoveTo(arcRect,startangle * 180 / M_PI); + path.arcTo(arcRect, startangle * 180 / M_PI, (labelangle - startangle) * 180 / M_PI); //unknown dir + } + } else { + path.arcTo(arcRect, endangle * 180 / M_PI, -range * 180 / M_PI); + } + + dimLines->setPath(path); + + aHead1->flip(true); + aHead1->setStyle(QGIArrow::getPrefArrowStyle()); + aHead1->setSize(QGIArrow::getPrefArrowSize()); + aHead1->draw(); + aHead2->setStyle(QGIArrow::getPrefArrowStyle()); + aHead2->setSize(QGIArrow::getPrefArrowSize()); + aHead2->draw(); + + Base::Vector3d norm1 = p1-p0; //(-dir1.y, dir1.x, 0.); + Base::Vector3d norm2 = p2-p0; //(-dir2.y, dir2.x, 0.); + + Base::Vector3d avg = (norm1 + norm2) / 2.; + + norm1 = norm1.ProjectToLine(avg, norm1); + norm2 = norm2.ProjectToLine(avg, norm2); + + aHead1->setPos(ar1Pos.x,ar1Pos.y ); + aHead2->setPos(ar2Pos.x,ar2Pos.y ); + + float ar1angle = atan2(-norm1.y, -norm1.x) * 180 / M_PI; + float ar2angle = atan2(norm2.y, norm2.x) * 180 / M_PI; + + if(isOutside) { + aHead1->setRotation(ar1angle + 180.); + aHead2->setRotation(ar2angle + 180.); + } else { + aHead1->setRotation(ar1angle); + aHead2->setRotation(ar2angle); + } + + // Set the angle of the dimension text + + Base::Vector3d labelNorm(-labelVec.y, labelVec.x, 0.); + double lAngle = atan2(labelNorm.y, labelNorm.x); + + //if label is more/less vertical, make it vertical + if (lAngle > M_PI_2+M_PI/12) { // label norm angle > 90 + 15 = 105 + lAngle -= M_PI; // lAngle - 180 Flip + } else if (lAngle <= -M_PI_2+M_PI/12) { // < -90 + 15 = - 85 + lAngle += M_PI; // langle + 180 Flip + } + + datumLabel->setTransformOriginPoint(bbX / 2., bbY /2.); + + datumLabel->setRotation(lAngle * 180 / M_PI); + } //endif Distance/Diameter/Radius/Angle // redraw the Dimension and the parent View @@ -1433,10 +1163,8 @@ QColor QGIViewDimension::getNormalColor() return m_colNormal; } - // Identify what changed to prevent complete redraw m_colNormal = vp->Color.getValue().asValue(); return m_colNormal; } - #include