146 lines
4.0 KiB
C#
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() );
|
|
}
|
|
}
|
|
} |