Sketcher: fix reversed geometry and rotated arcs

Fixes a bug where an arc, ellipse, or arc-of-ellipse, being reversed in
XY plane, behaved badly in sketcher (see forum thread "Sketch: how to
handle reversed external arcs?"
http://forum.freecadweb.org/viewtopic.php?f=10&t=9130 ).
Also fixes a problem with rotated arcs (see forum thread "Rotating Arc
in Sketcher"
http://forum.freecadweb.org/viewtopic.php?f=22&t=9145#p74262 ).

This is done by adding an emulation flag to a few methods in
Part::GeomXXX, which makes the shape to pretend being non-reversed
(CCW). This causes endpoints of reversed arcs of circles lineked as
external geometry to swap, causing broken sketches sometimes.
This commit is contained in:
DeepSOIC
2015-01-25 00:24:06 +03:00
committed by wmayer
parent 3d26960f4a
commit 1bbc764e9e
11 changed files with 451 additions and 172 deletions

View File

@@ -295,11 +295,11 @@ int Sketch::addArc(const Part::GeomArcOfCircle &circleSegment, bool fixed)
def.type = Arc;
Base::Vector3d center = aoc->getCenter();
Base::Vector3d startPnt = aoc->getStartPoint();
Base::Vector3d endPnt = aoc->getEndPoint();
Base::Vector3d startPnt = aoc->getStartPoint(/*emulateCCW=*/true);
Base::Vector3d endPnt = aoc->getEndPoint(/*emulateCCW=*/true);
double radius = aoc->getRadius();
double startAngle, endAngle;
aoc->getRange(startAngle, endAngle);
aoc->getRange(startAngle, endAngle, /*emulateCCW=*/true);
GCS::Point p1, p2, p3;
@@ -368,18 +368,18 @@ int Sketch::addArcOfEllipse(const Part::GeomArcOfEllipse &ellipseSegment, bool f
def.type = ArcOfEllipse;
Base::Vector3d center = aoe->getCenter();
Base::Vector3d startPnt = aoe->getStartPoint();
Base::Vector3d endPnt = aoe->getEndPoint();
Base::Vector3d startPnt = aoe->getStartPoint(/*emulateCCW=*/true);
Base::Vector3d endPnt = aoe->getEndPoint(/*emulateCCW=*/true);
double radmaj = aoe->getMajorRadius();
double radmin = aoe->getMinorRadius();
double phi = aoe->getAngleXU();
Base::Vector3d radmajdir = aoe->getMajorAxisDir();
double dist_C_F = sqrt(radmaj*radmaj-radmin*radmin);
// solver parameters
Base::Vector3d focus1 = center+dist_C_F*Vector3d(cos(phi), sin(phi),0); //+x
Base::Vector3d focus1 = center + dist_C_F*radmajdir;
double startAngle, endAngle;
aoe->getRange(startAngle, endAngle);
aoe->getRange(startAngle, endAngle, /*emulateCCW=*/true);
GCS::Point p1, p2, p3;
@@ -505,11 +505,11 @@ int Sketch::addEllipse(const Part::GeomEllipse &elip, bool fixed)
Base::Vector3d center = elips->getCenter();
double radmaj = elips->getMajorRadius();
double radmin = elips->getMinorRadius();
double phi = elips->getAngleXU();
Base::Vector3d radmajdir = elips->getMajorAxisDir();
double dist_C_F = sqrt(radmaj*radmaj-radmin*radmin);
// solver parameters
Base::Vector3d focus1 = center+dist_C_F*Vector3d(cos(phi), sin(phi),0); //+x
Base::Vector3d focus1 = center + dist_C_F*radmajdir; //+x
//double *radmin;
GCS::Point c;
@@ -1929,7 +1929,7 @@ bool Sketch::updateGeometry()
0.0)
);
aoc->setRadius(*myArc.rad);
aoc->setRange(*myArc.startAngle, *myArc.endAngle);
aoc->setRange(*myArc.startAngle, *myArc.endAngle, /*emulateCCW=*/true);
} else if (it->type == ArcOfEllipse) {
GCS::ArcOfEllipse &myArc = ArcsOfEllipse[it->index];
@@ -1942,8 +1942,6 @@ bool Sketch::updateGeometry()
Base::Vector3d fd=f1-center;
double radmaj = sqrt(fd*fd+radmin*radmin);
double phi = atan2(fd.y,fd.x);
aoe->setCenter(center);
if ( radmaj >= aoe->getMinorRadius() ){//ensure that ellipse's major radius is always larger than minor raduis... may still cause problems with degenerates.
aoe->setMajorRadius(radmaj);
@@ -1952,8 +1950,8 @@ bool Sketch::updateGeometry()
aoe->setMinorRadius(radmin);
aoe->setMajorRadius(radmaj);
}
aoe->setAngleXU(phi);
aoe->setRange(*myArc.startAngle, *myArc.endAngle);
aoe->setMajorAxisDir(fd);
aoe->setRange(*myArc.startAngle, *myArc.endAngle, /*emulateCCW=*/true);
} else if (it->type == Circle) {
GeomCircle *circ = dynamic_cast<GeomCircle*>(it->geo);
circ->setCenter(Vector3d(*Points[it->midPointId].x,
@@ -1972,8 +1970,6 @@ bool Sketch::updateGeometry()
Base::Vector3d fd=f1-center;
double radmaj = sqrt(fd*fd+radmin*radmin);
double phi = atan2(fd.y,fd.x);
ellipse->setCenter(center);
if ( radmaj >= ellipse->getMinorRadius() ){//ensure that ellipse's major radius is always larger than minor raduis... may still cause problems with degenerates.
ellipse->setMajorRadius(radmaj);
@@ -1982,7 +1978,7 @@ bool Sketch::updateGeometry()
ellipse->setMinorRadius(radmin);
ellipse->setMajorRadius(radmaj);
}
ellipse->setAngleXU(phi);
ellipse->setMajorAxisDir(fd);
}
} catch (Base::Exception e) {
Base::Console().Error("Updating geometry: Error build geometry(%d): %s\n",

View File

@@ -269,17 +269,17 @@ Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const
} else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) {
const Part::GeomArcOfCircle *aoc = dynamic_cast<const Part::GeomArcOfCircle*>(geo);
if (PosId == start)
return aoc->getStartPoint();
return aoc->getStartPoint(/*emulateCCW=*/true);
else if (PosId == end)
return aoc->getEndPoint();
return aoc->getEndPoint(/*emulateCCW=*/true);
else if (PosId == mid)
return aoc->getCenter();
} else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) {
const Part::GeomArcOfEllipse *aoc = dynamic_cast<const Part::GeomArcOfEllipse*>(geo);
if (PosId == start)
return aoc->getStartPoint();
return aoc->getStartPoint(/*emulateCCW=*/true);
else if (PosId == end)
return aoc->getEndPoint();
return aoc->getEndPoint(/*emulateCCW=*/true);
else if (PosId == mid)
return aoc->getCenter();
}
@@ -699,8 +699,8 @@ int SketchObject::fillet(int GeoId1, int GeoId2,
delete arc;
return -1;
}
dist1.ProjToLine(arc->getStartPoint()-intersection, dir1);
dist2.ProjToLine(arc->getStartPoint()-intersection, dir2);
dist1.ProjToLine(arc->getStartPoint(/*emulateCCW=*/true)-intersection, dir1);
dist2.ProjToLine(arc->getStartPoint(/*emulateCCW=*/true)-intersection, dir2);
Part::Geometry *newgeo = dynamic_cast<Part::Geometry* >(arc);
filletId = addGeometry(newgeo);
if (filletId < 0) {
@@ -733,14 +733,14 @@ int SketchObject::fillet(int GeoId1, int GeoId2,
if (dist1.Length() < dist2.Length()) {
tangent1->SecondPos = start;
tangent2->SecondPos = end;
movePoint(GeoId1, PosId1, arc->getStartPoint());
movePoint(GeoId2, PosId2, arc->getEndPoint());
movePoint(GeoId1, PosId1, arc->getStartPoint(/*emulateCCW=*/true));
movePoint(GeoId2, PosId2, arc->getEndPoint(/*emulateCCW=*/true));
}
else {
tangent1->SecondPos = end;
tangent2->SecondPos = start;
movePoint(GeoId1, PosId1, arc->getEndPoint());
movePoint(GeoId2, PosId2, arc->getStartPoint());
movePoint(GeoId1, PosId1, arc->getEndPoint(/*emulateCCW=*/true));
movePoint(GeoId2, PosId2, arc->getStartPoint(/*emulateCCW=*/true));
}
addConstraint(tangent1);
@@ -936,7 +936,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
Part::GeomArcOfCircle *geoNew = new Part::GeomArcOfCircle();
geoNew->setCenter(center);
geoNew->setRadius(circle->getRadius());
geoNew->setRange(theta1, theta2);
geoNew->setRange(theta1, theta2,/*emulateCCW=*/true);
std::vector< Part::Geometry * > newVals(geomlist);
newVals[GeoId] = geoNew;
@@ -1022,8 +1022,8 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
geoNew->setCenter(center);
geoNew->setMajorRadius(ellipse->getMajorRadius());
geoNew->setMinorRadius(ellipse->getMinorRadius());
geoNew->setAngleXU(ellipse->getAngleXU());
geoNew->setRange(theta1, theta2);
geoNew->setMajorAxisDir(ellipse->getMajorAxisDir());
geoNew->setRange(theta1, theta2, /*emulateCCW=*/true);
std::vector< Part::Geometry * > newVals(geomlist);
newVals[GeoId] = geoNew;
@@ -1083,7 +1083,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
const Part::GeomArcOfCircle *aoc = dynamic_cast<const Part::GeomArcOfCircle*>(geo);
Base::Vector3d center = aoc->getCenter();
double startAngle, endAngle;
aoc->getRange(startAngle, endAngle);
aoc->getRange(startAngle, endAngle, /*emulateCCW=*/true);
double dir = (startAngle < endAngle) ? 1 : -1; // this is always == 1
double arcLength = (endAngle - startAngle)*dir;
double theta0 = Base::fmod(atan2(point.y - center.y, point.x - center.x) - startAngle, 2.f*M_PI); // x0
@@ -1104,8 +1104,8 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
Part::GeomArcOfCircle *aoc1 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[GeoId]);
Part::GeomArcOfCircle *aoc2 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[newGeoId]);
aoc1->setRange(startAngle, startAngle + theta1);
aoc2->setRange(startAngle + theta2, endAngle);
aoc1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true);
aoc2->setRange(startAngle + theta2, endAngle, /*emulateCCW=*/true);
// constrain the trimming points on the corresponding geometries
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
@@ -1201,7 +1201,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
if (theta1 > theta0) { // trim arc start
delConstraintOnPoint(GeoId, start, false);
Part::GeomArcOfCircle *aoc1 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[GeoId]);
aoc1->setRange(startAngle + theta1, endAngle);
aoc1->setRange(startAngle + theta1, endAngle, /*emulateCCW=*/true);
// constrain the trimming point on the corresponding geometry
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = constrType;
@@ -1219,7 +1219,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
else { // trim arc end
delConstraintOnPoint(GeoId, end, false);
Part::GeomArcOfCircle *aoc1 = dynamic_cast<Part::GeomArcOfCircle*>(geomlist[GeoId]);
aoc1->setRange(startAngle, startAngle + theta1);
aoc1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true);
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = constrType;
newConstr->First = GeoId;
@@ -1239,21 +1239,21 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
const Part::GeomArcOfEllipse *aoe = dynamic_cast<const Part::GeomArcOfEllipse*>(geo);
Base::Vector3d center = aoe->getCenter();
double startAngle, endAngle;
aoe->getRange(startAngle, endAngle);
aoe->getRange(startAngle, endAngle,/*emulateCCW=*/true);
double dir = (startAngle < endAngle) ? 1 : -1; // this is always == 1
double arcLength = (endAngle - startAngle)*dir;
double theta0 = Base::fmod(
atan2(-aoe->getMajorRadius()*((point.x-center.x)*sin(aoe->getAngleXU())-(point.y-center.y)*cos(aoe->getAngleXU())),
aoe->getMinorRadius()*((point.x-center.x)*cos(aoe->getAngleXU())+(point.y-center.y)*sin(aoe->getAngleXU()))
atan2(-aoe->getMajorRadius()*((point.x-center.x)*aoe->getMajorAxisDir().y-(point.y-center.y)*aoe->getMajorAxisDir().x),
aoe->getMinorRadius()*((point.x-center.x)*aoe->getMajorAxisDir().x+(point.y-center.y)*aoe->getMajorAxisDir().y)
)- startAngle, 2.f*M_PI); // x0
if (GeoId1 >= 0 && GeoId2 >= 0) {
double theta1 = Base::fmod(
atan2(-aoe->getMajorRadius()*((point1.x-center.x)*sin(aoe->getAngleXU())-(point1.y-center.y)*cos(aoe->getAngleXU())),
aoe->getMinorRadius()*((point1.x-center.x)*cos(aoe->getAngleXU())+(point1.y-center.y)*sin(aoe->getAngleXU()))
atan2(-aoe->getMajorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().y-(point1.y-center.y)*aoe->getMajorAxisDir().x),
aoe->getMinorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().x+(point1.y-center.y)*aoe->getMajorAxisDir().y)
)- startAngle, 2.f*M_PI) * dir; // x1
double theta2 = Base::fmod(
atan2(-aoe->getMajorRadius()*((point2.x-center.x)*sin(aoe->getAngleXU())-(point2.y-center.y)*cos(aoe->getAngleXU())),
aoe->getMinorRadius()*((point2.x-center.x)*cos(aoe->getAngleXU())+(point2.y-center.y)*sin(aoe->getAngleXU()))
atan2(-aoe->getMajorRadius()*((point2.x-center.x)*aoe->getMajorAxisDir().y-(point2.y-center.y)*aoe->getMajorAxisDir().x),
aoe->getMinorRadius()*((point2.x-center.x)*aoe->getMajorAxisDir().x+(point2.y-center.y)*aoe->getMajorAxisDir().y)
)- startAngle, 2.f*M_PI) * dir; // x2
if (theta1 > theta2) {
@@ -1270,8 +1270,8 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
Part::GeomArcOfEllipse *aoe1 = dynamic_cast<Part::GeomArcOfEllipse*>(geomlist[GeoId]);
Part::GeomArcOfEllipse *aoe2 = dynamic_cast<Part::GeomArcOfEllipse*>(geomlist[newGeoId]);
aoe1->setRange(startAngle, startAngle + theta1);
aoe2->setRange(startAngle + theta2, endAngle);
aoe1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true);
aoe2->setRange(startAngle + theta2, endAngle, /*emulateCCW=*/true);
// constrain the trimming points on the corresponding geometries
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
@@ -1362,15 +1362,15 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
}
double theta1 = Base::fmod(
atan2(-aoe->getMajorRadius()*((point1.x-center.x)*sin(aoe->getAngleXU())-(point1.y-center.y)*cos(aoe->getAngleXU())),
aoe->getMinorRadius()*((point1.x-center.x)*cos(aoe->getAngleXU())+(point1.y-center.y)*sin(aoe->getAngleXU()))
atan2(-aoe->getMajorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().y-(point1.y-center.y)*aoe->getMajorAxisDir().x),
aoe->getMinorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().x+(point1.y-center.y)*aoe->getMajorAxisDir().y)
)- startAngle, 2.f*M_PI) * dir; // x1
if (theta1 >= 0.001*arcLength && theta1 <= 0.999*arcLength) {
if (theta1 > theta0) { // trim arc start
delConstraintOnPoint(GeoId, start, false);
Part::GeomArcOfEllipse *aoe1 = dynamic_cast<Part::GeomArcOfEllipse*>(geomlist[GeoId]);
aoe1->setRange(startAngle + theta1, endAngle);
aoe1->setRange(startAngle + theta1, endAngle, /*emulateCCW=*/true);
// constrain the trimming point on the corresponding geometry
Sketcher::Constraint *newConstr = new Sketcher::Constraint();
newConstr->Type = constrType;
@@ -1388,7 +1388,7 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point)
else { // trim arc end
delConstraintOnPoint(GeoId, end, false);
Part::GeomArcOfEllipse *aoe1 = dynamic_cast<Part::GeomArcOfEllipse*>(geomlist[GeoId]);
aoe1->setRange(startAngle, startAngle + theta1);
aoe1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true);
return 0;
}
@@ -1451,7 +1451,7 @@ int SketchObject::ExposeInternalGeometry(int GeoId)
Base::Vector3d center;
double majord;
double minord;
double phi;
Base::Vector3d majdir;
if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()){
const Part::GeomEllipse *ellipse = static_cast<const Part::GeomEllipse *>(geo);
@@ -1459,7 +1459,7 @@ int SketchObject::ExposeInternalGeometry(int GeoId)
center=ellipse->getCenter();
majord=ellipse->getMajorRadius();
minord=ellipse->getMinorRadius();
phi=ellipse->getAngleXU();
majdir=ellipse->getMajorAxisDir();
}
else {
const Part::GeomArcOfEllipse *aoe = static_cast<const Part::GeomArcOfEllipse *>(geo);
@@ -1467,18 +1467,20 @@ int SketchObject::ExposeInternalGeometry(int GeoId)
center=aoe->getCenter();
majord=aoe->getMajorRadius();
minord=aoe->getMinorRadius();
phi=aoe->getAngleXU();
majdir=aoe->getMajorAxisDir();
}
Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x);
Base::Vector3d majorpositiveend = center + majord * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d majornegativeend = center - majord * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d minorpositiveend = center + minord * Base::Vector3d(-sin(phi),cos(phi),0);
Base::Vector3d minornegativeend = center - minord * Base::Vector3d(-sin(phi),cos(phi),0);
Base::Vector3d majorpositiveend = center + majord * majdir;
Base::Vector3d majornegativeend = center - majord * majdir;
Base::Vector3d minorpositiveend = center + minord * mindir;
Base::Vector3d minornegativeend = center - minord * mindir;
double df= sqrt(majord*majord-minord*minord);
Base::Vector3d focus1P = center + df * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d focus2P = center - df * Base::Vector3d(cos(phi),sin(phi),0);
Base::Vector3d focus1P = center + df * majdir;
Base::Vector3d focus2P = center - df * majdir;
if(!major)
{
@@ -1982,16 +1984,14 @@ void SketchObject::rebuildExternalGeometry(void)
gp_Pnt P2 = projCurve.Value(projCurve.LastParameter());
//gp_Dir normal = e.Axis().Direction();
gp_Dir normal = gp_Dir(0,0,1);
gp_Dir normal = gp_Dir(0,0,1);
gp_Dir xdir = e.XAxis().Direction();
gp_Ax2 xdirref(p, normal);
if (P1.SquareDistance(P2) < Precision::Confusion()) {
Part::GeomEllipse* ellipse = new Part::GeomEllipse();
ellipse->setMajorRadius(e.MajorRadius());
ellipse->setMinorRadius(e.MinorRadius());
ellipse->setCenter(Base::Vector3d(p.X(),p.Y(),p.Z()));
ellipse->setAngleXU(-xdir.AngleWithRef(xdirref.XDirection(),normal));
Handle_Geom_Ellipse curve = new Geom_Ellipse(e);
ellipse->setHandle(curve);
ellipse->Construction = true;
ExternalGeo.push_back(ellipse);
}

View File

@@ -157,7 +157,6 @@ namespace GCS
int addConstraintTangent(Circle &c, Arc &a, int tagId=0);
int addConstraintCircleRadius(Circle &c, double *radius, int tagId=0);
int addConstraintEllipseAngleXU(Ellipse &e, double *angle, int tagId=0);
int addConstraintArcRadius(Arc &a, double *radius, int tagId=0);
int addConstraintEqualLength(Line &l1, Line &l2, double *length, int tagId=0);
int addConstraintEqualRadius(Circle &c1, Circle &c2, int tagId=0);