rj-action-library/Runtime/XML/SVG/SVGArc.cs

107 lines
2.6 KiB
C#

using Godot;
namespace Rokojori
{
public class SVGArc
{
public static Vector2 GetPointOnCenterArc( Vector2 r, float theta, float delta )
{
return new Vector2(
r.X * Mathf.Cos( theta ) * Mathf.Cos( delta ) - r.Y * Mathf.Sin( theta ) * Mathf.Sin( delta ),
r.X * Mathf.Sin( theta ) * Mathf.Cos( delta ) + r.Y * Mathf.Cos( theta ) * Mathf.Sin( delta )
);
}
public static void EndpointToCenterArc(
Vector2 start, Vector2 end, Vector2 radius, float xAngle, bool flagA, bool flagS,
out Vector2 centerPosition,
out Vector2 centerRadius,
out Vector2 centerAngles
)
{
var rX = Mathf.Abs( radius.X );
var rY = Mathf.Abs( radius.Y );
var dx2 = ( start.X - end.X ) / 2f;
var dy2 = ( start.Y - end.Y ) / 2f;
var x1p = Mathf.Cos( xAngle ) * dx2 + Mathf.Sin( xAngle ) * dy2;
var y1p = -Mathf.Sin( xAngle ) * dx2 + Mathf.Cos( xAngle ) * dy2;
var rxs = rX * rX;
var rys = rY * rY;
var x1ps = x1p * x1p;
var y1ps = y1p * y1p;
var cr = x1ps / rxs + y1ps / rys;
if ( cr > 1 )
{
var s = Mathf.Sqrt( cr );
rX = s * rX;
rY = s * rY;
rxs = rX * rX;
rys = rY * rY;
}
var dq = ( rxs * y1ps + rys * x1ps );
var pq = ( rxs * rys - dq ) / dq;
var q = Mathf.Sqrt( Mathf.Max( 0, pq ) );
if ( flagA == flagS )
{
q = -q;
}
var cxp = q * rX * y1p / rY;
var cyp = - q * rY * x1p / rX;
var cx = Mathf.Cos( xAngle ) * cxp - Mathf.Sin( xAngle ) * cyp + ( start.X + end.X ) / 2;
var cy = Mathf.Sin( xAngle ) * cxp + Mathf.Cos( xAngle ) * cyp + ( start.Y + end.Y ) / 2;
var theta = Angle( 1f, 0f, ( x1p-cxp ) / rX, ( y1p - cyp ) / rY );
var delta = Angle(
( x1p - cxp ) / rX,
( y1p - cyp ) / rY,
( -x1p - cxp ) / rX,
( -y1p-cyp ) / rY );
delta = delta % Mathf.Pi * 2;
if ( ! flagS )
{
delta -= 2 * Mathf.Pi;
}
centerRadius = new Vector2( rX, rY );
centerPosition = new Vector2(cx, cy );
centerAngles = new Vector2( theta, delta );
}
static float Angle( float ux, float uy, float vx, float vy )
{
var u = new Vector2( ux, uy );
var v = new Vector2( vx, vy );
var dot = Math2D.Dot( u, v );
var len = u.Length( ) * v.Length( );
var ang = Mathf.Acos( Mathf.Clamp( dot / len,-1,1 ) );
if ( ( u.X * v.Y - u.Y * v.X ) < 0 )
{
ang = -ang;
}
return ang;
}
}
}