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

146 lines
4.0 KiB
C#

using Godot;
using System;
using System.Collections.Generic;
namespace Rokojori
{
public enum SVGPathInstructionType
{
MoveTo,
LineTo,
QuadraticBezierTo,
CubicBezierTo,
ArcTo,
Close
}
public class SVGPathInstruction
{
public SVGPathCommand sourceCommand;
public int sourceCommandIndex;
public SVGPathInstructionType type = SVGPathInstructionType.MoveTo;
public Vector2 startPoint = Vector2.Zero;
public Vector2 controlPoint1 = Vector2.Zero;
public Vector2 controlPoint2 = Vector2.Zero;
public Vector2 endPoint = Vector2.Zero;
public Vector2 radius = Vector2.Zero;
public float angle = 0;
public bool largeArcFlag = false;
public bool sweepFlag = false;
public override string ToString()
{
return GetInfo();
}
public void AddPoints( List<Vector2> pathPoints, float resolution = 1, int maxPoints = 1000 )
{
if ( SVGPathInstructionType.MoveTo == type )
{
pathPoints.Add( startPoint );
}
else if (
SVGPathInstructionType.LineTo == type ||
SVGPathInstructionType.Close == type
)
{
pathPoints.Add( endPoint );
}
else if ( SVGPathInstructionType.ArcTo == type )
{
var centerPosition = new Vector2();
var centerRadius = new Vector2();
var centerAngles = new Vector2();
SVGArc.EndpointToCenterArc(
startPoint, endPoint, radius, angle, largeArcFlag, sweepFlag,
out centerPosition, out centerRadius, out centerAngles );
var arcResolution = Math.Max( centerRadius.X, centerRadius.Y ) / resolution;
arcResolution = Mathf.Clamp( arcResolution, 1, maxPoints );
RJLog.Log( "Arc Resolution", arcResolution );
for ( int i = 1; i < arcResolution - 1; i++ )
{
var t = centerAngles.Y * ( (float)i / ( arcResolution - 1 ) );
var arcPoint = SVGArc.GetPointOnCenterArc( centerRadius, centerAngles.X, t ) + centerPosition;
pathPoints.Add( arcPoint );
}
pathPoints.Add( endPoint );
}
else if (
SVGPathInstructionType.QuadraticBezierTo == type ||
SVGPathInstructionType.CubicBezierTo == type
)
{
var isQuadratic = SVGPathInstructionType.QuadraticBezierTo == type;
var curve = isQuadratic ?
new CustomCurve2( t => QuadraticBezier.Compute( t, startPoint, controlPoint1, endPoint ) ) :
new CustomCurve2( t => CubicBezier.Compute( t, startPoint, controlPoint1, controlPoint2, endPoint ) )
;
var length = curve.ComputeLength( isQuadratic ? 4 : 6 );
var numPoints = Mathf.Clamp( Mathf.RoundToInt( length / resolution ), 1, maxPoints );
for ( int i = 1; i < numPoints - 1; i++ )
{
var t = (float) i / ( numPoints - 1 );
pathPoints.Add( curve.SampleAt( t ) );
}
pathPoints.Add( curve.SampleAt( 1 ) );
}
}
public string GetInfo()
{
var infos = new List<object>();
infos.Add( type );
if ( SVGPathInstructionType.MoveTo == type )
{
infos.Add( endPoint );
}
else if ( SVGPathInstructionType.LineTo == type )
{
infos.Add( startPoint );
infos.Add( endPoint );
}
else if ( SVGPathInstructionType.QuadraticBezierTo == type )
{
infos.Add( startPoint );
infos.Add( controlPoint1 );
infos.Add( endPoint );
}
else if ( SVGPathInstructionType.CubicBezierTo == type )
{
infos.Add( startPoint );
infos.Add( controlPoint1 );
infos.Add( controlPoint2 );
infos.Add( endPoint );
}
else if ( SVGPathInstructionType.ArcTo == type )
{
infos.Add( startPoint );
infos.Add( radius );
infos.Add( angle );
infos.Add( largeArcFlag );
infos.Add( sweepFlag );
infos.Add( endPoint );
}
return RJLog.GetLogString( infos.ToArray() );
}
}
}