当前位置:网站首页>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
边栏推荐
猜你喜欢

Apache Hudi 如何加速传统的批处理模式?

Mongodb 启动警告信息处理

SQL针对字符串型数字进行排序

Shapley Explanation Networks

【NLP笔记】CRF原理初探

平面定义-平面方程

SAP pi / PO rfc2soap publishes RFC interface as WS example

Scrapy modifies the time in the statistics at the end of the crawler as the current system time

Mongodb starts warning information processing

基于NLP的软件安全研究(二)
随机推荐
系统与软件安全研究(一)
05数组的使用
js之排他思想及案例
Hot change scheme and dynamic update strategy of mobile game
IDEA快捷键
利用Lambda表达式解决c#文件名排序问题(是100大还是11大的问题)
Unity screen adaptation
unity UGUI判断点击在UI上和3D物体上的解决方案
定位、修饰样式
C#使用拉依达准则(3σ准则)剔除异常数据(.Net剔除一组数据中的奇异值)
Install and configure Taobao image NPM (cnpm)
Understanding the Role of Individual Units in a Deep Neural Networks(了解各个卷积核在神经网络中的作用)
Event system (II) multicast events
Redis connection error err auth < password > called without any password configured for the default user
移动端布局(3D转换、动画)
NodeJS(一) 事件驱动编程
js之自定义属性以及H5中如何判断自定义属性
Date object (JS built-in object)
ABAP 从CDS VIEW 发布OData Service示例
C operation registry full introduction