public override IDualSurfaceCurve[] GetPlaneIntersection(PlaneSurface pl, double umin, double umax, double vmin, double vmax, double precision) { if (Precision.IsPerpendicular(pl.Normal, zAxis, false)) { // two lines along the cylinder axis Plane lower = new Plane(location, zAxis); GeoPoint2D sp2d = lower.Project(pl.Location); GeoVector2D dir2d = lower.Project(pl.Normal).ToLeft(); GeoPoint2D[] ips = Geometry.IntersectLC(sp2d, dir2d, GeoPoint2D.Origin, xAxis.Length); IDualSurfaceCurve[] res = new IDualSurfaceCurve[ips.Length]; for (int i = 0; i < ips.Length; i++) { GeoPoint p = lower.ToGlobal(ips[i]); Line l3d = Line.TwoPoints(p, p + zAxis); res[i] = new DualSurfaceCurve(l3d, this, new Line2D(this.PositionOf(l3d.StartPoint), this.PositionOf(l3d.EndPoint)), pl, new Line2D(pl.PositionOf(l3d.StartPoint), pl.PositionOf(l3d.EndPoint))); } return(res); } else { // an ellipse GeoPoint2D[] cnts = pl.GetLineIntersection(location, zAxis); if (cnts.Length == 1) { // there must be exactly one intersection GeoPoint cnt = pl.PointAt(cnts[0]); GeoVector minorAxis = pl.Normal ^ zAxis; minorAxis.Length = xAxis.Length; GeoVector majorAxis = minorAxis ^ pl.Normal; Polynom impl = GetImplicitPolynomial(); Polynom toSolve = impl.Substitute(new Polynom(majorAxis.x, "u", cnt.x, ""), new Polynom(majorAxis.y, "u", cnt.y, ""), new Polynom(majorAxis.z, "u", cnt.z, "")); double[] roots = toSolve.Roots(); // there must be two roots majorAxis = roots[0] * majorAxis; Ellipse elli = Ellipse.Construct(); elli.SetEllipseCenterAxis(cnt, majorAxis, minorAxis); GeoPoint2D[] fpnts = new GeoPoint2D[5]; for (int i = 0; i < 5; i++) { fpnts[i] = PositionOf(elli.PointAt(i / 6.0)); } Ellipse2D e2d = Ellipse2D.FromFivePoints(fpnts); // there should be a better way to calculate the 2d ellipse, but the following is wrong: // Ellipse2D e2d = new Ellipse2D(GeoPoint2D.Origin, PositionOf(cnt + majorAxis).ToVector(), PositionOf(cnt + minorAxis).ToVector()); // and principal axis doesn't yield the correct result either // Geometry.PrincipalAxis(PositionOf(cnt + majorAxis).ToVector(), PositionOf(cnt + minorAxis).ToVector(), out GeoVector2D maj, out GeoVector2D min); return(new IDualSurfaceCurve[] { new DualSurfaceCurve(elli, this, e2d, pl, pl.GetProjectedCurve(elli, 0.0)) }); } } return(new IDualSurfaceCurve[0]); }
public override ICurve2D GetProjectedCurve(ICurve curve, double precision) { if (curve is Line line) { // this must be a line through the apex, otherwise there are no lines on the cone // if it is an extremely small line not through the apex, the result will also be a line, which // in reverse projection will give a very short ellipse return(new Line2D(PositionOf(line.StartPoint), PositionOf(line.EndPoint))); } else if (curve is Ellipse elli) { if (elli.IsCircle) { GeoPoint2D sp2d = PositionOf(elli.StartPoint); if (elli.IsArc) { } else { Arc2D a2d = new Arc2D(GeoPoint2D.Origin, sp2d.ToVector().Length, sp2d, sp2d, true); GeoVector sdir = a2d.StartDirection.x * UDirection(sp2d) + a2d.StartDirection.y * VDirection(sp2d); if (sdir * elli.StartDirection < 0) { a2d.counterClock = false; } return(a2d); } } else { // this is a intersection with a plane. GeoPoint2D[] fp2d = new GeoPoint2D[5]; double n = 5.0; if (elli.IsArc) { n = 4.0; } for (int i = 0; i < 5; i++) { fp2d[i] = PositionOf(elli.PointAt(i / n)); } Ellipse2D elli2d = Ellipse2D.FromFivePoints(fp2d, !elli.IsArc); // returns both full ellipse and ellipse arc if (elli2d != null) { return(elli2d); } } } return(base.GetProjectedCurve(curve, precision)); }
public override ICurve2D GetProjectedCurve(ICurve curve, double precision) { #if DEBUG if (id == 135 || id == 414) { } #endif if (curve is Line line) { // this must be a line parallel to the axis, otherwise there are no lines on the cylinder // if it is an extremely small line not parallel to the axis, the result will also be a line, which // in reverse projection will give a very short ellipse return(new Line2D(PositionOf(line.StartPoint), PositionOf(line.EndPoint))); } else if (curve is Ellipse elli) { // the ellipse must be above the projection center of the 2d system // otherwise it is probably a hyperbola GeoPoint p1 = Geometry.DropPL(elli.Center + elli.MajorAxis, location, zAxis); GeoPoint p2 = Geometry.DropPL(elli.Center - elli.MajorAxis, location, zAxis); double pos1 = Geometry.LinePar(location - zAxis, zAxis, p1); double pos2 = Geometry.LinePar(location - zAxis, zAxis, p2); if (pos1 < 0 || pos2 < 0) { return(base.GetProjectedCurve(curve, precision)); } double d = Geometry.DistPL(elli.Center, location, zAxis); double prec = (elli.MajorRadius + elli.MinorRadius) * 1e-6; // FromFivePoints for this case GeoPoint2D[] fp2d = new GeoPoint2D[5]; double n = 5.0; if (elli.IsArc) { n = 4; } for (int i = 0; i < 5; i++) { fp2d[i] = PositionOf(elli.PointAt(i / n)); } Ellipse2D elli2d = Ellipse2D.FromFivePoints(fp2d, !elli.IsArc); // returns both full ellipse and ellipse arc if (elli2d != null) { if (elli.IsArc) { double spar = elli2d.PositionOf(PositionOf(elli.StartPoint)); double epar = elli2d.PositionOf(PositionOf(elli.EndPoint)); EllipseArc2D elliarc2d = elli2d.Trim(spar, epar) as EllipseArc2D; // there must be a more sophisticated way to calculate the orientation and which part to use, but the following works: double pm = elliarc2d.PositionOf(PositionOf(elli.PointAt(0.5))); if (pm < 0 || pm > 1) { elliarc2d = elliarc2d.GetComplement(); } pm = elliarc2d.PositionOf(PositionOf(elli.PointAt(0.1))); if (pm > 0.5) { elliarc2d.Reverse(); } return(elliarc2d); } else { // get the correct orientation double pos = elli2d.PositionOf(PositionOf(elli.PointAt(0.1))); if (pos > 0.5) { elli2d.Reverse(); } return(elli2d); } } } return(base.GetProjectedCurve(curve, precision)); }
public override ICurve2D GetProjectedCurve(ICurve curve, double precision) { ICurve2D dbg = base.GetProjectedCurve(curve, precision); if (curve is Ellipse elli) { // a circle on the surface is projected to an ellipse in the uv plane GeoPoint2D[] positions = new GeoPoint2D[5]; for (int i = 0; i < 5; i++) { positions[i] = PositionOf(elli.PointAtParam(i * Math.PI * 2.0 / 6.0)); } Ellipse2D elli2d = Ellipse2D.FromFivePoints(positions, true); double prec = precision; if (prec == 0) { prec = Precision.eps; } if (elli2d == null) { BoundingRect ext = new BoundingRect(positions); GaussNewtonMinimizer.Ellipse2DFit(new ToIArray <GeoPoint2D>(positions), ext.GetCenter(), ext.Size / 2.0, ext.Size / 3.0, 0.0, prec, out elli2d); } else { GaussNewtonMinimizer.Ellipse2DFit(new ToIArray <GeoPoint2D>(positions), elli2d.center, elli2d.majrad, elli2d.minrad, elli2d.majorAxis.Angle, prec, out elli2d); } //GeoPoint2D center = PositionOf(elli.Center); //GeoPoint2D maj = PositionOf(elli.Center + elli.MajorAxis); //GeoPoint2D min = PositionOf(elli.Center + elli.MinorAxis); //Geometry.PrincipalAxis(maj - center, min - center, out GeoVector2D majorAxis, out GeoVector2D minorAxis); //Ellipse2D elli2d = new Ellipse2D(center, maj - center, min - center); if (elli2d == null) { return(base.GetProjectedCurve(curve, precision)); } if (elli.IsArc) { double sp = elli2d.PositionOf(PositionOf(elli.StartPoint)); double ep = elli2d.PositionOf(PositionOf(elli.EndPoint)); EllipseArc2D elliarc2d = elli2d.Trim(sp, ep) as EllipseArc2D; // there must be a more sophisticated way to calculate the orientation and which part to use, but the following works: double pm = elliarc2d.PositionOf(PositionOf(elli.PointAt(0.5))); if (pm < 0 || pm > 1) { elliarc2d = elliarc2d.GetComplement(); } pm = elliarc2d.PositionOf(PositionOf(elli.PointAt(0.1))); if (pm > 0.5) { elliarc2d.Reverse(); } return(elliarc2d); } else { // get the correct orientation double pos = elli2d.PositionOf(PositionOf(elli.PointAt(0.1))); if (pos > 0.5) { elli2d.Reverse(); } return(elli2d); } } return(base.GetProjectedCurve(curve, precision)); }