190 lines
4.4 KiB
C#
190 lines
4.4 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Rokojori
|
|
{
|
|
public class SVGPathParser
|
|
{
|
|
public static readonly string SVGPathCommands = "mlhvcsqtaz";
|
|
|
|
List<SVGPathCommand> commands = new List<SVGPathCommand>();
|
|
List<Message> messages = new List<Message>();
|
|
|
|
public static List<SVGPathCommand> Parse( string d )
|
|
{
|
|
var svgPath = new SVGPathParser();
|
|
var commands = svgPath.ParseCommands( d );
|
|
|
|
if ( Messages.HasError( svgPath.messages ) )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return commands;
|
|
}
|
|
|
|
public static List<Message> GetMessages( string d )
|
|
{
|
|
var svgPath = new SVGPathParser();
|
|
var commands = svgPath.ParseCommands( d );
|
|
|
|
return svgPath.messages;
|
|
}
|
|
|
|
public List<SVGPathCommand> ParseCommands( string d )
|
|
{
|
|
for ( int i = 0; i < d.Length; i++ )
|
|
{
|
|
if ( d[ i ] == ' ' )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var lowerCase = ( d[ i ] + "" ).ToLower();
|
|
|
|
|
|
|
|
var commandIndex = SVGPathCommands.IndexOf( lowerCase );
|
|
|
|
if ( commandIndex == -1 )
|
|
{
|
|
Messages.Error( messages, "Unknown command at '" + i + "'. Found " + d[ i ] );
|
|
return null;
|
|
}
|
|
|
|
var commandEnd = ProcessCommand( d, i );
|
|
|
|
// RJLog.Log( "Processing", d[ i ], ">>", lowerCase, " ends ", commandEnd );
|
|
|
|
if ( commandEnd == -1 || Messages.HasError( messages ) )
|
|
{
|
|
Messages.Error( messages, "Command couldn't be processed at '" + i + "'. Processed " + d[ i ] );
|
|
return null;
|
|
}
|
|
|
|
i = commandEnd;
|
|
}
|
|
|
|
return commands;
|
|
}
|
|
|
|
int ProcessCommand( string d, int offset )
|
|
{
|
|
var end = FindEnd( d, offset + 1 );
|
|
|
|
var pc = new SVGPathCommand();
|
|
pc.type = d[ offset ] + "";
|
|
pc.pathIndex = commands.Count;
|
|
|
|
ReadParameters( pc, d, offset + 1, end );
|
|
|
|
commands.Add( pc );
|
|
|
|
return end;
|
|
}
|
|
|
|
int FindEnd( string d, int offset )
|
|
{
|
|
for ( int i = offset; i < d.Length; i++ )
|
|
{
|
|
var chr = ( d[ i ] + "" ).ToLower();
|
|
|
|
if ( SVGPathParser.SVGPathCommands.IndexOf( chr ) != - 1 )
|
|
{
|
|
return i - 1;
|
|
}
|
|
}
|
|
|
|
return d.Length - 1;
|
|
}
|
|
|
|
void ReadParameters( SVGPathCommand command, string d, int start, int end )
|
|
{
|
|
|
|
var parameters = d.Substring( start, ( end + 1 ) - start );
|
|
parameters = parameters.Trim();
|
|
|
|
// RJLog.Log( "Parsing parameters:", parameters );
|
|
|
|
var regex = new Regex( " |," );
|
|
var splitted = RegexUtility.Split( parameters, " |," );
|
|
|
|
splitted.ForEach(
|
|
( s )=>
|
|
{
|
|
var number = RegexUtility.ParseFloat( s.Trim() );
|
|
command.paramaters.Add( number );
|
|
// RJLog.Log( s, ">>", number );
|
|
}
|
|
);
|
|
}
|
|
|
|
void ReadParametersOld( SVGPathCommand command, string d, int start, int end )
|
|
{
|
|
var matcher = LexerMatcherLibrary.NumberMatcher;
|
|
var offset = start;
|
|
var isNegative = false;
|
|
|
|
while ( offset < end )
|
|
{
|
|
if ( d[ offset ] == ' ' || d[ offset ] == ',' )
|
|
{
|
|
offset ++;
|
|
isNegative = false;
|
|
continue;
|
|
}
|
|
|
|
if ( d[ offset ] == '-' )
|
|
{
|
|
offset ++;
|
|
isNegative = true;
|
|
continue;
|
|
}
|
|
|
|
|
|
var matchLength = matcher.MatchLength( d, offset );
|
|
|
|
if ( matchLength == -1 )
|
|
{
|
|
Messages.Error( messages,
|
|
"Found no number." +
|
|
" Offset:" + offset +
|
|
" Start: " + start +
|
|
" End: " + end +
|
|
" Part: " + "'" + d.Substring( start, end - start ) + "'"
|
|
);
|
|
return;
|
|
}
|
|
|
|
var endIndex = offset + matchLength;
|
|
|
|
if ( endIndex > end )
|
|
{
|
|
Messages.Error( messages,
|
|
"Number parsing exceeded expected end." +
|
|
" Offset:" + offset +
|
|
" Start: " + start +
|
|
" End: " + end +
|
|
" Match End: " + endIndex +
|
|
" Part: " + "'" + d.Substring( start, end - start ) + "'"
|
|
);
|
|
return;
|
|
}
|
|
|
|
var number = RegexUtility.ParseFloat( d.Substring( offset, matchLength ) );
|
|
|
|
if ( isNegative )
|
|
{
|
|
number = -number;
|
|
}
|
|
|
|
offset += matchLength;
|
|
|
|
command.paramaters.Add( number );
|
|
|
|
isNegative = false;
|
|
}
|
|
}
|
|
}
|
|
} |