# 'Center' of ArcSegment

### Question

• (I hope this isn't too much of a math problem) I am hoping there is something built in for this or some solution out there for this:

Is it possible to find the center point of an ArcSegment? Edit: this is a circular arc segment where the size x and y are always the same.

Say I have a Path, one PathFigure with one ArcSegment. PathFigure's StartPoint is 0,4.  ArcSegment's Point is 4,0. Size 2,2, IsLargeArc = false, SweepDirection = Clockwise.  In my head I know the centerpoint is 4,4.. but is there an easy way to solve this in silverlight or .net?

The closest math forumula I found could find the two potential center points using the two points and radius.. but in silverlight we can specify the sweep and large part flag.. is there a solution to find a single center point then?

Wednesday, July 23, 2008 4:20 PM

• Hi

It's a math problem. Please try following code to get the center:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
using System.IO;
using System.Windows.Browser;

using System.ServiceModel;
using System.Reflection;
using System.Windows.Markup;
using System.ServiceModel.Channels;

namespace SilverlightApplication26
{

public partial class Page : UserControl
{

public Page()
{

InitializeComponent();

}

Point GetCircleCenter(Point p1, Point p2, double r, bool IsLargeArc, bool IsClockWise)
{

double x1 = p1.X, y1 = p1.Y, x2 = p2.X, y2 = p2.Y;
//Middle point
double xm = (x1 + x2) / 2, ym = (y1 + y2) / 2;
double result_x_1,result_x_2, result_y_1, result_y_2;
if ((Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2)) > Math.Pow(2 * r, 2))
{
return new Point(xm, ym);
}
else
{
if (Math.Abs(y1 - y2)<0.0000000000001)//corrected here
{
double k = (x2 - x1) / (y1 - y2);

//the center point's x axis value is the result of function ax^2+bx+c=0
double t = ym - k * xm;
double a = 1 + k * k;
double b = 2 * (k * t - x1 - y1 * k);
double c = x1 * x1 + t * t - 2 * t * y1 + y1 * y1 - r * r;
//Result
result_x_1 = (-1 * b + Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
result_x_2 = (-1 * b - Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
//Relevant y asix value
result_y_1 = k * result_x_1 + t;
result_y_2 = k * result_x_2 + t;
}
else
{
result_x_1 = result_x_2 = xm;
result_y_1 = y1 + Math.Sqrt(r * r - Math.Pow(result_x_1 - x1, 2));
result_y_2 = y1 - Math.Sqrt(r * r - Math.Pow(result_x_1 - x1, 2));
}

//Return

Vector v1_1 = new Vector(x1 - result_x_1, y1 - result_y_1);
Vector v1_2 = new Vector(x2 - result_x_1, y2 - result_y_1);
double b1 = Vector.AngleBetween(v1_1, v1_2);
bool result1_angle_larger_than_zero = b1 > 0;
Point result = new Point();
if (!IsClockWise)
{
if (IsLargeArc)
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_1;
result.Y = result_y_1;
}
else
{
result.X = result_x_2;
result.Y = result_y_2;

}
}
else
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_2;
result.Y = result_y_2;
}
else
{

result.X = result_x_1;
result.Y = result_y_1;
}

}
}
else
{
if (IsLargeArc)
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_2;
result.Y = result_y_2;
}
else
{
result.X = result_x_1;
result.Y = result_y_1;
}
}
else
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_1;
result.Y = result_y_1;
}
else
{

result.X = result_x_2;
result.Y = result_y_2;
}

}
}
return result;
}
}
Ellipse el = new Ellipse();
{
el.Width = 5;
el.Height = 5;

el.Fill = new SolidColorBrush(Colors.Red);

//Make sure ArcSegment1 is a circle or else the result is wrong!
Point p = GetCircleCenter(this.PathFigure1.StartPoint,this.ArcSegment1.Point,this.ArcSegment1.Size.Width,this.ArcSegment1.IsLargeArc,this.ArcSegment1.SweepDirection==SweepDirection.Clockwise);
el.SetValue(Canvas.LeftProperty, p.X);
el.SetValue(Canvas.TopProperty, p.Y);

}

}

public struct Vector
{
internal double _x;
internal double _y;
public static bool operator ==(Vector vector1, Vector vector2)
{
return ((vector1.X == vector2.X) && (vector1.Y == vector2.Y));
}

public static bool operator !=(Vector vector1, Vector vector2)
{
return !(vector1 == vector2);
}

public static bool Equals(Vector vector1, Vector vector2)
{
return (vector1.X.Equals(vector2.X) && vector1.Y.Equals(vector2.Y));
}

public override bool Equals(object o)
{
if ((o == null) || !(o is Vector))
{
return false;
}
Vector vector = (Vector)o;
return Equals(this, vector);
}

public bool Equals(Vector value)
{
return Equals(this, value);
}

public override int GetHashCode()
{
return (this.X.GetHashCode() ^ this.Y.GetHashCode());
}

public double X
{
get
{
return this._x;
}
set
{
this._x = value;
}
}
public double Y
{
get
{
return this._y;
}
set
{
this._y = value;
}
}

public Vector(double x, double y)
{
this._x = x;
this._y = y;
}

public double Length
{
get
{
return Math.Sqrt((this._x * this._x) + (this._y * this._y));
}
}
public double LengthSquared
{
get
{
return ((this._x * this._x) + (this._y * this._y));
}
}
public void Normalize()
{
this = (Vector)(this / Math.Max(Math.Abs(this._x), Math.Abs(this._y)));
this = (Vector)(this / this.Length);
}

public static double CrossProduct(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._y) - (vector1._y * vector2._x));
}

public static double AngleBetween(Vector vector1, Vector vector2)
{
double y = (vector1._x * vector2._y) - (vector2._x * vector1._y);
double x = (vector1._x * vector2._x) + (vector1._y * vector2._y);
return (Math.Atan2(y, x) * 57.295779513082323);
}

public static Vector operator -(Vector vector)
{
return new Vector(-vector._x, -vector._y);
}

public void Negate()
{
this._x = -this._x;
this._y = -this._y;
}

public static Vector operator +(Vector vector1, Vector vector2)
{
return new Vector(vector1._x + vector2._x, vector1._y + vector2._y);
}

public static Vector Add(Vector vector1, Vector vector2)
{
return new Vector(vector1._x + vector2._x, vector1._y + vector2._y);
}

public static Vector operator -(Vector vector1, Vector vector2)
{
return new Vector(vector1._x - vector2._x, vector1._y - vector2._y);
}

public static Vector Subtract(Vector vector1, Vector vector2)
{
return new Vector(vector1._x - vector2._x, vector1._y - vector2._y);
}

public static Vector operator *(Vector vector, double scalar)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector Multiply(Vector vector, double scalar)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector operator *(double scalar, Vector vector)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector Multiply(double scalar, Vector vector)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector operator /(Vector vector, double scalar)
{
return (Vector)(vector * (1.0 / scalar));
}

public static Vector Divide(Vector vector, double scalar)
{
return (Vector)(vector * (1.0 / scalar));
}

public static double operator *(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._x) + (vector1._y * vector2._y));
}

public static double Multiply(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._x) + (vector1._y * vector2._y));
}

public static double Determinant(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._y) - (vector1._y * vector2._x));
}

public static explicit operator Size(Vector vector)
{
return new Size(Math.Abs(vector._x), Math.Abs(vector._y));
}

public static explicit operator Point(Vector vector)
{
return new Point(vector._x, vector._y);
}
}

}

<Canvas x:Name="Canvas1" Width="500" Height="500" Background="Yellow">
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure x:Name="PathFigure1" StartPoint="50,140">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment x:Name="ArcSegment1" Size="40,40"  IsLargeArc="False"
SweepDirection="Clockwise"  Point="80,140" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>

</Canvas>

Please note even if it cannot create a circle with the given size (radius of the circle) it'll be auto stretched and create a semicircle. You can see I added some logic to handle this scenario.

Friday, July 25, 2008 4:52 AM

### All replies

• I dared to ask on a Math forum and every other response was theory or accusations of homework fishing! I may have found a work around although it is not an exact method like I was after.

Thursday, July 24, 2008 3:35 PM
• Hi

It's a math problem. Please try following code to get the center:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
using System.IO;
using System.Windows.Browser;

using System.ServiceModel;
using System.Reflection;
using System.Windows.Markup;
using System.ServiceModel.Channels;

namespace SilverlightApplication26
{

public partial class Page : UserControl
{

public Page()
{

InitializeComponent();

}

Point GetCircleCenter(Point p1, Point p2, double r, bool IsLargeArc, bool IsClockWise)
{

double x1 = p1.X, y1 = p1.Y, x2 = p2.X, y2 = p2.Y;
//Middle point
double xm = (x1 + x2) / 2, ym = (y1 + y2) / 2;
double result_x_1,result_x_2, result_y_1, result_y_2;
if ((Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2)) > Math.Pow(2 * r, 2))
{
return new Point(xm, ym);
}
else
{
if (Math.Abs(y1 - y2)<0.0000000000001)//corrected here
{
double k = (x2 - x1) / (y1 - y2);

//the center point's x axis value is the result of function ax^2+bx+c=0
double t = ym - k * xm;
double a = 1 + k * k;
double b = 2 * (k * t - x1 - y1 * k);
double c = x1 * x1 + t * t - 2 * t * y1 + y1 * y1 - r * r;
//Result
result_x_1 = (-1 * b + Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
result_x_2 = (-1 * b - Math.Sqrt(b * b - 4 * a * c)) / (2 * a);
//Relevant y asix value
result_y_1 = k * result_x_1 + t;
result_y_2 = k * result_x_2 + t;
}
else
{
result_x_1 = result_x_2 = xm;
result_y_1 = y1 + Math.Sqrt(r * r - Math.Pow(result_x_1 - x1, 2));
result_y_2 = y1 - Math.Sqrt(r * r - Math.Pow(result_x_1 - x1, 2));
}

//Return

Vector v1_1 = new Vector(x1 - result_x_1, y1 - result_y_1);
Vector v1_2 = new Vector(x2 - result_x_1, y2 - result_y_1);
double b1 = Vector.AngleBetween(v1_1, v1_2);
bool result1_angle_larger_than_zero = b1 > 0;
Point result = new Point();
if (!IsClockWise)
{
if (IsLargeArc)
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_1;
result.Y = result_y_1;
}
else
{
result.X = result_x_2;
result.Y = result_y_2;

}
}
else
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_2;
result.Y = result_y_2;
}
else
{

result.X = result_x_1;
result.Y = result_y_1;
}

}
}
else
{
if (IsLargeArc)
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_2;
result.Y = result_y_2;
}
else
{
result.X = result_x_1;
result.Y = result_y_1;
}
}
else
{
if (result1_angle_larger_than_zero)
{
result.X = result_x_1;
result.Y = result_y_1;
}
else
{

result.X = result_x_2;
result.Y = result_y_2;
}

}
}
return result;
}
}
Ellipse el = new Ellipse();
{
el.Width = 5;
el.Height = 5;

el.Fill = new SolidColorBrush(Colors.Red);

//Make sure ArcSegment1 is a circle or else the result is wrong!
Point p = GetCircleCenter(this.PathFigure1.StartPoint,this.ArcSegment1.Point,this.ArcSegment1.Size.Width,this.ArcSegment1.IsLargeArc,this.ArcSegment1.SweepDirection==SweepDirection.Clockwise);
el.SetValue(Canvas.LeftProperty, p.X);
el.SetValue(Canvas.TopProperty, p.Y);

}

}

public struct Vector
{
internal double _x;
internal double _y;
public static bool operator ==(Vector vector1, Vector vector2)
{
return ((vector1.X == vector2.X) && (vector1.Y == vector2.Y));
}

public static bool operator !=(Vector vector1, Vector vector2)
{
return !(vector1 == vector2);
}

public static bool Equals(Vector vector1, Vector vector2)
{
return (vector1.X.Equals(vector2.X) && vector1.Y.Equals(vector2.Y));
}

public override bool Equals(object o)
{
if ((o == null) || !(o is Vector))
{
return false;
}
Vector vector = (Vector)o;
return Equals(this, vector);
}

public bool Equals(Vector value)
{
return Equals(this, value);
}

public override int GetHashCode()
{
return (this.X.GetHashCode() ^ this.Y.GetHashCode());
}

public double X
{
get
{
return this._x;
}
set
{
this._x = value;
}
}
public double Y
{
get
{
return this._y;
}
set
{
this._y = value;
}
}

public Vector(double x, double y)
{
this._x = x;
this._y = y;
}

public double Length
{
get
{
return Math.Sqrt((this._x * this._x) + (this._y * this._y));
}
}
public double LengthSquared
{
get
{
return ((this._x * this._x) + (this._y * this._y));
}
}
public void Normalize()
{
this = (Vector)(this / Math.Max(Math.Abs(this._x), Math.Abs(this._y)));
this = (Vector)(this / this.Length);
}

public static double CrossProduct(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._y) - (vector1._y * vector2._x));
}

public static double AngleBetween(Vector vector1, Vector vector2)
{
double y = (vector1._x * vector2._y) - (vector2._x * vector1._y);
double x = (vector1._x * vector2._x) + (vector1._y * vector2._y);
return (Math.Atan2(y, x) * 57.295779513082323);
}

public static Vector operator -(Vector vector)
{
return new Vector(-vector._x, -vector._y);
}

public void Negate()
{
this._x = -this._x;
this._y = -this._y;
}

public static Vector operator +(Vector vector1, Vector vector2)
{
return new Vector(vector1._x + vector2._x, vector1._y + vector2._y);
}

public static Vector Add(Vector vector1, Vector vector2)
{
return new Vector(vector1._x + vector2._x, vector1._y + vector2._y);
}

public static Vector operator -(Vector vector1, Vector vector2)
{
return new Vector(vector1._x - vector2._x, vector1._y - vector2._y);
}

public static Vector Subtract(Vector vector1, Vector vector2)
{
return new Vector(vector1._x - vector2._x, vector1._y - vector2._y);
}

public static Vector operator *(Vector vector, double scalar)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector Multiply(Vector vector, double scalar)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector operator *(double scalar, Vector vector)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector Multiply(double scalar, Vector vector)
{
return new Vector(vector._x * scalar, vector._y * scalar);
}

public static Vector operator /(Vector vector, double scalar)
{
return (Vector)(vector * (1.0 / scalar));
}

public static Vector Divide(Vector vector, double scalar)
{
return (Vector)(vector * (1.0 / scalar));
}

public static double operator *(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._x) + (vector1._y * vector2._y));
}

public static double Multiply(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._x) + (vector1._y * vector2._y));
}

public static double Determinant(Vector vector1, Vector vector2)
{
return ((vector1._x * vector2._y) - (vector1._y * vector2._x));
}

public static explicit operator Size(Vector vector)
{
return new Size(Math.Abs(vector._x), Math.Abs(vector._y));
}

public static explicit operator Point(Vector vector)
{
return new Point(vector._x, vector._y);
}
}

}

<Canvas x:Name="Canvas1" Width="500" Height="500" Background="Yellow">
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure x:Name="PathFigure1" StartPoint="50,140">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment x:Name="ArcSegment1" Size="40,40"  IsLargeArc="False"
SweepDirection="Clockwise"  Point="80,140" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>

</Canvas>

Please note even if it cannot create a circle with the given size (radius of the circle) it'll be auto stretched and create a semicircle. You can see I added some logic to handle this scenario.