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 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(); 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() ); } } }