double DrawViewDimension::getDimValue() const { double result = 0.0; if (!has2DReferences()) { //happens during Dimension creation Base::Console().Message("INFO - DVD::getDimValue - Dimension has no References\n"); return result; } if (!getViewPart()->hasGeometry()) { //happens when loading saved document Base::Console().Message("INFO - DVD::getDimValue ViewPart has no Geometry yet\n"); return result; } if (MeasureType.isValue("True")) { // True Values if (!measurement->has3DReferences()) { return result; } if(Type.isValue("Distance")) { result = measurement->delta().Length(); } else if(Type.isValue("DistanceX")){ Base::Vector3d delta = measurement->delta(); result = delta.x; } else if(Type.isValue("DistanceY")){ Base::Vector3d delta = measurement->delta(); result = delta.y; } else if(Type.isValue("DistanceZ")){ Base::Vector3d delta = measurement->delta(); result = delta.z; } else if(Type.isValue("Radius")){ result = measurement->radius(); } else if(Type.isValue("Diameter")){ result = measurement->radius() * 2.0; } else if(Type.isValue("Angle")){ result = measurement->angle(); } else { throw Base::Exception("getDimValue() - Unknown Dimension Type (1)"); } } else { // Projected Values const std::vector<App::DocumentObject*> &objects = References2D.getValues(); const std::vector<std::string> &subElements = References2D.getSubValues(); if (Type.isValue("Distance") && getRefType() == oneEdge) { //TODO: Check for straight line Edge? int idx = DrawUtil::getIndexFromName(subElements[0]); TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); TechDrawGeometry::Generic* gen = static_cast<TechDrawGeometry::Generic*>(geom); Base::Vector2D start = gen->points[0]; Base::Vector2D end = gen->points[1]; Base::Vector2D line = end - start; result = line.Length() / getViewPart()->Scale.getValue(); } else if (Type.isValue("Distance") && 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::BaseGeom* geom1 = getViewPart()->getProjEdgeByIndex(idx1); TechDrawGeometry::Generic* gen0 = static_cast<TechDrawGeometry::Generic*>(geom0); TechDrawGeometry::Generic* gen1 = static_cast<TechDrawGeometry::Generic*>(geom1); Base::Vector2D s0 = gen0->points[0]; Base::Vector2D e0 = gen0->points[1]; Base::Vector2D s1 = gen1->points[0]; Base::Vector2D e1 = gen1->points[1]; result = dist2Segs(s0,e0,s1,e1) / getViewPart()->Scale.getValue(); } else if (Type.isValue("Distance") && 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); Base::Vector2D start = v0->pnt; Base::Vector2D end = v1->pnt; Base::Vector2D line = end - start; result = line.Length() / getViewPart()->Scale.getValue(); } else if (Type.isValue("DistanceX") && getRefType() == oneEdge) { int idx = DrawUtil::getIndexFromName(subElements[0]); TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); TechDrawGeometry::Generic* gen = static_cast<TechDrawGeometry::Generic*>(geom); Base::Vector2D start = gen->points[0]; Base::Vector2D end = gen->points[1]; Base::Vector2D line = end - start; return fabs(line.fX) / getViewPart()->Scale.getValue(); } else if (Type.isValue("DistanceY") && getRefType() == oneEdge) { int idx = DrawUtil::getIndexFromName(subElements[0]); TechDrawGeometry::BaseGeom* geom = getViewPart()->getProjEdgeByIndex(idx); TechDrawGeometry::Generic* gen = static_cast<TechDrawGeometry::Generic*>(geom); Base::Vector2D start = gen->points[0]; Base::Vector2D end = gen->points[1]; Base::Vector2D line = end - start; result = fabs(line.fY) / getViewPart()->Scale.getValue(); } else if (Type.isValue("DistanceX") && 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); Base::Vector2D start = v0->pnt; Base::Vector2D end = v1->pnt; Base::Vector2D line = end - start; result = fabs(line.fX) / getViewPart()->Scale.getValue(); } else if (Type.isValue("DistanceY") && 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); Base::Vector2D start = v0->pnt; Base::Vector2D end = v1->pnt; Base::Vector2D line = end - start; result = fabs(line.fY) / getViewPart()->Scale.getValue(); } 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 = static_cast<TechDrawGeometry::Circle*> (base); result = circle->radius / getViewPart()->Scale.getValue(); //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 = static_cast<TechDrawGeometry::Circle*> (base); result = (circle->radius * 2.0) / getViewPart()->Scale.getValue(); //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(subElements.size() != 2) { // throw Base::Exception("FVD - Two references required for angle measurement"); // } if (getRefType() != twoEdge) { throw Base::Exception("FVD - Two edge references required for angle measurement"); } int idx0 = DrawUtil::getIndexFromName(subElements[0]); int idx1 = DrawUtil::getIndexFromName(subElements[1]); TechDraw::DrawViewPart *viewPart = dynamic_cast<TechDraw::DrawViewPart *>(objects[0]); TechDrawGeometry::BaseGeom* edge0 = viewPart->getProjEdgeByIndex(idx0); TechDrawGeometry::BaseGeom* edge1 = viewPart->getProjEdgeByIndex(idx1); // Only can find angles with straight line edges if(edge0->geomType == TechDrawGeometry::GENERIC && edge1->geomType == TechDrawGeometry::GENERIC) { TechDrawGeometry::Generic *gen1 = static_cast<TechDrawGeometry::Generic *>(edge0); TechDrawGeometry::Generic *gen2 = static_cast<TechDrawGeometry::Generic *>(edge1); Base::Vector3d p1S(gen1->points.at(0).fX, gen1->points.at(0).fY, 0.); Base::Vector3d p1E(gen1->points.at(1).fX, gen1->points.at(1).fY, 0.); Base::Vector3d p2S(gen2->points.at(0).fX, gen2->points.at(0).fY, 0.); Base::Vector3d p2E(gen2->points.at(1).fX, gen2->points.at(1).fY, 0.); Base::Vector3d dir1 = p1E - p1S; Base::Vector3d dir2 = p2E - p2S; // 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"); double c1 = dir1.y*gen1->points.at(0).fX - dir1.x*gen1->points.at(0).fY; double c2 = dir2.y*gen2->points.at(1).fX - dir2.x*gen2->points.at(1).fY; double x = (dir1.x*c2 - dir2.x*c1)/det; double y = (dir1.y*c2 - dir2.y*c1)/det; // Intersection point Base::Vector3d p0 = Base::Vector3d(x,y,0); Base::Vector3d lPos((double) X.getValue(), (double) Y.getValue(), 0.); //Base::Vector3d delta = lPos - p0; // 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 return result; }
int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints, const Base::Vector2D& Pos, const Base::Vector2D& Dir, AutoConstraint::TargetType type) { suggestedConstraints.clear(); if (!sketchgui->Autoconstraints.getValue()) return 0; // If Autoconstraints property is not set quit Base::Vector3d hitShapeDir = Base::Vector3d(0,0,0); // direction of hit shape (if it is a line, the direction of the line) // Get Preselection int preSelPnt = sketchgui->getPreselectPoint(); int preSelCrv = sketchgui->getPreselectCurve(); int preSelCrs = sketchgui->getPreselectCross(); int GeoId = Constraint::GeoUndef; Sketcher::PointPos PosId = Sketcher::none; if (preSelPnt != -1) sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId); else if (preSelCrv != -1){ GeoId = preSelCrv; const Part::Geometry *geom = sketchgui->getSketchObject()->getGeometry(GeoId); if(geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ const Part::GeomLineSegment *line = static_cast<const Part::GeomLineSegment *>(geom); hitShapeDir= line->getEndPoint()-line->getStartPoint(); } } else if (preSelCrs == 0) { // root point GeoId = -1; PosId = Sketcher::start; } else if (preSelCrs == 1){ // x axis GeoId = -1; hitShapeDir = Base::Vector3d(1,0,0); } else if (preSelCrs == 2){ // y axis GeoId = -2; hitShapeDir = Base::Vector3d(0,1,0); } if (GeoId != Constraint::GeoUndef) { // Currently only considers objects in current Sketcher AutoConstraint constr; constr.Type = Sketcher::None; constr.GeoId = GeoId; constr.PosId = PosId; if (type == AutoConstraint::VERTEX && PosId != Sketcher::none) constr.Type = Sketcher::Coincident; else if (type == AutoConstraint::CURVE && PosId != Sketcher::none) constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::VERTEX && PosId == Sketcher::none) constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::CURVE && PosId == Sketcher::none) constr.Type = Sketcher::Tangent; if(constr.Type == Sketcher::Tangent && Dir.Length() > 1e-8 && hitShapeDir.Length() > 1e-8) { // We are hitting a line and have hitting vector information Base::Vector3d dir3d = Base::Vector3d(Dir.fX,Dir.fY,0); double cosangle=dir3d.Normalize()*hitShapeDir.Normalize(); // the angle between the line and the hitting direction are over around 6 degrees (it is substantially parallel) // or if it is an sketch axis (that can not move to accomodate to the shape), then only if it is around 6 degrees with the normal (around 84 degrees) if (fabs(cosangle) < 0.995f || ((GeoId==-1 || GeoId==-2) && fabs(cosangle) < 0.1)) suggestedConstraints.push_back(constr); return suggestedConstraints.size(); } if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); } if (Dir.Length() < 1e-8 || type == AutoConstraint::CURVE) // Direction not set so return; return suggestedConstraints.size(); // Suggest vertical and horizontal constraints // Number of Degree of deviation from horizontal or vertical lines const double angleDev = 2; const double angleDevRad = angleDev * M_PI / 180.; AutoConstraint constr; constr.Type = Sketcher::None; constr.GeoId = Constraint::GeoUndef; constr.PosId = Sketcher::none; double angle = std::abs(atan2(Dir.fY, Dir.fX)); if (angle < angleDevRad || (M_PI - angle) < angleDevRad ) // Suggest horizontal constraint constr.Type = Sketcher::Horizontal; else if (std::abs(angle - M_PI_2) < angleDevRad) // Suggest vertical constraint constr.Type = Sketcher::Vertical; if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); // Find if there are tangent constraints (currently arcs and circles) int tangId = Constraint::GeoUndef; // Do not consider if distance is more than that. // Decrease this value when a candidate is found. double tangDeviation = 0.1 * sketchgui->getScaleFactor(); // Get geometry list const std::vector<Part::Geometry *> geomlist = sketchgui->getSketchObject()->getCompleteGeometry(); Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f); // Current cursor point Base::Vector3d tmpDir(Dir.fX, Dir.fY, 0.f); // Direction of line Base::Vector3d tmpStart(Pos.fX-Dir.fX, Pos.fY-Dir.fY, 0.f); // Start point // Iterate through geometry int i = 0; for (std::vector<Part::Geometry *>::const_iterator it=geomlist.begin(); it != geomlist.end(); ++it, i++) { if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = static_cast<const Part::GeomCircle *>((*it)); Base::Vector3d center = circle->getCenter(); double radius = circle->getRadius(); // ignore if no touch (use dot product) if(tmpDir * (center-tmpPos) > 0 || tmpDir * (center-tmpStart) < 0) continue; Base::Vector3d projPnt(0.f, 0.f, 0.f); projPnt = projPnt.ProjectToLine(center - tmpPos, tmpDir); double projDist = std::abs(projPnt.Length() - radius); // Find if nearest if (projDist < tangDeviation) { tangId = i; tangDeviation = projDist; } } else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) { const Part::GeomEllipse *ellipse = static_cast<const Part::GeomEllipse *>((*it)); Base::Vector3d center = ellipse->getCenter(); double a = ellipse->getMajorRadius(); double b = ellipse->getMinorRadius(); Base::Vector3d majdir = ellipse->getMajorAxisDir(); double cf = sqrt(a*a - b*b); Base::Vector3d focus1P = center + cf * majdir; Base::Vector3d focus2P = center - cf * majdir; Base::Vector3d norm = Base::Vector3d(Dir.fY,-Dir.fX).Normalize(); double distancetoline = norm*(tmpPos - focus1P); // distance focus1 to line Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line double error = fabs((focus1PMirrored-focus2P).Length() - 2*a); if ( error< tangDeviation) { tangId = i; tangDeviation = error; } } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *arc = static_cast<const Part::GeomArcOfCircle *>((*it)); Base::Vector3d center = arc->getCenter(); double radius = arc->getRadius(); // ignore if no touch (use dot product) if(tmpDir * (center-tmpPos) > 0 || tmpDir * (center-tmpStart) < 0) continue; Base::Vector3d projPnt(0.f, 0.f, 0.f); projPnt = projPnt.ProjectToLine(center - tmpPos, tmpDir); double projDist = std::abs(projPnt.Length() - radius); if (projDist < tangDeviation) { double startAngle, endAngle; arc->getRange(startAngle, endAngle, /*emulateCCW=*/true); double angle = atan2(projPnt.y, projPnt.x); while(angle < startAngle) angle += 2*D_PI; // Bring it to range of arc // if the point is on correct side of arc if (angle <= endAngle) { // Now need to check only one side tangId = i; tangDeviation = projDist; } } } else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { const Part::GeomArcOfEllipse *aoe = static_cast<const Part::GeomArcOfEllipse *>((*it)); Base::Vector3d center = aoe->getCenter(); double a = aoe->getMajorRadius(); double b = aoe->getMinorRadius(); Base::Vector3d majdir = aoe->getMajorAxisDir(); double cf = sqrt(a*a - b*b); Base::Vector3d focus1P = center + cf * majdir; Base::Vector3d focus2P = center - cf * majdir; Base::Vector3d norm = Base::Vector3d(Dir.fY,-Dir.fX).Normalize(); double distancetoline = norm*(tmpPos - focus1P); // distance focus1 to line Base::Vector3d focus1PMirrored = focus1P + 2*distancetoline*norm; // mirror of focus1 with respect to the line double error = fabs((focus1PMirrored-focus2P).Length() - 2*a); if ( error< tangDeviation ) { tangId = i; tangDeviation = error; } if (error < tangDeviation) { double startAngle, endAngle; aoe->getRange(startAngle, endAngle, /*emulateCCW=*/true); double angle = Base::fmod( atan2(-aoe->getMajorRadius()*((tmpPos.x-center.x)*majdir.y-(tmpPos.y-center.y)*majdir.x), aoe->getMinorRadius()*((tmpPos.x-center.x)*majdir.x+(tmpPos.y-center.y)*majdir.y) )- startAngle, 2.f*M_PI); while(angle < startAngle) angle += 2*D_PI; // Bring it to range of arc // if the point is on correct side of arc if (angle <= endAngle) { // Now need to check only one side tangId = i; tangDeviation = error; } } } } if (tangId != Constraint::GeoUndef) { if (tangId > getHighestCurveIndex()) // external Geometry tangId = getHighestCurveIndex() - tangId; // Suggest vertical constraint constr.Type = Tangent; constr.GeoId = tangId; constr.PosId = Sketcher::none; suggestedConstraints.push_back(constr); } return suggestedConstraints.size(); }
int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggestedConstraints, const Base::Vector2D& Pos, const Base::Vector2D& Dir, AutoConstraint::TargetType type) { suggestedConstraints.clear(); if (!sketchgui->Autoconstraints.getValue()) return 0; // If Autoconstraints property is not set quit // Get Preselection int preSelPnt = sketchgui->getPreselectPoint(); int preSelCrv = sketchgui->getPreselectCurve(); int GeoId = Constraint::GeoUndef; Sketcher::PointPos PosId = Sketcher::none; if (preSelPnt != -1) sketchgui->getSketchObject()->getGeoVertexIndex(preSelPnt, GeoId, PosId); else if (preSelCrv != -1) GeoId = preSelCrv; // Currently only considers objects in current Sketcher AutoConstraint constr; constr.Type = Sketcher::None; constr.GeoId = GeoId; constr.PosId = PosId; if (type == AutoConstraint::VERTEX && preSelPnt != -1) constr.Type = Sketcher::Coincident; else if (type == AutoConstraint::CURVE && preSelPnt != -1) constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::VERTEX && preSelCrv != -1) constr.Type = Sketcher::PointOnObject; else if (type == AutoConstraint::CURVE && preSelCrv != -1) constr.Type = Sketcher::Tangent; if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); if (Dir.Length() < 1) // Direction not set so return; return suggestedConstraints.size(); // Suggest vertical and horizontal constraints // Number of Degree of deviation from horizontal or vertical lines const double angleDev = 2; const double angleDevRad = angleDev * M_PI / 180.; constr.Type = Sketcher::None; constr.GeoId = Constraint::GeoUndef; constr.PosId = Sketcher::none; double angle = std::abs(atan2(Dir.fY, Dir.fX)); if (angle < angleDevRad || (M_PI - angle) < angleDevRad ) // Suggest horizontal constraint constr.Type = Sketcher::Horizontal; else if (std::abs(angle - M_PI_2) < angleDevRad) // Suggest vertical constraint constr.Type = Sketcher::Vertical; if (constr.Type != Sketcher::None) suggestedConstraints.push_back(constr); // Find if there are tangent constraints (currently arcs and circles) // FIXME needs to consider when zooming out? const float tangDeviation = 2.; int tangId = Constraint::GeoUndef; float smlTangDist = 1e15f; // Get geometry list const std::vector<Part::Geometry *> geomlist = sketchgui->getSketchObject()->getCompleteGeometry(); // Iterate through geometry int i = 0; for (std::vector<Part::Geometry *>::const_iterator it=geomlist.begin(); it != geomlist.end(); ++it, i++) { if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>((*it)); Base::Vector3d center = circle->getCenter(); Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f); float radius = (float) circle->getRadius(); Base::Vector3d projPnt(0.f, 0.f, 0.f); projPnt = projPnt.ProjToLine(center - tmpPos, Base::Vector3d(Dir.fX, Dir.fY)); float projDist = projPnt.Length(); if ( (projDist < radius + tangDeviation ) && (projDist > radius - tangDeviation)) { // Find if nearest if (projDist < smlTangDist) { tangId = i; smlTangDist = projDist; } } } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *arc = dynamic_cast<const Part::GeomArcOfCircle *>((*it)); Base::Vector3d center = arc->getCenter(); double radius = arc->getRadius(); Base::Vector3d projPnt(0.f, 0.f, 0.f); Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f); projPnt = projPnt.ProjToLine(center - tmpPos, Base::Vector3d(Dir.fX, Dir.fY)); float projDist = projPnt.Length(); if ( projDist < radius + tangDeviation && projDist > radius - tangDeviation) { double startAngle, endAngle; arc->getRange(startAngle, endAngle); projPnt += center; double angle = atan2(projPnt.y, projPnt.x); // if the pnt is on correct side of arc and find if nearest if ((angle > startAngle && angle < endAngle) && (projDist < smlTangDist) ) { tangId = i; smlTangDist = projDist; } } } } if (tangId != Constraint::GeoUndef) { if (tangId > getHighestCurveIndex()) // external Geometry tangId = getHighestCurveIndex() - tangId; // Suggest vertical constraint constr.Type = Tangent; constr.GeoId = tangId; constr.PosId = Sketcher::none; suggestedConstraints.push_back(constr); } return suggestedConstraints.size(); }