Fix automatic creation of tangent constriants.

a. Use scale to calculate max distance
b. Consider only circle/arc that actually touch the newly created line
c. Use of arc angles correctly
d. Find nearest touch point (not nearest center)
e. some optimization
This commit is contained in:
Itai Nahshon 2014-08-23 03:20:28 +03:00 committed by wmayer
parent 6eeaae57b8
commit e9ea1e2727

View File

@ -200,17 +200,22 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
if (constr.Type != Sketcher::None) if (constr.Type != Sketcher::None)
suggestedConstraints.push_back(constr); suggestedConstraints.push_back(constr);
// Find if there are tangent constraints (currently arcs and circles) // Find if there are tangent constraints (currently arcs and circles)
// FIXME needs to consider when zooming out?
const double tangDeviation = 2.;
int tangId = Constraint::GeoUndef; int tangId = Constraint::GeoUndef;
double smlTangDist = 1e15f;
// 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 // Get geometry list
const std::vector<Part::Geometry *> geomlist = sketchgui->getSketchObject()->getCompleteGeometry(); 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 // Iterate through geometry
int i = 0; int i = 0;
for (std::vector<Part::Geometry *>::const_iterator it=geomlist.begin(); it != geomlist.end(); ++it, i++) { for (std::vector<Part::Geometry *>::const_iterator it=geomlist.begin(); it != geomlist.end(); ++it, i++) {
@ -219,20 +224,21 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>((*it)); const Part::GeomCircle *circle = dynamic_cast<const Part::GeomCircle *>((*it));
Base::Vector3d center = circle->getCenter(); Base::Vector3d center = circle->getCenter();
Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f);
double radius = circle->getRadius(); double radius = circle->getRadius();
Base::Vector3d projPnt(0.f, 0.f, 0.f); // ignore if no touch (use dot product)
projPnt = projPnt.ProjToLine(center - tmpPos, Base::Vector3d(Dir.fX, Dir.fY)); if(tmpDir * (center-tmpPos) > 0 || tmpDir * (center-tmpStart) < 0)
double projDist = projPnt.Length(); continue;
if ( (projDist < radius + tangDeviation ) && (projDist > radius - tangDeviation)) { Base::Vector3d projPnt(0.f, 0.f, 0.f);
// Find if nearest projPnt = projPnt.ProjToLine(center - tmpPos, tmpDir);
if (projDist < smlTangDist) { double projDist = std::abs(projPnt.Length() - radius);
tangId = i;
smlTangDist = projDist; // Find if nearest
} if (projDist < tangDeviation) {
tangId = i;
tangDeviation = projDist;
} }
} else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
@ -241,24 +247,26 @@ int DrawSketchHandler::seekAutoConstraint(std::vector<AutoConstraint> &suggested
Base::Vector3d center = arc->getCenter(); Base::Vector3d center = arc->getCenter();
double radius = arc->getRadius(); 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); Base::Vector3d projPnt(0.f, 0.f, 0.f);
Base::Vector3d tmpPos(Pos.fX, Pos.fY, 0.f); projPnt = projPnt.ProjToLine(center - tmpPos, tmpDir);
double projDist = std::abs(projPnt.Length() - radius);
projPnt = projPnt.ProjToLine(center - tmpPos, Base::Vector3d(Dir.fX, Dir.fY)); if (projDist < tangDeviation) {
double projDist = projPnt.Length();
if ( projDist < radius + tangDeviation && projDist > radius - tangDeviation) {
double startAngle, endAngle; double startAngle, endAngle;
arc->getRange(startAngle, endAngle); arc->getRange(startAngle, endAngle);
projPnt += center;
double angle = atan2(projPnt.y, projPnt.x); double angle = atan2(projPnt.y, projPnt.x);
while(angle < startAngle)
angle += 2*D_PI; // Bring it to range of arc
// if the pnt is on correct side of arc and find if nearest // if the point is on correct side of arc
if ((angle > startAngle && angle < endAngle) && if (angle <= endAngle) { // Now need to check only one side
(projDist < smlTangDist) ) {
tangId = i; tangId = i;
smlTangDist = projDist; tangDeviation = projDist;
} }
} }
} }