SVGGraphicsPath.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.Profiling;
  4. public enum SVGFillRule : ushort {
  5. NoneZero = 0,
  6. EvenOdd = 1
  7. }
  8. // TODO: Find a way to break this the hell up.
  9. // TODO: Normalize conventions away from Java-style SetX to properties.
  10. public class SVGGraphicsPath {
  11. private Vector2 beginPoint;
  12. private Vector2 boundUL, boundBR;
  13. private bool needSetFirstPoint;
  14. private Matrix2x3 _matrixTransform;
  15. private readonly List<ISVGPathSegment> listObject = new List<ISVGPathSegment>();
  16. public SVGFillRule fillRule = SVGFillRule.NoneZero;
  17. public Matrix2x3 matrixTransform {
  18. get {
  19. if(_matrixTransform == null)
  20. _matrixTransform = transformList.Consolidate().matrix;
  21. return _matrixTransform;
  22. }
  23. }
  24. public float transformAngle {
  25. get {
  26. float angle = 0.0f;
  27. for(int i = 0; i < transformList.Count; ++i) {
  28. SVGTransform temp = transformList[i];
  29. if(temp.type == SVGTransformMode.Rotate)
  30. angle += temp.angle;
  31. }
  32. return angle;
  33. }
  34. }
  35. public SVGTransformList transformList { get; set; }
  36. public SVGGraphicsPath() {
  37. beginPoint = new Vector2(0f, 0f);
  38. needSetFirstPoint = true;
  39. boundUL = new Vector2(+10000f, +10000f);
  40. boundBR = new Vector2(-10000f, -10000f);
  41. transformList = new SVGTransformList();
  42. }
  43. public void Reset() {
  44. beginPoint = new Vector2(0f, 0f);
  45. needSetFirstPoint = true;
  46. boundUL = new Vector2(+10000f, +10000f);
  47. boundBR = new Vector2(-10000f, -10000f);
  48. fillRule = SVGFillRule.NoneZero;
  49. transformList.Clear();
  50. listObject.Clear();
  51. }
  52. public void ExpandBounds(float x, float y) {
  53. if(x < boundUL.x)
  54. boundUL.x = x;
  55. if(y < boundUL.y)
  56. boundUL.y = y;
  57. if(x > boundBR.x)
  58. boundBR.x = x;
  59. if(y > boundBR.y)
  60. boundBR.y = y;
  61. }
  62. private void ExpandBounds(float x, float y, float dx, float dy) {
  63. if((x - dx) < boundUL.x)
  64. boundUL.x = x - dx;
  65. if((y - dy) < boundUL.y)
  66. boundUL.y = y - dy;
  67. if((x + dx) > boundBR.x)
  68. boundBR.x = x + dx;
  69. if((y + dy) > boundBR.y)
  70. boundBR.y = y + dy;
  71. }
  72. public void ExpandBounds(Vector2 point) {
  73. ExpandBounds(point.x, point.y);
  74. }
  75. public void ExpandBounds(Vector2 point, float deltax, float deltay) {
  76. ExpandBounds(point.x, point.y, deltax, deltay);
  77. }
  78. public void ExpandBounds(List<Vector2> points) {
  79. int length = points.Count;
  80. for(int i = 0; i < length; i++)
  81. ExpandBounds(points[i]);
  82. }
  83. private void SetFirstPoint(Vector2 p) {
  84. if(needSetFirstPoint) {
  85. beginPoint = p;
  86. needSetFirstPoint = false;
  87. }
  88. }
  89. public void Add(SVGPolygonElement polygonElement) {
  90. SetFirstPoint(polygonElement.listPoints[0]);
  91. listObject.Add(new SVGGPolygon(polygonElement.listPoints));
  92. }
  93. public void Add(SVGPolylineElement polylineElement) {
  94. SetFirstPoint(polylineElement.listPoints[0]);
  95. listObject.Add(new SVGGPolyLine(polylineElement.listPoints));
  96. }
  97. public void Add(SVGRectElement rectElement) {
  98. SVGGRect rect = new SVGGRect(rectElement.x.value, rectElement.y.value, rectElement.width.value,
  99. rectElement.height.value, rectElement.rx.value, rectElement.ry.value);
  100. SetFirstPoint(new Vector2(rect.x, rect.y));
  101. listObject.Add(rect);
  102. }
  103. public void Add(SVGCircleElement circleElement) {
  104. Vector2 p = new Vector2(circleElement.cx.value, circleElement.cy.value);
  105. SetFirstPoint(p);
  106. listObject.Add(new SVGGCircle(p, circleElement.r.value));
  107. }
  108. public void Add(SVGEllipseElement ellipseElement) {
  109. Vector2 p = new Vector2(ellipseElement.cx.value, ellipseElement.cy.value);
  110. SetFirstPoint(p);
  111. listObject.Add(new SVGGEllipse(p, ellipseElement.rx.value, ellipseElement.ry.value, 0));
  112. }
  113. public void AddCircleTo(Vector2 p, float r) {
  114. listObject.Add(new SVGGCircle(p, r));
  115. }
  116. public void AddEllipseTo(Vector2 p, float r1, float r2, float angle) {
  117. listObject.Add(new SVGGEllipse(p, r1, r2, angle));
  118. }
  119. public void AddMoveTo(Vector2 p) {
  120. SetFirstPoint(p);
  121. listObject.Add(new SVGGMoveTo(p));
  122. }
  123. public void AddArcTo(float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, Vector2 p) {
  124. SVGGArcAbs svgGArcAbs = new SVGGArcAbs(r1, r2, angle, largeArcFlag, sweepFlag, p);
  125. listObject.Add(svgGArcAbs);
  126. }
  127. public void AddCubicCurveTo(Vector2 p1, Vector2 p2, Vector2 p) {
  128. SVGGCubicAbs svgGCubicAbs = new SVGGCubicAbs(p1, p2, p);
  129. listObject.Add(svgGCubicAbs);
  130. }
  131. public void AddQuadraticCurveTo(Vector2 p1, Vector2 p) {
  132. SVGGQuadraticAbs svgGQuadraticAbs = new SVGGQuadraticAbs(p1, p);
  133. listObject.Add(svgGQuadraticAbs);
  134. }
  135. public void AddLineTo(Vector2 p) {
  136. listObject.Add(new SVGGLineTo(p));
  137. }
  138. public Rect GetBound() {
  139. Profiler.BeginSample("SVGGraphicsPath.GetBound");
  140. for(int i = 0; i < listObject.Count; ++i) {
  141. ISVGPathSegment seg = listObject[i];
  142. seg.ExpandBounds(this);
  143. }
  144. Rect tmp = new Rect(boundUL.x - 1, boundUL.y - 1, boundBR.x - boundUL.x + 2, boundBR.y - boundUL.y + 2);
  145. Profiler.EndSample();
  146. return tmp;
  147. }
  148. public void RenderPath(ISVGPathDraw pathDraw, bool isClose) {
  149. Profiler.BeginSample("SVGGraphicsPath.RenderPath");
  150. isClose = !isClose;
  151. Profiler.BeginSample("SVGGraphicsPath.RenderPath[for...]");
  152. for(int i = 0; i < listObject.Count; i++) {
  153. Profiler.BeginSample("SVGGraphicsPath.RenderPath[...each]");
  154. ISVGPathSegment seg = listObject[i];
  155. isClose = seg.Render(this, pathDraw) || isClose;
  156. Profiler.EndSample();
  157. }
  158. Profiler.EndSample();
  159. if(!isClose) {
  160. Profiler.BeginSample("SVGPathSegment.Render[LineTo]");
  161. pathDraw.LineTo(matrixTransform.Transform(beginPoint));
  162. Profiler.EndSample();
  163. }
  164. Profiler.EndSample();
  165. }
  166. }