FileImporter.cs 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. using System.Threading.Tasks;
  9. namespace SketchAssistant
  10. {
  11. public class FileImporter
  12. {
  13. /// <summary>
  14. /// scale factor for coordinates of svg file
  15. /// </summary>
  16. double scale;
  17. /// <summary>
  18. /// line pointer for the current svg document
  19. /// </summary>
  20. int i;
  21. /// <summary>
  22. /// array containing all characters interpreted as whitespaces which seperate words/tokens in the input file
  23. /// </summary>
  24. readonly char[] whitespaces = new char[] { ' ' , ',' };
  25. /// <summary>
  26. /// number of points to create along the outline of an ellipse, divisible by 4
  27. /// </summary>
  28. readonly int samplingRateEllipse = 12;
  29. /// <summary>
  30. /// number of points to create on a bezier curve, including start and end point (even numbr will result in "flat" bezier curves, uneven number in "pointed" ones
  31. /// </summary>
  32. readonly int samplingRateBezier = 101;
  33. public FileImporter()
  34. {
  35. }
  36. /// <summary>
  37. /// parses a drawing consisting of line objects, given as a file in the application specific .isad format
  38. /// </summary>
  39. /// <param name="fileName">the path of the input file</param>
  40. /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
  41. public (int, int, List<Line>) ParseISADInputFile(String fileName)
  42. {
  43. return ParseISADInput(System.IO.File.ReadAllLines(fileName));
  44. }
  45. /// <summary>
  46. /// parses a drawing consisting of line objects, given as the content of a .isad file, seperated into lines
  47. /// </summary>
  48. /// <param name="allLines">an array holding all lines of the input file</param>
  49. /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
  50. private (int, int, List<Line>) ParseISADInput(String[] allLines)
  51. {
  52. if (allLines.Length == 0)
  53. {
  54. throw new FileImporterException("file is empty", "", -1);
  55. }
  56. if (!"drawing".Equals(allLines[0]))
  57. {
  58. throw new FileImporterException("file is not an interactive sketch assistant drawing", ".isad files have to start with the 'drawing' token", 1);
  59. }
  60. if (!"enddrawing".Equals(allLines[allLines.Length - 1]))
  61. {
  62. throw new FileImporterException("unterminated drawing definition", ".isad files have to end with the 'enddrawing' token", allLines.Length);
  63. }
  64. (int, int) dimensions = ParseISADHeader(allLines);
  65. List<Line> picture = ParseISADBody(allLines, dimensions.Item1, dimensions.Item2);
  66. return (dimensions.Item1, dimensions.Item2, picture);
  67. }
  68. /// <summary>
  69. /// parses the first two lines of an input file in .isad format
  70. /// </summary>
  71. /// <param name="allLines">the input file as an array of lines</param>
  72. /// <returns>the width and height of the left canvas</returns>
  73. private (int, int) ParseISADHeader(String[] allLines)
  74. {
  75. int width;
  76. int height;
  77. if (!(allLines.Length > 1) || !Regex.Match(allLines[1], @"^\d+x?\d+$", RegexOptions.None).Success)
  78. {
  79. throw new FileImporterException("invalid or missing canvas size definition", "format: [width]x[heigth]", 2);
  80. }
  81. String[] size = allLines[1].Split('x');
  82. width = Convert.ToInt32(size[0]);
  83. height = Convert.ToInt32(size[1]);
  84. return (width, height);
  85. }
  86. /// <summary>
  87. /// parses all line entries of an input file in .isad format
  88. /// </summary>
  89. /// <param name="allLines">the input file as an array of lines</param>
  90. /// <returns>the parsed picture as a list of lines</returns>
  91. private List<Line> ParseISADBody(String[] allLines, int width, int height)
  92. {
  93. String lineStartString = "line";
  94. String lineEndString = "endline";
  95. List<Line> drawing = new List<Line>();
  96. //number of the line currently being parsed, enumeration starting at 0, body starts at the third line, therefore lin number 2
  97. int i = 2;
  98. //parse 'line' token and complete line definition
  99. int lineStartPointer = i;
  100. //holds the line number of the next expected beginning of a line definition, or of the enddrawing token
  101. while (lineStartString.Equals(allLines[i]))
  102. {
  103. //start parsing next line
  104. i++;
  105. List<Point> newLine = new List<Point>();
  106. while (!lineEndString.Equals(allLines[i]))
  107. {
  108. if (i == allLines.Length)
  109. {
  110. throw new FileImporterException("unterminated line definition", null, (i + 1));
  111. }
  112. //parse single point definition
  113. if (!Regex.Match(allLines[i], @"^\d+;\d+$", RegexOptions.None).Success)
  114. {
  115. throw new FileImporterException("invalid Point definition: wrong format", "format: [xCoordinate];[yCoordinate]", (i + 1) );
  116. }
  117. String[] coordinates = allLines[i].Split(';');
  118. //no errors possible, convertability to int already checked above
  119. int xCoordinate = Convert.ToInt32(coordinates[0]);
  120. int yCoordinate = Convert.ToInt32(coordinates[1]);
  121. if (xCoordinate < 0 || yCoordinate < 0 || xCoordinate > width - 1 || yCoordinate > height - 1)
  122. {
  123. throw new FileImporterException("invalid Point definition: point out of bounds", null, (i + 1) );
  124. }
  125. newLine.Add(new Point(xCoordinate, yCoordinate));
  126. //start parsing next line
  127. i++;
  128. }
  129. //"parse" 'endline' token, syntax already checked at the beginning, and start parsing next line
  130. i++;
  131. //add line to drawing
  132. drawing.Add(new Line(newLine));
  133. //update lineStartPointer to the presumable start of the next line
  134. lineStartPointer = i;
  135. }
  136. //check if end of body is reached after there are no more line definitions
  137. if(i != allLines.Length - 1)
  138. {
  139. throw new FileImporterException("missing or invalid line definition token", "line definitions start with the 'line' token", (i + 1));
  140. }
  141. //return parsed picture
  142. return drawing;
  143. }
  144. /// <summary>
  145. /// connection point for testing use only: calls ParseISADInput(String[] allLines) and directly passes the given argument (effectively bypassing the File Input functionality)
  146. /// </summary>
  147. /// <param name="allLines">an array holding all lines of the input file</param>
  148. /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
  149. public (int, int, List<Line>) ParseISADInputForTesting(String[] allLines)
  150. {
  151. return ParseISADInput(allLines);
  152. }
  153. /// <summary>
  154. /// parses a svg drawing, given as a .svg file
  155. /// </summary>
  156. /// <param name="fileName">the path of the input file</param>
  157. /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
  158. public (int, int, List<Line>) ParseSVGInputFile(String fileName, int windowWidth, int windowHeight)
  159. {
  160. return ParseSVGInput(System.IO.File.ReadAllLines(fileName), windowWidth, windowHeight);
  161. }
  162. /// <summary>
  163. /// parses a svg drawing, given as the content of a .svg file, seperated into lines
  164. /// </summary>
  165. /// <param name="allLines">an array holding all lines of the input file</param>
  166. /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
  167. private (int, int, List<Line>) ParseSVGInput(String[] allLines, double windowWidth, double windowHeight)
  168. {
  169. i = 0; //reset line pointer
  170. if (allLines.Length == 0) //check for empty file
  171. {
  172. throw new FileImporterException("file is empty", "", -1);
  173. }
  174. (int, int) sizedef = ParseSVGHeader(allLines); //parse svg file header and get internal coordinate range
  175. i++;
  176. int width; //width of the resulting picture in pixels
  177. int height; //height of the resulting picture in pixels
  178. if (windowWidth / windowHeight > sizedef.Item1 / sizedef.Item2) //height dominant, width has to be smaller than drawing window to preserve xy-scale
  179. {
  180. scale = windowHeight / sizedef.Item2;
  181. Console.WriteLine("scale: (heights) " + windowHeight + "/" + sizedef.Item2);
  182. Console.WriteLine("widths: " + windowWidth + "/" + sizedef.Item1);
  183. height = (int)Math.Round(windowHeight);
  184. width = (int) Math.Round(scale * sizedef.Item1);
  185. Console.WriteLine(width + "x" + height + " (" + scale + ")");
  186. }
  187. else //width dominant, height has to be smaller than drawing window to preserve xy-scale
  188. {
  189. scale = windowWidth / sizedef.Item1;
  190. Console.WriteLine("scale: (widths) " + windowWidth + "/" + sizedef.Item1);
  191. Console.WriteLine("heights: " + windowHeight + "/" + sizedef.Item2);
  192. width = (int)Math.Round(windowWidth);
  193. height = (int)Math.Round(scale * sizedef.Item2);
  194. Console.WriteLine(width + "x" + height + " (" + scale + ")");
  195. }
  196. for(int j=0; j < allLines.Length; j++)
  197. {
  198. allLines[j] = allLines[j].Trim(whitespaces);
  199. }
  200. List<Line> picture = ParseSVGBody(allLines); //parse whole svg drawing into list of lines
  201. return (width, height, picture);
  202. }
  203. /// <summary>
  204. /// parses the svg file header and returns the internal coordinate range of this drawing, and iterates i to point to the start of svg element definitions
  205. /// </summary>
  206. /// <param name="allLines">an array holding all lines of the input file</param>
  207. /// <returns>the internal coordinate range of this drawing</returns>
  208. private (int, int) ParseSVGHeader(String[] allLines)
  209. {
  210. while (!allLines[i].StartsWith("<svg")) //skip non-relevant metadata at start of svg file
  211. {
  212. i++;
  213. }
  214. String[] currentLine = allLines[i].Split(' ');
  215. int width= -1;
  216. int height= -1;
  217. for(int j= 0; j < currentLine.Length; j++)
  218. {
  219. if (currentLine[j].StartsWith("width"))
  220. {
  221. width = Convert.ToInt32(ParseSingleSVGAttribute(currentLine[j]));
  222. }
  223. else if (currentLine[j].StartsWith("height"))
  224. {
  225. height = Convert.ToInt32(ParseSingleSVGAttribute(currentLine[j]));
  226. }
  227. }
  228. if(width == -1)
  229. {
  230. throw new FileImporterException("missing width definition in SVG header", "the header should contain the \"width=...\" attribute", i+1);
  231. }
  232. if (height == -1)
  233. {
  234. throw new FileImporterException("missing height definition in SVG header", "the header should contain the \"height=...\" attribute", i + 1);
  235. }
  236. return (width, height);
  237. }
  238. /// <summary>
  239. /// parses all relevant svg element definitions and skips the ones not representable by the sketch assistant
  240. /// </summary>
  241. /// <param name="allLines">an array holding all lines of the input file</param>
  242. /// <returns>the parsed picture as a list of lines</returns>
  243. private List<Line> ParseSVGBody(String[] allLines)
  244. {
  245. List<Line> picture = new List<Line>();
  246. while (!allLines[i].StartsWith("</svg"))
  247. {
  248. List<Line> element = ParseSingleSVGElement(allLines);
  249. if (element != null)
  250. {
  251. picture.AddRange(element);
  252. }
  253. i++;
  254. }
  255. return picture;
  256. }
  257. /// <summary>
  258. /// parses one toplevel svg element
  259. /// </summary>
  260. /// <param name="allLines">an array holding all lines of the input file</param>
  261. /// <returns>the parsed Element as a list of lines</returns>
  262. private List<Line> ParseSingleSVGElement(string[] allLines)
  263. {
  264. String[] currentElement = GetCurrentElement(allLines);
  265. if (currentElement[currentElement.Length - 1].EndsWith("/>")) //single line element
  266. {
  267. return ParseSingleLineSVGElement(currentElement);
  268. }
  269. else //element containing sub-elements
  270. {
  271. return ParseMultiLineSVGElement(currentElement, allLines);
  272. }
  273. }
  274. /// <summary>
  275. /// parses a single toplevel svg element only taking one line
  276. /// </summary>
  277. /// <param name="allLines">an array holding all lines of the input file</param>
  278. /// <returns>the parsed element as a Line object, or null if the element is not supported</returns>
  279. private List<Line> ParseSingleLineSVGElement(string[] currentElement)
  280. {
  281. List<Point> points= null;
  282. List<Line> element = null;
  283. switch (currentElement[0])
  284. {
  285. case "<rect":
  286. points = parseRect(currentElement);
  287. break;
  288. case "<circle":
  289. points = parseCircle(currentElement);
  290. break;
  291. case "<ellipse":
  292. points = parseEllipse(currentElement);
  293. break;
  294. case "<line":
  295. points = parseLine(currentElement);
  296. break;
  297. case "<polyline":
  298. points = parsePolyline(currentElement);
  299. break;
  300. case "<polygon":
  301. points = parsePolygon(currentElement);
  302. break;
  303. case "<path":
  304. element = parsePath(currentElement);
  305. break;
  306. default: //unsupported svg element
  307. Console.WriteLine("unsupported element: " + currentElement[0] + currentElement[0].Length);
  308. return null;
  309. }
  310. if (element == null)
  311. {
  312. element = new List<Line>();
  313. element.Add(new Line(points));
  314. }
  315. return element;
  316. }
  317. /// <summary>
  318. /// parses a rectangle definition into a List of Points representing a single line around the rectangle (in clockwise direction)
  319. /// </summary>
  320. /// <param name="currentElement">the definition of the element as whitespace seperated String[]</param>
  321. /// <returns>the parsed element as a List of Points</returns>
  322. private List<Point> parseRect(string[] currentElement)
  323. {
  324. double x = 0;
  325. double y = 0;
  326. double w = 0;
  327. double h = 0;
  328. double rx = 0;
  329. double ry = 0;
  330. for(int j= 0; j < currentElement.Length; j++)
  331. {
  332. if (currentElement[j].StartsWith("x="))
  333. {
  334. x = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  335. }
  336. else if (currentElement[j].StartsWith("y="))
  337. {
  338. y = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  339. }
  340. else if (currentElement[j].StartsWith("width="))
  341. {
  342. w = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  343. }
  344. else if (currentElement[j].StartsWith("height="))
  345. {
  346. h = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  347. }
  348. else if (currentElement[j].StartsWith("rx="))
  349. {
  350. rx = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  351. }
  352. else if (currentElement[j].StartsWith("ry="))
  353. {
  354. ry = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  355. }
  356. }
  357. List<Point> rect = new List<Point>();
  358. rect.Add(ScaleAndCreatePoint(x, y));
  359. rect.Add(ScaleAndCreatePoint(x + w, y));
  360. rect.Add(ScaleAndCreatePoint(x + w, y + h));
  361. rect.Add(ScaleAndCreatePoint(x, y + h));
  362. rect.Add(ScaleAndCreatePoint(x, y));
  363. Console.WriteLine("parsed point: " + x + ";" + y);
  364. return rect;
  365. }
  366. /// <summary>
  367. /// parses a circle definition into a List of Points
  368. /// </summary>
  369. /// <param name="currentElement">the definition of the element as whitespace seperated String[]</param>
  370. /// <returns>the parsed element as a List of Points</returns>
  371. private List<Point> parseCircle(string[] currentElement)
  372. {
  373. double x = 0;
  374. double y = 0;
  375. double r = 0;
  376. for (int j = 0; j < currentElement.Length; j++)
  377. {
  378. if (currentElement[j].StartsWith("cx="))
  379. {
  380. x = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  381. }
  382. else if (currentElement[j].StartsWith("cy="))
  383. {
  384. y = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  385. }
  386. else if (currentElement[j].StartsWith("r="))
  387. {
  388. r = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  389. }
  390. }
  391. return SampleEllipse(x, y, r, r);
  392. }
  393. /// <summary>
  394. /// parses a ellipse definition into a List of Points
  395. /// </summary>
  396. /// <param name="currentElement">the definition of the element as whitespace seperated String[]</param>
  397. /// <returns>the parsed element as a List of Points</returns>
  398. private List<Point> parseEllipse(string[] currentElement)
  399. {
  400. double x = 0;
  401. double y = 0;
  402. double rx = 0;
  403. double ry = 0;
  404. for (int j = 0; j < currentElement.Length; j++)
  405. {
  406. if (currentElement[j].StartsWith("cx="))
  407. {
  408. x = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  409. }
  410. else if (currentElement[j].StartsWith("cy="))
  411. {
  412. y = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  413. }
  414. else if (currentElement[j].StartsWith("rx="))
  415. {
  416. rx = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  417. }
  418. else if (currentElement[j].StartsWith("ry="))
  419. {
  420. ry = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  421. }
  422. }
  423. return SampleEllipse(x, y, rx, ry);
  424. }
  425. /// <summary>
  426. /// parses a line definition into a List of two Points
  427. /// </summary>
  428. /// <param name="currentElement">the definition of the element as whitespace seperated String[]</param>
  429. /// <returns>the parsed element as a List of Points</returns>
  430. private List<Point> parseLine(string[] currentElement)
  431. {
  432. double x1 = 0;
  433. double y1 = 0;
  434. double x2 = 0;
  435. double y2 = 0;
  436. for (int j = 0; j < currentElement.Length; j++)
  437. {
  438. if (currentElement[j].StartsWith("x1="))
  439. {
  440. x1 = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  441. }
  442. else if (currentElement[j].StartsWith("y1="))
  443. {
  444. y1 = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  445. }
  446. else if (currentElement[j].StartsWith("x2="))
  447. {
  448. x2 = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  449. }
  450. else if (currentElement[j].StartsWith("y2="))
  451. {
  452. y2 = Convert.ToDouble(ParseSingleSVGAttribute(currentElement[j]), CultureInfo.InvariantCulture);
  453. }
  454. }
  455. List<Point> line = new List<Point>();
  456. line.Add(ScaleAndCreatePoint(x1, y1));
  457. line.Add(ScaleAndCreatePoint(x2, y2));
  458. return line;
  459. }
  460. /// <summary>
  461. /// parses a polyline definition into a List of Points
  462. /// </summary>
  463. /// <param name="currentElement">the definition of the element as whitespace seperated String[]</param>
  464. /// <returns>the parsed element as a List of Points</returns>
  465. private List<Point> parsePolyline(string[] currentElement)
  466. {
  467. String[] points = null;
  468. for (int j = 0; j < currentElement.Length; j++)
  469. {
  470. if (currentElement[j].StartsWith("points="))
  471. {
  472. List<String> pointDefs = new List<string>();
  473. pointDefs.Add(currentElement[j].Substring(8)); //parse first point coordinates by removing 'points="'
  474. j++;
  475. while (!currentElement[j].EndsWith("\""))
  476. {
  477. pointDefs.Add(currentElement[j]); //parse intermediate point coordinates
  478. j++;
  479. }
  480. pointDefs.Add(currentElement[j].Trim('"')); //parse last point coordinates by removing '"'
  481. points = pointDefs.ToArray();
  482. }
  483. }
  484. List<Point> polyline = new List<Point>();
  485. for (int k = 0; k < points.Length - 1; k += 2)
  486. {
  487. polyline.Add(ScaleAndCreatePoint(Convert.ToDouble(points[k], CultureInfo.InvariantCulture), Convert.ToDouble(points[k + 1], CultureInfo.InvariantCulture)));
  488. }
  489. return polyline;
  490. }
  491. /// <summary>
  492. /// parses a polygon definition into a List of Points
  493. /// </summary>
  494. /// <param name="currentElement">the definition of the element as whitespace seperated String[]</param>
  495. /// <returns>the parsed element as a List of Points</returns>
  496. private List<Point> parsePolygon(string[] currentElement)
  497. {
  498. String[] points = null;
  499. for (int j = 0; j < currentElement.Length; j++)
  500. {
  501. if (currentElement[j].StartsWith("points="))
  502. {
  503. List<String> pointDefs = new List<string>();
  504. pointDefs.Add(currentElement[j].Substring(8)); //parse first point coordinates by removing 'points="'
  505. j++;
  506. while (!currentElement[j].EndsWith("\""))
  507. {
  508. pointDefs.Add(currentElement[j]); //parse intermediate point coordinates
  509. j++;
  510. }
  511. pointDefs.Add(currentElement[j].Trim('"')); //parse last point coordinates by removing '"'
  512. points = pointDefs.ToArray();
  513. }
  514. }
  515. List<Point> polygon = new List<Point>();
  516. for (int k = 0; k < points.Length - 1; k+=2)
  517. {
  518. polygon.Add(ScaleAndCreatePoint(Convert.ToDouble(points[k], CultureInfo.InvariantCulture), Convert.ToDouble(points[k+1], CultureInfo.InvariantCulture)));
  519. Console.WriteLine("parsed point: " + points[k] + ";" + points[k + 1]);
  520. }
  521. polygon.Add(ScaleAndCreatePoint(Convert.ToDouble(points[0], CultureInfo.InvariantCulture), Convert.ToDouble(points[1], CultureInfo.InvariantCulture))); //close polygon
  522. Console.WriteLine("parsed point: " + points[0] + ";" + points[1]);
  523. return polygon;
  524. }
  525. /// <summary>
  526. /// parses a path definition into a List of Points
  527. /// </summary>
  528. /// <param name="currentElement">the definition of the element as whitespace seperated String[]</param>
  529. /// <returns>the parsed element as a List of Points</returns>
  530. private List<Line> parsePath(string[] currentElement)
  531. {
  532. List<String> pathElements = new List<string>();
  533. for (int j = 0; j < currentElement.Length; j++)
  534. {
  535. if (currentElement[j].StartsWith("d="))
  536. {
  537. pathElements.Add(currentElement[j].Substring(3)); //parse first path element by removing 'd="'
  538. j++;
  539. while (!currentElement[j].EndsWith("\""))
  540. {
  541. pathElements.Add(currentElement[j]); //parse intermediate path element
  542. j++;
  543. }
  544. pathElements.Add(currentElement[j].Trim('"')); //parse last path element by removing '"'
  545. }
  546. }
  547. List<Line> element = new List<Line>();
  548. List<Point> currentLine = new List<Point>();
  549. double lastBezierControlPointX= 0;
  550. double lastBezierControlPointY= 0;
  551. double lastPositionX;
  552. double lastPositionY;
  553. //assume that svg is well formatted with spaces between each token, no emitted characters and only "[char] (appropriateNumber*[coordinate])" segments
  554. //pathElements = PreparePathElements(pathElements); //split pathElement list objects until every object is atomar (single character or single number (coordinate))
  555. //int k = 0; //index of active element in pathElements is always 0
  556. (List<Point>, double, double) valuesArc; //list of points, new values for: lastPositionX, lastPositionY
  557. (List<Point>, double, double, double, double) valuesBezierCurve; //list of points, new values for: lastPositionX, lastPositionY, lastBezierControlPointX, lastBezierControlPointY
  558. (Point, double, double) valuesSinglePoint = parse_M_Z_L(pathElements); //new point, new values for: lastPositionX, lastPositionY
  559. currentLine = new List<Point>();
  560. currentLine.Add(valuesSinglePoint.Item1);
  561. lastPositionX = valuesSinglePoint.Item2;
  562. lastPositionY = valuesSinglePoint.Item3;
  563. String currentToken;
  564. while (!(pathElements.Count == 0)){
  565. currentToken = pathElements.First();
  566. if (currentToken.Equals("M"))
  567. {
  568. element.Add(new Line(currentLine)); //save current line
  569. valuesSinglePoint = parse_M_Z_L(pathElements);
  570. currentLine = new List<Point>(); //create new empty line
  571. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  572. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  573. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  574. }
  575. else if (currentToken.Equals("m"))
  576. {
  577. element.Add(new Line(currentLine)); //save current line
  578. valuesSinglePoint = parse_m_z_l(pathElements, lastPositionX, lastPositionY);
  579. currentLine = new List<Point>(); //create new empty line
  580. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  581. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  582. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  583. }
  584. else if (currentToken.Equals("Z"))
  585. {
  586. valuesSinglePoint = parse_M_Z_L(pathElements);
  587. currentLine.Add(valuesSinglePoint.Item1); //add point to old line
  588. element.Add(new Line(currentLine)); //save current line
  589. currentLine = new List<Point>(); //create new empty line
  590. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  591. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  592. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  593. }
  594. else if (currentToken.Equals("z"))
  595. {
  596. valuesSinglePoint = parse_m_z_l(pathElements, lastPositionX, lastPositionY);
  597. currentLine.Add(valuesSinglePoint.Item1); //add point to old line
  598. element.Add(new Line(currentLine)); //save current line
  599. currentLine = new List<Point>(); //create new empty line
  600. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  601. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  602. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  603. }
  604. else if (currentToken.Equals("L"))
  605. {
  606. valuesSinglePoint = parse_M_Z_L(pathElements);
  607. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  608. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  609. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  610. }
  611. else if (currentToken.Equals("l"))
  612. {
  613. valuesSinglePoint = parse_m_z_l(pathElements, lastPositionX, lastPositionY);
  614. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  615. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  616. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  617. }
  618. else if (currentToken.Equals("H"))
  619. {
  620. valuesSinglePoint = parse_H(pathElements, lastPositionY);
  621. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  622. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  623. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  624. }
  625. else if (currentToken.Equals("h"))
  626. {
  627. valuesSinglePoint = parse_h(pathElements, lastPositionX, lastPositionY);
  628. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  629. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  630. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  631. }
  632. else if (currentToken.Equals("V"))
  633. {
  634. valuesSinglePoint = parse_V(pathElements, lastPositionX);
  635. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  636. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  637. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  638. }
  639. else if (currentToken.Equals("v"))
  640. {
  641. valuesSinglePoint = parse_v(pathElements, lastPositionX, lastPositionY);
  642. currentLine.Add(valuesSinglePoint.Item1); //add point to new line
  643. lastPositionX = valuesSinglePoint.Item2; //save last point coordinates
  644. lastPositionY = valuesSinglePoint.Item3; //save last point coordinates
  645. }
  646. else if (currentToken.Equals("C"))
  647. {
  648. valuesBezierCurve = parse_C(pathElements, lastPositionX, lastPositionY);
  649. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  650. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  651. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  652. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  653. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  654. }
  655. else if (currentToken.Equals("c"))
  656. {
  657. valuesBezierCurve = parse_C(pathElements, lastPositionX, lastPositionY);
  658. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  659. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  660. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  661. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  662. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  663. }
  664. else if (currentToken.Equals("S"))
  665. {
  666. valuesBezierCurve = parse_S(pathElements, lastPositionX, lastPositionY, lastBezierControlPointX, lastBezierControlPointY);
  667. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  668. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  669. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  670. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  671. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  672. }
  673. else if (currentToken.Equals("s"))
  674. {
  675. valuesBezierCurve = parse_s(pathElements, lastPositionX, lastPositionY, lastBezierControlPointX, lastBezierControlPointY);
  676. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  677. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  678. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  679. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  680. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  681. }
  682. else if (currentToken.Equals("Q"))
  683. {
  684. valuesBezierCurve = parse_Q(pathElements, lastPositionX, lastPositionY);
  685. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  686. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  687. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  688. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  689. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  690. }
  691. else if (currentToken.Equals("q"))
  692. {
  693. valuesBezierCurve = parse_q(pathElements, lastPositionX, lastPositionY);
  694. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  695. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  696. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  697. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  698. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  699. }
  700. else if (currentToken.Equals("T"))
  701. {
  702. valuesBezierCurve = parse_T(pathElements, lastPositionX, lastPositionY, lastBezierControlPointX, lastBezierControlPointY);
  703. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  704. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  705. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  706. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  707. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  708. }
  709. else if (currentToken.Equals("t"))
  710. {
  711. valuesBezierCurve = parse_t(pathElements, lastPositionX, lastPositionY, lastBezierControlPointX, lastBezierControlPointY);
  712. currentLine.AddRange(valuesBezierCurve.Item1); //add point to new line
  713. lastPositionX = valuesBezierCurve.Item2; //save last point coordinates
  714. lastPositionY = valuesBezierCurve.Item3; //save last point coordinates
  715. lastBezierControlPointX = valuesBezierCurve.Item4; //save last bezier control point coordinates
  716. lastBezierControlPointY = valuesBezierCurve.Item5; //save last bezier control point coordinates
  717. }
  718. else if (currentToken.Equals("A"))
  719. {
  720. valuesArc = parse_A(pathElements);
  721. currentLine.AddRange(valuesArc.Item1); //add points to new line
  722. lastPositionX = valuesArc.Item2; //save last point coordinates
  723. lastPositionY = valuesArc.Item3; //save last point coordinates
  724. }
  725. else if (currentToken.Equals("a"))
  726. {
  727. valuesArc = parse_a(pathElements, lastPositionX, lastPositionY);
  728. currentLine.AddRange(valuesArc.Item1); //add points to new line
  729. lastPositionX = valuesArc.Item2; //save last point coordinates
  730. lastPositionY = valuesArc.Item3; //save last point coordinates
  731. }
  732. else
  733. {
  734. throw new FileImporterException("invalid path argument or path data formatting: read argument " + pathElements.First(), "valid path arguments are: {M,Z,L,H,V,C,S,Q,T,A} in upper and lower case", i + 1);
  735. }
  736. }
  737. if (currentLine.Count > 1)
  738. {
  739. element.Add(new Line(currentLine)); //save current line
  740. }
  741. return element;
  742. }
  743. /// <summary>
  744. /// parses a "moveto", "close loop" or "lineto" path element with absolute coordinates
  745. /// </summary>
  746. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  747. /// <returns>the point at the end of the move, close loop or line action and its exact, unscaled coordinates</returns>
  748. private (Point, double, double) parse_M_Z_L(List<string> pathElements)
  749. {
  750. pathElements.RemoveAt(0); //remove element descriptor token
  751. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse x coordinate
  752. pathElements.RemoveAt(0); //remove x coordinate token
  753. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse y coordinate
  754. pathElements.RemoveAt(0); //remove y coordinate token
  755. return (ScaleAndCreatePoint(x, y), x, y);
  756. }
  757. /// <summary>
  758. /// parses a "moveto", "close loop" or "lineto" path element with relative coordinates
  759. /// </summary>
  760. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  761. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  762. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  763. /// <returns>the point at the end of the move, close loop or line action and its exact, unscaled coordinates</returns>
  764. private (Point, double, double) parse_m_z_l(List<string> pathElements, double lastPositionX, double lastPositionY)
  765. {
  766. pathElements.RemoveAt(0); //remove element descriptor token
  767. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse relative x coordinate
  768. pathElements.RemoveAt(0); //remove x coordinate token
  769. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse relative y coordinate
  770. pathElements.RemoveAt(0); //remove y coordinate token
  771. x = lastPositionX + x; //compute absolute x coordinate
  772. y = lastPositionY + y; //compute absolute y coordinate
  773. return (ScaleAndCreatePoint(x, y), x, y);
  774. }
  775. /// <summary>
  776. /// parses a "horizontal lineto" path element with absolute coordinates
  777. /// </summary>
  778. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  779. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  780. /// <returns>the point at the end of the horizontal line action and its exact, unscaled coordinates</returns>
  781. private (Point, double, double) parse_H(List<string> pathElements, double lastPositionY)
  782. {
  783. pathElements.RemoveAt(0); //remove element descriptor token
  784. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse x coordinate
  785. pathElements.RemoveAt(0); //remove x coordinate token
  786. return (ScaleAndCreatePoint(x, lastPositionY), x, lastPositionY);
  787. }
  788. /// <summary>
  789. /// parses a "horizontal lineto" path element with relative coordinates
  790. /// </summary>
  791. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  792. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  793. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  794. /// <returns>the point at the end of the horizontal line action and its exact, unscaled coordinates</returns>
  795. private (Point, double, double) parse_h(List<string> pathElements, double lastPositionX, double lastPositionY)
  796. {
  797. pathElements.RemoveAt(0); //remove element descriptor token
  798. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse relative x coordinate
  799. pathElements.RemoveAt(0); //remove x coordinate token
  800. x = lastPositionX + x; //compute absolute x coordinate
  801. return (ScaleAndCreatePoint(x, lastPositionY), x, lastPositionY);
  802. }
  803. /// <summary>
  804. /// parses a "vertical lineto" path element with absolute coordinates
  805. /// </summary>
  806. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  807. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  808. /// <returns>the point at the end of the vertical line action and its exact, unscaled coordinates</returns>
  809. private (Point, double, double) parse_V(List<string> pathElements, double lastPositionX)
  810. {
  811. pathElements.RemoveAt(0); //remove element descriptor token
  812. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse y coordinate
  813. pathElements.RemoveAt(0); //remove y coordinate token
  814. return (ScaleAndCreatePoint(lastPositionX, y), lastPositionX, y);
  815. }
  816. /// <summary>
  817. /// parses a "vertical lineto" path element with relative coordinates
  818. /// </summary>
  819. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  820. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  821. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  822. /// <returns>the point at the end of the vertical line action and its exact, unscaled coordinates</returns>
  823. private (Point, double, double) parse_v(List<string> pathElements, double lastPositionX, double lastPositionY)
  824. {
  825. pathElements.RemoveAt(0); //remove element descriptor token
  826. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse relative y coordinate
  827. pathElements.RemoveAt(0); //remove y coordinate token
  828. y = lastPositionY + y; //compute absolute y coordinate
  829. return (ScaleAndCreatePoint(lastPositionX, y), lastPositionX, y);
  830. }
  831. /// <summary>
  832. /// parses a "cubic bezier curve" path element with absolute coordinates
  833. /// </summary>
  834. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  835. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  836. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  837. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the second bezier control point</returns>
  838. private (List<Point>, double, double, double, double) parse_C(List<string> pathElements, double lastPositionX, double lastPositionY)
  839. {
  840. pathElements.RemoveAt(0); //remove element descriptor token
  841. double x1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse first control point x coordinate
  842. pathElements.RemoveAt(0); //remove x coordinate token
  843. double y1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse first control point y coordinate
  844. pathElements.RemoveAt(0); //remove y coordinate token
  845. double x2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point x coordinate
  846. pathElements.RemoveAt(0); //remove x coordinate token
  847. double y2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point y coordinate
  848. pathElements.RemoveAt(0); //remove y coordinate token
  849. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  850. pathElements.RemoveAt(0); //remove x coordinate token
  851. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  852. pathElements.RemoveAt(0); //remove y coordinate token
  853. return (SampleCubicBezier(lastPositionX, lastPositionY, x1, y1, x2, y2, x, y), x, y, x2, y2);
  854. }
  855. /// <summary>
  856. /// parses a "cubic bezier curve" path element with relative coordinates
  857. /// </summary>
  858. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  859. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  860. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  861. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the second bezier control point</returns>
  862. private (List<Point>, double, double, double, double) parse_c(List<string> pathElements, double lastPositionX, double lastPositionY)
  863. {
  864. pathElements.RemoveAt(0); //remove element descriptor token
  865. double x1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse first control point x coordinate
  866. pathElements.RemoveAt(0); //remove x coordinate token
  867. double y1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse first control point y coordinate
  868. pathElements.RemoveAt(0); //remove y coordinate token
  869. double x2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point x coordinate
  870. pathElements.RemoveAt(0); //remove x coordinate token
  871. double y2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point y coordinate
  872. pathElements.RemoveAt(0); //remove y coordinate token
  873. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  874. pathElements.RemoveAt(0); //remove x coordinate token
  875. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  876. pathElements.RemoveAt(0); //remove y coordinate token
  877. x1 = lastPositionX + x1; //compute absolute x coordinate
  878. y1 = lastPositionY + y1; //compute absolute y coordinate
  879. x2 = lastPositionX + x2; //compute absolute x coordinate
  880. y2 = lastPositionY + y2; //compute absolute y coordinate
  881. x = lastPositionX + x; //compute absolute x coordinate
  882. y = lastPositionY + y; //compute absolute y coordinate
  883. return (SampleCubicBezier(lastPositionX, lastPositionY, x1, y1, x2, y2, x, y), x, y, x2, y2);
  884. }
  885. /// <summary>
  886. /// parses a "cubic bezier curve shorthand" path element with absolute coordinates
  887. /// </summary>
  888. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  889. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  890. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  891. /// <param name="lastBezierControlPointX">absolute x coordinate of the last bezier control point of the previous bezier curve</param>
  892. /// <param name="lastBezierControlPointY">absolute y coordinate of the last bezier control point of the previous bezier curve</param>
  893. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the second bezier control point</returns>
  894. private (List<Point>, double, double, double, double) parse_S(List<string> pathElements, double lastPositionX, double lastPositionY, double lastBezierControlPointX, double lastBezierControlPointY)
  895. {
  896. pathElements.RemoveAt(0); //remove element descriptor token
  897. double x2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point x coordinate
  898. pathElements.RemoveAt(0); //remove x coordinate token
  899. double y2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point y coordinate
  900. pathElements.RemoveAt(0); //remove y coordinate token
  901. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  902. pathElements.RemoveAt(0); //remove x coordinate token
  903. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  904. pathElements.RemoveAt(0); //remove y coordinate token
  905. double x1 = lastPositionX + (lastPositionX - lastBezierControlPointX); //mirror last bezier control point at bezier start point to get first new bezier control point
  906. double y1 = lastPositionY + (lastPositionY - lastBezierControlPointY); //mirror last bezier control point at bezier start point to get first new bezier control point
  907. return (SampleCubicBezier(lastPositionX, lastPositionY, x1, y1, x2, y2, x, y), x, y, x2, y2);
  908. }
  909. /// <summary>
  910. /// parses a "cubic bezier curve shorthand" path element with relative coordinates
  911. /// </summary>
  912. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  913. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  914. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  915. /// <param name="lastBezierControlPointX">absolute x coordinate of the last bezier control point of the previous bezier curve</param>
  916. /// <param name="lastBezierControlPointY">absolute y coordinate of the last bezier control point of the previous bezier curve</param>
  917. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the second bezier control point</returns>
  918. private (List<Point>, double, double, double, double) parse_s(List<string> pathElements, double lastPositionX, double lastPositionY, double lastBezierControlPointX, double lastBezierControlPointY)
  919. {
  920. pathElements.RemoveAt(0); //remove element descriptor token
  921. double x2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point x coordinate
  922. pathElements.RemoveAt(0); //remove x coordinate token
  923. double y2 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse second control point y coordinate
  924. pathElements.RemoveAt(0); //remove y coordinate token
  925. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  926. pathElements.RemoveAt(0); //remove x coordinate token
  927. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  928. pathElements.RemoveAt(0); //remove y coordinate token
  929. double x1 = lastPositionX + (lastPositionX - lastBezierControlPointX); //mirror last bezier control point at bezier start point to get first new bezier control point
  930. double y1 = lastPositionY + (lastPositionY - lastBezierControlPointY); //mirror last bezier control point at bezier start point to get first new bezier control point
  931. x2 = lastPositionX + x2; //compute absolute x coordinate
  932. y2 = lastPositionY + y2; //compute absolute y coordinate
  933. x = lastPositionX + x; //compute absolute x coordinate
  934. y = lastPositionY + y; //compute absolute y coordinate
  935. return (SampleCubicBezier(lastPositionX, lastPositionY, x1, y1, x2, y2, x, y), x, y, x2, y2);
  936. }
  937. /// <summary>
  938. /// parses a "quadratic bezier curve" path element with absolute coordinates
  939. /// </summary>
  940. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  941. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  942. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  943. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the bezier control point</returns>
  944. private (List<Point>, double, double, double, double) parse_Q(List<string> pathElements, double lastPositionX, double lastPositionY)
  945. {
  946. pathElements.RemoveAt(0); //remove element descriptor token
  947. double x1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse control point x coordinate
  948. pathElements.RemoveAt(0); //remove x coordinate token
  949. double y1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse control point y coordinate
  950. pathElements.RemoveAt(0); //remove y coordinate token
  951. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  952. pathElements.RemoveAt(0); //remove x coordinate token
  953. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  954. pathElements.RemoveAt(0); //remove y coordinate token
  955. return (SampleQuadraticBezier(lastPositionX, lastPositionY, x1, y1, x, y), x, y, x1, y1);
  956. }
  957. /// <summary>
  958. /// parses a "quadratic bezier curve" path element with relative coordinates
  959. /// </summary>
  960. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  961. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  962. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  963. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the bezier control point</returns>
  964. private (List<Point>, double, double, double, double) parse_q(List<string> pathElements, double lastPositionX, double lastPositionY)
  965. {
  966. pathElements.RemoveAt(0); //remove element descriptor token
  967. double x1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse control point x coordinate
  968. pathElements.RemoveAt(0); //remove x coordinate token
  969. double y1 = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse control point y coordinate
  970. pathElements.RemoveAt(0); //remove y coordinate token
  971. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  972. pathElements.RemoveAt(0); //remove x coordinate token
  973. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  974. pathElements.RemoveAt(0); //remove y coordinate token
  975. x1 = lastPositionX + x1; //compute absolute x coordinate
  976. y1 = lastPositionY + y1; //compute absolute y coordinate
  977. x = lastPositionX + x; //compute absolute x coordinate
  978. y = lastPositionY + y; //compute absolute y coordinate
  979. return (SampleQuadraticBezier(lastPositionX, lastPositionY, x1, y1, x, y), x, y, x1, y1);
  980. }
  981. /// <summary>
  982. /// parses a "quadratic bezier curve shorthand" path element with absolute coordinates
  983. /// </summary>
  984. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  985. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  986. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  987. /// <param name="lastBezierControlPointX">absolute x coordinate of the last bezier control point of the previous bezier curve</param>
  988. /// <param name="lastBezierControlPointY">absolute y coordinate of the last bezier control point of the previous bezier curve</param>
  989. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the bezier control point</returns>
  990. private (List<Point>, double, double, double, double) parse_T(List<string> pathElements, double lastPositionX, double lastPositionY, double lastBezierControlPointX, double lastBezierControlPointY)
  991. {
  992. pathElements.RemoveAt(0); //remove element descriptor token
  993. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  994. pathElements.RemoveAt(0); //remove x coordinate token
  995. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  996. pathElements.RemoveAt(0); //remove y coordinate token
  997. double x1 = lastPositionX + (lastPositionX - lastBezierControlPointX); //mirror last bezier control point at bezier start point to get first new bezier control point
  998. double y1 = lastPositionY + (lastPositionY - lastBezierControlPointY); //mirror last bezier control point at bezier start point to get first new bezier control point
  999. return (SampleQuadraticBezier(lastPositionX, lastPositionY, x1, y1, x, y), x, y, x1, y1);
  1000. }
  1001. /// <summary>
  1002. /// parses a "quadratic bezier curve shorthand" path element with relative coordinates
  1003. /// </summary>
  1004. /// <param name="pathElements">a list of all not yet parsed path element tokens and values in correct order, starting with the element to be parsed</param>
  1005. /// <param name="lastPositionX">absolute x coordinate of the last active point</param>
  1006. /// <param name="lastPositionY">absolute y coordinate of the last active point</param>
  1007. /// <param name="lastBezierControlPointX">absolute x coordinate of the last bezier control point of the previous bezier curve</param>
  1008. /// <param name="lastBezierControlPointY">absolute y coordinate of the last bezier control point of the previous bezier curve</param>
  1009. /// <returns>a List of Points containing all sampled points on the bezier curve, aswell as the unscaled x and y coordinates of the last point of the curve and of the bezier control point</returns>
  1010. private (List<Point>, double, double, double, double) parse_t(List<string> pathElements, double lastPositionX, double lastPositionY, double lastBezierControlPointX, double lastBezierControlPointY)
  1011. {
  1012. pathElements.RemoveAt(0); //remove element descriptor token
  1013. double x = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point x coordinate
  1014. pathElements.RemoveAt(0); //remove x coordinate token
  1015. double y = Convert.ToDouble(pathElements.First(), CultureInfo.InvariantCulture); //parse target point y coordinate
  1016. pathElements.RemoveAt(0); //remove y coordinate token
  1017. x = lastPositionX + x; //compute absolute x coordinate
  1018. y = lastPositionY + y; //compute absolute y coordinate
  1019. double x1 = lastPositionX + (lastPositionX - lastBezierControlPointX); //mirror last bezier control point at bezier start point to get first new bezier control point
  1020. double y1 = lastPositionY + (lastPositionY - lastBezierControlPointY); //mirror last bezier control point at bezier start point to get first new bezier control point
  1021. return (SampleQuadraticBezier(lastPositionX, lastPositionY, x1, y1, x, y), x, y, x1, y1);
  1022. }
  1023. private (List<Point>, double, double) parse_A(List<string> pathElements)
  1024. {
  1025. throw new NotImplementedException();
  1026. }
  1027. private (List<Point>, double, double) parse_a(List<string> pathElements, double lastPositionX, double lastPositionY)
  1028. {
  1029. throw new NotImplementedException();
  1030. }
  1031. /// <summary>
  1032. /// samples a cubic bezier curve with a static number of steps (samplingRateBezier)
  1033. /// </summary>
  1034. /// <param name="lastPositionX">x coordinate of last point</param>
  1035. /// <param name="lastPositionY">y coordinate of last point</param>
  1036. /// <param name="controlPoint1X">x coordinate of control point 1</param>
  1037. /// <param name="controlPoint1Y">y coordinate of control point 1</param>
  1038. /// <param name="controlPoint2X">x coordinate of control point 2</param>
  1039. /// <param name="controlPoint2Y">y coordinate of control point 2</param>
  1040. /// <param name="nextPositionX">x coordinate of next point</param>
  1041. /// <param name="nextPositionY">y coordinate of next point</param>
  1042. /// <returns>a List of Points containing all sampled points</returns>
  1043. private List<Point> SampleCubicBezier(double lastPositionX, double lastPositionY, double controlPoint1X, double controlPoint1Y, double controlPoint2X, double controlPoint2Y, double nextPositionX, double nextPositionY)
  1044. {
  1045. (double[], double[]) line1 = CreateDiscreteLine(lastPositionX, lastPositionY, controlPoint1X, controlPoint1Y);
  1046. (double[], double[]) line2 = CreateDiscreteLine(controlPoint1X, controlPoint1Y, controlPoint2X, controlPoint2Y);
  1047. (double[], double[]) line3 = CreateDiscreteLine(controlPoint2X, controlPoint2Y, nextPositionX, nextPositionY);
  1048. (double[], double[]) quadraticBezier1 = computeBezierStep(line1.Item1, line1.Item2, line2.Item1, line2.Item2);
  1049. (double[], double[]) quadraticBezier2 = computeBezierStep(line2.Item1, line2.Item2, line3.Item1, line3.Item2);
  1050. (double[], double[]) values = computeBezierStep(quadraticBezier1.Item1, quadraticBezier1.Item2, quadraticBezier2.Item1, quadraticBezier2.Item2);
  1051. List<Point> result = new List<Point>();
  1052. for (int j = 0; j < samplingRateBezier; j++)
  1053. {
  1054. result.Add(ScaleAndCreatePoint(values.Item1[j], values.Item2[j]));
  1055. }
  1056. return result;
  1057. }
  1058. /// <summary>
  1059. /// samples a quadratic bezier curve with a static number of steps (samplingRateBezier)
  1060. /// </summary>
  1061. /// <param name="lastPositionX">x coordinate of last point</param>
  1062. /// <param name="lastPositionY">y coordinate of last point</param>
  1063. /// <param name="controlPointX">x coordinate of control point</param>
  1064. /// <param name="controlPointY">y coordinate of control point</param>
  1065. /// <param name="nextPositionX">x coordinate of next point</param>
  1066. /// <param name="nextPositionY">y coordinate of next point</param>
  1067. /// <returns>a List of Points containing all sampled points</returns>
  1068. private List<Point> SampleQuadraticBezier(double lastPositionX, double lastPositionY, double controlPointX, double controlPointY, double nextPositionX, double nextPositionY)
  1069. {
  1070. (double[], double[]) line1 = CreateDiscreteLine(lastPositionX, lastPositionY, controlPointX, controlPointY);
  1071. (double[], double[]) line2 = CreateDiscreteLine(controlPointX, controlPointY, nextPositionX, nextPositionY);
  1072. (double[], double[]) values = computeBezierStep(line1.Item1, line1.Item2, line2.Item1, line2.Item2);
  1073. List<Point> result = new List<Point>();
  1074. for (int j = 0; j < samplingRateBezier; j++)
  1075. {
  1076. result.Add(ScaleAndCreatePoint(values.Item1[j], values.Item2[j]));
  1077. }
  1078. return result;
  1079. }
  1080. /// <summary>
  1081. /// create a discrete line with [samplingRateBezier] points (including start and end point) between two points
  1082. /// </summary>
  1083. /// <param name="point1X">coordinate of point 1</param>
  1084. /// <param name="point1Y">y coordinate of point 1</param>
  1085. /// <param name="point2X">x coordinate of point 2</param>
  1086. /// <param name="point2Y">y coordinate of point 2</param>
  1087. /// <returns>the discrete line as arrays of x and y coordinates</returns>
  1088. private (double[], double[]) CreateDiscreteLine(double point1X, double point1Y, double point2X, double point2Y)
  1089. {
  1090. double[] resultX = new double[samplingRateBezier];
  1091. double[] resultY = new double[samplingRateBezier];
  1092. for (int j = 0; j < samplingRateBezier; j++)
  1093. {
  1094. (double, double) pointResult = LinearInterpolationForBezier(point1X, point1Y, point2X, point2Y, j);
  1095. resultX[j] = pointResult.Item1;
  1096. resultY[j] = pointResult.Item2;
  1097. }
  1098. return (resultX, resultY);
  1099. }
  1100. /// <summary>
  1101. /// computes the discrete bezier curve between two given dicrete lines/curves
  1102. /// </summary>
  1103. /// <param name="line1X">x coordinates of all points in line 1</param>
  1104. /// <param name="line1Y">y coordinates of all points in line 1</param>
  1105. /// <param name="line2X">x coordinates of all points in line 2</param>
  1106. /// <param name="line2Y">y coordinates of all points in line 2</param>
  1107. /// <returns>the discrete bezier curve</returns>
  1108. private (double[], double[]) computeBezierStep(double[] line1X, double[] line1Y, double[] line2X, double[] line2Y)
  1109. {
  1110. double[] resultX = new double[samplingRateBezier];
  1111. double[] resultY = new double[samplingRateBezier];
  1112. for (int j = 0; j < samplingRateBezier; j++)
  1113. {
  1114. (double, double) pointResult = LinearInterpolationForBezier(line1X[j], line1Y[j], line2X[j], line2Y[j], j);
  1115. resultX[j] = pointResult.Item1;
  1116. resultY[j] = pointResult.Item2;
  1117. }
  1118. return (resultX, resultY);
  1119. }
  1120. /// <summary>
  1121. /// creates the linearly interpolated point at j/(samplingRateBezier - 1) between point 1 and point 2
  1122. /// </summary>
  1123. /// <param name="point1X">x coordinate of point 1</param>
  1124. /// <param name="point1Y">y coordinate of point 1</param>
  1125. /// <param name="point2X">x coordinate of point 2</param>
  1126. /// <param name="point2Y">y coordinate of point 2</param>
  1127. /// <param name="j">number of point to be interpolated, at a total number of [samplingRateBezier] points</param>
  1128. /// <returns>the linearly interpolated point</returns>
  1129. private (double, double) LinearInterpolationForBezier(double point1X, double point1Y, double point2X, double point2Y, int j)
  1130. {
  1131. double factor = ((double)1 / (double)(samplingRateBezier - 1)) * (double)j; //factor for linear interpolation
  1132. double x = point1X + ((point2X - point1X) * factor);
  1133. double y = point1Y + ((point2Y - point1Y) * factor);
  1134. return (x, y);
  1135. }
  1136. /// <summary>
  1137. /// parses a hierarchical svg element and all its sub-elements
  1138. /// </summary>
  1139. /// <param name="currentElement">the definition of the top level element as whitespace seperated String[]</param>
  1140. /// <param name="allLines">an array holding all lines of the input file</param>
  1141. /// <returns>the parsed element as a Line object, or null if the element is not supported</returns>
  1142. private List<Line> ParseMultiLineSVGElement(string[] currentElement, string[] allLines)
  1143. {
  1144. throw new NotImplementedException();
  1145. }
  1146. /// <summary>
  1147. /// removes the name of the attribute aswell as the '="' at the beginning and the '"' or '">' at the end of an attribute definition
  1148. /// </summary>
  1149. /// <param name="definition">the definition from the svg file</param>
  1150. /// <returns>the value of the attribute, as String (the part of definition contained between '"'s)</returns>
  1151. private String ParseSingleSVGAttribute(String definition)
  1152. {
  1153. return definition.Split('"')[1];
  1154. }
  1155. /// <summary>
  1156. /// fetches a single svg element definition that may extend ovr several lines of the input file, iterates i to point to the last line of the element definition
  1157. /// </summary>
  1158. /// <param name="allLines">an array holding all lines of the input file</param>
  1159. /// <returns>the definition of the current svg element, as String[] split by whitespaces</returns>
  1160. private String[] GetCurrentElement(String[] allLines)
  1161. {
  1162. List<String> currentElementTemp = allLines[i].Split(whitespaces).ToList();
  1163. while (!currentElementTemp.Last().EndsWith(">"))
  1164. {
  1165. i++;
  1166. currentElementTemp.AddRange(allLines[i].Split(whitespaces).ToList());
  1167. }
  1168. return currentElementTemp.ToArray();
  1169. }
  1170. /// <summary>
  1171. /// applies the scale factor to the coordinates and creates a new Point
  1172. /// </summary>
  1173. /// <param name="x">unscaled x coordinate</param>
  1174. /// <param name="y">unscaled y coordinate</param>
  1175. /// <returns>new Point with scaled coordinates</returns>
  1176. private Point ScaleAndCreatePoint(double x, double y)
  1177. {
  1178. return new Point((int)Math.Round(x * scale), (int)Math.Round(y * scale));
  1179. }
  1180. /// <summary>
  1181. /// creates a representation of an ellipse as a List of Points by sampling the outline of the ellipse
  1182. /// </summary>
  1183. /// <param name="x">x coordinate of the center of the ellipse</param>
  1184. /// <param name="y">y coordinate of the center of the ellipse</param>
  1185. /// <param name="rx">x radius of the ellipse</param>
  1186. /// <param name="ry">y radius of the ellipse</param>
  1187. /// <returns>the parsed element as a List of Points</returns>
  1188. private List<Point> SampleEllipse(double x, double y, double rx, double ry)
  1189. {
  1190. List<Point> ellipse = new List<Point>();
  1191. double angle = ((double)2 * Math.PI) / (double)samplingRateEllipse;
  1192. double yScale = ry / rx;
  1193. Console.WriteLine("parsing ellipse: " + x + ";" + y + "(" + rx + "x" + ry + ")" + " " + yScale + ":" + angle);
  1194. double[] xValues = new double[samplingRateEllipse / 4];
  1195. double[] yValues = new double[samplingRateEllipse / 4];
  1196. for (int j = 0; j < samplingRateEllipse / 4; j++) //compute offset values of points for one quadrant
  1197. {
  1198. xValues[j] = Math.Sin((double)j * angle) * rx;
  1199. yValues[j] = Math.Cos((double)j * angle) * rx;
  1200. Console.WriteLine("parsed ellipse value: " + xValues[j] + ";" + yValues[j]);
  1201. }
  1202. for (int j = 0; j < samplingRateEllipse / 4; j++) //create actual points for first quadrant
  1203. {
  1204. int xCoord = Convert.ToInt32(Math.Round(x + xValues[j]));
  1205. int yCoord = Convert.ToInt32(Math.Round(y - yValues[j] * yScale));
  1206. ellipse.Add(ScaleAndCreatePoint(xCoord, yCoord));
  1207. Console.WriteLine("parsed ellipse point: " + xCoord + ";" + yCoord + " pointCount: " + (samplingRateEllipse / 4));
  1208. }
  1209. for (int j = 0; j < samplingRateEllipse / 4; j++) //create actual points for second quadrant
  1210. {
  1211. int xCoord = Convert.ToInt32(Math.Round(x + yValues[j]));
  1212. int yCoord = Convert.ToInt32(Math.Round(y + xValues[j] * yScale));
  1213. ellipse.Add(ScaleAndCreatePoint(xCoord, yCoord));
  1214. Console.WriteLine("parsed ellipse point: " + xCoord + ";" + yCoord + " pointCount: " + (samplingRateEllipse / 4));
  1215. }
  1216. for (int j = 0; j < samplingRateEllipse / 4; j++) //create actual points for third quadrant
  1217. {
  1218. int xCoord = Convert.ToInt32(Math.Round(x - xValues[j]));
  1219. int yCoord = Convert.ToInt32(Math.Round(y + yValues[j] * yScale));
  1220. ellipse.Add(ScaleAndCreatePoint(xCoord, yCoord));
  1221. Console.WriteLine("parsed ellipse point: " + xCoord + ";" + yCoord + " pointCount: " + (samplingRateEllipse / 4));
  1222. }
  1223. for (int j = 0; j < samplingRateEllipse / 4; j++) //create actual points for fourth quadrant
  1224. {
  1225. int xCoord = Convert.ToInt32(Math.Round(x - yValues[j]));
  1226. int yCoord = Convert.ToInt32(Math.Round(y - xValues[j] * yScale));
  1227. ellipse.Add(ScaleAndCreatePoint(xCoord, yCoord));
  1228. Console.WriteLine("parsed ellipse point: " + xCoord + ";" + yCoord + " pointCount: " + (samplingRateEllipse / 4));
  1229. }
  1230. ellipse.Add(ScaleAndCreatePoint(Convert.ToInt32(Math.Round(x + 0)), Convert.ToInt32(Math.Round(y - rx * yScale)))); //close ellipse
  1231. return ellipse;
  1232. }
  1233. }
  1234. }