ExtendedGeneralPath.jvm.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  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. int nPts = PointCount;
  147. for (int i = 0; i < TypesCount; i++)
  148. if ((Types [i] & SEG_MASK) == SEG_QUADTO)
  149. nPts++;
  150. pathData.Types = new byte [nPts];
  151. pathData.Points = new PointF [nPts];
  152. int tpos = 0;
  153. int ppos = 0;
  154. int cpos = 0;
  155. byte marker;
  156. bool start;
  157. for (int i = 0; i < TypesCount; i++) {
  158. sbyte segmentType = (sbyte)(Types [i] & SEG_MASK);
  159. // set the masks and the markers
  160. marker = ((Types [i] & SEG_MARKER) != 0) ? (byte)PathPointType.PathMarker : (byte)0;
  161. start = ((Types [i] & SEG_START) != 0);
  162. switch (segmentType) {
  163. case SEG_CLOSE:
  164. pathData.Types [tpos - 1] = (byte) (pathData.Types [tpos - 1] | (byte) PathPointType.CloseSubpath | marker);
  165. break;
  166. case SEG_MOVETO:
  167. pathData.Types [tpos++] = (byte)((byte) PathPointType.Start | marker);
  168. pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  169. break;
  170. case SEG_LINETO:
  171. pathData.Types [tpos++] = (byte) ((byte) PathPointType.Line | marker);
  172. pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  173. break;
  174. case SEG_QUADTO:
  175. /*
  176. .net does not support Quadratic curves, so convert to Cubic according to http://pfaedit.sourceforge.net/bezier.html
  177. The end points of the cubic will be the same as the quadratic's.
  178. CP0 = QP0
  179. CP3 = QP2
  180. The two control points for the cubic are:
  181. CP1 = QP0 + 2/3 *(QP1-QP0)
  182. CP2 = CP1 + 1/3 *(QP2-QP0)
  183. */
  184. float x0 = Coords[cpos-2]; //QP0
  185. float y0 = Coords[cpos-1]; //QP0
  186. float x1 = x0 + (2/3 * (Coords [cpos++]-x0));
  187. float y1 = y0 + (2/3 * (Coords [cpos++]-y0));
  188. float x3 = Coords [cpos++]; //QP2
  189. float y3 = Coords [cpos++]; //QP2
  190. float x2 = x1 + (1/3 * (x3-x0));
  191. float y2 = y1 + (1/3 * (y3-y0));
  192. pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier;
  193. pathData.Points [ppos++] = new PointF (x1, y1);
  194. pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier;
  195. pathData.Points [ppos++] = new PointF (x2, y2);
  196. pathData.Types [tpos++] = (byte) ((byte)PathPointType.Bezier | marker);
  197. pathData.Points [ppos++] = new PointF (x3, y3);
  198. break;
  199. case SEG_CUBICTO:
  200. pathData.Types [tpos++] = (byte)(byte) PathPointType.Bezier3;
  201. pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  202. pathData.Types [tpos++] = (byte) PathPointType.Bezier3;
  203. pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  204. pathData.Types [tpos++] = (byte) ((byte)PathPointType.Bezier3 | marker);
  205. pathData.Points [ppos++] = new PointF (Coords [cpos++], Coords [cpos++]);
  206. break;
  207. }
  208. }
  209. return pathData;
  210. }
  211. #endregion // CachedData
  212. public void append(Shape s)
  213. {
  214. append (s, !LastFigureClosed);
  215. }
  216. #region GeneralPath
  217. public void append(PathIterator pi, bool connect)
  218. {
  219. ClearCache ();
  220. float [] coords = new float [6];
  221. while (!pi.isDone ()) {
  222. switch (pi.currentSegment (coords)) {
  223. case SEG_MOVETO:
  224. if (!connect || _typesCount < 1 || _coordsCount < 2) {
  225. moveTo (coords [0], coords [1]);
  226. break;
  227. }
  228. if (_types [_typesCount - 1] != SEG_CLOSE &&
  229. _coords [_coordsCount - 2] == coords [0] &&
  230. _coords [_coordsCount - 1] == coords [1])
  231. break;
  232. goto case SEG_LINETO;
  233. case SEG_LINETO:
  234. lineTo (coords [0], coords [1]);
  235. break;
  236. case SEG_QUADTO:
  237. quadTo (coords [0], coords [1], coords [2], coords [3]);
  238. break;
  239. case SEG_CUBICTO:
  240. curveTo (coords [0], coords [1], coords [2], coords [3], coords [4], coords [5]);
  241. break;
  242. case SEG_CLOSE:
  243. closePath ();
  244. break;
  245. }
  246. pi.next ();
  247. connect = false;
  248. }
  249. }
  250. public void append(Shape s, bool connect)
  251. {
  252. PathIterator pi = s.getPathIterator (null);
  253. append (pi,connect);
  254. }
  255. public object Clone()
  256. {
  257. ExtendedGeneralPath copy = (ExtendedGeneralPath)MemberwiseClone ();
  258. copy._types = (sbyte []) _types.Clone ();
  259. copy._coords = (float []) _coords.Clone ();
  260. return copy;
  261. }
  262. public void closePath()
  263. {
  264. ClearCache ();
  265. if (_typesCount == 0 || _types[_typesCount - 1] != SEG_CLOSE) {
  266. needRoom (1, 0, true);
  267. _types [_typesCount++] = SEG_CLOSE;
  268. }
  269. }
  270. public bool contains(double x, double y)
  271. {
  272. return GeneralPath.contains (x, y);
  273. }
  274. public bool contains(double x, double y, double w, double h)
  275. {
  276. return GeneralPath.contains (x, y, w, h);
  277. }
  278. public bool contains(Point2D p)
  279. {
  280. return contains (p.getX (), p.getY ());
  281. }
  282. public bool contains(Rectangle2D r)
  283. {
  284. return contains (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
  285. }
  286. public Shape createTransformedShape(AffineTransform at)
  287. {
  288. ExtendedGeneralPath gp = (ExtendedGeneralPath) Clone ();
  289. if (at != null) {
  290. gp.transform (at);
  291. }
  292. return gp;
  293. }
  294. public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3)
  295. {
  296. ClearCache ();
  297. needRoom (1, 6, true);
  298. _types [_typesCount++] = SEG_CUBICTO;
  299. _coords [_coordsCount++] = x1;
  300. _coords [_coordsCount++] = y1;
  301. _coords [_coordsCount++] = x2;
  302. _coords [_coordsCount++] = y2;
  303. _coords [_coordsCount++] = x3;
  304. _coords [_coordsCount++] = y3;
  305. }
  306. public java.awt.Rectangle getBounds()
  307. {
  308. return getBounds2D ().getBounds ();
  309. }
  310. public Rectangle2D getBounds2D()
  311. {
  312. float x1, y1, x2, y2;
  313. int i = _coordsCount;
  314. if (i > 0) {
  315. y1 = y2 = _coords [--i];
  316. x1 = x2 = _coords [--i];
  317. while (i > 0) {
  318. float y = _coords [--i];
  319. float x = _coords [--i];
  320. if (x < x1) x1 = x;
  321. if (y < y1) y1 = y;
  322. if (x > x2) x2 = x;
  323. if (y > y2) y2 = y;
  324. }
  325. }
  326. else {
  327. x1 = y1 = x2 = y2 = 0f;
  328. }
  329. return new Rectangle2D.Float (x1, y1, x2 - x1, y2 - y1);
  330. }
  331. public Point2D getCurrentPoint()
  332. {
  333. if (_typesCount < 1 || _coordsCount < 2)
  334. return null;
  335. int index = _coordsCount;
  336. if (_types [_typesCount - 1] == SEG_CLOSE)
  337. for (int i = _typesCount - 2; i > 0; i--) {
  338. switch (_types [i]) {
  339. case SEG_MOVETO:
  340. //break loop;
  341. goto loopend;
  342. case SEG_LINETO:
  343. index -= 2;
  344. break;
  345. case SEG_QUADTO:
  346. index -= 4;
  347. break;
  348. case SEG_CUBICTO:
  349. index -= 6;
  350. break;
  351. case SEG_CLOSE:
  352. break;
  353. }
  354. }
  355. loopend:
  356. return new Point2D.Float (_coords [index - 2], _coords [index - 1]);
  357. }
  358. public PathIterator getPathIterator(AffineTransform at) {
  359. return new GeneralPathIterator (this, at);
  360. }
  361. public PathIterator getPathIterator(AffineTransform at, double flatness) {
  362. return new FlatteningPathIterator (getPathIterator (at), flatness);
  363. }
  364. public int getWindingRule()
  365. {
  366. return _windingRule;
  367. }
  368. public bool intersects(double x, double y, double w, double h)
  369. {
  370. return GeneralPath.intersects (x, y, w, h);
  371. }
  372. public bool intersects(Rectangle2D r)
  373. {
  374. return intersects (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
  375. }
  376. public void lineTo(float x, float y)
  377. {
  378. ClearCache ();
  379. needRoom (1, 2, true);
  380. _types [_typesCount++] = SEG_LINETO;
  381. _coords [_coordsCount++] = x;
  382. _coords [_coordsCount++] = y;
  383. }
  384. public void moveTo(float x, float y)
  385. {
  386. ClearCache ();
  387. if (_typesCount > 0 && _types [_typesCount - 1] == SEG_MOVETO) {
  388. _coords [_coordsCount - 2] = x;
  389. _coords [_coordsCount - 1] = y;
  390. }
  391. else {
  392. needRoom (1, 2, false);
  393. _types [_typesCount++] = SEG_MOVETO;
  394. _coords [_coordsCount++] = x;
  395. _coords [_coordsCount++] = y;
  396. }
  397. }
  398. public void quadTo(float x1, float y1, float x2, float y2)
  399. {
  400. // restore quadTo as cubic affects quality
  401. ClearCache ();
  402. needRoom (1, 4, true);
  403. _types [_typesCount++] = SEG_QUADTO;
  404. _coords [_coordsCount++] = x1;
  405. _coords [_coordsCount++] = y1;
  406. _coords [_coordsCount++] = x2;
  407. _coords [_coordsCount++] = y2;
  408. }
  409. public void reset()
  410. {
  411. ClearCache ();
  412. _typesCount = 0;
  413. _coordsCount = 0;
  414. }
  415. public void setWindingRule(int rule)
  416. {
  417. if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
  418. throw new IllegalArgumentException ("winding rule must be WIND_EVEN_ODD or WIND_NON_ZERO");
  419. }
  420. _windingRule = rule;
  421. }
  422. public void transform(AffineTransform at)
  423. {
  424. transform(at, 0, CoordsCount);
  425. }
  426. public void transform(AffineTransform at, int startCoord, int numCoords) {
  427. ClearCache ();
  428. at.transform (_coords, startCoord, _coords, startCoord, numCoords/2);
  429. }
  430. private void needRoom(int newTypes, int newCoords, bool needMove)
  431. {
  432. if (needMove && _typesCount == 0)
  433. throw new IllegalPathStateException ("missing initial moveto in path definition");
  434. int size = _coords.Length;
  435. if (_coordsCount + newCoords > size) {
  436. int grow = size;
  437. if (grow > EXPAND_MAX * 2)
  438. grow = EXPAND_MAX * 2;
  439. if (grow < newCoords)
  440. grow = newCoords;
  441. float [] arr = new float [size + grow];
  442. Array.Copy (_coords, 0, arr, 0, _coordsCount);
  443. _coords = arr;
  444. }
  445. size = _types.Length;
  446. if (_typesCount + newTypes > size) {
  447. int grow = size;
  448. if (grow > EXPAND_MAX)
  449. grow = EXPAND_MAX;
  450. if (grow < newTypes)
  451. grow = newTypes;
  452. sbyte [] arr = new sbyte [size + grow];
  453. Array.Copy (_types, 0, arr, 0, _typesCount);
  454. _types = arr;
  455. }
  456. }
  457. #endregion // GeneralPath
  458. public void SetMarkers()
  459. {
  460. ClearCache ();
  461. if (TypesCount > 0)
  462. Types [ TypesCount - 1] |= SEG_MARKER;
  463. }
  464. public void ClearMarkers()
  465. {
  466. ClearCache ();
  467. for (int i = 0; i < TypesCount; i++)
  468. Types [i] &= ~SEG_MARKER;
  469. }
  470. public void StartFigure ()
  471. {
  472. ClearCache ();
  473. if (TypesCount > 0)
  474. Types [TypesCount - 1] |= ExtendedGeneralPath.SEG_START;
  475. }
  476. private void Reset (int initialTypes, int initialCoords)
  477. {
  478. ClearCache ();
  479. _types = new sbyte [initialTypes];
  480. _coords = new float [initialCoords * 2];
  481. _typesCount = 0;
  482. _coordsCount = 0;
  483. }
  484. internal void Clear ()
  485. {
  486. Reset (INIT_SIZE, INIT_SIZE);
  487. }
  488. internal void Reverse ()
  489. {
  490. ClearCache ();
  491. // revert coordinates
  492. for (int i=0, max = CoordsCount / 2; i < max;) {
  493. int ix = i++;
  494. int iy = i++;
  495. int rix = CoordsCount - i;
  496. int riy = rix + 1;
  497. float tmpx = Coords [ix];
  498. float tmpy = Coords [iy];
  499. Coords [ix] = Coords [rix];
  500. Coords [iy] = Coords [riy];
  501. Coords [rix] = tmpx;
  502. Coords [riy] = tmpy;
  503. }
  504. // revert types
  505. sbyte [] newTypes = new sbyte [TypesCount];
  506. int oldIdx = 0;
  507. int newIdx = TypesCount - 1;
  508. int copyStart;
  509. int copyEnd;
  510. sbyte mask1 = 0;
  511. sbyte mask2 = 0;
  512. sbyte closeMask = 0;
  513. bool closedFigure = false;
  514. while (oldIdx < TypesCount) {
  515. // start copying after moveto
  516. copyStart = ++oldIdx;
  517. // continue to the next figure start
  518. while ((Types [oldIdx] != SEG_MOVETO) && (oldIdx < TypesCount))
  519. oldIdx++;
  520. copyEnd = oldIdx - 1;
  521. // check whenever current figure is closed
  522. if ((Types [oldIdx - 1] & SEG_CLOSE) != 0) {
  523. closedFigure = true;
  524. // close figure
  525. newTypes [newIdx--] = (sbyte)(SEG_CLOSE | mask1);
  526. mask1 = 0;
  527. mask2 = 0;
  528. // end copy one cell earlier
  529. copyEnd--;
  530. closeMask = (sbyte)(Types [oldIdx - 1] & (sbyte)SEG_MARKER);
  531. }
  532. else {
  533. mask2 = mask1;
  534. mask1 = 0;
  535. }
  536. // copy reverted "inner" types
  537. for(int i = copyStart; i <= copyEnd; i++) {
  538. newTypes [newIdx--] = (sbyte)((Types [i] & SEG_MASK) | mask2);
  539. mask2 = mask1;
  540. mask1 = (sbyte)(Types [i] & (sbyte)SEG_MARKER);
  541. }
  542. // copy moveto
  543. newTypes [newIdx--] = SEG_MOVETO;
  544. // pass close mask to the nex figure
  545. if (closedFigure) {
  546. mask1 = closeMask;
  547. closedFigure = false;
  548. }
  549. }
  550. _types = newTypes;
  551. }
  552. public PointF GetLastPoint ()
  553. {
  554. if (CoordsCount == 0)
  555. throw new System.ArgumentException ("Invalid parameter used.");
  556. return new PointF (Coords [CoordsCount - 2], Coords [CoordsCount - 1]);
  557. }
  558. #endregion //Methods
  559. #region Private helpers
  560. #if DEBUG
  561. private void Print()
  562. {
  563. Console.WriteLine ("\n\n");
  564. float [] fpoints = _coords;
  565. int cpos = 0;
  566. for (int i=0; i < _typesCount; i++) {
  567. sbyte type = _types [i];
  568. string marker = String.Empty;
  569. if ((type & SEG_MARKER) != 0)
  570. marker = " | MARKER";
  571. switch (type & SEG_MASK) {
  572. case SEG_CLOSE:
  573. Console.WriteLine ("CLOSE {0}",marker);
  574. break;
  575. case SEG_MOVETO:
  576. Console.WriteLine("{0}{3} ({1},{2})","MOVETO", fpoints[cpos++], fpoints[cpos++], marker);
  577. break;
  578. case SEG_LINETO:
  579. Console.WriteLine("{0}{3} ({1},{2})","LINETO", fpoints[cpos++], fpoints[cpos++], marker);
  580. break;
  581. case SEG_QUADTO:
  582. Console.WriteLine("{0}{3} ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++], marker);
  583. Console.WriteLine(" ({1},{2})","QUADTO", fpoints[cpos++], fpoints[cpos++]);
  584. break;
  585. case SEG_CUBICTO:
  586. Console.WriteLine("{0}{3} ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++], marker);
  587. Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);
  588. Console.WriteLine(" ({1},{2})","CUBICTO", fpoints[cpos++], fpoints[cpos++]);
  589. break;
  590. }
  591. }
  592. }
  593. #endif
  594. #endregion // Private helpers
  595. }
  596. }