当前位置:网站首页>C SVG path parser of xamarin version
C SVG path parser of xamarin version
2022-04-23 07:48:00 【Dake mountain man】
Xamarin Version of C# SVG Path parser , Yes SVG Of Path Path analysis , These include :
The main program SvgPathParser.cs,
Relevant interface definitions :ISourceFormatter.cs,
Auxiliary class :FormatterRocks.cs,
Derived from interface CSharpCoreGraphicsFormatter.cs.
// The main program SvgPathParser.cs:
// Authors:
// Sebastien Pouliot <[email protected]>
//
// Copyright 2012-2013 Xamarin Inc.
//
// This file is mostly based on the C++ code from once magnificent Moonlight
// https://github.com/mono/moon/blob/master/src/xaml.cpp
// Copyright 2007 Novell, Inc. (http://www.novell.com)
//
// Licensed under the GNU LGPL 2 license only (no "later versions")
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
namespace Poupou.SvgPathConverter {
public class SvgPathParser {
static int i;
public ISourceFormatter Formatter { get; set; }
public void Parse (string svgPath, string name = null)
{
if (Formatter == null)
throw new InvalidOperationException ("Missing formatter");
if (name == null)
name = "Unnamed_" + (++i).ToString ();
Parse (svgPath, name, Formatter);
}
static void Advance (string s, ref int pos)
{
if (pos >= s.Length)
return;
char c = s [pos];
while (!Char.IsLetterOrDigit (c) && c != '.' && c!= '-' && c != '+') {
if (++pos == s.Length)
return;
c = s [pos];
}
}
static int FindNonFloat (string s, int pos)
{
char c = s [pos];
while ((Char.IsNumber (c) || c == '.' || c == '-' || c == '+')) {
if (++pos == s.Length)
return pos;
c = s [pos];
}
return pos;
}
static bool MorePointsAvailable (string s, int pos)
{
if (pos >= s.Length)
return false;
char c = s [pos];
while (Char.IsWhiteSpace (c) || c == ',')
c = s [++pos];
return Char.IsDigit (c) || c == '.' || c == '-' || c == '+';
}
static float GetFloat (string svg, ref int pos)
{
int end = FindNonFloat (svg, pos);
string s = svg.Substring (pos, end - pos);
float f = Single.Parse (s, CultureInfo.InvariantCulture);
pos = end;
return f;
}
static PointF GetPoint (string svg, ref int pos)
{
while (Char.IsWhiteSpace (svg [pos]))
pos++;
float x = GetFloat (svg, ref pos);
while (Char.IsWhiteSpace (svg [pos]))
pos++;
if (svg [pos] == ',')
pos++;
while (Char.IsWhiteSpace (svg [pos]))
pos++;
float y = GetFloat (svg, ref pos);
return new PointF (x, y);
}
static PointF MakeRelative (PointF c, PointF m)
{
return new PointF (m.X + c.X, m.Y + c.Y);
}
static void Parse (string svg, string name, ISourceFormatter formatter)
{
formatter.Prologue (name);
PointF start;
PointF cp = new PointF (0, 0);
PointF cp1, cp2, cp3;
PointF qbzp, cbzp;
int fill_rule = 0;
int pos = 0;
bool cbz = false;
bool qbz = false;
while (pos < svg.Length) {
char c = svg [pos++];
if (Char.IsWhiteSpace (c))
continue;
bool relative = false;
switch (c) {
case 'f':
case 'F':
c = svg [pos++];
if (c == '0')
fill_rule = 0;
else if (c == '1')
fill_rule = 1;
else
throw new FormatException ();
break;
case 'h':
relative = true;
goto case 'H';
case 'H':
float x = GetFloat (svg, ref pos);
if (relative)
x += cp.X;
cp = new PointF (x, cp.Y);
formatter.LineTo (cp);
cbz = qbz = false;
break;
case 'm':
relative = true;
goto case 'M';
case 'M':
cp1 = GetPoint (svg, ref pos);
if (relative)
cp1 = MakeRelative (cp, cp1);
formatter.MoveTo (cp1);
start = cp = cp1;
Advance (svg, ref pos);
while (MorePointsAvailable (svg, pos)) {
cp1 = GetPoint (svg, ref pos);
if (relative)
cp1 = MakeRelative (cp, cp1);
formatter.LineTo (cp1);
}
cp = cp1;
cbz = qbz = false;
break;
case 'l':
relative = true;
goto case 'L';
case 'L':
while (MorePointsAvailable (svg, pos)) {
cp1 = GetPoint (svg, ref pos);
if (relative)
cp1 = MakeRelative (cp, cp1);
Advance (svg, ref pos);
formatter.LineTo (cp1);
cp = cp1;
}
cbz = qbz = false;
break;
case 'a':
relative = true;
goto case 'A';
case 'A':
while (MorePointsAvailable (svg, pos)) {
cp1 = GetPoint (svg, ref pos);
// this is a width and height so it's not made relative to cp
Advance (svg, ref pos);
float angle = GetFloat (svg, ref pos);
Advance (svg, ref pos);
bool is_large = GetFloat (svg, ref pos) != 0.0f;
Advance (svg, ref pos);
bool positive_sweep = GetFloat (svg, ref pos) != 0.0f;
Advance (svg, ref pos);
cp2 = GetPoint (svg, ref pos);
if (relative)
cp2 = MakeRelative (cp, cp2);
Advance (svg, ref pos);
formatter.ArcTo (cp1, angle, is_large, positive_sweep, cp2, cp);
cp = cp2;
Advance (svg, ref pos);
}
qbz = false;
cbz = false;
break;
case 'q':
relative = true;
goto case 'Q';
case 'Q':
while (MorePointsAvailable (svg, pos)) {
cp1 = GetPoint (svg, ref pos);
if (relative)
cp1 = MakeRelative (cp, cp1);
Advance (svg, ref pos);
cp2 = GetPoint (svg, ref pos);
if (relative)
cp2 = MakeRelative (cp, cp2);
Advance (svg, ref pos);
formatter.QuadCurveTo (cp1, cp2);
cp = cp2;
Advance (svg, ref pos);
}
qbz = true;
qbzp = cp1;
cbz = false;
break;
case 'c':
relative = true;
goto case 'C';
case 'C':
while (MorePointsAvailable (svg, pos)) {
cp1 = GetPoint (svg, ref pos);
if (relative)
cp1 = MakeRelative (cp, cp1);
Advance (svg, ref pos);
cp2 = GetPoint (svg, ref pos);
if (relative)
cp2 = MakeRelative (cp, cp2);
Advance (svg, ref pos);
cp3 = GetPoint (svg, ref pos);
if (relative)
cp3 = MakeRelative (cp, cp3);
Advance (svg, ref pos);
formatter.CurveTo (cp1, cp2, cp3);
cp1 = cp3;
}
cp = cp3;
cbz = true;
cbzp = cp2;
qbz = false;
break;
case 't':
relative = true;
goto case 'T';
case 'T':
while (MorePointsAvailable (svg, pos)) {
cp2 = GetPoint (svg, ref pos);
if (relative)
cp2 = MakeRelative (cp, cp2);
if (qbz) {
cp1.X = 2 * cp.X - qbzp.X;
cp1.Y = 2 * cp.Y - qbzp.Y;
} else {
cp1 = cp;
}
formatter.QuadCurveTo (cp1, cp2);
qbz = true;
qbzp = cp1;
cp = cp2;
Advance (svg, ref pos);
}
cbz = false;
break;
case 's':
relative = true;
goto case 'S';
case 'S':
while (MorePointsAvailable (svg, pos)) {
cp2 = GetPoint (svg, ref pos);
if (relative)
cp2 = MakeRelative (cp, cp2);
Advance (svg, ref pos);
cp3 = GetPoint (svg, ref pos);
if (relative)
cp3 = MakeRelative (cp, cp3);
if (cbz) {
cp1.X = 2 * cp.X - cbzp.X;
cp1.Y = 2 * cp.Y - cbzp.Y;
} else {
cp1 = cp;
}
formatter.CurveTo (cp1, cp2, cp3);
cbz = true;
cbzp = cp2;
cp = cp3;
Advance (svg, ref pos);
}
qbz = false;
break;
case 'v':
relative = true;
goto case 'V';
case 'V':
float y = GetFloat (svg, ref pos);
if (relative)
y += cp.Y;
cp = new PointF (cp.X, y);
formatter.LineTo (cp);
cbz = qbz = false;
break;
case 'z':
case 'Z':
formatter.ClosePath ();
formatter.MoveTo (start);
cp = start;
cbz = qbz = false;
break;
default:
throw new FormatException (c.ToString ());
}
}
formatter.Epilogue ();
}
}
}
// Relevant interface definitions :ISourceFormatter.cs
// Authors:
// Sebastien Pouliot <[email protected]>
//
// Copyright 2012 Xamarin Inc.
//
// Licensed under the GNU LGPL 2 license only (no "later versions")
using System;
using System.Drawing;
namespace Poupou.SvgPathConverter {
public interface ISourceFormatter {
void Prologue (string name);
void Epilogue ();
void MoveTo (PointF pt);
void LineTo (PointF pt);
void QuadCurveTo (PointF pt1, PointF pt2);
void CurveTo (PointF pt1, PointF pt2, PointF pt3);
void ArcTo (PointF size, float angle, bool isLarge, bool sweep, PointF ep, PointF sp);
void ClosePath ();
}
}
// Auxiliary class :FormatterRocks.cs
// Authors:
// Sebastien Pouliot <[email protected]>
//
// Copyright 2012 Xamarin Inc.
//
// This file is mostly based on the C++ code from once magnificent Moonlight
// https://github.com/mono/moon/blob/master/src/moon-path.cpp
// Copyright 2007-2008 Novell, Inc. (http://www.novell.com)
//
// Licensed under the GNU LGPL 2 license only (no "later versions")
using System;
using System.Drawing;
using System.IO;
namespace Poupou.SvgPathConverter {
public static class FormatterRocks {
static bool IsNearZero (float value)
{
return Math.Abs (value) < 0.000019;
}
// The SVG Arc is a bit more complex than others - and also quite different than many existing API
// This implementation will use a ISourceFormatter's CurveTo method to draw the arc
public static void ArcHelper (this ISourceFormatter formatter, PointF size, float anglef,
bool isLarge, bool sweep, PointF endPoint, PointF startPoint)
{
if (IsNearZero (endPoint.X - startPoint.X) && IsNearZero (endPoint.Y - startPoint.Y))
return;
// Correction of out-of-range radii, see F6.6 (step 1)
if (IsNearZero (size.X) || IsNearZero (size.Y)) {
// treat this as a straight line (to end point)
formatter.LineTo (endPoint);
return;
}
// Correction of out-of-range radii, see F6.6.1 (step 2)
float rx = Math.Abs (size.X);
float ry = Math.Abs (size.Y);
// convert angle into radians
double angle = anglef * Math.PI / 180.0f;
// variables required for F6.3.1
double cos_phi = Math.Cos (angle);
double sin_phi = Math.Sin (angle);
double dx2 = (startPoint.X - endPoint.X) / 2.0;
double dy2 = (startPoint.Y - endPoint.Y) / 2.0;
double x1p = cos_phi * dx2 + sin_phi * dy2;
double y1p = cos_phi * dy2 - sin_phi * dx2;
double x1p2 = x1p * x1p;
double y1p2 = y1p * y1p;
float rx2 = rx * rx;
float ry2 = ry * ry;
// Correction of out-of-range radii, see F6.6.2 (step 4)
double lambda = (x1p2 / rx2) + (y1p2 / ry2);
if (lambda > 1.0) {
// see F6.6.3
float lambda_root = (float) Math.Sqrt (lambda);
rx *= lambda_root;
ry *= lambda_root;
// update rx2 and ry2
rx2 = rx * rx;
ry2 = ry * ry;
}
double cxp, cyp, cx, cy;
double c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2);
// check if there is no possible solution (i.e. we can't do a square root of a negative value)
if (c < 0.0) {
// scale uniformly until we have a single solution (see F6.2) i.e. when c == 0.0
float scale = (float) Math.Sqrt (1.0 - c / (rx2 * ry2));
rx *= scale;
ry *= scale;
// update rx2 and ry2
rx2 = rx * rx;
ry2 = ry * ry;
// step 2 (F6.5.2) - simplified since c == 0.0
cxp = 0.0;
cyp = 0.0;
// step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0
cx = 0.0;
cy = 0.0;
} else {
// complete c calculation
c = Math.Sqrt (c / ((rx2 * y1p2) + (ry2 * x1p2)));
// inverse sign if Fa == Fs
if (isLarge == sweep)
c = -c;
// step 2 (F6.5.2)
cxp = c * ( rx * y1p / ry);
cyp = c * (-ry * x1p / rx);
// step 3 (F6.5.3 first part)
cx = cos_phi * cxp - sin_phi * cyp;
cy = sin_phi * cxp + cos_phi * cyp;
}
// step 3 (F6.5.3 second part) we now have the center point of the ellipse
cx += (startPoint.X + endPoint.X) / 2.0;
cy += (startPoint.Y + endPoint.Y) / 2.0;
// step 4 (F6.5.4)
// we dont' use arccos (as per w3c doc), see http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
// note: atan2 (0.0, 1.0) == 0.0
double at = Math.Atan2 (((y1p - cyp) / ry), ((x1p - cxp) / rx));
double theta1 = (at < 0.0) ? 2.0 * Math.PI + at : at;
double nat = Math.Atan2 (((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
double delta_theta = (nat < at) ? 2.0 * Math.PI - at + nat : nat - at;
if (sweep) {
// ensure delta theta < 0 or else add 360 degrees
if (delta_theta < 0.0)
delta_theta += 2.0 * Math.PI;
} else {
// ensure delta theta > 0 or else substract 360 degrees
if (delta_theta > 0.0)
delta_theta -= 2.0 * Math.PI;
}
// add several cubic bezier to approximate the arc (smaller than 90 degrees)
// we add one extra segment because we want something smaller than 90deg (i.e. not 90 itself)
int segments = (int) (Math.Abs (delta_theta / Math.PI)) + 1;
double delta = delta_theta / segments;
// http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13)
float bcp = (float) (4.0 / 3 * (1 - Math.Cos (delta / 2)) / Math.Sin (delta / 2));
double cos_phi_rx = cos_phi * rx;
double cos_phi_ry = cos_phi * ry;
double sin_phi_rx = sin_phi * rx;
double sin_phi_ry = sin_phi * ry;
double cos_theta1 = Math.Cos (theta1);
double sin_theta1 = Math.Sin (theta1);
PointF c1, c2;
int i;
for (i = 0; i < segments; ++i) {
// end angle (for this segment) = current + delta
double theta2 = theta1 + delta;
double cos_theta2 = Math.Cos (theta2);
double sin_theta2 = Math.Sin (theta2);
// first control point (based on start point sx,sy)
c1.X = startPoint.X - bcp * (float) (cos_phi_rx * sin_theta1 + sin_phi_ry * cos_theta1);
c1.Y = startPoint.Y + bcp * (float) (cos_phi_ry * cos_theta1 - sin_phi_rx * sin_theta1);
// end point (for this segment)
endPoint.X = (float) (cx + (cos_phi_rx * cos_theta2 - sin_phi_ry * sin_theta2));
endPoint.Y = (float) (cy + (sin_phi_rx * cos_theta2 + cos_phi_ry * sin_theta2));
// second control point (based on end point ex,ey)
c2.X = endPoint.X + bcp * (float) (cos_phi_rx * sin_theta2 + sin_phi_ry * cos_theta2);
c2.Y = endPoint.Y + bcp * (float) (sin_phi_rx * sin_theta2 - cos_phi_ry * cos_theta2);
formatter.CurveTo (c1, c2, endPoint);
// next start point is the current end point (same for angle)
startPoint = endPoint;
theta1 = theta2;
// avoid recomputations
cos_theta1 = cos_theta2;
sin_theta1 = sin_theta2;
}
}
}
}
// Derived from interface CSharpCoreGraphicsFormatter.cs
// Authors:
// Sebastien Pouliot <[email protected]>
//
// Copyright 2012-2013 Xamarin Inc.
//
// Licensed under the GNU LGPL 2 license only (no "later versions")
using System;
using System.Drawing;
using System.Globalization;
using System.IO;
namespace Poupou.SvgPathConverter {
public class CSharpCoreGraphicsFormatter : ISourceFormatter {
TextWriter writer;
public CSharpCoreGraphicsFormatter (TextWriter textWriter)
{
writer = textWriter;
}
public void Prologue (string name)
{
writer.WriteLine ("\tstatic void {0} (CGContext c)", name);
writer.WriteLine ("\t{");
}
public void Epilogue ()
{
writer.WriteLine ("\t\tc.FillPath ();");
writer.WriteLine ("\t\tc.StrokePath ();");
writer.WriteLine ("\t}");
writer.WriteLine ();
}
public void MoveTo (PointF pt)
{
writer.WriteLine ("\t\tc.MoveTo ({0}f, {1}f);", pt.X.ToString (CultureInfo.InvariantCulture),
pt.Y.ToString (CultureInfo.InvariantCulture));
}
public void LineTo (PointF pt)
{
writer.WriteLine ("\t\tc.AddLineToPoint ({0}f, {1}f);", pt.X.ToString (CultureInfo.InvariantCulture),
pt.Y.ToString (CultureInfo.InvariantCulture));
}
public void ClosePath ()
{
writer.WriteLine ("\t\tc.ClosePath ();");
}
public void QuadCurveTo (PointF pt1, PointF pt2)
{
writer.WriteLine ("\t\tc.AddQuadCurveToPoint ({0}f, {1}f, {2}f, {3}f);",
pt1.X.ToString (CultureInfo.InvariantCulture), pt1.Y.ToString (CultureInfo.InvariantCulture),
pt2.X.ToString (CultureInfo.InvariantCulture), pt2.Y.ToString (CultureInfo.InvariantCulture));
}
public void CurveTo (PointF pt1, PointF pt2, PointF pt3)
{
writer.WriteLine ("\t\tc.AddCurveToPoint ({0}f, {1}f, {2}f, {3}f, {4}f, {5}f);",
pt1.X.ToString (CultureInfo.InvariantCulture), pt1.Y.ToString (CultureInfo.InvariantCulture),
pt2.X.ToString (CultureInfo.InvariantCulture), pt2.Y.ToString (CultureInfo.InvariantCulture),
pt3.X.ToString (CultureInfo.InvariantCulture), pt3.Y.ToString (CultureInfo.InvariantCulture));
}
public void ArcTo (PointF size, float angle, bool isLarge, bool sweep, PointF endPoint, PointF startPoint)
{
this.ArcHelper (size, angle, isLarge, sweep, endPoint, startPoint);
}
}
}
版权声明
本文为[Dake mountain man]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230625378796.html
边栏推荐
猜你喜欢

将指定路径下的所有SVG文件导出成PNG等格式的图片(缩略图或原图大小)

'NPM' is not an internal or external command, nor is it a runnable program or batch file

设置了body的最大宽度,但是为什么body的背景颜色还铺满整个页面?

int a = 1存放在哪

SAP DEBUG调试FOR IN、REDUCE等复杂的语句

MySQL in window10 version does not work after setting remote access permission

Mongodb 启动警告信息处理

Scrapy 修改爬虫结束时统计数据中的时间为当前系统时间

Robust and Efficient Quadrotor Trajectory Generation for Fast Autonomous Flight

Dropping Pixels for Adversarial Robustness
随机推荐
Use of typescript dictionary
平面定义-平面方程
大学学习路线规划建议贴
SAP PI/PO登录使用及基本功能简介
事件系统(二)多播事件
Ogldev reading notes
Game assisted script development journey
SampleCameraFilter
FUEL: Fast UAV Exploration using Incremental Frontier Structure and Hierarchical Planning
面经的总结
Super classic & Programming Guide (red and blue book) - Reading Notes
Window10版MySQL设置远程访问权限后不起效果
取得所有点列表中的最大值GetMaxPoint
Scrapy 修改爬虫结束时统计数据中的时间为当前系统时间
Scrapy modifies the time in the statistics at the end of the crawler as the current system time
Thorough inquiry -- understanding and analysis of cocos2d source code
Unable to process jar entry [module info. Class]
【NLP笔记】CRF原理初探
C operation registry full introduction
js中对象的三种创建方式