Polygon.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Drawing.Drawing2D;
  6. using System.Runtime.InteropServices;
  7. namespace PaintDotNet.SystemLayer.GpcWrapper
  8. {
  9. internal sealed class Polygon
  10. {
  11. public int NofContours;
  12. public bool[] ContourIsHole;
  13. public VertexList[] Contour;
  14. public Polygon()
  15. {
  16. }
  17. // path should contain only polylines ( use Flatten )
  18. // furthermore the constructor assumes that all Subpathes of path except the first one are holes
  19. public Polygon(GraphicsPath path)
  20. {
  21. byte[] pathTypes = path.PathTypes;
  22. NofContours = 0;
  23. foreach (byte b in pathTypes)
  24. {
  25. if ((b & ((byte)PathPointType.CloseSubpath)) != 0)
  26. {
  27. NofContours++;
  28. }
  29. }
  30. ContourIsHole = new bool[NofContours];
  31. Contour = new VertexList[NofContours];
  32. for (int i = 0; i < NofContours; i++)
  33. {
  34. ContourIsHole[i] = (i == 0);
  35. }
  36. int contourNr = 0;
  37. List<PointF> contour = new List<PointF>();
  38. PointF[] pathPoints = path.PathPoints;
  39. for (int i = 0; i < pathPoints.Length; i++)
  40. {
  41. contour.Add(pathPoints[i]);
  42. if ((pathTypes[i] & ((byte)PathPointType.CloseSubpath)) != 0)
  43. {
  44. PointF[] pointArray = contour.ToArray();
  45. VertexList vl = new VertexList(pointArray);
  46. Contour[contourNr++] = vl;
  47. contour.Clear();
  48. }
  49. }
  50. }
  51. public GraphicsPath ToGraphicsPath()
  52. {
  53. GraphicsPath path = new GraphicsPath();
  54. for (int i = 0; i < NofContours; i++)
  55. {
  56. PointF[] points = Contour[i].ToPoints();
  57. if (ContourIsHole[i])
  58. {
  59. Array.Reverse(points);
  60. }
  61. path.AddPolygon(points);
  62. }
  63. return path;
  64. }
  65. public Polygon Clip(CombineMode operation, Polygon polygon)
  66. {
  67. return Clip(operation, this, polygon);
  68. }
  69. public static bool Check(CombineMode combineMode)
  70. {
  71. switch (combineMode)
  72. {
  73. case CombineMode.Exclude:
  74. case CombineMode.Intersect:
  75. case CombineMode.Union:
  76. case CombineMode.Xor:
  77. return true;
  78. case CombineMode.Complement:
  79. case CombineMode.Replace:
  80. default:
  81. return false;
  82. }
  83. }
  84. public static void Validate(CombineMode combineMode)
  85. {
  86. if (Check(combineMode))
  87. {
  88. return;
  89. }
  90. else
  91. {
  92. throw new InvalidEnumArgumentException();
  93. }
  94. }
  95. private static NativeConstants.gpc_op Convert(CombineMode combineMode)
  96. {
  97. switch (combineMode)
  98. {
  99. case CombineMode.Exclude:
  100. return NativeConstants.gpc_op.GPC_DIFF;
  101. case CombineMode.Intersect:
  102. return NativeConstants.gpc_op.GPC_INT;
  103. case CombineMode.Union:
  104. return NativeConstants.gpc_op.GPC_UNION;
  105. case CombineMode.Xor:
  106. return NativeConstants.gpc_op.GPC_XOR;
  107. case CombineMode.Complement:
  108. case CombineMode.Replace:
  109. default:
  110. throw new InvalidEnumArgumentException();
  111. }
  112. }
  113. public static Polygon Clip(CombineMode clipMode, Polygon subject_polygon, Polygon clip_polygon)
  114. {
  115. Validate(clipMode);
  116. NativeConstants.gpc_op gpcOp = Convert(clipMode);
  117. NativeStructs.gpc_polygon gpc_polygon = new NativeStructs.gpc_polygon();
  118. NativeStructs.gpc_polygon gpc_subject_polygon = PolygonTo_gpc_polygon(subject_polygon);
  119. NativeStructs.gpc_polygon gpc_clip_polygon = PolygonTo_gpc_polygon(clip_polygon);
  120. NativeMethods.gpc_polygon_clip(gpcOp, ref gpc_subject_polygon, ref gpc_clip_polygon, ref gpc_polygon);
  121. Polygon polygon = gpc_polygon_ToPolygon(gpc_polygon);
  122. Free_gpc_polygon(gpc_subject_polygon);
  123. Free_gpc_polygon(gpc_clip_polygon);
  124. NativeMethods.gpc_free_polygon(ref gpc_polygon);
  125. return polygon;
  126. }
  127. private static NativeStructs.gpc_polygon PolygonTo_gpc_polygon(Polygon polygon)
  128. {
  129. NativeStructs.gpc_polygon gpc_pol = new NativeStructs.gpc_polygon();
  130. gpc_pol.num_contours = polygon.NofContours;
  131. int[] hole = new int[polygon.NofContours];
  132. for (int i = 0; i < polygon.NofContours; i++)
  133. {
  134. hole[i] = (polygon.ContourIsHole[i] ? 1 : 0);
  135. }
  136. gpc_pol.hole = Marshal.AllocCoTaskMem(polygon.NofContours * Marshal.SizeOf(typeof(int) /*hole[0]*/));
  137. if (polygon.NofContours > 0)
  138. {
  139. Marshal.Copy(hole, 0, gpc_pol.hole, polygon.NofContours);
  140. }
  141. gpc_pol.contour = Marshal.AllocCoTaskMem(polygon.NofContours * Marshal.SizeOf(typeof(NativeStructs.gpc_vertex_list)));
  142. IntPtr ptr = gpc_pol.contour;
  143. for (int i = 0; i < polygon.NofContours; i++)
  144. {
  145. NativeStructs.gpc_vertex_list gpc_vtx_list = new NativeStructs.gpc_vertex_list();
  146. gpc_vtx_list.num_vertices = polygon.Contour[i].NofVertices;
  147. gpc_vtx_list.vertex = Marshal.AllocCoTaskMem(polygon.Contour[i].NofVertices * Marshal.SizeOf(typeof(NativeStructs.gpc_vertex)));
  148. IntPtr ptr2 = gpc_vtx_list.vertex;
  149. for (int j = 0; j < polygon.Contour[i].NofVertices; j++)
  150. {
  151. NativeStructs.gpc_vertex gpc_vtx = new NativeStructs.gpc_vertex();
  152. gpc_vtx.x = polygon.Contour[i].Vertex[j].X;
  153. gpc_vtx.y = polygon.Contour[i].Vertex[j].Y;
  154. Marshal.StructureToPtr(gpc_vtx, ptr2, false);
  155. //ptr2 = (IntPtr)(((int)ptr2) + Marshal.SizeOf(gpc_vtx));
  156. ptr2 = (IntPtr)((ptr2.ToInt64()) + Marshal.SizeOf(gpc_vtx));
  157. }
  158. Marshal.StructureToPtr(gpc_vtx_list, ptr, false);
  159. //ptr = (IntPtr)(((int)ptr) + Marshal.SizeOf(gpc_vtx_list));
  160. ptr = (IntPtr)((ptr.ToInt64()) + Marshal.SizeOf(gpc_vtx_list));
  161. }
  162. return gpc_pol;
  163. }
  164. private static Polygon gpc_polygon_ToPolygon(NativeStructs.gpc_polygon gpc_polygon)
  165. {
  166. Polygon polygon = new Polygon();
  167. polygon.NofContours = gpc_polygon.num_contours;
  168. polygon.ContourIsHole = new bool[polygon.NofContours];
  169. polygon.Contour = new VertexList[polygon.NofContours];
  170. short[] holeShort = new short[polygon.NofContours];
  171. IntPtr ptr = gpc_polygon.hole;
  172. if (polygon.NofContours > 0)
  173. {
  174. Marshal.Copy(gpc_polygon.hole, holeShort, 0, polygon.NofContours);
  175. }
  176. for (int i = 0; i < polygon.NofContours; i++)
  177. polygon.ContourIsHole[i] = (holeShort[i] != 0);
  178. ptr = gpc_polygon.contour;
  179. for (int i = 0; i < polygon.NofContours; i++)
  180. {
  181. NativeStructs.gpc_vertex_list gpc_vtx_list = (NativeStructs.gpc_vertex_list)Marshal.PtrToStructure(ptr, typeof(NativeStructs.gpc_vertex_list));
  182. polygon.Contour[i] = new VertexList();
  183. polygon.Contour[i].NofVertices = gpc_vtx_list.num_vertices;
  184. polygon.Contour[i].Vertex = new Vertex[polygon.Contour[i].NofVertices];
  185. IntPtr ptr2 = gpc_vtx_list.vertex;
  186. for (int j = 0; j < polygon.Contour[i].NofVertices; j++)
  187. {
  188. NativeStructs.gpc_vertex gpc_vtx = (NativeStructs.gpc_vertex)Marshal.PtrToStructure(ptr2, typeof(NativeStructs.gpc_vertex));
  189. polygon.Contour[i].Vertex[j].X = gpc_vtx.x;
  190. polygon.Contour[i].Vertex[j].Y = gpc_vtx.y;
  191. //ptr2 = (IntPtr)(((int)ptr2) + Marshal.SizeOf(gpc_vtx));
  192. ptr2 = (IntPtr)((ptr2.ToInt64()) + Marshal.SizeOf(gpc_vtx));
  193. }
  194. //ptr = (IntPtr)(((int)ptr) + Marshal.SizeOf(gpc_vtx_list));
  195. ptr = (IntPtr)((ptr.ToInt64()) + Marshal.SizeOf(gpc_vtx_list));
  196. }
  197. return polygon;
  198. }
  199. private static void Free_gpc_polygon(NativeStructs.gpc_polygon gpc_pol)
  200. {
  201. Marshal.FreeCoTaskMem(gpc_pol.hole);
  202. IntPtr ptr = gpc_pol.contour;
  203. for (int i = 0; i < gpc_pol.num_contours; i++)
  204. {
  205. NativeStructs.gpc_vertex_list gpc_vtx_list = (NativeStructs.gpc_vertex_list)Marshal.PtrToStructure(ptr, typeof(NativeStructs.gpc_vertex_list));
  206. Marshal.FreeCoTaskMem(gpc_vtx_list.vertex);
  207. //ptr = (IntPtr)(((int)ptr) + Marshal.SizeOf(gpc_vtx_list));
  208. ptr = (IntPtr)((ptr.ToInt64()) + Marshal.SizeOf(gpc_vtx_list));
  209. }
  210. }
  211. }
  212. }