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)); }
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)); }
void IPaintTo3D.Arc(GeoPoint center, GeoVector majorAxis, GeoVector minorAxis, double startParameter, double sweepParameter) { try { GeoVector normal = majorAxis ^ minorAxis; // normale der Ebene des Bogens // wird der Bogen von vorne oder hinten betrachtet? // statt projection.Direction besser die Richtung zum Mittelpunkt (bei perspektivischer Projektion) double sc = projection.Direction.Normalized * normal.Normalized; if (Math.Abs(sc) < 1e-6) { // eine Linie GeoVector dir = normal ^ projection.Direction; // Richtung der Linie double pmin, pmax; double par = Geometry.LinePar(center, dir, center + Math.Cos(startParameter) * majorAxis + Math.Sin(startParameter) * minorAxis); pmin = pmax = par; par = Geometry.LinePar(center, dir, center + Math.Cos(startParameter + sweepParameter) * majorAxis + Math.Sin(startParameter + sweepParameter) * minorAxis); if (par < pmin) { pmin = par; } if (par > pmax) { pmax = par; } // fehlt noch: jetzt noch die Achsenpunkt abprüfen... (this as IPaintTo3D).Polyline(new GeoPoint[] { center + pmin * dir, center + pmax * dir }); } else { GeoPoint2D center2d = projection.Project(center); GeoVector2D maj2D = projection.Project(center + majorAxis) - center2d; GeoVector2D min2D = projection.Project(center + minorAxis) - center2d; if (maj2D.IsNullVector() || min2D.IsNullVector()) { // eigentlich auch eine Linie return; } GeoPoint2D sp = center2d + Math.Cos(startParameter) * maj2D + Math.Sin(startParameter) * min2D; GeoPoint2D ep = center2d + Math.Cos(startParameter + sweepParameter) * maj2D + Math.Sin(startParameter + sweepParameter) * min2D; bool counterclock = sweepParameter > 0.0; //if (normal.z > 0.0) counterclock = !counterclock; EllipseArc2D ea2d = EllipseArc2D.Create(center2d, maj2D, min2D, sp, ep, counterclock); ea2d.MakePositivOriented(); GeoVector2D prmaj2D, prmin2D; // Geometry.PrincipalAxis(maj2D, min2D, out prmaj2D, out prmin2D); prmaj2D = ea2d.MajorAxis; prmin2D = ea2d.MinorAxis; Angle rot = prmaj2D.Angle; //ModOp2D toHorizontal = ModOp2D.Rotate(center2d, -rot.Radian); ModOp2D fromHorizontal = ModOp2D.Rotate(center2d, rot.Radian); SweepAngle swapar = new SweepAngle(ea2d.StartPoint - center2d, ea2d.EndPoint - center2d); if (counterclock && swapar < 0) { swapar += 360; } if (!counterclock && swapar > 0) { swapar -= 360; } float swPar = (float)(ea2d.axisSweep / Math.PI * 180); float stPar = (float)(ea2d.axisStart / Math.PI * 180); if (sweepParameter >= Math.PI * 2.0 || sweepParameter <= -Math.PI * 2.0) { // Notlösung wg. ERSACAD und wg. Nürnberger 5.12.13 swPar = 360.0f; } try { Matrix r = fromHorizontal.Matrix2D; double maxRad = prmaj2D.Length; double minRad = prmin2D.Length; if ((maxRad + minRad) * Projection.WorldToDeviceFactor < 1) { // sonst gibt es ein out of memory exception if (graphicsPath != null) { // kann auch schräge Ellipsen zufügen mit Transformation GraphicsPath tmpPath = new GraphicsPath(); tmpPath.AddLine((float)center2d.x, (float)center2d.y, (float)center2d.x, (float)center2d.y); tmpPath.Transform(r); graphicsPath.AddPath(tmpPath, true); } else { Pen drawPen = MakePen(); using (drawPen) { using (new Transform(graphics, r, false)) { // wenigstens einen Pixel darstellen graphics.DrawLine(drawPen, (float)(center2d.x - 0.5), (float)center2d.y, (float)(center2d.x + 0.5), (float)center2d.y); } } } } else { if (graphicsPath != null) { // kann auch schräge Ellipsen zufügen mit Transformation GraphicsPath tmpPath = new GraphicsPath(); tmpPath.AddArc((float)(center2d.x - maxRad), (float)(center2d.y - minRad), (float)(2.0 * maxRad), (float)(2.0 * minRad), stPar, swPar); tmpPath.Transform(r); graphicsPath.AddPath(tmpPath, true); } else { Pen drawPen = MakePen(); using (drawPen) { using (new Transform(graphics, r, false)) { graphics.DrawArc(drawPen, (float)(center2d.x - maxRad), (float)(center2d.y - minRad), (float)(2.0 * maxRad), (float)(2.0 * minRad), stPar, swPar); } } } } } catch (ArgumentException) { } catch (ModOpException) { } catch (OutOfMemoryException) { } } } catch { // damit es sicher durchläuft. z.B. eine Ellipse, bei der beide Achsen dieselbe Richtung haben, erzeugt eine ModOp Exception } }