Board index » cppbuilder » Computing Center point of arc given only start point, end point , sweep angle direction draw

Computing Center point of arc given only start point, end point , sweep angle direction draw

Hello,

I am trying to compute the x,y coordinates for the center point of an arc
given only the following informatio:
- Starting x,y of arc
- Ending x,y of arc
- direction of drawing from start to end, either clockwise or counter
clockwise
- The sweep angle of the arc from center point to the two end points of the
arc.

I can't seem to get the center location computed properly.

I have tried the following code: but it doesn't work correctly.

What am I doing wrong?

Thanks,

James

  //TODO: Add your source code here
  //There are some things to do before we can actually draw the polyarc.
  // 1. Get midpoint of chord which joints the two end points.
  // 2. Compute chord length.
  // 3. Compute radius.
  // 4. Compute Chord of arc arc perendicular to y axis.
  // 5. Compute sweep angle bisect to arcchord midpoint length.
  // 6. Use midpoint location and step 5 length of line to compute
  //    x,y of ChordAngle+90.  This should give use one centerpoint
location.
  //    Second should be ChordAngle-90.
  double SweepAngle = v1->PArgSweep;
  double HalfSweepAngle = DegToRad(RadToDeg(SweepAngle)/2.0);
  double ChordLength,HalfChordLength,ChordIntersect;
  double Deltax,Deltay;
  double Radius;
  double StartAngle,EndAngle,theta;
  TReal2DPoint MidPoint,tv1,tv2,iv,iz;
  Deltax = v2->Vertex.x-v1->Vertex.x;
  Deltay = v2->Vertex.y-v1->Vertex.y;
  MidPoint.x = v1->Vertex.x + (Deltax/2.0);
  MidPoint.y = v1->Vertex.y + (Deltay/2.0);

  ChordLength = sqrt((Deltax*Deltax)+(Deltay*Deltay));
  HalfChordLength=ChordLength/2.0;
  //Ok the radius is now computed as follows R= HalfChordLength/sin(sweep/2)
  Radius = HalfChordLength/sin(HalfSweepAngle);//asin
  Radius = fabs(Radius);
  ChordIntersect =
sqrt(fabs((HalfChordLength*HalfChordLength)-(Radius*Radius)));

  //Things to do now.
  // 1. Translate chord line to orgin.  Translate by start point.
  // 2. Compute angle of line.
  iv = v1->Vertex;
  iv.x = iv.x*-1.0;
  iv.y = iv.y*-1.0;  //Causes an translate oposite the start point.
  //Now, translate the endpoint
  iv = v2->Vertex.TranslatePoint(iv);

  theta = acos(iv.x/ChordLength);
  theta = DegToRad(180.0)-theta;
  iz.x = MidPoint.x + ChordIntersect*cos(theta-1.0);
  iz.y = MidPoint.y + ChordIntersect*sin(theta-1.0);
  Memo1->Lines->Add("MID " + FloatToStrF(MidPoint.x,ffFixed,8,4) + ","  +
    FloatToStrF(MidPoint.y,ffFixed,8,4));
  Memo1->Lines->Add("End x: " +FloatToStrF(iv.x,ffFixed,8,4) + "," +
    FloatToStrF(iv.y,ffFixed,8,4));
  Memo1->Lines->Add("Radius:" + FloatToStrF(Radius,ffFixed,8,4) + " Theta: "
+
     FloatToStrF(RadToDeg(theta),ffFixed,8,4));
  Memo1->Lines->Add("CENTER X:" + FloatToStrF(iz.x,ffFixed,8,4) + ","
                    + FloatToStrF(iz.y,ffFixed,8,4));

 

Re:Computing Center point of arc given only start point, end point , sweep angle direction draw


James,

The middle point between P1 and P2 is very important (HalfChord)
for the calculations.
Things would be much easier if its coordinates were (0, 0).
Why not make it so?
If we translate both P1 and P2 so that the HalfChord falls
on the origin, we get this situation. (Make a drawing and you'll
see the benefits of this.)
So, I suggest to move P1 and P2 so that their middle point
falls on the origin;  make the calculations; and move back
the calculated center.

Steps:
1 - Calculate the middle point (Xm, Ym)

2 - Subtract these values from P1 and P2 coordinates.
You'll get two new points: new P1 = X,Y and new P2 = -X,-Y.
(Since they simetric only one is used.)

3 - The equation for the chord line will simply be
y = X/Y * x

4 - The equation for the line containing the center will be:
y = -Y/X * x
The circle center must lie in this line, so
Xc = -Y/X * Xc

5 - The half chord length will be:
HalfChordLength = sqrt(X*X + Y*Y)

6 - The distance from the center to the chord will be
d = HalfChordLength / tan(HalfSweepAngle)
As the circle center must be 'd' away from the middle of
the chord, we get
Xc*Xc + Yc*Yc = d*d

7 -  Combining (4) and (6) you get
Xc = +- d / sqrt(1 + X*X/(Y*Y) )
Yc = - X/Y * Xc

8 - Translate (move) back the center:
Xc += Xm;
Yc += Ym;

9 - The radius will be
Radius = HalfChordLength / sin(HalfSweepAngle)

The plus or minus sign for Xc will depend on the arc
being clockwise or ccw.

Be aware of the case in which P1 and P2 lie on a horizontal
line. You should trap this and treat it accordingly.

To test, start a new Project with 3 edit boxes, a check box
and a button.
Ctrl-left click to define the first point.
Shift-left click to define the second point.
The sweep angle goes in Edit3.
The checkbox holds the cw/ccw direction.
The button fires the calculation and draws the results.
The code is below (horizontal case not implemented).

Eudy

//---------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

TPoint P1, P2;

//---------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{

Quote
}

//---------------------------------------------------------

void __fastcall TForm1::FormMouseDown(TObject *Sender,
                TMouseButton Button, TShiftState Shift, int X, int Y)
{
if (Button == mbLeft) {
     if (Shift.Contains(ssCtrl)) {
       P1.x = X;
       P1.y = Y;
       Canvas->Rectangle(X-2, Y-2, X+2, Y+2);
       }
     else if (Shift.Contains(ssShift)) {
       P2.x = X;
       P2.y = Y;
       Canvas->Rectangle(X-2, Y-2, X+2, Y+2);
       }
     }
Edit1->Text = IntToStr(P1.x) + " " + IntToStr(P1.y);
Edit2->Text = IntToStr(P2.x) + " " + IntToStr(P2.y);

Quote
}

//---------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
double Xm, Ym, Xc, Yc, HalfChord, HalfSweepAngle, Radius;
double X, Y;

HalfSweepAngle =  M_PI/180. * StrToFloat(Edit3->Text)/2.;

Xm = (P1.x + P2.x)/2.; // translation amount
Ym = (P1.y + P2.y)/2.;

X = P1.x - Xm;  //  new "translated" P1
Y = P1.y - Ym;

HalfChord = sqrt(X*X + Y*Y);

Xc = - HalfChord / tan(HalfSweepAngle) / sqrt(1+X*X/(Y*Y));
if (CounterClokwiseCheckBox->Checked)
     Xc *= -1.;
Yc = - X/Y*Xc;

Xc += Xm;
Yc += Ym;

Radius = HalfChord / sin(HalfSweepAngle);

Canvas->Ellipse(Xc - Radius, Yc - Radius,                                                    Xc + Radius, Yc + Radius);

Canvas->Rectangle(Xc-2, Yc-2, Xc+2, Yc+2);
Canvas->Rectangle(P1.x-2, P1.y-2, P1.x+2, P1.y+2);
Canvas->Rectangle(P2.x-2, P2.y-2, P2.x+2, P2.y+2);

Quote
}

//---------------------------------------------------------

Quote
James Williams wrote:

  > Hello,
  >
  > I am trying to compute the x,y coordinates for the center point of
an arc
  > given only the following informatio:
  > - Starting x,y of arc
  > - Ending x,y of arc
  > - direction of drawing from start to end, either clockwise or counter
  > clockwise
  > - The sweep angle of the arc from center point to the two end points
of the
  > arc.
  >
  > I can't seem to get the center location computed properly.
  >
  > I have tried the following code: but it doesn't work correctly.
  >
  > What am I doing wrong?
  >
  > Thanks,
  >
  > James
  >
  >   //TODO: Add your source code here
  >   //There are some things to do before we can actually draw the polyarc.
  >   // 1. Get midpoint of chord which joints the two end points.
  >   // 2. Compute chord length.
  >   // 3. Compute radius.
  >   // 4. Compute Chord of arc arc perendicular to y axis.
  >   // 5. Compute sweep angle bisect to arcchord midpoint length.
  >   // 6. Use midpoint location and step 5 length of line to compute
  >   //    x,y of ChordAngle+90.  This should give use one centerpoint
  > location.
  >   //    Second should be ChordAngle-90.
  >   double SweepAngle = v1->PArgSweep;
  >   double HalfSweepAngle = DegToRad(RadToDeg(SweepAngle)/2.0);
  >   double ChordLength,HalfChordLength,ChordIntersect;
  >   double Deltax,Deltay;
  >   double Radius;
  >   double StartAngle,EndAngle,theta;
  >   TReal2DPoint MidPoint,tv1,tv2,iv,iz;
  >   Deltax = v2->Vertex.x-v1->Vertex.x;
  >   Deltay = v2->Vertex.y-v1->Vertex.y;
  >   MidPoint.x = v1->Vertex.x + (Deltax/2.0);
  >   MidPoint.y = v1->Vertex.y + (Deltay/2.0);
  >
  >   ChordLength = sqrt((Deltax*Deltax)+(Deltay*Deltay));
  >   HalfChordLength=ChordLength/2.0;
  >   //Ok the radius is now computed as follows R=
HalfChordLength/sin(sweep/2)
  >   Radius = HalfChordLength/sin(HalfSweepAngle);//asin
  >   Radius = fabs(Radius);
  >   ChordIntersect =
  > sqrt(fabs((HalfChordLength*HalfChordLength)-(Radius*Radius)));
  >
  >   //Things to do now.
  >   // 1. Translate chord line to orgin.  Translate by start point.
  >   // 2. Compute angle of line.
  >   iv = v1->Vertex;
  >   iv.x = iv.x*-1.0;
  >   iv.y = iv.y*-1.0;  //Causes an translate oposite the start point.
  >   //Now, translate the endpoint
  >   iv = v2->Vertex.TranslatePoint(iv);
  >
  >   theta = acos(iv.x/ChordLength);
  >   theta = DegToRad(180.0)-theta;
  >   iz.x = MidPoint.x + ChordIntersect*cos(theta-1.0);
  >   iz.y = MidPoint.y + ChordIntersect*sin(theta-1.0);
  >   Memo1->Lines->Add("MID " + FloatToStrF(MidPoint.x,ffFixed,8,4) +
","  +
  >     FloatToStrF(MidPoint.y,ffFixed,8,4));
  >   Memo1->Lines->Add("End x: " +FloatToStrF(iv.x,ffFixed,8,4) + "," +
  >     FloatToStrF(iv.y,ffFixed,8,4));
  >   Memo1->Lines->Add("Radius:" + FloatToStrF(Radius,ffFixed,8,4) + "
Theta: "
  > +
  >      FloatToStrF(RadToDeg(theta),ffFixed,8,4));
  >   Memo1->Lines->Add("CENTER X:" + FloatToStrF(iz.x,ffFixed,8,4) + ","
  >                     + FloatToStrF(iz.y,ffFixed,8,4));
  >
  >
  >

Other Threads