SVGGraphicsStroke.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.Profiling;
  4. // TODO: Find a way to break this the hell up.
  5. // TODO: Normalize conventions away from Java-style SetX to properties.
  6. public class SVGGraphicsStroke : ISVGPathDraw {
  7. private SVGGraphics _graphics;
  8. private SVGBasicDraw _basicDraw;
  9. private float _width;
  10. private bool isUseWidth = false;
  11. public SVGGraphicsStroke(SVGGraphics graphics) {
  12. _graphics = graphics;
  13. _basicDraw = new SVGBasicDraw();
  14. _basicDraw.SetPixelMethod = new SetPixelDelegate(SetPixel);
  15. }
  16. private void SetPixel(int x, int y) {
  17. _graphics.SetPixel(x, y);
  18. }
  19. //Ve Line Cap, dau cuoi Left
  20. private static Vector2[] rect_points = new Vector2[4];
  21. private void StrokeLineCapLeft(Vector2 p1, Vector2 p2, float width) {
  22. if((int)width == 1)
  23. return;
  24. if((_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Unknown) ||
  25. (_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Butt))
  26. return;
  27. if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
  28. return;
  29. if(_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Round) {
  30. _graphics.FillCircle(p1, width / 2f);
  31. return;
  32. }
  33. Vector2 _p1 = Vector2.zero;
  34. Vector2 _p2 = Vector2.zero;
  35. Vector2 _p3 = Vector2.zero;
  36. Vector2 _p4 = Vector2.zero;
  37. _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);
  38. Vector2 t_p1 = Vector2.zero;
  39. Vector2 t_p2 = Vector2.zero;
  40. Vector2 t_p3 = Vector2.zero;
  41. Vector2 t_p4 = Vector2.zero;
  42. _graphics.GetThickLine(_p2, _p1, width, ref t_p1, ref t_p2, ref t_p3, ref t_p4);
  43. rect_points[0] = t_p1;
  44. rect_points[1] = _p2;
  45. rect_points[2] = _p1;
  46. rect_points[3] = t_p3;
  47. _graphics.FillPolygon(rect_points);
  48. }
  49. //Ve Line Cap, dau cuoi Right
  50. private void StrokeLineCapRight(Vector2 p1, Vector2 p2, float width) {
  51. if((int)width == 1)
  52. return;
  53. if((_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Unknown) ||
  54. (_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Butt))
  55. return;
  56. if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
  57. return;
  58. if(_graphics.StrokeLineCap == SVGStrokeLineCapMethod.Round) {
  59. _graphics.FillCircle(p2, width / 2f);
  60. return;
  61. }
  62. Vector2 _p1 = Vector2.zero;
  63. Vector2 _p2 = Vector2.zero;
  64. Vector2 _p3 = Vector2.zero;
  65. Vector2 _p4 = Vector2.zero;
  66. _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);
  67. Vector2 t_p1 = Vector2.zero;
  68. Vector2 t_p2 = Vector2.zero;
  69. Vector2 t_p3 = Vector2.zero;
  70. Vector2 t_p4 = Vector2.zero;
  71. _graphics.GetThickLine(_p4, _p3, width, ref t_p1, ref t_p2, ref t_p3, ref t_p4);
  72. rect_points[0] = _p4;
  73. rect_points[1] = t_p2;
  74. rect_points[2] = t_p4;
  75. rect_points[3] = _p3;
  76. _graphics.FillPolygon(rect_points);
  77. }
  78. private static Vector2[] joint_points = new Vector2[8],
  79. joint_points_small = new Vector2[6];
  80. private void StrokeLineJoin(Vector2 p1, Vector2 p2, Vector2 p3, float width) {
  81. if((int)width == 1)
  82. return;
  83. if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
  84. return;
  85. if(_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Round) {
  86. _graphics.FillCircle(p2, width / 2f);
  87. return;
  88. }
  89. if((_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Miter) ||
  90. (_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Unknown)) {
  91. Vector2 _p1 = Vector2.zero;
  92. Vector2 _p2 = Vector2.zero;
  93. Vector2 _p3 = Vector2.zero;
  94. Vector2 _p4 = Vector2.zero;
  95. _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);
  96. Vector2 _p5 = Vector2.zero;
  97. Vector2 _p6 = Vector2.zero;
  98. Vector2 _p7 = Vector2.zero;
  99. Vector2 _p8 = Vector2.zero;
  100. _graphics.GetThickLine(p2, p3, width, ref _p5, ref _p6, ref _p7, ref _p8);
  101. Vector2 _cp1, _cp2;
  102. _cp1 = _graphics.GetCrossPoint(_p1, _p3, _p5, _p7);
  103. _cp2 = _graphics.GetCrossPoint(_p2, _p4, _p6, _p8);
  104. //Vector2[] points = new Vector2[8];
  105. joint_points[0] = p2;
  106. joint_points[1] = _p3;
  107. joint_points[2] = _cp1;
  108. joint_points[3] = _p5;
  109. joint_points[4] = p2;
  110. joint_points[5] = _p6;
  111. joint_points[6] = _cp2;
  112. joint_points[7] = _p4;
  113. _graphics.FillPolygon(joint_points);
  114. return;
  115. }
  116. if(_graphics.StrokeLineJoin == SVGStrokeLineJoinMethod.Bevel) {
  117. Vector2 _p1 = Vector2.zero;
  118. Vector2 _p2 = Vector2.zero;
  119. Vector2 _p3 = Vector2.zero;
  120. Vector2 _p4 = Vector2.zero;
  121. _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);
  122. Vector2 _p5 = Vector2.zero;
  123. Vector2 _p6 = Vector2.zero;
  124. Vector2 _p7 = Vector2.zero;
  125. Vector2 _p8 = Vector2.zero;
  126. _graphics.GetThickLine(p2, p3, width, ref _p5, ref _p6, ref _p7, ref _p8);
  127. joint_points_small[0] = p2;
  128. joint_points_small[1] = _p3;
  129. joint_points_small[2] = _p5;
  130. joint_points_small[3] = p2;
  131. joint_points_small[4] = _p6;
  132. joint_points_small[5] = _p4;
  133. _graphics.FillPolygon(joint_points_small);
  134. return;
  135. }
  136. }
  137. public void MoveTo(Vector2 p) {
  138. _basicDraw.MoveTo(p);
  139. }
  140. public void CircleTo(Vector2 p, float r) {
  141. if((isUseWidth) && ((int)_width > 1)) {
  142. CircleTo(p, r, _width);
  143. return;
  144. }
  145. Circle(p, r);
  146. }
  147. // TODO: Kill this method.
  148. public void CircleTo(Vector2 p, float r, float width) {
  149. Circle(p, r, width);
  150. }
  151. public void EllipseTo(Vector2 p, float r1, float r2, float angle) {
  152. if((isUseWidth) && ((int)_width > 1)) {
  153. EllipseTo(p, r1, r2, angle, _width);
  154. return;
  155. }
  156. Ellipse(p, r1, r2, angle);
  157. }
  158. public void EllipseTo(Vector2 p, float r1, float r2, float angle, float width) {
  159. Ellipse(p, r1, r2, angle, width);
  160. }
  161. public void ArcTo(float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, Vector2 p) {
  162. if((isUseWidth) && ((int)_width > 1))
  163. ArcTo(r1, r2, angle, largeArcFlag, sweepFlag, p, _width);
  164. else
  165. _basicDraw.ArcTo(r1, r2, angle, largeArcFlag, sweepFlag, p);
  166. }
  167. public void ArcTo(float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, Vector2 p, float width) {
  168. Profiler.BeginSample("SVGGraphicsStroke.ArcTo");
  169. float rx = r1, ry = r2;
  170. Vector2 p1 = _basicDraw.currentPoint, p2 = p;
  171. float _radian = (angle * Mathf.PI / 180.0f);
  172. // TODO: Do we have single-precision methods we can use here? How's the performance?
  173. float _CosRadian = (float)Math.Cos(_radian);
  174. float _SinRadian = (float)Math.Sin(_radian);
  175. float temp1 = (p1.x - p2.x) / 2.0f;
  176. float temp2 = (p1.y - p2.y) / 2.0f;
  177. float tx = (_CosRadian * temp1) + (_SinRadian * temp2);
  178. float ty = (-_SinRadian * temp1) + (_CosRadian * temp2);
  179. double trx2 = rx * rx;
  180. double try2 = ry * ry;
  181. double tx2 = tx * tx;
  182. double ty2 = ty * ty;
  183. double radiiCheck = tx2 / trx2 + ty2 / try2;
  184. if(radiiCheck > 1) {
  185. rx = (float)Math.Sqrt((float)radiiCheck) * rx;
  186. ry = (float)Math.Sqrt((float)radiiCheck) * ry;
  187. trx2 = rx * rx;
  188. try2 = ry * ry;
  189. }
  190. double tm1 = (trx2 * try2 - trx2 * ty2 - try2 * tx2) / (trx2 * ty2 + try2 * tx2);
  191. tm1 = (tm1 < 0) ? 0 : tm1;
  192. float tm2 = (largeArcFlag == sweepFlag) ? -(float)Math.Sqrt((float)tm1) : (float)Math.Sqrt((float)tm1);
  193. float tcx = tm2 * ((rx * ty) / ry);
  194. float tcy = tm2 * (-(ry * tx) / rx);
  195. float cx = _CosRadian * tcx - _SinRadian * tcy + ((p1.x + p2.x) / 2.0f);
  196. float cy = _SinRadian * tcx + _CosRadian * tcy + ((p1.y + p2.y) / 2.0f);
  197. float ux = (tx - tcx) / rx;
  198. float uy = (ty - tcy) / ry;
  199. float vx = (-tx - tcx) / rx;
  200. float vy = (-ty - tcy) / ry;
  201. float tp, n;
  202. n = (float)Math.Sqrt((ux * ux) + (uy * uy));
  203. tp = ux;
  204. float _angle = (uy < 0) ? -(float)Math.Acos(tp / n) : (float)Math.Acos(tp / n);
  205. _angle = _angle * 180.0f / Mathf.PI;
  206. _angle %= 360f;
  207. n = (float)Math.Sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
  208. tp = ux * vx + uy * vy;
  209. float _delta = (ux * vy - uy * vx < 0) ? -(float)Math.Acos(tp / n) : (float)Math.Acos(tp / n);
  210. _delta = _delta * 180.0f / Mathf.PI;
  211. if(!sweepFlag && _delta > 0)
  212. _delta -= 360f;
  213. else if(sweepFlag && _delta < 0)
  214. _delta += 360f;
  215. _delta %= 360f;
  216. int number = 50;
  217. float deltaT = _delta / number;
  218. //---Get Control Point
  219. Vector2 _controlPoint1 = Vector2.zero;
  220. Vector2 _controlPoint2 = Vector2.zero;
  221. for(int i = 0; i <= number; i++) {
  222. float t_angle = (deltaT * i + _angle) * Mathf.PI / 180.0f;
  223. _controlPoint1.x = _CosRadian * rx * (float)Math.Cos(t_angle) - _SinRadian * ry * (float)Math.Sin(t_angle) + cx;
  224. _controlPoint1.y = _SinRadian * rx * (float)Math.Cos(t_angle) + _CosRadian * ry * (float)Math.Sin(t_angle) + cy;
  225. if((_controlPoint1.x != p1.x) && (_controlPoint1.y != p1.y))
  226. i = number + 1;
  227. }
  228. for(int i = number; i >= 0; i--) {
  229. float t_angle = (deltaT * i + _angle) * Mathf.PI / 180.0f;
  230. _controlPoint2.x = _CosRadian * rx * (float)Math.Cos(t_angle) - _SinRadian * ry * (float)Math.Sin(t_angle) + cx;
  231. _controlPoint2.y = _SinRadian * rx * (float)Math.Cos(t_angle) + _CosRadian * ry * (float)Math.Sin(t_angle) + cy;
  232. if((_controlPoint2.x != p2.x) && (_controlPoint2.y != p2.y))
  233. i = -1;
  234. }
  235. //-----
  236. Vector2 _p1 = Vector2.zero;
  237. Vector2 _p2 = Vector2.zero;
  238. Vector2 _p3 = Vector2.zero;
  239. Vector2 _p4 = Vector2.zero;
  240. _graphics.GetThickLine(p1, _controlPoint1, width, ref _p1, ref _p2, ref _p3, ref _p4);
  241. Vector2 _p5 = Vector2.zero;
  242. Vector2 _p6 = Vector2.zero;
  243. Vector2 _p7 = Vector2.zero;
  244. Vector2 _p8 = Vector2.zero;
  245. _graphics.GetThickLine(_controlPoint2, p2, width, ref _p5, ref _p6, ref _p7, ref _p8);
  246. float _half = width / 2f;
  247. float _ihalf1 = _half;
  248. float _ihalf2 = width - _ihalf1 + 0.5f;
  249. //-----
  250. float t_len1 = (_p1.x - cx) * (_p1.x - cx) + (_p1.y - cy) * (_p1.y - cy);
  251. float t_len2 = (_p2.x - cx) * (_p2.x - cx) + (_p2.y - cy) * (_p2.y - cy);
  252. Vector2 tempPoint;
  253. if(t_len1 > t_len2) {
  254. tempPoint = _p1;
  255. _p1 = _p2;
  256. _p2 = tempPoint;
  257. }
  258. t_len1 = (_p7.x - cx) * (_p7.x - cx) + (_p7.y - cy) * (_p7.y - cy);
  259. t_len2 = (_p8.x - cx) * (_p8.x - cx) + (_p8.y - cy) * (_p8.y - cy);
  260. if(t_len1 > t_len2) {
  261. tempPoint = _p7;
  262. _p7 = _p8;
  263. _p8 = tempPoint;
  264. }
  265. Profiler.BeginSample("SVGGraphicsStroke.ArcTo[CreateGraphicsPath]");
  266. SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
  267. _graphicsPath.AddMoveTo(_p2);
  268. _graphicsPath.AddArcTo(r1 + _ihalf1, r2 + _ihalf1, angle, largeArcFlag, sweepFlag, _p8);
  269. _graphicsPath.AddLineTo(_p7);
  270. _graphicsPath.AddArcTo(r1 - _ihalf2, r2 - _ihalf2, angle, largeArcFlag, !sweepFlag, _p1);
  271. _graphicsPath.AddLineTo(_p2);
  272. Profiler.EndSample();
  273. Profiler.BeginSample("SVGGraphicsStroke.ArcTo[FillPath]");
  274. _graphics.FillPath(_graphicsPath);
  275. Profiler.EndSample();
  276. MoveTo(p);
  277. Profiler.EndSample();
  278. }
  279. public void CubicCurveTo(Vector2 p1, Vector2 p2, Vector2 p) {
  280. if((isUseWidth) && ((int)_width > 1)) {
  281. CubicCurveTo(p1, p2, p, _width);
  282. return;
  283. }
  284. _basicDraw.CubicCurveTo(p1, p2, p);
  285. }
  286. public void CubicCurveTo(Vector2 p1, Vector2 p2, Vector2 p, float width) {
  287. Vector2 _point = Vector2.zero;
  288. _point = _basicDraw.currentPoint;
  289. Vector2 _p1 = Vector2.zero;
  290. Vector2 _p2 = Vector2.zero;
  291. Vector2 _p3 = Vector2.zero;
  292. Vector2 _p4 = Vector2.zero;
  293. bool temp;
  294. temp = _graphics.GetThickLine(_point, p1, width, ref _p1, ref _p2, ref _p3, ref _p4);
  295. if(temp == false) {
  296. QuadraticCurveTo(p2, p, width);
  297. return;
  298. }
  299. Vector2 _p5 = Vector2.zero;
  300. Vector2 _p6 = Vector2.zero;
  301. Vector2 _p7 = Vector2.zero;
  302. Vector2 _p8 = Vector2.zero;
  303. _graphics.GetThickLine(p1, p2, width, ref _p5, ref _p6, ref _p7, ref _p8);
  304. Vector2 _p9 = Vector2.zero;
  305. Vector2 _p10 = Vector2.zero;
  306. Vector2 _p11 = Vector2.zero;
  307. Vector2 _p12 = Vector2.zero;
  308. _graphics.GetThickLine(p2, p, width, ref _p9, ref _p10, ref _p11, ref _p12);
  309. Vector2 _cp1, _cp2, _cp3, _cp4;
  310. _cp1 = _graphics.GetCrossPoint(_p1, _p3, _p5, _p7);
  311. _cp2 = _graphics.GetCrossPoint(_p2, _p4, _p6, _p8);
  312. _cp3 = _graphics.GetCrossPoint(_p5, _p7, _p9, _p11);
  313. _cp4 = _graphics.GetCrossPoint(_p6, _p8, _p10, _p12);
  314. _basicDraw.MoveTo(_point);
  315. _basicDraw.CubicCurveTo(p1, p2, p);
  316. SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
  317. _graphicsPath.AddMoveTo(_p2);
  318. _graphicsPath.AddCubicCurveTo(_cp2, _cp4, _p12);
  319. _graphicsPath.AddLineTo(_p11);
  320. _graphicsPath.AddCubicCurveTo(_cp3, _cp1, _p1);
  321. _graphicsPath.AddLineTo(_p2);
  322. _graphics.FillPath(_graphicsPath);
  323. MoveTo(p);
  324. }
  325. public void QuadraticCurveTo(Vector2 p1, Vector2 p) {
  326. if((isUseWidth) && ((int)_width > 1)) {
  327. QuadraticCurveTo(p1, p, _width);
  328. return;
  329. }
  330. _basicDraw.QuadraticCurveTo(p1, p);
  331. }
  332. public void QuadraticCurveTo(Vector2 p1, Vector2 p, float width) {
  333. Vector2 _point = Vector2.zero;
  334. _point = _basicDraw.currentPoint;
  335. Vector2 _p1 = Vector2.zero;
  336. Vector2 _p2 = Vector2.zero;
  337. Vector2 _p3 = Vector2.zero;
  338. Vector2 _p4 = Vector2.zero;
  339. _graphics.GetThickLine(_point, p1, width, ref _p1, ref _p2, ref _p3, ref _p4);
  340. Vector2 _p5 = Vector2.zero;
  341. Vector2 _p6 = Vector2.zero;
  342. Vector2 _p7 = Vector2.zero;
  343. Vector2 _p8 = Vector2.zero;
  344. _graphics.GetThickLine(p1, p, width, ref _p5, ref _p6, ref _p7, ref _p8);
  345. Vector2 _cp1, _cp2;
  346. _cp1 = _graphics.GetCrossPoint(_p1, _p3, _p5, _p7);
  347. _cp2 = _graphics.GetCrossPoint(_p2, _p4, _p6, _p8);
  348. SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
  349. _graphicsPath.AddMoveTo(_p2);
  350. _graphicsPath.AddQuadraticCurveTo(_cp2, _p8);
  351. _graphicsPath.AddLineTo(_p7);
  352. _graphicsPath.AddQuadraticCurveTo(_cp1, _p1);
  353. _graphicsPath.AddLineTo(_p2);
  354. _graphics.FillPath(_graphicsPath);
  355. MoveTo(p);
  356. }
  357. public void LineTo(Vector2 p) {
  358. if((isUseWidth) && ((int)_width > 1)) {
  359. LineTo(p, _width);
  360. return;
  361. }
  362. _basicDraw.LineTo(p);
  363. }
  364. public void LineTo(Vector2 p, float width) {
  365. Vector2 _point = Vector2.zero;
  366. _point = _basicDraw.currentPoint;
  367. Line(_point, p, width);
  368. MoveTo(p);
  369. }
  370. public void Line(Vector2 p1, Vector2 p2) {
  371. if((isUseWidth) && ((int)_width > 1)) {
  372. Line(p1, p2, _width);
  373. return;
  374. }
  375. _basicDraw.Line(p1, p2);
  376. }
  377. public void Line(Vector2 p1, Vector2 p2, float width) {
  378. if((int)width == 1)
  379. Line(p1, p2);
  380. else {
  381. if(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) <= 4f)
  382. return;
  383. StrokeLineCapLeft(p1, p2, width);
  384. StrokeLineCapRight(p1, p2, width);
  385. Vector2 _p1 = Vector2.zero;
  386. Vector2 _p2 = Vector2.zero;
  387. Vector2 _p3 = Vector2.zero;
  388. Vector2 _p4 = Vector2.zero;
  389. _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);
  390. Vector2[] points = new Vector2[4];
  391. points[0] = _p1;
  392. points[1] = _p3;
  393. points[2] = _p4;
  394. points[3] = _p2;
  395. _graphics.FillPolygon(points);
  396. }
  397. }
  398. public void Rect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4) {
  399. if((isUseWidth) && ((int)_width > 1)) {
  400. Rect(p1, p2, p3, p4, _width);
  401. return;
  402. }
  403. _basicDraw.Rect(p1, p2, p3, p4);
  404. }
  405. public void Rect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float width) {
  406. if((int)width == 1)
  407. Rect(p1, p2, p3, p4);
  408. //Vector2[] points = new Vector2[4];
  409. rect_points[0] = p1;
  410. rect_points[1] = p2;
  411. rect_points[2] = p3;
  412. rect_points[3] = p4;
  413. Polygon(rect_points, width);
  414. }
  415. public void RoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7, Vector2 p8,
  416. float r1, float r2,
  417. float angle) {
  418. if((isUseWidth) && ((int)_width > 1)) {
  419. RoundedRect(p1, p2, p3, p4, p5, p6, p7, p8, r1, r2,
  420. angle, _width);
  421. return;
  422. }
  423. _basicDraw.MoveTo(p1);
  424. _basicDraw.LineTo(p2);
  425. _basicDraw.ArcTo(r1, r2, angle, false, true, p3);
  426. _basicDraw.MoveTo(p3);
  427. _basicDraw.LineTo(p4);
  428. _basicDraw.ArcTo(r1, r2, angle, false, true, p5);
  429. _basicDraw.MoveTo(p5);
  430. _basicDraw.LineTo(p6);
  431. _basicDraw.ArcTo(r1, r2, angle, false, true, p7);
  432. _basicDraw.MoveTo(p7);
  433. _basicDraw.LineTo(p8);
  434. _basicDraw.ArcTo(r1, r2, angle, false, true, p1);
  435. }
  436. public void RoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7, Vector2 p8,
  437. float r1, float r2,
  438. float angle, float width) {
  439. if((int)width == 1) {
  440. RoundedRect(p1, p2, p3, p4, p5, p6, p7, p8, r1, r2,
  441. angle);
  442. return;
  443. }
  444. Line(p1, p2, width);
  445. Line(p3, p4, width);
  446. Line(p5, p6, width);
  447. Line(p7, p8, width);
  448. // TODO: IIRC, `Vector2.zero` is a p/invoke. Would it be safe to chain assignments here? Would it be more
  449. // TODO: performant? What about just calling `new Vector2(0f, 0f)`?
  450. Vector2 _p1 = Vector2.zero;
  451. Vector2 _p2 = Vector2.zero;
  452. Vector2 _p3 = Vector2.zero;
  453. Vector2 _p4 = Vector2.zero;
  454. _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);
  455. Vector2 _p5 = Vector2.zero;
  456. Vector2 _p6 = Vector2.zero;
  457. Vector2 _p7 = Vector2.zero;
  458. Vector2 _p8 = Vector2.zero;
  459. //-------
  460. _graphics.GetThickLine(p3, p4, width, ref _p5, ref _p6, ref _p7, ref _p8);
  461. SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
  462. _graphicsPath.AddMoveTo(_p4);
  463. _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p6);
  464. _graphicsPath.AddLineTo(_p5);
  465. _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p3);
  466. _graphicsPath.AddLineTo(_p4);
  467. _graphics.FillPath(_graphicsPath);
  468. //-------
  469. _graphics.GetThickLine(p5, p6, width, ref _p1, ref _p2, ref _p3, ref _p4);
  470. _graphicsPath.Reset();
  471. _graphicsPath.AddMoveTo(_p8);
  472. _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p2);
  473. _graphicsPath.AddLineTo(_p1);
  474. _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p7);
  475. _graphicsPath.AddLineTo(_p8);
  476. _graphics.FillPath(_graphicsPath);
  477. //----------
  478. _graphics.GetThickLine(p7, p8, width, ref _p5, ref _p6, ref _p7, ref _p8);
  479. _graphicsPath.Reset();
  480. _graphicsPath.AddMoveTo(_p4);
  481. _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p6);
  482. _graphicsPath.AddLineTo(_p5);
  483. _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p3);
  484. _graphicsPath.AddLineTo(_p4);
  485. _graphics.FillPath(_graphicsPath);
  486. //-------
  487. _graphics.GetThickLine(p1, p2, width, ref _p1, ref _p2, ref _p3, ref _p4);
  488. _graphicsPath.Reset();
  489. _graphicsPath.AddMoveTo(_p8);
  490. _graphicsPath.AddArcTo(r1 + (width / 2f), r2 + (width / 2f), angle, false, true, _p2);
  491. _graphicsPath.AddLineTo(_p1);
  492. _graphicsPath.AddArcTo(r1 - (width / 2f), r2 - (width / 2f), angle, false, false, _p7);
  493. _graphicsPath.AddLineTo(_p8);
  494. _graphics.FillPath(_graphicsPath);
  495. }
  496. public void Circle(Vector2 p, float r) {
  497. if((isUseWidth) && ((int)_width > 1)) {
  498. Circle(p, r, _width);
  499. return;
  500. }
  501. _basicDraw.Circle(p, r);
  502. }
  503. public void Circle(Vector2 p, float r, float width) {
  504. if((int)width == 1)
  505. Circle(p, r);
  506. else {
  507. int r1 = (int)(width / 2f);
  508. int r2 = (int)width - r1;
  509. //Vector2[] _points = new Vector2[1];
  510. //_points[0] = new Vector2(p.x, p.y);
  511. SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
  512. _graphicsPath.AddCircleTo(p, r + r1);
  513. _graphicsPath.AddCircleTo(p, r - r2);
  514. _graphics.FillPath(_graphicsPath, p);
  515. }
  516. }
  517. public void Ellipse(Vector2 p, float rx, float ry, float angle) {
  518. if((isUseWidth) && ((int)_width > 1)) {
  519. Ellipse(p, rx, ry, angle, _width);
  520. return;
  521. }
  522. _basicDraw.Ellipse(p, rx, ry, angle);
  523. }
  524. public void Ellipse(Vector2 p, float rx, float ry, float angle, float width) {
  525. if((int)width == 1)
  526. Ellipse(p, rx, ry, angle);
  527. else {
  528. int r1 = (int)(width / 2f);
  529. int r2 = (int)width - r1;
  530. //Vector2[] _points = new Vector2[1] { p };
  531. SVGGraphicsPath _graphicsPath = new SVGGraphicsPath();
  532. _graphicsPath.AddEllipseTo(p, rx + r1, ry + r1, angle);
  533. _graphicsPath.AddEllipseTo(p, rx - r2, ry - r2, angle);
  534. _graphics.FillPath(_graphicsPath, p);
  535. }
  536. }
  537. public void Polygon(Vector2[] points) {
  538. if((isUseWidth) && ((int)_width > 1)) {
  539. Polygon(points, _width);
  540. return;
  541. }
  542. int _length = points.GetLength(0);
  543. if(_length > 1) {
  544. _basicDraw.MoveTo(points[0]);
  545. for(int i = 1; i < _length; i++)
  546. _basicDraw.LineTo(points[i]);
  547. _basicDraw.LineTo(points[0]);
  548. }
  549. }
  550. public void Polygon(Vector2[] points, float width) {
  551. if((int)width == 1) {
  552. Polygon(points);
  553. return;
  554. }
  555. int _length = points.GetLength(0);
  556. if(_length > 1) {
  557. if(_length == 2) {
  558. Line(points[0], points[1], width);
  559. StrokeLineCapLeft(points[0], points[1], width);
  560. StrokeLineCapRight(points[0], points[1], width);
  561. } else if(_length > 2) {
  562. StrokeLineJoin(points[_length - 1], points[0], points[1], width);
  563. Line(points[0], points[1], width);
  564. StrokeLineJoin(points[_length - 2], points[_length - 1], points[0], width);
  565. Line(points[_length - 1], points[0], width);
  566. for(int i = 1; i < _length - 1; i++) {
  567. StrokeLineJoin(points[i - 1], points[i], points[i + 1], width);
  568. Line(points[i], points[i + 1], width);
  569. }
  570. }
  571. }
  572. }
  573. public void DrawPath(SVGGraphicsPath graphicsPath) {
  574. graphicsPath.RenderPath(this, false);
  575. }
  576. //Fill co Stroke trong do luon
  577. public void DrawPath(SVGGraphicsPath graphicsPath, float width) {
  578. _width = width;
  579. isUseWidth = true;
  580. graphicsPath.RenderPath(this, false);
  581. isUseWidth = false;
  582. }
  583. }