Centerpoint Arc Ellipse berechnen



  • Guten Tag Leute, ich mal wieder:)

    Und zwar folgendes, ich zeichne in WPF (C#) shapes mit Hilfe von ArcSegments.

    Diese "arc's" (Bogen) werden definiert mit einem Start-Punkt, Endpunkt, Sweepdirection, Size (R1/R2).

    Nun möchte ich den Center-Point bzw. den Middel-Point des Bogens der gezeichneten kurven berechnen. (für Overlay Geschichten)

    Ich habe Google durchstöbert, aber irgendwie finde ich nichts zuführendes außer ein Haufen an Formeln , und ich sehe den Wald vor lauten bäumen nicht mehr 😞

    Dann habe ich mir den Source-Code des C# ArcSegment angeschaut. um mir da die Berechnung einzusehen und das herzuleiten.. aber leider wird da intern eine native funktion+

    [SecurityCritical]
            [SuppressUnmanagedCodeSecurity]
            [DllImport(DllImport.MilCore)]
            internal unsafe static extern void MilUtility_ArcToBezier(
                Point ptStart,              // The arc's start point
                Size rRadii,                // The ellipse's X and Y radii
                double rRotation,           // Rotation angle of the ellipse's x axis
                bool fLargeArc,             // Choose the larger of the 2 arcs if TRUE
                SweepDirection fSweepUp,    // Sweep the arc increasing the angle if TRUE
                Point ptEnd,                // The arc's end point
                MilMatrix3x2D* pMatrix,    // Transformation matrix
                Point* pPt,                 // An array receiving the Bezier points
                out int cPieces);           // The number of output Bezier curves
    

    verwendet, welche mir auch nicht hilft!?

    Um es kurz zu machen, kann mir jemand behilflich sein , um eine "kurze" Herleitung zur Berechnung der Punkt anhand der oben genannten Parametern sein zugeben? 🙂

    Wäre super toll für tipps;)



  • Schau mal in How to find center of an arc given start point, end point, radius, and arc direction? - dort ist auch C# Code dafür enthalten.



  • @Th69 sagte in Centerpoint Arc Ellipse berechnen:

    Schau mal in How to find center of an arc given start point, end point, radius, and arc direction? - dort ist auch C# Code dafür enthalten.

    Guten Morgen, vielen dank für deine Hilfe. Dieses Beispiel kenne ich, aber da geht es um einen Bogen eines Kreisen, und nicht Ellipse, da habe ich nur einen Radius

    Hat noch jemand nen Vorschlag;)



  • @Th69 : du hast mir aber den Anstoß andere Suchbegriffe zu verwenden, und PAAAM

    [https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/](Link Adresse)

    da gibt source code den ich noch in c# protieren musste:

    class ArcHelper
      {
          /**
      Perform the endpoint to center arc parameter conversion as detailed in the SVG 1.1 spec.
      F.6.5 Conversion from endpoint to center parameterization
    
      @param r must be a ref in case it needs to be scaled up, as per the SVG spec
    */
          public static void EndpointToCenterArcParams(Point p1, Point p2, ref Point r_, float xAngle,
              bool flagA, bool flagS, out Point c, out Point angles)
          {
              double rX = Math.Abs(r_.X);
              double rY = Math.Abs(r_.Y);
    
              //(F.6.5.1)
              double dx2 = (p1.X - p2.X) / 2.0;
              double dy2 = (p1.Y - p2.Y) / 2.0;
              double x1p = Math.Cos(xAngle) * dx2 + Math.Sin(xAngle) * dy2;
              double y1p = -Math.Sin(xAngle) * dx2 + Math.Cos(xAngle) * dy2;
    
              //(F.6.5.2)
              double rxs = rX * rX;
              double rys = rY * rY;
              double x1ps = x1p * x1p;
              double y1ps = y1p * y1p;
              // check if the radius is too small `pq < 0`, when `dq > rxs * rys` (see below)
              // cr is the ratio (dq : rxs * rys) 
              double cr = x1ps / rxs + y1ps / rys;
              if (cr > 1)
              {
                  //scale up rX,rY equally so cr == 1
                  var s = Math.Sqrt(cr);
                  rX = s * rX;
                  rY = s * rY;
                  rxs = rX * rX;
                  rys = rY * rY;
              }
              double dq = (rxs * y1ps + rys * x1ps);
              double pq = (rxs * rys - dq) / dq;
              double q = Math.Sqrt(Math.Max(0, pq)); //use Max to account for float precision
              if (flagA == flagS)
                  q = -q;
              double cxp = q * rX * y1p / rY;
              double cyp = -q * rY * x1p / rX;
    
              //(F.6.5.3)
              double cx = Math.Cos(xAngle) * cxp - Math.Sin(xAngle) * cyp + (p1.X + p2.X) / 2;
              double cy = Math.Sin(xAngle) * cxp + Math.Cos(xAngle) * cyp + (p1.Y + p2.Y) / 2;
    
              //(F.6.5.5)
              double theta = svgAngle(1, 0, (x1p - cxp) / rX, (y1p - cyp) / rY);
              //(F.6.5.6)
              double delta = svgAngle(
                  (x1p - cxp) / rX, (y1p - cyp) / rY,
                  (-x1p - cxp) / rX, (-y1p - cyp) / rY);
              //delta = Math.Mod(delta, Math.PI * 2);
              delta = delta % (Math.PI * 2);
              if (!flagS)
                  delta -= 2 * Math.PI;
    
              r_ =new  Point((float)rX, (float)rY);
              c = new Point((float)cx, (float)cy);
              angles = new Point((float)theta, (float)delta);
          }
    
          public static T Clamp<T>(T val, T min, T max) where T : IComparable<T>
          {
              if (val.CompareTo(min) < 0) return min;
              else if (val.CompareTo(max) > 0) return max;
              else return val;
          }
    
          static double svgAngle(double ux, double uy, double vx, double vy)
          {
              var u = new Vector((float)ux, (float)uy);
              var v = new Vector((float)vx, (float)vy);
              //(F.6.5.4)
    
              var dot = u * v;
              //var dot = Vector.Dot(u, v);
    
             
              var len = u.Length * v.Length;
              // var len = Vector.Length(u) * Vector.Length(v);
    
              var ang = Math.Acos(Clamp(dot / len, -1, 1)); //floating point precision, slightly over values appear
              if ((u.X * v.Y - u.Y * v.X) < 0)
                  ang = -ang;
              return ang;
          }
      }
    

    klappt einwandfrei;)


Anmelden zum Antworten