/// <summary> /// Calculates the intersection points of the two curves. /// </summary> /// <param name="curve1">First curve</param> /// <param name="curve2">Second curve</param> /// <param name="par1">Resulting parameters for the first curve</param> /// <param name="par2">Resulting parameters for the second curve</param> /// <param name="intersection">Three dimensional intersection points</param> /// <returns>Number of intersection points</returns> public static int Intersect(ICurve curve1, ICurve curve2, out double[] par1, out double[] par2, out GeoPoint[] intersection) { // wenn es eine gemeinsame Ebene gibt, dann in dieser Ebene schneiden if (GetCommonPlane(curve1, curve2, out Plane pln)) { ICurve2D c2d1 = curve1.GetProjectedCurve(pln); ICurve2D c2d2 = curve2.GetProjectedCurve(pln); GeoPoint2DWithParameter[] ips = c2d1.Intersect(c2d2); // geht die Parametrierung der projizierten Kurven analog zu den Originalen? // da wir ja nur in die Ebene Projizieren, in der sich duie Kurven ohnehin befinden, müsste das stimmen // das muss aber noch getestet werden par1 = new double[ips.Length]; par2 = new double[ips.Length]; intersection = new GeoPoint[ips.Length]; for (int i = 0; i < ips.Length; ++i) { par1[i] = ips[i].par1; par2[i] = ips[i].par2; intersection[i] = pln.ToGlobal(ips[i].p); } return(ips.Length); } // eine Linie und eine nichtebene Kurve noch gesondert prüfen if (curve1.GetPlanarState() == PlanarState.Planar) { double[] ips = curve2.GetPlaneIntersection(curve1.GetPlane()); List <double> lpar1 = new List <double>(); List <double> lpar2 = new List <double>(); List <GeoPoint> lip = new List <GeoPoint>(); for (int i = 0; i < ips.Length; ++i) { GeoPoint p = curve2.PointAt(ips[i]); double ppar1 = curve1.PositionOf(p); GeoPoint p1 = curve1.PointAt(ppar1); if (Precision.IsEqual(p, p1)) { lpar1.Add(ppar1); lpar2.Add(ips[i]); lip.Add(new GeoPoint(p, p1)); } } par1 = lpar1.ToArray(); par2 = lpar2.ToArray(); intersection = lip.ToArray(); return(par1.Length); } if (curve2.GetPlanarState() == PlanarState.Planar) { return(Intersect(curve2, curve1, out par2, out par1, out intersection)); } // Fehlt noch die Abfrage nach einer Linie, denn die ist ja nicht planar // allgemeiner Fall: zwei nicht ebene Kurven TetraederHull th1 = new TetraederHull(curve1); TetraederHull th2 = new TetraederHull(curve2); return(th1.Intersect(th2, out par1, out par2, out intersection)); }
/// <summary> /// Overrides <see cref="CADability.GeoObject.ISurfaceImpl.HitTest (BoundingCube, out GeoPoint2D)"/> /// </summary> /// <param name="bc"></param> /// <param name="uv"></param> /// <returns></returns> public override bool HitTest(BoundingCube bc, out GeoPoint2D uv) { Plane p = new Plane(GeoPoint.Origin, direction); PlaneSurface ps = new PlaneSurface(p); ICurve2D c = basisCurve.GetProjectedCurve(p); GeoPoint[] points = bc.Points; GeoPoint2D[] points2D = new GeoPoint2D[8]; for (int i = 0; i < 8; ++i) { points2D[i] = ps.PositionOf(points[i]); } // does c hit the polygon? int[,] l = bc.LineNumbers; for (int k = 0; k < 12; ++k) { int i = l[k, 0]; int j = l[k, 1]; ICurve2D c2 = new Line2D(points2D[i], points2D[j]); if (c2.Length > 0) { GeoPoint2DWithParameter[] list = c.Intersect(c2); for (int m = 0; m < list.Length; ++m) { GeoPoint2D d0 = list[m].p; double d1 = (points2D[i] - d0).Length; double d2 = (points2D[j] - d0).Length; double d3 = (points2D[i] - points2D[j]).Length; if (Math.Abs(d1 + d2 - d3) < Precision.eps) { if (d3 < Precision.eps) { throw new Exception(); } GeoPoint gp = points[i] + (d1 / d3) * (points[j] - points[i]); uv = PositionOf(gp); return(true); } } } } // is c in the polygon? GeoPoint e = ps.PointAt(c.EndPoint); bool res = (bc.Interferes(e, direction, bc.Size * 1e-8, false)); if (res) { // nur berechnen, wenn auch gültig uv = PositionOf(e); } else { uv = GeoPoint2D.Origin; } return(res); }
/// <summary> /// Overrides <see cref="CADability.Curve2D.GeneralCurve2D.Intersect (ICurve2D)"/> /// </summary> /// <param name="IntersectWith"></param> /// <returns></returns> public override GeoPoint2DWithParameter[] Intersect(ICurve2D IntersectWith) { Circle2D c2d = IntersectWith as Circle2D; if (c2d != null) { GeoPoint2D[] isp = Geometry.IntersectCC(center, radius, c2d.center, c2d.radius); GeoPoint2DWithParameter[] res = new GeoPoint2DWithParameter[isp.Length]; for (int i = 0; i < isp.Length; ++i) { res[i].p = isp[i]; res[i].par1 = this.PositionOf(isp[i]); res[i].par2 = c2d.PositionOf(isp[i]); } return(res); } Line2D l2d = IntersectWith as Line2D; if (l2d != null) { GeoPoint2D[] isp = Geometry.IntersectLC(l2d.StartPoint, l2d.EndPoint, center, radius); GeoPoint2DWithParameter[] res = new GeoPoint2DWithParameter[isp.Length]; for (int i = 0; i < isp.Length; ++i) { res[i].p = isp[i]; res[i].par1 = this.PositionOf(isp[i]); res[i].par2 = l2d.PositionOf(isp[i]); } return(res); } if (IntersectWith is Ellipse2D) // git auch für Arc, ist dort jeweils implementiert { GeoPoint2DWithParameter[] res = IntersectWith.Intersect(this); for (int i = 0; i < res.Length; ++i) { // Parameter im Ergebnis vertauschen double tmp = res[i].par1; res[i].par1 = res[i].par2; res[i].par2 = tmp; } return(res); } return(base.Intersect(IntersectWith)); // der allgemeine Fall }
/// <summary> /// Returns the parameters of the intersection points of curve1 with curve2. /// Parameters are with respect to curve1. The two curves must reside in a common plane. /// </summary> /// <param name="curve1">First curve for intersection</param> /// <param name="curve2">Second curve for intersection</param> /// <param name="onlyInside">if true, only intersction point that are actually on the curves are returned /// otherwise also intersection points on the extension of ther curves are returned</param> /// <returns>Parameters for the intersection points</returns> public static double[] Intersect(ICurve curve1, ICurve curve2, bool onlyInside) { ArrayList res = new ArrayList(); if (GetCommonPlane(curve1, curve2, out Plane pl)) { ICurve2D c12d = curve1.GetProjectedCurve(pl); ICurve2D c22d = curve2.GetProjectedCurve(pl); GeoPoint2DWithParameter[] pp = c12d.Intersect(c22d); for (int i = 0; i < pp.Length; ++i) { if (!onlyInside || (c12d.IsParameterOnCurve(pp[i].par1) && c22d.IsParameterOnCurve(pp[i].par2))) { // double pos = curve1.PositionOf(pl.ToGlobal(c12d.PointAt(pp[i].par1))); // geht z.Z. davon aus, dass die Parametrierung im 2d und 3d gleich läuft, ansonsten mit obiger Zeile res.Add(pp[i].par1); } } } return((double[])(res.ToArray(typeof(double)))); }
private bool showRound() { // jetzt werden die Rundparameter bestimmt base.ActiveObject = null; base.FeedBack.ClearSelected(); if ((iCurve1 != null) && (iCurve2 != null) && (iCurve1 != iCurve2)) { Plane pl; if (Curves.GetCommonPlane(iCurve1, iCurve2, out pl)) { if (composedSplit) { if (iCurveComposedSplit != null) { owner = (iCurveComposedSplit as IGeoObject).Owner; // owner merken für löschen und Einfügen } else { owner = ownerCreated; } } else { owner = (iCurve1 as IGeoObject).Owner; // owner merken für löschen und Einfügen } // owner = (iCurve1 as IGeoObject).Owner; // owner merken für löschen und Einfügen bool rndPos = false; // Runden möglich double distCP; // Entfernung Pickpunkt - Schnittpunkte GeoPoint2D arcP1 = new GeoPoint2D(0.0, 0.0); GeoPoint2D arcP2 = new GeoPoint2D(0.0, 0.0); GeoPoint2D arcCenter = new GeoPoint2D(0.0, 0.0); ICurve2D curve1_2D = iCurve1.GetProjectedCurve(pl); // die 2D-Kurven if (curve1_2D is Path2D) { (curve1_2D as Path2D).Flatten(); } ICurve2D curve2_2D = iCurve2.GetProjectedCurve(pl); if (curve2_2D is Path2D) { (curve2_2D as Path2D).Flatten(); } // hier die Schnittpunkte bestimmen und den cutPoint auf den nächsten Schnittpunt setzen GeoPoint2DWithParameter cutPoint; rndPos = Curves2D.NearestPoint(curve1_2D.Intersect(curve2_2D), pl.Project(objectPoint), out cutPoint); if (rndPos) // runden war möglich { arcCenter = cutPoint.p; double locmin1, locmin2; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt locmin1 = 0.0; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt locmin2 = 0.0; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt double locmax1, locmax2; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt locmax1 = 1.0; locmax2 = 1.0; double locPar; // für den Fall: virtueller Schnittpunkt die Parametergrenzen anpassen locPar = curve1_2D.PositionOf(cutPoint.p); // position des Schnittpunktes auf der Kurve1 //if ( locPar > 0.5) locmax1 = locPar; //else locmin1 = locPar; if (locPar > 1.0) { locmax1 = locPar; } if (locPar < 0.0) { locmin1 = locPar; } locPar = curve2_2D.PositionOf(cutPoint.p); // position des Schnittpunktes auf der Kurve2 if (locPar > 1.0) { locmax2 = locPar; } if (locPar < 0.0) { locmin2 = locPar; } //if (locPar > 0.5) locmax2 = locPar; //else locmin2 = locPar; // Kreis synthetisieren arc.SetArcPlaneCenterRadius(pl, pl.ToGlobal(arcCenter), roundRad); ICurve2D curveArc_2D = (arc as ICurve).GetProjectedCurve(pl); // Schnittpunkte Kreisbogen mit Kurve 1 GeoPoint2DWithParameter[] cutPoints = curve1_2D.Intersect(curveArc_2D); distCP = double.MaxValue; for (int i = 0; i < cutPoints.Length; ++i) // Schleife über alle Schnittpunkte { // nur der Schnittpunkt innerhalb der Kurve if ((cutPoints[i].par1 > locmin1) & (cutPoints[i].par1 < locmax1)) { double distLoc = Geometry.Dist(cutPoints[i].p, pl.Project(objectPoint)); if (distLoc < distCP) { distCP = distLoc; arcP1 = cutPoints[i].p; // Schnittpunkt schonmal merken } //arcP1 = cutPoints[i].p; //break; } } // Schnittpunkte Kreisbogen mit Kurve 2 cutPoints = curve2_2D.Intersect(curveArc_2D); distCP = double.MaxValue; for (int i = 0; i < cutPoints.Length; ++i) // Schleife über alle Schnittpunkte { // nur der Schnittpunkt innerhalb der Kurve if ((cutPoints[i].par1 > locmin2) & (cutPoints[i].par1 < locmax2)) { double distLoc = Geometry.Dist(cutPoints[i].p, pl.Project(objectPoint)); if (distLoc < distCP) { distCP = distLoc; arcP2 = cutPoints[i].p; // Schnittpunkt schonmal merken } // arcP2 = cutPoints[i].p; // break; } } if (!Precision.IsEqual(arcP1, arcP2)) // runden war möglich { // Mittelwert zwischen dem Kurven // roundRadCalc = (Math.Abs(curve1_2D.Distance(pl.Project(radiusPoint))) + Math.Abs(curve2_2D.Distance(pl.Project(radiusPoint)))) / 2.0; // objectPoint = pl.ToGlobal(cutPoint.p); // merken für onDone, als Entscheidungskriterium arc.SetArcPlaneCenterStartEndPoint(base.ActiveDrawingPlane, arcCenter, arcP1, arcP2, pl, false); Ellipse arc1 = Ellipse.Construct(); arc1.SetArcPlaneCenterStartEndPoint(base.ActiveDrawingPlane, arcCenter, arcP1, arcP2, pl, true); if (Math.Abs(arc.SweepParameter) > Math.Abs(arc1.SweepParameter)) // es ist immer der kleinere Bogen! { arc = arc1; } arc.CopyAttributes(iCurve1 as IGeoObject); base.ActiveObject = arc; // merken base.FeedBack.AddSelected(arc); // darstellen return(true); } } } } // roundObject.HitCursor = CursorTable.GetCursor("RoundIn.cur"); return(false); }
static public CurveGraph CrackCurves(GeoObjectList l, Plane plane, double maxGap) { // alle Kurven in l werden in die Ebene plane projiziert. Das ist mal ein erster Ansatz // Man könnte auch gemeinsame Ebenen finden u.s.w. ArrayList curves = new ArrayList(); BoundingRect ext = BoundingRect.EmptyBoundingRect; foreach (IGeoObject go in l) { ICurve cv = go as ICurve; if (cv != null) { ICurve2D cv2 = cv.GetProjectedCurve(plane); if (cv2 != null) { // "3d" wird nur verwendet um hinterher aus den Originalkurven die Ebene zu bestimmen // in die alles zurücktranformiert wird. Besser würde man vermutlich mit "plane" arbeiten // so wie es hier reinkommt. if (cv2 is Path2D && (cv2 as Path2D).GetSelfIntersections().Length > 0) { // ein sich selbst überschneidender Pfad muss aufgelöst werden ICurve2D[] sub = (cv2 as Path2D).SubCurves; curves.AddRange(sub); for (int i = 0; i < sub.Length; ++i) { sub[i].UserData.Add("3d", cv); } ext.MinMax(cv2.GetExtent()); } else { cv2.UserData.Add("3d", cv); curves.Add(cv2); ext.MinMax(cv2.GetExtent()); } } } } if (curves.Count == 0) { return(null); } QuadTree qt = new QuadTree(ext); qt.MaxDeepth = 8; qt.MaxListLen = 3; for (int i = 0; i < curves.Count; ++i) { qt.AddObject(curves[i] as ICurve2D); } // jetzt alle mit allen schneiden und die Schnipsel in eine weitere Liste stecken ArrayList snippet = new ArrayList(); for (int i = 0; i < curves.Count; ++i) { ICurve2D cv1 = curves[i] as ICurve2D; ArrayList intersectionPoints = new ArrayList(); // double ICollection closecurves = qt.GetObjectsCloseTo(cv1); foreach (ICurve2D cv2 in closecurves) { if (cv2 != cv1) { //if ((cv1 is Line2D && (cv1 as Line2D).Length > 10 && (cv1 as Line2D).Length < 15) || // (cv2 is Line2D && (cv2 as Line2D).Length > 10 && (cv2 as Line2D).Length < 15)) //{ //} GeoPoint2DWithParameter[] isp = cv1.Intersect(cv2); for (int k = 0; k < isp.Length; ++k) { if (cv2.IsParameterOnCurve(isp[k].par2) && 0.0 < isp[k].par1 && isp[k].par1 < 1.0) { intersectionPoints.Add(isp[k].par1); } } } } if (intersectionPoints.Count == 0) { snippet.Add(cv1); } else { intersectionPoints.Add(0.0); intersectionPoints.Add(1.0); // damit sinds mindesten 3 double[] pps = (double[])intersectionPoints.ToArray(typeof(double)); Array.Sort(pps); for (int ii = 1; ii < pps.Length; ++ii) { if (pps[ii - 1] < pps[ii]) { ICurve2D cv3 = cv1.Trim(pps[ii - 1], pps[ii]); if (cv3 != null) { #if DEBUG GeoPoint2D dbg1 = cv1.PointAt(pps[ii - 1]); GeoPoint2D dbg2 = cv1.PointAt(pps[ii]); GeoPoint2D dbg3 = cv3.StartPoint; GeoPoint2D dbg4 = cv3.EndPoint; double d1 = dbg1 | dbg3; double d2 = dbg2 | dbg4; #endif cv3.UserData.Add("3d", cv1.UserData.GetData("3d")); snippet.Add(cv3); } } } } } // snippet ist jetzt die Liste aller Schnipsel return(new CurveGraph((ICurve2D[])snippet.ToArray(typeof(ICurve2D)), maxGap)); }
/// <summary> /// Overrides <see cref="CADability.GeoObject.ISurfaceImpl.Orientation (GeoPoint)"/> /// </summary> /// <param name="p"></param> /// <returns></returns> public override double Orientation(GeoPoint p) { // soll vermutlich feststellen ob außerhalb oder innerhalb der Fläche im Bezug auf die Achse // Richards code verwendet das aufwendige GetLineIntersection. // Hier die bessere Version, die das Problem ins zweidimensionale projiziert: GeoPoint up = fromSurface * p; double x = Math.Sqrt(up.z * up.z + up.x * up.x); double y = up.y; GeoPoint2D toCeck = new GeoPoint2D(x, y); BoundingRect ext = basisCurve2D.GetExtent(); GeoPoint2D sp, ep; if (ext.Left > 0) { sp = new GeoPoint2D(ext.Left, y); ep = new GeoPoint2D(ext.Right, y); } else { sp = new GeoPoint2D(ext.Right, y); ep = new GeoPoint2D(ext.Left, y); } GeoPoint2DWithParameter[] isp = basisCurve2D.Intersect(sp, ep); // muss die Kurve immer rechts von der Achse liegen? Durch sp und ep sid wir davon unabhängig, es sei denn die Kurve schneidet die Achse SortedList <double, GeoPoint2D> par = new SortedList <double, GeoPoint2D>(); for (int i = 0; i < isp.Length; ++i) { if (isp[i].par2 >= 0.0 && isp[i].par2 <= 1.0 && isp[i].par1 >= 0.0 && isp[i].par1 <= 1.0) { // nur wenn echter Schnitt par[isp[i].par2] = isp[i].p; // nach Position auf der horizontalen Linie } } if (par.Count == 0) { return(0.0); // Seite kann nicht bestimmt werden, da völlig außerhalb. Das Vorzeichen von 0.0 } // ist aber verschieden von +1 und von -1, so dass wenn es andere konkrete Punkte gibt also ein Test gemacht wird double ppar = Geometry.LinePar(sp, ep, toCeck); for (int i = 0; i < par.Count; ++i) { if (ppar < par.Keys[i]) { if ((i & 1) == 0) // gerade, also innerhalb { return(-(toCeck | par.Values[i])); // innerhalb ist negativ } else { return(toCeck | par.Values[i]); // außerhalb positiv } } } // größer als alle if ((par.Count & 1) == 1) // ungerade, also letzer Punkt innerhalb { return(toCeck | par.Values[par.Count - 1]); // außerhalb positiv } else { return(-(toCeck | par.Values[par.Count - 1])); // innerhalb ist negativ } // Richards code: //GeoPoint gp = fromSurface * p; //double d = gp.y; //double e = Math.Abs(d); //GeoPoint ac = new GeoPoint(0, d, 0); //GeoPoint2D[] sp = GetLineIntersection(p, toSurface * (ac - gp)); //int n = 0; //for (int i = 0; i < sp.Length; ++i) //{ // double ds = (sp[i] - GeoPoint2D.Origin).Length - e; // if (Math.Abs(ds) > Precision.eps) // { // if (ds < 0) // n++; // } // else return 0; //} //if (n % 4 == 2) // return (-e); //else // return e; }
private bool showCutOff() { // nur wenn beide Kurven gültig sind if ((iCurve1 != null) && (iCurve2 != null) && (iCurve1 != iCurve2)) { Plane pl; // nur bei gemeisamer Ebene if (Curves.GetCommonPlane(iCurve1, iCurve2, out pl)) { // !!! // owner = (iCurve1 as IGeoObject).Owner; // owner merken für löschen und Einfügen pl.Align(base.ActiveDrawingPlane, false); // Winkel anpassen ICurve2D curve1_2D = iCurve1.GetProjectedCurve(pl); // die 2D-Kurven if (curve1_2D is Path2D) { (curve1_2D as Path2D).Flatten(); } ICurve2D curve2_2D = iCurve2.GetProjectedCurve(pl); if (curve2_2D is Path2D) { (curve2_2D as Path2D).Flatten(); } ICurve newCurve = iCurve1.Clone(); // neue Kurve bis zum Schnittpunkt // hier die Schnittpunkte bestimmen und den cutPoint auf den nächsten Schnittpunt setzen GeoPoint2DWithParameter cutPoint; if (Curves2D.NearestPoint(curve1_2D.Intersect(curve2_2D), pl.Project(objectPoint), out cutPoint)) // runden war möglich { GeoVector2D v1 = curve1_2D.DirectionAt(cutPoint.par1); // die Richtung im Schnittpunkt if (cutPoint.par1 > 0.5) { v1 = v1.Opposite(); // evtl rumdrehen, falls am Ende } v1.Norm(); GeoVector2D v2 = curve2_2D.DirectionAt(cutPoint.par2); // die Richtung im Schnittpunkt if (cutPoint.par2 > 0.5) { v2 = v2.Opposite(); // evtl rumdrehen, falls am Ende } v2.Norm(); GeoVector2D v = (v1 + v2); // Winkelhalbierende if (Precision.IsNullVector(pl.ToGlobal(v))) { return(false); } v.Norm(); v = cutOffLen * v; // Winkelhalbierende mit Fas-Abstand GeoPoint2D dirPoint = cutPoint.p + v; // wird unten auch als Auswahlpunkt für die Richtung genutzt Line2D line2D = new Line2D(dirPoint, cutPoint.p); // Linie vorbesetzen, Punkte eigentlich egal if ((methodSelect == 0) || (methodSelect == 1)) { // 0: Länge cutOffLen = Seitenlänge Kurve1 1: Länge cutOffLen = Fasenlänge double sideLength; if (methodSelect == 1) // Länge cutOffLen = Fasenlänge // Geometrie, Pythagoras, bekannt Seite=cutOffLen, Winkel 1 = cutOffAng, Winkel 2 = Winkel der Kurven im Schnittpunkt { sideLength = cutOffLen * (Math.Cos(cutOffAng.Radian) + (Math.Sin(cutOffAng.Radian) / Math.Tan(Math.Abs(new SweepAngle(v1, v2).Radian)))); } else { sideLength = cutOffLen; } // neue Kurve bis zum Schnittpunkt synthetisieren, dazu: Schnittpunkt finden des Abschnitts mit der iCurve1 Ellipse arcTmp = Ellipse.Construct(); arcTmp.SetCirclePlaneCenterRadius(pl, pl.ToGlobal(cutPoint.p), sideLength); ICurve2D curveArc_2D = (arcTmp as ICurve).GetProjectedCurve(pl); // die 2D-Kurve GeoPoint2DWithParameter cutArc; GeoPoint2D startPoint; if (Curves2D.NearestPoint(curve1_2D.Intersect(curveArc_2D), dirPoint, out cutArc)) // war möglich { startPoint = cutArc.p; } else { return(false); } /* * double parCut; * // neue Kurve bis zum Schnittpunkt sythetisieren: * if (cutPoint.par1 <= 0.5) * { * newCurve.StartPoint = iCurve1.PointAt(cutPoint.par1); * parCut = (sideLength)/newCurve.Length; // der Parameter des Fasenpunktes * } * else * { * newCurve.EndPoint = iCurve1.PointAt(cutPoint.par1); * parCut = (newCurve.Length-sideLength)/newCurve.Length; // der Parameter des Fasenpunktes * } * GeoPoint2D startPoint = pl.Project(newCurve.PointAt(parCut)); * GeoVector2D vc = curve1_2D.DirectionAt(parCut); // die Richtung im Schnittpunkt */ GeoVector2D vc = curve1_2D.DirectionAt(curve1_2D.PositionOf(startPoint)); // die Richtung im Schnittpunkt if (cutPoint.par1 <= 0.5) { vc = vc.Opposite(); // evtl rumdrehen, falls am Ende } if (Geometry.OnLeftSide(dirPoint, startPoint, vc)) // Richtung festlegen für Winkeloffset { vc.Angle = vc.Angle + new SweepAngle(cutOffAng); } else { vc.Angle = vc.Angle - new SweepAngle(cutOffAng); } // Hilfslinie im Fasabstand, im Offsetwinkel line2D = new Line2D(startPoint, startPoint + vc); } if (methodSelect == 2) // Länge cutOffLen = Winkelhalbierendenlänge { v.Angle = v.Angle + new SweepAngle(cutOffAng); // Winkelhalbierendenwinkel + Offset // Hilfslinie im Fasabstand, senkrecht auf der Winkelhalbierenden v line2D = new Line2D(dirPoint, dirPoint + v.ToLeft()); } GeoPoint2DWithParameter cutPoint1; GeoPoint2DWithParameter cutPoint2; // schnittpunkte der Hilfslinie mit den beiden Kurven if (Curves2D.NearestPoint(curve1_2D.Intersect(line2D as ICurve2D), cutPoint.p + v, out cutPoint1)) { if (Curves2D.NearestPoint(curve2_2D.Intersect(line2D as ICurve2D), cutPoint.p + v, out cutPoint2)) { // da isse, die Fas-Linie, nur, wenn die Punkte echt auf der Kurve bis zum Schnittpunkt liegen: bool onCurve1, onCurve2; if (cutPoint.par1 > 0.5) { onCurve1 = (cutPoint1.par1 > 0.0) & (cutPoint1.par1 < 100); } // im Quasi-Parallelfall stehen in par1 riesige Werte else { onCurve1 = (cutPoint1.par1 < 1.0) & (cutPoint1.par1 > -100); } if (cutPoint.par2 > 0.5) { onCurve2 = (cutPoint2.par1 > 0.0) & (cutPoint2.par1 < 100); } else { onCurve2 = (cutPoint2.par1 < 1.0) & (cutPoint2.par1 > -100); } if (onCurve1 && onCurve2) { Line line = Line.Construct(); line.SetTwoPoints(pl.ToGlobal(cutPoint1.p), pl.ToGlobal(cutPoint2.p)); // Fasenlänge vorgegeben, aber mit obiger Berechnung falsch, da dort Linien vorausgesetzt werden if ((methodSelect == 1) && (Math.Abs(line.Length - cutOffLen) > Precision.eps)) { // jetzt mit Iteration annähern double parInd = 0.5; double parIndDelta = 0.25; for (int i = 0; i < 49; ++i) // 48 Schritte müssen reichen, par kann zwischen 0 und 1 liegen { GeoPoint2D startPoint = pl.Project(newCurve.PointAt(parInd)); GeoVector2D vc = curve1_2D.DirectionAt(parInd); // die Richtung im Schnittpunkt if (cutPoint.par1 <= 0.5) { vc = vc.Opposite(); // evtl rumdrehen, falls am Ende } if (Geometry.OnLeftSide(dirPoint, startPoint, vc)) // Richtung festlegen für Winkeloffset { vc.Angle = vc.Angle + new SweepAngle(cutOffAng); } else { vc.Angle = vc.Angle - new SweepAngle(cutOffAng); } // Hilfslinie im Fasabstand, im Offsetwinkel line2D = new Line2D(startPoint, startPoint + vc); if (Curves2D.NearestPoint(curve1_2D.Intersect(line2D as ICurve2D), cutPoint.p + v, out cutPoint1)) { if (Curves2D.NearestPoint(curve2_2D.Intersect(line2D as ICurve2D), cutPoint.p + v, out cutPoint2)) { // da isse, die Fas-Linie, nur, wenn die Punkte echt auf der Kurvr liegen: if (cutPoint.par1 > 0.5) { onCurve1 = (cutPoint1.par1 > 0.0) & (cutPoint1.par1 < 100); } // im Quasi-Parallelfall stehen in par1 riesige Werte else { onCurve1 = (cutPoint1.par1 < 1.0) & (cutPoint1.par1 > -100); } if (cutPoint.par2 > 0.5) { onCurve2 = (cutPoint2.par1 > 0.0) & (cutPoint2.par1 < 100); } else { onCurve2 = (cutPoint2.par1 < 1.0) & (cutPoint2.par1 > -100); } if (onCurve1 && onCurve2) { line.SetTwoPoints(pl.ToGlobal(cutPoint1.p), pl.ToGlobal(cutPoint2.p)); if ((Math.Abs(line.Length - cutOffLen) < Precision.eps)) // gefunden und raus { break; } else { if (line.Length < cutOffLen) { // Fase ist zu klein: Parameter parInd vergrößern parInd = parInd + parIndDelta; parIndDelta = parIndDelta / 2.0; // delta halbieren (Bisection!!) continue; // nächster Schritt in der For-Schleife } } } } } // alle anderen Fälle: // Fase ist zu gross: Parameter parInd verkleinern parInd = parInd - parIndDelta; parIndDelta = parIndDelta / 2.0; // delta halbieren (Bisection!!) } // for schleife Iteration } // Ende Iteration objectPoint = pl.ToGlobal(cutPoint.p); if (iCurve1.PositionOf(objectPoint) > 0.5) // am oberen Ende geklickt { iCurve1.Trim(0.0, iCurve1.PositionOf(line.StartPoint)); } else { iCurve1.Trim(iCurve1.PositionOf(line.StartPoint), 1.0); } if (iCurve2.PositionOf(objectPoint) > 0.5) // am oberen Ende geklickt { iCurve2.Trim(0.0, iCurve2.PositionOf(line.EndPoint)); objectPoint = iCurve2.StartPoint; } else { iCurve2.Trim(iCurve2.PositionOf(line.EndPoint), 1.0); objectPoint = iCurve2.EndPoint; } (line as IGeoObject).CopyAttributes(iCurve1 as IGeoObject); // objectPoint = pl.ToGlobal(cutPoint2.p); blk.Add(iCurve1 as IGeoObject); blk.Add(line); // base.FeedBack.AddSelected(iCurve1 as IGeoObject);// darstellen // base.FeedBack.AddSelected(line);// darstellen iCurve1 = iCurve2; // getrimmte Curve2 als Grundlage zur nächsten Berechnung return(true); } } } } } blk.Add(iCurve1 as IGeoObject); // unveränderte 1. Kurve zufügen, da kein Fasen möglich // base.FeedBack.AddSelected(iCurve1 as IGeoObject);// darstellen iCurve1 = iCurve2; // unveränderte Curve2 als Grundlage zur nächsten Berechnung } // base.ActiveObject = null; return(false); }
private bool showObject() { base.FeedBack.ClearSelected(); base.ActiveObject = null; double[] cutPlace; ICurve2D c2d = iCurve.GetProjectedCurve(CurrentMouseView.Projection.ProjectionPlane); GeoPoint2D op2d = CurrentMouseView.Projection.ProjectUnscaled(objectPoint); lowerEnd = (c2d.PositionOf(op2d) < 0.5); // im 2D überprüfen, in 3D ist objectPoint möglicherweise weit von iCurve entfernt // bool lowerEnd = (iCurve.PositionOf(objectPoint)< 0.5); ProjectedModel.IntersectionMode cutMode; bool realCut; if (lowerEnd) { cutMode = ProjectedModel.IntersectionMode.StartExtension; } else { cutMode = ProjectedModel.IntersectionMode.EndExtension; } // if (expandSourceObject.Fixed) ICurve[] targetCurves = null; if (sourceCurve != null) { cutPlace = Curves.Intersect(iCurve, sourceCurve, false); } else { cutPlace = base.Frame.ActiveView.ProjectedModel.GetIntersectionParameters(iCurve, cutMode, out targetCurves); } if (cutPlace.Length > 0) { realCut = false; for (int i = 0; i < cutPlace.Length; ++i) { if (distToCurve.Length == 0) { if (cutPlace[i] < -1e-8 || cutPlace[i] > 1 + 1e-8) // Endpunkte nicht mit berücksichtigen //if (!((Math.Abs(cutPlace[i]) < 1e-8) || (Math.Abs(cutPlace[i] - 1) < 1e-8))) { realCut = true; break; } } else { //if (cutPlace[i] < 1e-8 || cutPlace[i] > 1 - 1e-8) // Endpunkte mit berücksichtigen { realCut = true; break; } } } if (realCut) { int k = -1; if (lowerEnd) { param = double.MinValue; } else { param = double.MaxValue; } double eps; // wenn distToCurve gesetzt ist, dann bleibt ein exakt getrimmtes am Ende gültig, ansonsten wird die nächste Querkurve verwendet if (distToCurve.Length == 0) { eps = 1e-8; } else { if (sourceCurve != null && sourceCurve.Length > 0) // eine Zielkurve wurde angewählt. Schnitte dürfen jetzt vor dem Ende von iCurve sein //eps = -Math.Abs(distToCurve.Length) / sourceCurve.Length; { eps = -1.0; // egal, Hauptsache auf der Kurve } else { eps = -1e-8; } } for (int i = 0; i < cutPlace.Length; ++i) { if (lowerEnd) { // verlängern nach hinten, der größte Wert, der kleiner Null und ungleich quasi Null if ((cutPlace[i] > param) && (cutPlace[i] < 0.0 - eps)) { param = cutPlace[i]; k = i; } } else { // verlängern nach vorne, der kleinste Wert, der größer 1.0 und ungleich quasi 1.0 if ((cutPlace[i] < param) && (cutPlace[i] > 1.0 + eps)) { param = cutPlace[i]; k = i; } } } if (k >= 0) // was gefunden { newCurve = iCurve.Clone(); if (distToCurve.Length != 0.0) { // zusätzlich länger oder kürzer machen ICurve targetCurve = sourceCurve; if (targetCurves != null) { targetCurve = targetCurves[k]; } Plane pl; if (Curves.GetCommonPlane(iCurve, targetCurve, out pl)) { // muss der Fall sein ICurve2D targetCurve2d = targetCurve.GetProjectedCurve(pl); ICurve2D parl1 = targetCurve2d.Parallel(-distToCurve.Length, true, Precision.eps, 0.0); ICurve2D parl2 = targetCurve2d.Parallel(distToCurve.Length, true, Precision.eps, 0.0); ICurve2D newCurve2d = newCurve.GetProjectedCurve(pl); // im 2d verlängern if (lowerEnd) { newCurve2d.StartPoint = newCurve2d.PointAt(param); } else { newCurve2d.EndPoint = newCurve2d.PointAt(param); } if (lowerEnd) { // jetzt nur den Vorwärtsfall betrachten newCurve2d.Reverse(); } // betrachte beide Parallelen, wir kennen die Richtungen nicht GeoPoint2DWithParameter[] gp1 = newCurve2d.Intersect(parl1); GeoPoint2DWithParameter[] gp2 = newCurve2d.Intersect(parl2); double bestPar; if (distToCurve.Length > 0) { // Kurve muss kürzer werden bestPar = 0.0; for (int i = 0; i < gp1.Length; i++) { if (gp1[i].par2 >= 0 && gp1[i].par2 <= 1 && gp1[i].par1 <1 && gp1[i].par1> bestPar) { bestPar = gp1[i].par1; } } for (int i = 0; i < gp2.Length; i++) { if (gp2[i].par2 >= 0 && gp2[i].par2 <= 1 && gp2[i].par1 <1 && gp2[i].par1> bestPar) { bestPar = gp2[i].par1; } } } else { bestPar = double.MaxValue; for (int i = 0; i < gp1.Length; i++) { if (gp1[i].par2 >= 0 && gp1[i].par2 <= 1 && gp1[i].par1 > 1 && gp1[i].par1 < bestPar) { bestPar = gp1[i].par1; } } for (int i = 0; i < gp2.Length; i++) { if (gp2[i].par2 >= 0 && gp2[i].par2 <= 1 && gp2[i].par1 > 1 && gp2[i].par1 < bestPar) { bestPar = gp2[i].par1; } } } // den gefundenen Punkt auf die Kurve setzen if (bestPar > 0 && bestPar < double.MaxValue) { GeoPoint pp = pl.ToGlobal(newCurve2d.PointAt(bestPar)); param = iCurve.PositionOf(pp); // param ist das eigentliche Ergebnis, welches bei onDone verwendet wird if (lowerEnd) { newCurve.StartPoint = pp; } else { newCurve.EndPoint = pp; } } } } else { if (lowerEnd) { newCurve.StartPoint = iCurve.PointAt(param); } else { newCurve.EndPoint = iCurve.PointAt(param); } } (newCurve as IGeoObject).CopyAttributes(iCurve as IGeoObject); //Color backColor = base.Frame.GetColorSetting("Colors.Feedback", Color.DarkGray); //if (newCurve is IColorDef) // (newCurve as IColorDef).ColorDef = new ColorDef("", backColor); base.ActiveObject = (newCurve as IGeoObject); base.FeedBack.AddSelected(newCurve as IGeoObject);// letzte Linie einfügen return(true); } } } param = 0.0; return(false); }
private bool showRound() { // jetzt werden die Rundparameter bestimmt Plane pl; try { if (Curves.GetCommonPlane(iCurve1, iCurve2, out pl)) { bool rndPos = false; // Runden möglich GeoPoint2D arcP1 = new GeoPoint2D(0.0, 0.0); GeoPoint2D arcP2 = new GeoPoint2D(0.0, 0.0); GeoPoint2D arcP1Loc = new GeoPoint2D(0.0, 0.0); GeoPoint2D arcP2Loc = new GeoPoint2D(0.0, 0.0); GeoPoint2D arcCenter = new GeoPoint2D(0.0, 0.0); ICurve2D curve1_2D = iCurve1.GetProjectedCurve(pl); // die 2D-Kurven if (curve1_2D is Path2D) { (curve1_2D as Path2D).Flatten(); } ICurve2D curve2_2D = iCurve2.GetProjectedCurve(pl); if (curve2_2D is Path2D) { (curve2_2D as Path2D).Flatten(); } // ist beim menrfachrunden nicht nötig!! // hier die Schnittpunkte bestimmen und den ObjectPoint auf den nächsten Schnittpunt setzen // GeoPoint2DWithParameter[] intersectPoints = curve1_2D.Intersect(curve2_2D); // GeoPoint2D objectPoint2D = new GeoPoint2D(0.0,0.0); // double distS = double.MaxValue; // Entfernung des Pickpunkts zu den Schnittpunkten // for (int i=0; i< intersectPoints.Length; ++i) // macht hier wenig Sinn, schadet aber auch nicht // { // macht hier wenig Sinn, schadet aber auch nicht, Kompatibilität zum einfachrunden // double distLoc = Geometry.dist(intersectPoints[i].p,pl.Project(objectPoint)); // if (distLoc < distS) // { // distS = distLoc; // objectPoint2D = intersectPoints[i].p; // Pickpunkt merken // } // } // statt der Berechnung oben: Auswahlpunkt ist der gemeinsame Punkt der beiden Kurven!! GeoPoint2D objectPoint2D = curve1_2D.EndPoint; double locmin1, locmin2; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt locmin1 = 0.0; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt locmin2 = 0.0; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt double locmax1, locmax2; // Parametergrenzen vorbesetzen für den Fall: Realer Schnittpunkt locmax1 = 1.0; locmax2 = 1.0; // bei mehfachrunden nicht nötig, da alle aneinanderhängen, also nur reale Schnittpunkte! // double locPar; // für den Fall: virtueller Schnittpunkt die Parametergrenzen anpassen // locPar = curve1_2D.PositionOf(objectPoint2D); // position des Schnittpunktes auf der Kurve1 // if ( locPar > 1.0) locmax1 = locPar; // if ( locPar < 0.0) locmin1 = locPar; // locPar = curve2_2D.PositionOf(objectPoint2D); // position des Schnittpunktes auf der Kurve2 // if ( locPar > 1.0) locmax2 = locPar; // if ( locPar < 0.0) locmin2 = locPar; // die Parallelen links und rechts der 2 Kurven ICurve2D P1L1 = curve1_2D.Parallel(roundRad, false, 0.0, 0.0); ICurve2D P1L2 = curve1_2D.Parallel(-roundRad, false, 0.0, 0.0); ICurve2D P2L1 = curve2_2D.Parallel(roundRad, false, 0.0, 0.0); ICurve2D P2L2 = curve2_2D.Parallel(-roundRad, false, 0.0, 0.0); // nun alle mit allen schneiden und Schnittpunkte (=evtl. Mittelpunkte des Bogens) merken ArrayList centers = new ArrayList(); centers.AddRange(P1L1.Intersect(P2L1)); centers.AddRange(P1L1.Intersect(P2L2)); centers.AddRange(P1L2.Intersect(P2L1)); centers.AddRange(P1L2.Intersect(P2L2)); GeoPoint2DWithParameter[] centerPoints = (GeoPoint2DWithParameter[])centers.ToArray(typeof(GeoPoint2DWithParameter)); GeoPoint2D[] perpP; // Lotfusspunkte double loc; // location des schnittpunktes der parallelen auf der Kurve double distCP; // Entfernung von der Ecke für Fusspunkte double distCS = double.MaxValue; // Entfernung von der Ecke für Schnittpunkte bool ok1, ok2; // der gesuchte Schnittpunkt hat einen realen Lotfusspunkt auf beiden Kurven und den Abstand roundRad von diesen for (int i = 0; i < centerPoints.Length; ++i) // Schleife über alle Schnittpunkte { ok1 = false; ok2 = false; perpP = curve1_2D.PerpendicularFoot(centerPoints[i].p); // Lotpunkt(e) Kurve 1 distCP = double.MaxValue; for (int j = 0; j < perpP.Length; ++j) // Schleife über alle Lotpunkte Kurve 1 { loc = curve1_2D.PositionOf(perpP[j]); // der Parameter des j. Lotpunktes auf Kurve1 // der Parameter muss innerhalb der Kurve sein und der Abstand = roundRad if ((loc >= locmin1) & (loc <= locmax1) & (Math.Abs(Geometry.Dist(perpP[j], centerPoints[i].p) - roundRad) < Precision.eps)) { double distLoc = Geometry.Dist(perpP[j], objectPoint2D); if (distLoc < distCP) { distCP = distLoc; arcP1Loc = perpP[j]; // Lotpunkt schonmal merken } ok1 = true; } } if (ok1) // also was gefunden oben, jetzt dasselbe mit Kurve 2 { perpP = curve2_2D.PerpendicularFoot(centerPoints[i].p); // Lotpunkt(e) Kurve 2 distCP = double.MaxValue; for (int j = 0; j < perpP.Length; ++j) // Schleife über alle Lotpunkte Kurve 2 { loc = curve2_2D.PositionOf(perpP[j]); // der Parameter des j. Lotpunktes auf Kurve2 // der Parameter muss innerhalb der Kurve sein und der Abstand = roundRad if ((loc >= locmin2) & (loc <= locmax2) & (Math.Abs(Geometry.Dist(perpP[j], centerPoints[i].p) - roundRad) < Precision.eps)) { double distLoc = Geometry.Dist(perpP[j], objectPoint2D); if (distLoc < distCP) { distCP = distLoc; arcP2Loc = perpP[j]; // Lotpunkt schonmal merken } ok2 = true; } } } if (ok2) { // falls mehrere Schnittpunkte alle Bedingungen erfüllen: Den nächsten nehmen! double distLoc = Geometry.Dist(centerPoints[i].p, objectPoint2D); if (distLoc < distCS) { distCS = distLoc; // jetzt merken arcCenter = centerPoints[i].p; arcP1 = arcP1Loc; arcP2 = arcP2Loc; rndPos = true; } } } if (rndPos && !Precision.IsEqual(arcP1, arcP2)) // runden war möglich { // Mittelwert zwischen dem Kurven // roundRadCalc = (Math.Abs(curve1_2D.Distance(pl.Project(radiusPoint))) + Math.Abs(curve2_2D.Distance(pl.Project(radiusPoint)))) / 2.0; objectPoint = pl.ToGlobal(objectPoint2D); // merken als Entscheidungskriterium, ist hier immer der Schnittpunkt Ellipse arc = Ellipse.Construct(); Ellipse arc1 = Ellipse.Construct(); arc.SetArcPlaneCenterStartEndPoint(base.ActiveDrawingPlane, arcCenter, arcP1, arcP2, pl, false); arc1.SetArcPlaneCenterStartEndPoint(base.ActiveDrawingPlane, arcCenter, arcP1, arcP2, pl, true); if (Math.Abs(arc.SweepParameter) > Math.Abs(arc1.SweepParameter)) // es ist immer der kleinere Bogen! { arc = arc1; } arc.CopyAttributes(iCurve1 as IGeoObject); if (iCurve1.PositionOf(objectPoint) > 0.5) { iCurve1.Trim(0.0, iCurve1.PositionOf(arc.StartPoint)); } else { iCurve1.Trim(iCurve1.PositionOf(arc.StartPoint), 1.0); } if (iCurve2.PositionOf(objectPoint) > 0.5) { iCurve2.Trim(0.0, iCurve2.PositionOf(arc.EndPoint)); } else { iCurve2.Trim(iCurve2.PositionOf(arc.EndPoint), 1.0); } if (iCurve1.Length > Precision.eps) { blk.Add(iCurve1 as IGeoObject); // base.FeedBack.AddSelected(iCurve1 as IGeoObject); // darstellen } blk.Add(arc); // base.FeedBack.AddSelected(arc); // darstellen iCurve1 = iCurve2; // getrimmte Curve2 als Grundlage zur nächsten Berechnung return(true); } } } catch (ApplicationException e) { return(false); } blk.Add(iCurve1 as IGeoObject); // unveränderte 1. Kurve zufügen, da kein Runden möglich // base.FeedBack.AddSelected(iCurve1 as IGeoObject); // darstellen iCurve1 = iCurve2; // unveränderte Curve2 als Grundlage zur nächsten Berechnung return(false); }