/lib/ha/aggx/vectorial/VectorPath.hx

http://aggx.googlecode.com/ · Haxe · 553 lines · 476 code · 16 blank · 61 comment · 45 complexity · 62354e3c2baaab04888b63aa28a8412b MD5 · raw file

  1. package lib.ha.aggx.vectorial;
  2. //=======================================================================================================
  3. import lib.ha.core.geometry.AffineTransformer;
  4. import lib.ha.core.memory.Ref;
  5. import lib.ha.core.math.Calc;
  6. //=======================================================================================================
  7. class VectorPath implements IVertexSource
  8. {
  9. private var _vertices:VertexBlockStorage;
  10. private var _vertextIterator:UInt;
  11. //---------------------------------------------------------------------------------------------------
  12. public function new()
  13. {
  14. _vertices = new VertexBlockStorage();
  15. }
  16. public function removeAll():Void { _vertices.removeAll(); _vertextIterator = 0; }
  17. //---------------------------------------------------------------------------------------------------
  18. public function freeAll():Void { _vertices.freeAll(); _vertextIterator = 0; }
  19. //---------------------------------------------------------------------------------------------------
  20. public function startNewPath():Int
  21. {
  22. if(!PathUtils.isStop(_vertices.lastCommand))
  23. {
  24. _vertices.addVertex(0.0, 0.0, PathCommands.STOP);
  25. }
  26. return _vertices.verticesCount;
  27. }
  28. //---------------------------------------------------------------------------------------------------
  29. public function relToAbs(x:FloatRef, y:FloatRef):Void
  30. {
  31. if(_vertices.verticesCount!=0)
  32. {
  33. var x2 = Ref.float1;
  34. var y2 = Ref.float2;
  35. if(PathUtils.isVertex(_vertices.getLastVertex(x2, y2)))
  36. {
  37. x.value += x2.value;
  38. y.value += y2.value;
  39. }
  40. }
  41. }
  42. //---------------------------------------------------------------------------------------------------
  43. public function moveTo(x:Float, y:Float):Void
  44. {
  45. _vertices.addVertex(x, y, PathCommands.MOVE_TO);
  46. }
  47. //---------------------------------------------------------------------------------------------------
  48. public function moveRel(dx:Float, dy:Float):Void
  49. {
  50. var rdx = Ref.float1;
  51. var rdy = Ref.float2;
  52. relToAbs(rdx.set(dx), rdy.set(dy));
  53. _vertices.addVertex(rdx.value, rdy.value, PathCommands.MOVE_TO);
  54. }
  55. //---------------------------------------------------------------------------------------------------
  56. public function lineTo(x:Float, y:Float):Void
  57. {
  58. _vertices.addVertex(x, y, PathCommands.LINE_TO);
  59. }
  60. //---------------------------------------------------------------------------------------------------
  61. public function lineRel(dx:Float, dy:Float):Void
  62. {
  63. var rdx = Ref.float1.set(dx);
  64. var rdy = Ref.float2.set(dy);
  65. relToAbs(rdx, rdy);
  66. _vertices.addVertex(rdx.value, rdy.value, PathCommands.LINE_TO);
  67. }
  68. //---------------------------------------------------------------------------------------------------
  69. public function hlineTo(x:Float):Void
  70. {
  71. _vertices.addVertex(x, lastY, PathCommands.LINE_TO);
  72. }
  73. //---------------------------------------------------------------------------------------------------
  74. public function hlineRel(dx:Float)
  75. {
  76. var rdx = Ref.float1.set(dx);
  77. var rdy = Ref.float2;
  78. relToAbs(rdx, rdy);
  79. _vertices.addVertex(rdx.value, rdy.value, PathCommands.LINE_TO);
  80. }
  81. //---------------------------------------------------------------------------------------------------
  82. public function vlineTo(y:Float):Void
  83. {
  84. _vertices.addVertex(lastX, y, PathCommands.LINE_TO);
  85. }
  86. //---------------------------------------------------------------------------------------------------
  87. public function vlineRel(dy:Float):Void
  88. {
  89. var rdx = Ref.float1;
  90. var rdy = Ref.float2.set(dy);
  91. relToAbs(rdx, rdy);
  92. _vertices.addVertex(rdx.value, rdy.value, PathCommands.LINE_TO);
  93. }
  94. //---------------------------------------------------------------------------------------------------
  95. public function curve3(x_ctrl:Float, y_ctrl:Float, x_to:Float, y_to:Float):Void
  96. {
  97. _vertices.addVertex(x_ctrl, y_ctrl, PathCommands.CURVE3);
  98. _vertices.addVertex(x_to, y_to, PathCommands.CURVE3);
  99. }
  100. //---------------------------------------------------------------------------------------------------
  101. public function curve3Rel(dx_ctrl:Float, dy_ctrl:Float, dx_to:Float, dy_to:Float):Void
  102. {
  103. var rdx_ctrl = Ref.float1.set(dx_ctrl);
  104. var rdy_ctrl = Ref.float2.set(dy_ctrl);
  105. var rdx_to = Ref.float3.set(dx_to);
  106. var rdy_to = Ref.float4.set(dy_to);
  107. relToAbs(rdx_ctrl, rdy_ctrl);
  108. relToAbs(rdx_to, rdy_to);
  109. _vertices.addVertex(rdx_ctrl.value, rdy_ctrl.value, PathCommands.CURVE3);
  110. _vertices.addVertex(rdx_to.value, rdy_to.value, PathCommands.CURVE3);
  111. }
  112. //---------------------------------------------------------------------------------------------------
  113. public function curve3To(x_to:Float, y_to:Float):Void
  114. {
  115. var x0 = Ref.float1;
  116. var y0 = Ref.float2;
  117. if(PathUtils.isVertex(_vertices.getLastVertex(x0, y0)))
  118. {
  119. var x_ctrl = Ref.float3;
  120. var y_ctrl = Ref.float4;
  121. var cmd = _vertices.getPrevVertex(x_ctrl, y_ctrl);
  122. if(PathUtils.isCurve(cmd))
  123. {
  124. x_ctrl.value = x0.value + x0.value - x_ctrl.value;
  125. y_ctrl.value = y0.value + y0.value - y_ctrl.value;
  126. }
  127. else
  128. {
  129. x_ctrl.value = x0.value;
  130. y_ctrl.value = y0.value;
  131. }
  132. curve3(x_ctrl.value, y_ctrl.value, x_to, y_to);
  133. }
  134. }
  135. //---------------------------------------------------------------------------------------------------
  136. public function curve3RelTo(dx_to:Float, dy_to:Float):Void
  137. {
  138. var rdx_to = Ref.float1.set(dx_to);
  139. var rdy_to = Ref.float2.set(dy_to);
  140. relToAbs(rdx_to, rdy_to);
  141. curve3To(rdx_to.value, rdy_to.value);
  142. }
  143. //---------------------------------------------------------------------------------------------------
  144. public function curve4(x_ctrl1:Float, y_ctrl1:Float, x_ctrl2:Float, y_ctrl2:Float, x_to:Float, y_to:Float):Void
  145. {
  146. _vertices.addVertex(x_ctrl1, y_ctrl1, PathCommands.CURVE4);
  147. _vertices.addVertex(x_ctrl2, y_ctrl2, PathCommands.CURVE4);
  148. _vertices.addVertex(x_to, y_to, PathCommands.CURVE4);
  149. }
  150. //---------------------------------------------------------------------------------------------------
  151. public function curve4Rel(dx_ctrl1:Float, dy_ctrl1:Float, dx_ctrl2:Float, dy_ctrl2:Float, dx_to:Float, dy_to:Float):Void
  152. {
  153. var rdx_ctrl1 = Ref.float1.set(dx_ctrl1);
  154. var rdy_ctrl1 = Ref.float2.set(dy_ctrl1);
  155. var rdx_ctrl2 = Ref.float3.set(dx_ctrl2);
  156. var rdy_ctrl2 = Ref.float4.set(dy_ctrl2);
  157. var rdx_to = Ref.float5.set(dx_to);
  158. var rdy_to = Ref.float6.set(dy_to);
  159. relToAbs(rdx_ctrl1, rdy_ctrl1);
  160. relToAbs(rdx_ctrl2, rdy_ctrl2);
  161. relToAbs(rdx_to, rdy_to);
  162. _vertices.addVertex(rdx_ctrl1.value, rdy_ctrl1.value, PathCommands.CURVE4);
  163. _vertices.addVertex(rdx_ctrl2.value, rdy_ctrl2.value, PathCommands.CURVE4);
  164. _vertices.addVertex(rdx_to.value, rdy_to.value, PathCommands.CURVE4);
  165. }
  166. //---------------------------------------------------------------------------------------------------
  167. public function curve4To(x_ctrl2:Float, y_ctrl2:Float, x_to:Float, y_to:Float):Void
  168. {
  169. var x0 = Ref.float1;
  170. var y0 = Ref.float2;
  171. if(PathUtils.isVertex(getLastVertex(x0, y0)))
  172. {
  173. var x_ctrl1 = Ref.float3;
  174. var y_ctrl1 = Ref.float4;
  175. var cmd = getPrevVertex(x_ctrl1, y_ctrl1);
  176. if(PathUtils.isCurve(cmd))
  177. {
  178. x_ctrl1.value = x0.value + x0.value - x_ctrl1.value;
  179. y_ctrl1.value = y0.value + y0.value - y_ctrl1.value;
  180. }
  181. else
  182. {
  183. x_ctrl1.value = x0.value;
  184. y_ctrl1.value = y0.value;
  185. }
  186. curve4(x_ctrl1.value, y_ctrl1.value, x_ctrl2, y_ctrl2, x_to, y_to);
  187. }
  188. }
  189. //---------------------------------------------------------------------------------------------------
  190. public function curve4RelTo(dx_ctrl2:Float, dy_ctrl2:Float, dx_to:Float, dy_to:Float):Void
  191. {
  192. var rdx_ctrl2 = Ref.float1.set(dx_ctrl2);
  193. var rdy_ctrl2 = Ref.float2.set(dy_ctrl2);
  194. var rdx_to = Ref.float3.set(dx_to);
  195. var rdy_to = Ref.float4.set(dy_to);
  196. relToAbs(rdx_ctrl2, rdy_ctrl2);
  197. relToAbs(rdx_to, rdy_to);
  198. curve4To(rdx_ctrl2.value, rdy_ctrl2.value, rdx_to.value, rdy_to.value);
  199. }
  200. //---------------------------------------------------------------------------------------------------
  201. public inline function endPoly(flags:Int):Void
  202. {
  203. if(PathUtils.isVertex(_vertices.lastCommand))
  204. {
  205. _vertices.addVertex(0.0, 0.0, PathCommands.END_POLY | flags);
  206. }
  207. }
  208. //---------------------------------------------------------------------------------------------------
  209. public inline function closePolygon(flags:Int = 0):Void
  210. {
  211. endPoly(PathFlags.CLOSE | flags);
  212. }
  213. //---------------------------------------------------------------------------------------------------
  214. public function concatPath(vs:IVertexSource, pathId:Int = 0)
  215. {
  216. var x = Ref.float1;
  217. var y = Ref.float2;
  218. var cmd:Int;
  219. vs.rewind(pathId);
  220. while(!PathUtils.isStop(cmd = vs.getVertex(x, y)))
  221. {
  222. _vertices.addVertex(x.value, y.value, cmd);
  223. }
  224. }
  225. //---------------------------------------------------------------------------------------------------
  226. public function joinPath(vs:IVertexSource, pathId:Int = 0)
  227. {
  228. var x = Ref.float1;
  229. var y = Ref.float2;
  230. var cmd:Int;
  231. vs.rewind(pathId);
  232. cmd = vs.getVertex(x, y);
  233. if(!PathUtils.isStop(cmd))
  234. {
  235. if(PathUtils.isVertex(cmd))
  236. {
  237. var x0 = Ref.float3;
  238. var y0 = Ref.float4;
  239. var cmd0 = getLastVertex(x0, y0);
  240. if(PathUtils.isVertex(cmd0))
  241. {
  242. if(Calc.distance(x.value, y.value, x0.value, y0.value) > Calc.VERTEX_DIST_EPSILON)
  243. {
  244. if(PathUtils.isMoveTo(cmd)) cmd = PathCommands.LINE_TO;
  245. _vertices.addVertex(x.value, y.value, cmd);
  246. }
  247. }
  248. else
  249. {
  250. if(PathUtils.isStop(cmd0))
  251. {
  252. cmd = PathCommands.MOVE_TO;
  253. }
  254. else
  255. {
  256. if(PathUtils.isMoveTo(cmd)) cmd = PathCommands.LINE_TO;
  257. }
  258. _vertices.addVertex(x.value, y.value, cmd);
  259. }
  260. }
  261. while(!PathUtils.isStop(cmd = vs.getVertex(x, y)))
  262. {
  263. _vertices.addVertex(x.value, y.value, PathUtils.isMoveTo(cmd) ? PathCommands.LINE_TO : cmd);
  264. }
  265. }
  266. }
  267. //---------------------------------------------------------------------------------------------------
  268. public inline function getLastVertex(x:FloatRef, y:FloatRef):Int
  269. {
  270. return _vertices.getLastVertex(x, y);
  271. }
  272. //---------------------------------------------------------------------------------------------------
  273. public inline function getPrevVertex(x:FloatRef, y:FloatRef):Int
  274. {
  275. return _vertices.getPrevVertex(x, y);
  276. }
  277. //---------------------------------------------------------------------------------------------------
  278. public inline function getVertex(x:FloatRef, y:FloatRef):UInt
  279. {
  280. //if (_vertextIterator >= _vertices.verticesCount) return PathCommands.STOP;
  281. return (_vertextIterator >= _vertices.verticesCount) ? PathCommands.STOP : _vertices.getVertex(_vertextIterator++, x, y);
  282. }
  283. //---------------------------------------------------------------------------------------------------
  284. public inline function getVertexByIndex(idx:Int, x:FloatRef, y:FloatRef):Int
  285. {
  286. return _vertices.getVertex(idx, x, y);
  287. }
  288. //---------------------------------------------------------------------------------------------------
  289. public inline function getCommand(idx:Int):Int
  290. {
  291. return _vertices.getCommand(idx);
  292. }
  293. //---------------------------------------------------------------------------------------------------
  294. public inline function modifyVertex(idx:Int, x:Float, y:Float, ?cmd:Int):Void
  295. {
  296. _vertices.modifyVertex(idx, x, y, cmd);
  297. }
  298. //---------------------------------------------------------------------------------------------------
  299. public inline function modifyCommand(idx:Int, cmd:Int):Void
  300. {
  301. _vertices.modifyCommand(idx, cmd);
  302. }
  303. //---------------------------------------------------------------------------------------------------
  304. public inline function rewind(pathId:UInt):Void
  305. {
  306. _vertextIterator = pathId;
  307. }
  308. //---------------------------------------------------------------------------------------------------
  309. //public function concatPoly(data:PtrFloat, num_points:Int, closed:Bool):Void
  310. //{
  311. //var poly = new PolyPlainAdaptor(data, num_points, closed);
  312. //concat_path(poly);
  313. //}
  314. //---------------------------------------------------------------------------------------------------
  315. //public function joinPoly(data:PtrFloat, num_points:Int, closed:Bool):Void
  316. //{
  317. //var poly = new PolyPlainAdaptor(data, num_points, closed);
  318. //join_path(poly);
  319. //}
  320. //---------------------------------------------------------------------------------------------------
  321. public function transform(trans:AffineTransformer, pathId:Int=0)
  322. {
  323. var numVer = _vertices.verticesCount;
  324. var i:UInt = pathId;
  325. while(i < numVer)
  326. {
  327. var x = Ref.float1;
  328. var y = Ref.float2;
  329. var cmd = _vertices.getVertex(pathId, x, y);
  330. if(PathUtils.isStop(cmd)) break;
  331. if(PathUtils.isVertex(cmd))
  332. {
  333. trans.transform(x, y);
  334. _vertices.modifyVertex(pathId, x.value, y.value);
  335. }
  336. i++;
  337. }
  338. }
  339. //---------------------------------------------------------------------------------------------------
  340. public function transformAllPaths(trans:AffineTransformer):Void
  341. {
  342. var idx:UInt = 0;
  343. var numVer = _vertices.verticesCount;
  344. while (idx < numVer)
  345. {
  346. var x = Ref.float1;
  347. var y = Ref.float2;
  348. if(PathUtils.isVertex(_vertices.getVertex(idx, x, y)))
  349. {
  350. trans.transform(x, y);
  351. _vertices.modifyVertex(idx, x.value, y.value);
  352. }
  353. idx++;
  354. }
  355. }
  356. //---------------------------------------------------------------------------------------------------
  357. private function perceivePolygonOrientation(start:Int, end:Int):Int
  358. {
  359. var np = end - start;
  360. var area = 0.0;
  361. var i = 0;
  362. while(i < np)
  363. {
  364. var x1 = Ref.float1;
  365. var y1 = Ref.float2;
  366. var x2 = Ref.float3;
  367. var y2 = Ref.float4;
  368. _vertices.getVertex(start + i, x1, y1);
  369. _vertices.getVertex(start + (i + 1) % np, x2, y2);
  370. area += x1.value * y2.value - y1.value * x2.value;
  371. i++;
  372. }
  373. return (area < 0.0) ? PathFlags.CW : PathFlags.CCW;
  374. }
  375. //---------------------------------------------------------------------------------------------------
  376. public function invertPolygon(start:UInt, ?end:UInt):Void
  377. {
  378. if (end == null)
  379. {
  380. while (start < _vertices.verticesCount &&
  381. !PathUtils.isVertex(_vertices.getCommand(start))) {++start; }
  382. while (cast(start + 1) < _vertices.verticesCount &&
  383. PathUtils.isMoveTo(_vertices.getCommand(start)) &&
  384. PathUtils.isMoveTo(_vertices.getCommand(start + 1))) {++start; }
  385. end = start + 1;
  386. while(end < _vertices.verticesCount &&
  387. !PathUtils.isNextPoly(_vertices.getCommand(end))) {++end; }
  388. }
  389. var tmp_cmd = _vertices.getCommand(start);
  390. --end;
  391. var i = start;
  392. while(i < end)
  393. {
  394. _vertices.modifyCommand(i, _vertices.getCommand(i + 1));
  395. i++;
  396. }
  397. _vertices.modifyCommand(end, tmp_cmd);
  398. while(end > start)
  399. {
  400. _vertices.swapVertices(start++, end--);
  401. }
  402. }
  403. //---------------------------------------------------------------------------------------------------
  404. public function arrangePolygonOrientation(start:UInt, orientation:Int):Int
  405. {
  406. if(orientation == PathFlags.NONE) return start;
  407. while (start < _vertices.verticesCount && !PathUtils.isVertex(_vertices.getCommand(start))) {++start; }
  408. while (cast (start + 1) < _vertices.verticesCount &&
  409. PathUtils.isMoveTo(_vertices.getCommand(start)) &&
  410. PathUtils.isMoveTo(_vertices.getCommand(start + 1))) {++start; }
  411. var end:UInt = start + 1;
  412. while (end < _vertices.verticesCount && !PathUtils.isNextPoly(_vertices.getCommand(end))) {++end; }
  413. if(end - start > 2)
  414. {
  415. if(perceivePolygonOrientation(start, end) != orientation)
  416. {
  417. invertPolygon(start, end);
  418. var cmd;
  419. while(end < _vertices.verticesCount && PathUtils.isEndPoly(cmd = _vertices.getCommand(end)))
  420. {
  421. _vertices.modifyCommand(end++, PathUtils.setOrientation(cmd, orientation));
  422. }
  423. }
  424. }
  425. return end;
  426. }
  427. //---------------------------------------------------------------------------------------------------
  428. public function arrangeOrientations(start:UInt, orientation:Int):Int
  429. {
  430. if(orientation != PathFlags.NONE)
  431. {
  432. while(start < _vertices.verticesCount)
  433. {
  434. start = arrangePolygonOrientation(start, orientation);
  435. if(PathUtils.isStop(_vertices.getCommand(start)))
  436. {
  437. ++start;
  438. break;
  439. }
  440. }
  441. }
  442. return start;
  443. }
  444. //---------------------------------------------------------------------------------------------------
  445. public function arrangeOrientationsAllPaths(orientation:Int):Void
  446. {
  447. if(orientation != PathFlags.NONE)
  448. {
  449. var start:UInt = 0;
  450. while(start < _vertices.verticesCount)
  451. {
  452. start = arrangeOrientations(start, orientation);
  453. }
  454. }
  455. }
  456. //---------------------------------------------------------------------------------------------------
  457. public function flipX(x1:Float, x2:Float):Void
  458. {
  459. var i:UInt = 0;
  460. var x = Ref.float1;
  461. var y = Ref.float2;
  462. var z = _vertices.verticesCount;
  463. while (i < z)
  464. {
  465. var cmd = _vertices.getVertex(i, x, y);
  466. if(PathUtils.isVertex(cmd))
  467. {
  468. _vertices.modifyVertex(i, x2 - x.value + x1, y.value);
  469. }
  470. i++;
  471. }
  472. }
  473. //---------------------------------------------------------------------------------------------------
  474. public function flipY(y1:Float, y2:Float):Void
  475. {
  476. var i:UInt = 0;
  477. var x = Ref.float1;
  478. var y = Ref.float2;
  479. var z = _vertices.verticesCount;
  480. while (i < z)
  481. {
  482. var cmd = _vertices.getVertex(i, x, y);
  483. if(PathUtils.isVertex(cmd))
  484. {
  485. _vertices.modifyVertex(i, x.value, y2 - y.value + y1);
  486. }
  487. i++;
  488. }
  489. }
  490. //---------------------------------------------------------------------------------------------------
  491. public function translate(dx:Float, dy:Float, pathId:Int):Void
  492. {
  493. var num_ver = _vertices.verticesCount;
  494. var i:UInt = pathId;
  495. while(i < num_ver)
  496. {
  497. var x = Ref.float1;
  498. var y = Ref.float2;
  499. var cmd = _vertices.getVertex(pathId, x, y);
  500. if(PathUtils.isStop(cmd)) break;
  501. if(PathUtils.isVertex(cmd))
  502. {
  503. x.value += dx;
  504. y.value += dy;
  505. _vertices.modifyVertex(pathId, x.value, y.value);
  506. }
  507. i++;
  508. }
  509. }
  510. //------------------------------------------------------------------------
  511. public function translateAllPaths(dx:Float, dy:Float):Void
  512. {
  513. var idx:UInt = 0;
  514. var num_ver = _vertices.verticesCount;
  515. while(idx < num_ver)
  516. {
  517. var x = Ref.float1;
  518. var y = Ref.float2;
  519. if(PathUtils.isVertex(_vertices.getVertex(idx, x, y)))
  520. {
  521. x.value += dx;
  522. y.value += dy;
  523. _vertices.modifyVertex(idx, x.value, y.value);
  524. }
  525. idx++;
  526. }
  527. }
  528. //---------------------------------------------------------------------------------------------------
  529. private inline function get_lastX():Float { return _vertices.lastX; }
  530. public inline var lastX(get_lastX, null):Float;
  531. //---------------------------------------------------------------------------------------------------
  532. private inline function get_lastY():Float { return _vertices.lastY; }
  533. public inline var lastY(get_lastY, null):Float;
  534. //---------------------------------------------------------------------------------------------------
  535. private inline function get_verticesCount():Int { return _vertices.verticesCount; }
  536. public inline var verticesCount(get_verticesCount, null):Int;
  537. }