ExtendedGeneralPath.jvm.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. //
  2. // System.Drawing.Drawing2D.ExtendedGeneralPath.cs
  3. //
  4. // Author:
  5. // Bors Kirzner <[email protected]>
  6. //
  7. // Copyright (C) 2005 Mainsoft Corporation, (http://www.mainsoft.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using java.awt;
  30. using java.awt.geom;
  31. using java.lang;
  32. namespace System.Drawing.Drawing2D
  33. {
  34. internal class ExtendedGeneralPath : Shape, ICloneable
  35. {
  36. #region Fields
  37. public const int WIND_EVEN_ODD = 0; //PathIterator__Finals.WIND_EVEN_ODD;
  38. public const int WIND_NON_ZERO = 1; //PathIterator__Finals.WIND_NON_ZERO;
  39. public const sbyte SEG_MOVETO = 0; //(byte) PathIterator__Finals.SEG_MOVETO;
  40. public const sbyte SEG_LINETO = 1; //(byte) PathIterator__Finals.SEG_LINETO;
  41. public const sbyte SEG_QUADTO = 2; //(byte) PathIterator__Finals.SEG_QUADTO;
  42. public const sbyte SEG_CUBICTO = 3; //(byte) PathIterator__Finals.SEG_CUBICTO;
  43. public const sbyte SEG_CLOSE = 4; //(byte) PathIterator__Finals.SEG_CLOSE;
  44. public const sbyte SEG_START = 16; // segment start
  45. public const sbyte SEG_MASK = SEG_MOVETO | SEG_LINETO | SEG_QUADTO | SEG_CUBICTO | SEG_CLOSE; // mask to eliminate SEG_CLOSE and SEG_MARKER
  46. private const sbyte SEG_MARKER = 32; // path marker
  47. private sbyte [] _types;
  48. private float [] _coords;
  49. private int _typesCount;
  50. private int _coordsCount;
  51. private int _windingRule;
  52. private PathData _pathData;
  53. private GeneralPath _generalPath;
  54. const int INIT_SIZE = 20;
  55. const int EXPAND_MAX = 500;
  56. #endregion // Fileds
  57. #region Constructors
  58. public ExtendedGeneralPath() : this (WIND_NON_ZERO, INIT_SIZE, INIT_SIZE)
  59. {
  60. }
  61. public ExtendedGeneralPath(int rule) : this (rule, INIT_SIZE, INIT_SIZE)
  62. {
  63. }
  64. public ExtendedGeneralPath(int rule, int initialCapacity) : this (rule, initialCapacity, initialCapacity)
  65. {
  66. }
  67. public ExtendedGeneralPath(Shape s) : this(WIND_NON_ZERO, INIT_SIZE, INIT_SIZE)
  68. {
  69. PathIterator pi = s.getPathIterator (null);
  70. setWindingRule (pi.getWindingRule ());
  71. append (pi, false);
  72. }
  73. private ExtendedGeneralPath(int rule, int initialTypes, int initialCoords)
  74. {
  75. setWindingRule(rule);
  76. Reset (initialTypes, initialCoords);
  77. }
  78. #endregion // Constructors
  79. #region Properties
  80. private GeneralPath GeneralPath
  81. {
  82. get {
  83. if (_generalPath == null) {
  84. _generalPath = GetGeneralPath ();
  85. }
  86. return _generalPath;
  87. }
  88. }
  89. public sbyte [] Types
  90. {
  91. get { return _types; }
  92. }
  93. public float [] Coords
  94. {
  95. get { return _coords; }
  96. }
  97. public int TypesCount
  98. {
  99. get { return _typesCount; }
  100. }
  101. public int CoordsCount
  102. {
  103. get { return _coordsCount; }
  104. }
  105. public bool LastFigureClosed
  106. {
  107. get {
  108. return ((TypesCount == 0) ||
  109. ((Types [TypesCount - 1] & ExtendedGeneralPath.SEG_CLOSE) != 0) ||
  110. ((Types [TypesCount - 1] & ExtendedGeneralPath.SEG_START) != 0));
  111. }
  112. }
  113. public int PointCount
  114. {
  115. get {
  116. return CoordsCount / 2;
  117. }
  118. }
  119. public PathData PathData
  120. {
  121. get
  122. {
  123. if (_pathData == null)
  124. _pathData = GetPathData ();
  125. return _pathData;
  126. }
  127. }
  128. #endregion // Properties
  129. #region Methods
  130. #region CachedData
  131. private void ClearCache ()
  132. {
  133. _pathData = null;
  134. _generalPath = null;
  135. }
  136. private GeneralPath GetGeneralPath ()
  137. {
  138. PathIterator iter = getPathIterator (null);
  139. GeneralPath path = new GeneralPath ();
  140. path.append (iter, false);
  141. return path;
  142. }
  143. private PathData GetPathData ()
  144. {
  145. PathData pathData = new PathData();
  146. pathData.Types = new byte [PointCount];
  147. pathData.Points = new PointF [PointCount];
  148. int tpos = 0;
  149. int ppos = 0;
  150. int cpos = 0;
  151. byte marker;
  152. bool start;
  153. for (int i = 0; i < TypesCount; i++) {
  154. sbyte segmentType = (sbyte)(Types [i] & SEG_MASK);
  155. // set the masks and the markers
  156. marker = ((Types [i] & SEG_MARKER) != 0) ? (byte)PathPointType.PathMarker : (byte)0;
  157. start = ((Types [i] & SEG_START) != 0);
  158. switch (segmentType) {
  159. case SEG_CLOSE:
  160. pathData.InternalTypes [tpos - 1] = (byte) (pathData.InternalTypes [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);
  161. break;
  162. case SEG_MOVETO:
  163. pathData.InternalTypes [tpos++] = (byte)((byte) PathPointType.Start | marker);
  164. pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  165. break;
  166. case SEG_LINETO:
  167. pathData.InternalTypes [tpos++] = (byte) ((byte) PathPointType.Line | marker);
  168. pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  169. break;
  170. case SEG_QUADTO:
  171. // FIXME : use 4 cp , two of which
  172. pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier;
  173. pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  174. pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);
  175. pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  176. break;
  177. case SEG_CUBICTO:
  178. pathData.InternalTypes [tpos++] = (byte)(byte) PathPointType.Bezier3;
  179. pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  180. pathData.InternalTypes [tpos++] = (byte) PathPointType.Bezier3;
  181. pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  182. pathData.InternalTypes [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);
  183. pathData.InternalPoints [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  184. break;
  185. }
  186. }
  187. return pathData;
  188. }
  189. #endregion // CachedData
  190. public void append(Shape s)
  191. {
  192. append (s, !LastFigureClosed);
  193. }
  194. #region GeneralPath
  195. public void append(PathIterator pi, bool connect)
  196. {
  197. ClearCache ();
  198. float [] coords = new float [6];
  199. while (!pi.isDone ()) {
  200. switch (pi.currentSegment (coords)) {
  201. case SEG_MOVETO:
  202. if (!connect || _typesCount < 1 || _coordsCount < 2) {
  203. moveTo (coords [0], coords [1]);
  204. break;
  205. }
  206. if (_types [_typesCount - 1] != SEG_CLOSE &&
  207. _coords [_coordsCount - 2] == coords [0] &&
  208. _coords [_coordsCount - 1] == coords [1])
  209. break;
  210. goto case SEG_LINETO;
  211. case SEG_LINETO:
  212. lineTo (coords [0], coords [1]);
  213. break;
  214. case SEG_QUADTO:
  215. quadTo (coords [0], coords [1], coords [2], coords [3]);
  216. break;
  217. case SEG_CUBICTO:
  218. curveTo (coords [0], coords [1], coords [2], coords [3], coords [4], coords [5]);
  219. break;
  220. case SEG_CLOSE:
  221. closePath ();
  222. break;
  223. }
  224. pi.next ();
  225. connect = false;
  226. }
  227. }
  228. public void append(Shape s, bool connect)
  229. {
  230. PathIterator pi = s.getPathIterator (null);
  231. append (pi,connect);
  232. }
  233. public object Clone()
  234. {
  235. ExtendedGeneralPath copy = (ExtendedGeneralPath)MemberwiseClone ();
  236. copy._types = (sbyte []) _types.Clone ();
  237. copy._coords = (float []) _coords.Clone ();
  238. return copy;
  239. }
  240. public void closePath()
  241. {
  242. ClearCache ();
  243. if (_typesCount == 0 || _types[_typesCount - 1] != SEG_CLOSE) {
  244. needRoom (1, 0, true);
  245. _types [_typesCount++] = SEG_CLOSE;
  246. }
  247. }
  248. public bool contains(double x, double y)
  249. {
  250. return GeneralPath.contains (x, y);
  251. }
  252. public bool contains(double x, double y, double w, double h)
  253. {
  254. return GeneralPath.contains (x, y, w, h);
  255. }
  256. public bool contains(Point2D p)
  257. {
  258. return contains (p.getX (), p.getY ());
  259. }
  260. public bool contains(Rectangle2D r)
  261. {
  262. return contains (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
  263. }
  264. public Shape createTransformedShape(AffineTransform at)
  265. {
  266. ExtendedGeneralPath gp = (ExtendedGeneralPath) Clone ();
  267. if (at != null) {
  268. gp.transform (at);
  269. }
  270. return gp;
  271. }
  272. public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3)
  273. {
  274. ClearCache ();
  275. needRoom (1, 6, true);
  276. _types [_typesCount++] = SEG_CUBICTO;
  277. _coords [_coordsCount++] = x1;
  278. _coords [_coordsCount++] = y1;
  279. _coords [_coordsCount++] = x2;
  280. _coords [_coordsCount++] = y2;
  281. _coords [_coordsCount++] = x3;
  282. _coords [_coordsCount++] = y3;
  283. }
  284. public java.awt.Rectangle getBounds()
  285. {
  286. return getBounds2D ().getBounds ();
  287. }
  288. public Rectangle2D getBounds2D()
  289. {
  290. float x1, y1, x2, y2;
  291. int i = _coordsCount;
  292. if (i > 0) {
  293. y1 = y2 = _coords [--i];
  294. x1 = x2 = _coords [--i];
  295. while (i > 0) {
  296. float y = _coords [--i];
  297. float x = _coords [--i];
  298. if (x < x1) x1 = x;
  299. if (y < y1) y1 = y;
  300. if (x > x2) x2 = x;
  301. if (y > y2) y2 = y;
  302. }
  303. }
  304. else {
  305. x1 = y1 = x2 = y2 = 0f;
  306. }
  307. return new Rectangle2D.Float (x1, y1, x2 - x1, y2 - y1);
  308. }
  309. public Point2D getCurrentPoint()
  310. {
  311. if (_typesCount < 1 || _coordsCount < 2)
  312. return null;
  313. int index = _coordsCount;
  314. if (_types [_typesCount - 1] == SEG_CLOSE)
  315. for (int i = _typesCount - 2; i > 0; i--) {
  316. switch (_types [i]) {
  317. case SEG_MOVETO:
  318. //break loop;
  319. goto loopend;
  320. case SEG_LINETO:
  321. index -= 2;
  322. break;
  323. case SEG_QUADTO:
  324. index -= 4;
  325. break;
  326. case SEG_CUBICTO:
  327. index -= 6;
  328. break;
  329. case SEG_CLOSE:
  330. break;
  331. }
  332. }
  333. loopend:
  334. return new Point2D.Float (_coords [index - 2], _coords [index - 1]);
  335. }
  336. public PathIterator getPathIterator(AffineTransform at) {
  337. return new GeneralPathIterator (this, at);
  338. }
  339. public PathIterator getPathIterator(AffineTransform at, double flatness) {
  340. return new FlatteningPathIterator (getPathIterator (at), flatness);
  341. }
  342. public int getWindingRule()
  343. {
  344. return _windingRule;
  345. }
  346. public bool intersects(double x, double y, double w, double h)
  347. {
  348. return GeneralPath.intersects (x, y, w, h);
  349. }
  350. public bool intersects(Rectangle2D r)
  351. {
  352. return intersects (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
  353. }
  354. public void lineTo(float x, float y)
  355. {
  356. ClearCache ();
  357. needRoom (1, 2, true);
  358. _types [_typesCount++] = SEG_LINETO;
  359. _coords [_coordsCount++] = x;
  360. _coords [_coordsCount++] = y;
  361. }
  362. public void moveTo(float x, float y)
  363. {
  364. ClearCache ();
  365. if (_typesCount > 0 && _types [_typesCount - 1] == SEG_MOVETO) {
  366. _coords [_coordsCount - 2] = x;
  367. _coords [_coordsCount - 1] = y;
  368. }
  369. else {
  370. needRoom (1, 2, false);
  371. _types [_typesCount++] = SEG_MOVETO;
  372. _coords [_coordsCount++] = x;
  373. _coords [_coordsCount++] = y;
  374. }
  375. }
  376. public void quadTo(float x1, float y1, float x2, float y2)
  377. {
  378. ClearCache ();
  379. needRoom (1, 4, true);
  380. _types [_typesCount++] = SEG_QUADTO;
  381. _coords [_coordsCount++] = x1;
  382. _coords [_coordsCount++] = y1;
  383. _coords [_coordsCount++] = x2;
  384. _coords [_coordsCount++] = y2;
  385. }
  386. public void reset()
  387. {
  388. ClearCache ();
  389. _typesCount = 0;
  390. _coordsCount = 0;
  391. }
  392. public void setWindingRule(int rule)
  393. {
  394. if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
  395. throw new IllegalArgumentException ("winding rule must be WIND_EVEN_ODD or WIND_NON_ZERO");
  396. }
  397. _windingRule = rule;
  398. }
  399. public void transform(AffineTransform at)
  400. {
  401. ClearCache ();
  402. at.transform (_coords, 0, _coords, 0, _coordsCount/2);
  403. }
  404. private void needRoom(int newTypes, int newCoords, bool needMove)
  405. {
  406. if (needMove && _typesCount == 0)
  407. throw new IllegalPathStateException ("missing initial moveto in path definition");
  408. int size = _coords.Length;
  409. if (_coordsCount + newCoords > size) {
  410. int grow = size;
  411. if (grow > EXPAND_MAX * 2)
  412. grow = EXPAND_MAX * 2;
  413. if (grow < newCoords)
  414. grow = newCoords;
  415. float [] arr = new float [size + grow];
  416. Array.Copy (_coords, 0, arr, 0, _coordsCount);
  417. _coords = arr;
  418. }
  419. size = _types.Length;
  420. if (_typesCount + newTypes > size) {
  421. int grow = size;
  422. if (grow > EXPAND_MAX)
  423. grow = EXPAND_MAX;
  424. if (grow < newTypes)
  425. grow = newTypes;
  426. sbyte [] arr = new sbyte [size + grow];
  427. Array.Copy (_types, 0, arr, 0, _typesCount);
  428. _types = arr;
  429. }
  430. }
  431. #endregion // GeneralPath
  432. public void SetMarkers()
  433. {
  434. ClearCache ();
  435. if (TypesCount > 0)
  436. Types [ TypesCount - 1] |= SEG_MARKER;
  437. }
  438. public void ClearMarkers()
  439. {
  440. ClearCache ();
  441. for (int i = 0; i < TypesCount; i++)
  442. Types [i] &= ~SEG_MARKER;
  443. }
  444. public void StartFigure ()
  445. {
  446. ClearCache ();
  447. if (TypesCount > 0)
  448. Types [TypesCount - 1] |= ExtendedGeneralPath.SEG_START;
  449. }
  450. private void Reset (int initialTypes, int initialCoords)
  451. {
  452. ClearCache ();
  453. _types = new sbyte [initialTypes];
  454. _coords = new float [initialCoords * 2];
  455. _typesCount = 0;
  456. _coordsCount = 0;
  457. }
  458. internal void Clear ()
  459. {
  460. Reset (INIT_SIZE, INIT_SIZE);
  461. }
  462. internal void Reverse ()
  463. {
  464. ClearCache ();
  465. // revert coordinates
  466. for (int i=0, max = CoordsCount / 2; i < max;) {
  467. int ix = i++;
  468. int iy = i++;
  469. int rix = CoordsCount - i;
  470. int riy = rix + 1;
  471. float tmpx = Coords [ix];
  472. float tmpy = Coords [iy];
  473. Coords [ix] = Coords [rix];
  474. Coords [iy] = Coords [riy];
  475. Coords [rix] = tmpx;
  476. Coords [riy] = tmpy;
  477. }
  478. // revert types
  479. sbyte [] newTypes = new sbyte [TypesCount];
  480. int oldIdx = 0;
  481. int newIdx = TypesCount - 1;
  482. int copyStart;
  483. int copyEnd;
  484. sbyte mask1 = 0;
  485. sbyte mask2 = 0;
  486. sbyte closeMask = 0;
  487. bool closedFigure = false;
  488. while (oldIdx < TypesCount) {
  489. // start copying after moveto
  490. copyStart = ++oldIdx;
  491. // continue to the next figure start
  492. while ((Types [oldIdx] != SEG_MOVETO) && (oldIdx < TypesCount))
  493. oldIdx++;
  494. copyEnd = oldIdx - 1;
  495. // check whenever current figure is closed
  496. if ((Types [oldIdx - 1] & SEG_CLOSE) != 0) {
  497. closedFigure = true;
  498. // close figure
  499. newTypes [newIdx--] = (sbyte)(SEG_CLOSE | mask1);
  500. mask1 = 0;
  501. mask2 = 0;
  502. // end copy one cell earlier
  503. copyEnd--;
  504. closeMask = (sbyte)(Types [oldIdx - 1] & (sbyte)SEG_MARKER);
  505. }
  506. else {
  507. mask2 = mask1;
  508. mask1 = 0;
  509. }
  510. // copy reverted "inner" types
  511. for(int i = copyStart; i <= copyEnd; i++) {
  512. newTypes [newIdx--] = (sbyte)((Types [i] & SEG_MASK) | mask2);
  513. mask2 = mask1;
  514. mask1 = (sbyte)(Types [i] & (sbyte)SEG_MARKER);
  515. }
  516. // copy moveto
  517. newTypes [newIdx--] = SEG_MOVETO;
  518. // pass close mask to the nex figure
  519. if (closedFigure) {
  520. mask1 = closeMask;
  521. closedFigure = false;
  522. }
  523. }
  524. _types = newTypes;
  525. }
  526. public PointF GetLastPoint ()
  527. {
  528. if (CoordsCount == 0)
  529. throw new System.ArgumentException ("Invalid parameter used.");
  530. return new PointF (Coords [CoordsCount - 2], Coords [CoordsCount - 1]);
  531. }
  532. #endregion //Methods
  533. #region Private helpers
  534. #if DEBUG
  535. private void Print()
  536. {
  537. Console.WriteLine ("\n\n");
  538. float [] fpoints = _coords;
  539. int cpos = 0;
  540. for (int i=0; i < _typesCount; i++) {
  541. sbyte type = _types [i];
  542. string marker = String.Empty;
  543. if ((type & SEG_MARKER) != 0)
  544. marker = " | MARKER";
  545. switch (type & SEG_MASK) {
  546. case SEG_CLOSE:
  547. Console.WriteLine ("CLOSE {0}",marker);
  548. break;
  549. case SEG_MOVETO:
  550. Console.WriteLine("{0}{3} ({1},{2})","MOVETO", fpoints[cpos++], fpoints[cpos++], marker);
  551. break;
  552. case SEG_LINETO:
  553. Console.WriteLine("{0}{3} ({1},{2})","LINETO", fpoints[cpos++], fpoints[cpos++], marker);
  554. break;
  555. case SEG_QUADTO:
  556. Console.WriteLine("{0}{3} ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++], marker);
  557. Console.WriteLine(" ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++]);
  558. break;
  559. case SEG_CUBICTO:
  560. Console.WriteLine("{0}{3} ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++], marker);
  561. Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);
  562. Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);
  563. break;
  564. }
  565. }
  566. }
  567. #endif
  568. #endregion // Private helpers
  569. }
  570. }