EditableVectorPathTests.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. using Drawie.Backend.Core.Bridge;
  2. using Drawie.Backend.Core.Vector;
  3. using Drawie.Numerics;
  4. using Drawie.Skia;
  5. using DrawiEngine;
  6. using PixiEditor.Views.Overlays.PathOverlay;
  7. namespace PixiEditor.Tests;
  8. public class EditableVectorPathTests : PixiEditorTest
  9. {
  10. [Fact]
  11. public void TestThatRectVectorShapeReturnsCorrectSubShapes()
  12. {
  13. VectorPath path = new VectorPath();
  14. path.AddRect(new RectD(0, 0, 10, 10));
  15. EditableVectorPath editablePath = new EditableVectorPath(path);
  16. Assert.Single(editablePath.SubShapes);
  17. Assert.True(editablePath.SubShapes[0].IsClosed);
  18. Assert.Equal(4, editablePath.SubShapes[0].Points.Count);
  19. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Position);
  20. Assert.Equal(new VecF(10, 0), editablePath.SubShapes[0].Points[1].Position);
  21. Assert.Equal(new VecF(10, 10), editablePath.SubShapes[0].Points[2].Position);
  22. Assert.Equal(new VecF(0, 10), editablePath.SubShapes[0].Points[3].Position);
  23. }
  24. [Fact]
  25. public void TestThatOvalVectorShapeReturnsCorrectSubShapes()
  26. {
  27. VectorPath path = new VectorPath();
  28. path.AddOval(RectD.FromCenterAndSize(new VecD(5, 5), new VecD(10, 10)));
  29. EditableVectorPath editablePath = new EditableVectorPath(path);
  30. Assert.Single(editablePath.SubShapes);
  31. Assert.True(editablePath.SubShapes[0].IsClosed);
  32. Assert.Equal(4, editablePath.SubShapes[0].Points.Count);
  33. Assert.Equal(new VecF(10, 5), editablePath.SubShapes[0].Points[0].Position);
  34. Assert.Equal(new VecF(5, 10), editablePath.SubShapes[0].Points[1].Position);
  35. Assert.Equal(new VecF(0, 5), editablePath.SubShapes[0].Points[2].Position);
  36. Assert.Equal(new VecF(5, 0), editablePath.SubShapes[0].Points[3].Position);
  37. }
  38. [Fact]
  39. public void TestThatLineVectorShapeReturnsCorrectSubShapes()
  40. {
  41. VectorPath path = new VectorPath();
  42. path.LineTo(new VecF(2, 2));
  43. path.Close();
  44. EditableVectorPath editablePath = new EditableVectorPath(path);
  45. Assert.Single(editablePath.SubShapes);
  46. Assert.True(editablePath.SubShapes[0].IsClosed);
  47. Assert.Equal(2, editablePath.SubShapes[0].Points.Count);
  48. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Position);
  49. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[1].Position);
  50. }
  51. [Fact]
  52. public void TestThatNotClosedPolyReturnsCorrectSubShape()
  53. {
  54. VectorPath path = new VectorPath();
  55. path.MoveTo(new VecF(0, 0));
  56. path.LineTo(new VecF(2, 2));
  57. path.LineTo(new VecF(4, 4));
  58. EditableVectorPath editablePath = new EditableVectorPath(path);
  59. Assert.Single(editablePath.SubShapes);
  60. Assert.False(editablePath.SubShapes[0].IsClosed);
  61. Assert.Equal(3, editablePath.SubShapes[0].Points.Count);
  62. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Position);
  63. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[1].Position);
  64. Assert.Equal(new VecF(4, 4), editablePath.SubShapes[0].Points[2].Position);
  65. }
  66. [Fact]
  67. public void TestThatMultipleRectsReturnCorrectSubShapes()
  68. {
  69. VectorPath path = new VectorPath();
  70. path.AddRect(new RectD(0, 0, 10, 10));
  71. path.AddRect(new RectD(10, 10, 20, 20));
  72. EditableVectorPath editablePath = new EditableVectorPath(path);
  73. Assert.Equal(2, editablePath.SubShapes.Count);
  74. Assert.True(editablePath.SubShapes[0].IsClosed);
  75. Assert.Equal(4, editablePath.SubShapes[0].Points.Count);
  76. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Position);
  77. Assert.Equal(new VecF(10, 0), editablePath.SubShapes[0].Points[1].Position);
  78. Assert.Equal(new VecF(10, 10), editablePath.SubShapes[0].Points[2].Position);
  79. Assert.Equal(new VecF(0, 10), editablePath.SubShapes[0].Points[3].Position);
  80. Assert.True(editablePath.SubShapes[1].IsClosed);
  81. Assert.Equal(4, editablePath.SubShapes[1].Points.Count);
  82. Assert.Equal(new VecF(10, 10), editablePath.SubShapes[1].Points[0].Position);
  83. Assert.Equal(new VecF(30, 10), editablePath.SubShapes[1].Points[1].Position);
  84. Assert.Equal(new VecF(30, 30), editablePath.SubShapes[1].Points[2].Position);
  85. Assert.Equal(new VecF(10, 30), editablePath.SubShapes[1].Points[3].Position);
  86. }
  87. [Fact]
  88. public void TestThatTwoPolysWithSecondUnclosedReturnsCorrectShapeData()
  89. {
  90. VectorPath path = new VectorPath();
  91. path.MoveTo(new VecF(0, 0));
  92. path.LineTo(new VecF(2, 2));
  93. path.LineTo(new VecF(4, 4));
  94. path.Close();
  95. path.MoveTo(new VecF(10, 10));
  96. path.LineTo(new VecF(12, 12));
  97. path.LineTo(new VecF(14, 14));
  98. EditableVectorPath editablePath = new EditableVectorPath(path);
  99. Assert.Equal(2, editablePath.SubShapes.Count);
  100. Assert.True(editablePath.SubShapes[0].IsClosed);
  101. Assert.Equal(3, editablePath.SubShapes[0].Points.Count);
  102. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Position);
  103. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[1].Position);
  104. Assert.Equal(new VecF(4, 4), editablePath.SubShapes[0].Points[2].Position);
  105. Assert.False(editablePath.SubShapes[1].IsClosed);
  106. Assert.Equal(3, editablePath.SubShapes[1].Points.Count);
  107. Assert.Equal(new VecF(10, 10), editablePath.SubShapes[1].Points[0].Position);
  108. Assert.Equal(new VecF(12, 12), editablePath.SubShapes[1].Points[1].Position);
  109. Assert.Equal(new VecF(14, 14), editablePath.SubShapes[1].Points[2].Position);
  110. }
  111. [Fact]
  112. public void TestThatStartAndEndIndexesForMultipleShapesAreCorrect()
  113. {
  114. VectorPath path = new VectorPath();
  115. path.MoveTo(new VecF(0, 0));
  116. path.LineTo(new VecF(2, 2));
  117. path.LineTo(new VecF(4, 4));
  118. path.Close();
  119. path.MoveTo(new VecF(10, 10));
  120. path.LineTo(new VecF(12, 12));
  121. path.Close();
  122. int expectedFirstShapeStartIndex = 0;
  123. int expectedFirstShapeEndIndex = 2;
  124. int expectedSecondShapeStartIndex = 3;
  125. int expectedSecondShapeEndIndex = 5;
  126. EditableVectorPath editablePath = new EditableVectorPath(path);
  127. Assert.Equal(2, editablePath.SubShapes.Count);
  128. }
  129. [Fact]
  130. public void TestThatGetNextPointInTriangleShapeReturnsCorrectPoint()
  131. {
  132. VectorPath path = new VectorPath();
  133. path.MoveTo(new VecF(0, 0));
  134. path.LineTo(new VecF(2, 2));
  135. path.LineTo(new VecF(4, 4));
  136. path.Close();
  137. EditableVectorPath editablePath = new EditableVectorPath(path);
  138. ShapePoint nextPoint = editablePath.SubShapes[0].GetNextPoint(0);
  139. Assert.Equal(new VecF(2, 2), nextPoint.Position);
  140. Assert.Equal(1, nextPoint.Index);
  141. nextPoint = editablePath.SubShapes[0].GetNextPoint(1);
  142. Assert.Equal(new VecF(4, 4), nextPoint.Position);
  143. Assert.Equal(2, nextPoint.Index);
  144. nextPoint = editablePath.SubShapes[0].GetNextPoint(2);
  145. Assert.Equal(new VecF(0, 0), nextPoint.Position);
  146. Assert.Equal(0, nextPoint.Index);
  147. }
  148. [Fact]
  149. public void TestThatGetPreviousPointInTriangleShapeReturnsCorrectPoint()
  150. {
  151. VectorPath path = new VectorPath();
  152. path.MoveTo(new VecF(0, 0));
  153. path.LineTo(new VecF(2, 2));
  154. path.LineTo(new VecF(4, 4));
  155. path.Close();
  156. EditableVectorPath editablePath = new EditableVectorPath(path);
  157. ShapePoint previousPoint = editablePath.SubShapes[0].GetPreviousPoint(0);
  158. Assert.Equal(new VecF(4, 4), previousPoint.Position);
  159. Assert.Equal(2, previousPoint.Index);
  160. previousPoint = editablePath.SubShapes[0].GetPreviousPoint(1);
  161. Assert.Equal(new VecF(0, 0), previousPoint.Position);
  162. Assert.Equal(0, previousPoint.Index);
  163. previousPoint = editablePath.SubShapes[0].GetPreviousPoint(2);
  164. Assert.Equal(new VecF(2, 2), previousPoint.Position);
  165. Assert.Equal(1, previousPoint.Index);
  166. }
  167. [Fact]
  168. public void TestThatVerbsInTriangleAreCorrect()
  169. {
  170. VectorPath path = new VectorPath();
  171. path.MoveTo(new VecF(0, 0));
  172. path.LineTo(new VecF(2, 2));
  173. path.LineTo(new VecF(4, 4));
  174. path.Close();
  175. EditableVectorPath editablePath = new EditableVectorPath(path);
  176. Assert.Equal(3, editablePath.SubShapes[0].Points.Count);
  177. Assert.Equal(PathVerb.Line, editablePath.SubShapes[0].Points[0].Verb.VerbType);
  178. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Verb.From);
  179. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[0].Verb.To);
  180. Assert.Equal(PathVerb.Line, editablePath.SubShapes[0].Points[1].Verb.VerbType);
  181. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[1].Verb.From);
  182. Assert.Equal(new VecF(4, 4), editablePath.SubShapes[0].Points[1].Verb.To);
  183. Assert.Equal(PathVerb.Line, editablePath.SubShapes[0].Points[2].Verb.VerbType);
  184. Assert.Equal(new VecF(4, 4), editablePath.SubShapes[0].Points[2].Verb.From);
  185. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[2].Verb.To);
  186. }
  187. [Fact]
  188. public void TestThatVerbsInOvalAreCorrect()
  189. {
  190. const float conic = 0.70710769f;
  191. const float rangeLower = conic - 0.001f;
  192. const float rangeUpper = conic + 0.001f;
  193. VectorPath path = new VectorPath();
  194. path.AddOval(RectD.FromCenterAndSize(new VecD(5, 5), new VecD(10, 10)));
  195. EditableVectorPath editablePath = new EditableVectorPath(path);
  196. Assert.Equal(4, editablePath.SubShapes[0].Points.Count);
  197. Assert.Equal(PathVerb.Conic, editablePath.SubShapes[0].Points[0].Verb.VerbType);
  198. Assert.Equal(new VecF(10, 5), editablePath.SubShapes[0].Points[0].Verb.From);
  199. Assert.Equal(new VecF(5, 10), editablePath.SubShapes[0].Points[0].Verb.To);
  200. Assert.InRange(editablePath.SubShapes[0].Points[0].Verb.ConicWeight, rangeLower, rangeUpper);
  201. Assert.Equal(PathVerb.Conic, editablePath.SubShapes[0].Points[1].Verb.VerbType);
  202. Assert.Equal(new VecF(5, 10), editablePath.SubShapes[0].Points[1].Verb.From);
  203. Assert.Equal(new VecF(0, 5), editablePath.SubShapes[0].Points[1].Verb.To);
  204. Assert.InRange(editablePath.SubShapes[0].Points[1].Verb.ConicWeight, rangeLower, rangeUpper);
  205. Assert.Equal(PathVerb.Conic, editablePath.SubShapes[0].Points[2].Verb.VerbType);
  206. Assert.Equal(new VecF(0, 5), editablePath.SubShapes[0].Points[2].Verb.From);
  207. Assert.Equal(new VecF(5, 0), editablePath.SubShapes[0].Points[2].Verb.To);
  208. Assert.InRange(editablePath.SubShapes[0].Points[2].Verb.ConicWeight, rangeLower, rangeUpper);
  209. Assert.Equal(PathVerb.Conic, editablePath.SubShapes[0].Points[3].Verb.VerbType);
  210. Assert.Equal(new VecF(5, 0), editablePath.SubShapes[0].Points[3].Verb.From);
  211. Assert.Equal(new VecF(10, 5), editablePath.SubShapes[0].Points[3].Verb.To);
  212. Assert.InRange(editablePath.SubShapes[0].Points[3].Verb.ConicWeight, rangeLower, rangeUpper);
  213. }
  214. [Fact]
  215. public void TestThatOverlappingPolyPointsReturnCorrectSubShapePoints()
  216. {
  217. VectorPath path = new VectorPath();
  218. /*
  219. * |\
  220. * |_\
  221. * |
  222. */
  223. path.MoveTo(new VecF(0, 0));
  224. path.LineTo(new VecF(0, 2));
  225. path.LineTo(new VecF(0, 4));
  226. path.LineTo(new VecF(2, 2));
  227. path.LineTo(new VecF(0, 2));
  228. path.Close();
  229. EditableVectorPath editablePath = new EditableVectorPath(path);
  230. Assert.Equal(5, editablePath.SubShapes[0].Points.Count);
  231. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Verb.From);
  232. Assert.Equal(new VecF(0, 2), editablePath.SubShapes[0].Points[0].Verb.To);
  233. Assert.Equal(new VecF(0, 2), editablePath.SubShapes[0].Points[1].Verb.From);
  234. Assert.Equal(new VecF(0, 4), editablePath.SubShapes[0].Points[1].Verb.To);
  235. Assert.Equal(new VecF(0, 4), editablePath.SubShapes[0].Points[2].Verb.From);
  236. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[2].Verb.To);
  237. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[3].Verb.From);
  238. Assert.Equal(new VecF(0, 2), editablePath.SubShapes[0].Points[3].Verb.To);
  239. Assert.Equal(new VecF(0, 2), editablePath.SubShapes[0].Points[4].Verb.From);
  240. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[4].Verb.To);
  241. }
  242. [Fact]
  243. public void TestThatMultiSubShapesWithUnclosedReturnsCorrectPoints()
  244. {
  245. VectorPath path = new VectorPath();
  246. path.LineTo(new VecF(2, 2));
  247. path.LineTo(new VecF(0, 4));
  248. path.AddOval(RectD.FromCenterAndSize(new VecD(5, 5), new VecD(10, 10)));
  249. EditableVectorPath editablePath = new EditableVectorPath(path);
  250. Assert.Equal(2, editablePath.SubShapes.Count);
  251. Assert.Equal(3, editablePath.SubShapes[0].Points.Count);
  252. Assert.Equal(new VecF(0, 0), editablePath.SubShapes[0].Points[0].Position);
  253. Assert.Equal(new VecF(2, 2), editablePath.SubShapes[0].Points[1].Position);
  254. Assert.Equal(new VecF(0, 4), editablePath.SubShapes[0].Points[2].Position);
  255. Assert.False(editablePath.SubShapes[0].IsClosed);
  256. Assert.Equal(4, editablePath.SubShapes[1].Points.Count);
  257. Assert.Equal(new VecF(10, 5), editablePath.SubShapes[1].Points[0].Position);
  258. Assert.Equal(new VecF(5, 10), editablePath.SubShapes[1].Points[1].Position);
  259. Assert.Equal(new VecF(0, 5), editablePath.SubShapes[1].Points[2].Position);
  260. Assert.Equal(new VecF(5, 0), editablePath.SubShapes[1].Points[3].Position);
  261. Assert.True(editablePath.SubShapes[1].IsClosed);
  262. }
  263. [Fact]
  264. public void TestThatMoveToProducesEmptyVerb()
  265. {
  266. VectorPath path = new VectorPath();
  267. path.MoveTo(new VecF(0, 0));
  268. EditableVectorPath editablePath = new EditableVectorPath(path);
  269. Assert.Single(editablePath.SubShapes);
  270. Assert.Single(editablePath.SubShapes[0].Points);
  271. Assert.Equal(null, editablePath.SubShapes[0].Points[0].Verb.VerbType);
  272. }
  273. [Fact]
  274. public void TestThatMultipleMoveToProduceEmptyVerbs()
  275. {
  276. VectorPath path = new VectorPath();
  277. path.MoveTo(new VecF(0, 0));
  278. path.MoveTo(new VecF(2, 2));
  279. EditableVectorPath editablePath = new EditableVectorPath(path);
  280. Assert.Equal(2, editablePath.SubShapes.Count);
  281. Assert.Single(editablePath.SubShapes[0].Points);
  282. Assert.Single(editablePath.SubShapes[1].Points);
  283. Assert.Null(editablePath.SubShapes[0].Points[0].Verb.VerbType);
  284. Assert.Null(editablePath.SubShapes[1].Points[0].Verb.VerbType);
  285. }
  286. [Fact]
  287. public void TestThatEditingPointResultsInCorrectVectorPath()
  288. {
  289. VectorPath path = new VectorPath();
  290. path.MoveTo(new VecF(0, 0));
  291. path.LineTo(new VecF(2, 2));
  292. path.LineTo(new VecF(4, 4));
  293. path.Close();
  294. EditableVectorPath editablePath = new EditableVectorPath(path);
  295. editablePath.SubShapes[0].SetPointPosition(1, new VecF(3, 3), true);
  296. VectorPath newPath = editablePath.ToVectorPath();
  297. PathVerb[] sequence = [ PathVerb.Move, PathVerb.Line, PathVerb.Line, PathVerb.Line, PathVerb.Close, PathVerb.Done ];
  298. VecF[] points = [ new VecF(0, 0), new VecF(3, 3), new VecF(4, 4), new VecF(0, 0) ];
  299. int i = 0;
  300. foreach (var data in newPath)
  301. {
  302. Assert.Equal(sequence[i], data.verb);
  303. if(data.verb != PathVerb.Close && data.verb != PathVerb.Done)
  304. {
  305. Assert.Equal(points[i], Verb.GetPointFromVerb(data));
  306. }
  307. i++;
  308. }
  309. }
  310. [Theory]
  311. [InlineData(0, 0)]
  312. [InlineData(1, 0)]
  313. [InlineData(2, 0)]
  314. [InlineData(3, 0)]
  315. [InlineData(4, 1)]
  316. [InlineData(5, 1)]
  317. [InlineData(6, 1)]
  318. [InlineData(7, 1)]
  319. public void TestThatGetSubShapeByPointIndexReturnsCorrectSubShapeIndex(int index, int expected)
  320. {
  321. VectorPath path = new VectorPath();
  322. path.AddOval(RectD.FromCenterAndSize(new VecD(5, 5), new VecD(10, 10)));
  323. path.AddOval(RectD.FromCenterAndSize(new VecD(15, 15), new VecD(20, 20)));
  324. EditableVectorPath editablePath = new EditableVectorPath(path);
  325. Assert.Equal(expected, editablePath.SubShapes.ToList().IndexOf(editablePath.GetSubShapeContainingIndex(index)));
  326. }
  327. }