TrajectoryGenerator.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using System.Windows.Shapes;
  8. using System.Windows.Media;
  9. namespace SketchAssistantWPF
  10. {
  11. class TrajectoryGenerator
  12. {
  13. static readonly int CONSTANT_A = 50;
  14. static readonly double DEADZONE = 3;
  15. MVP_View programView_debug;
  16. List<Polyline> previousLines;
  17. /// <summary>
  18. /// the template for the line currently being drawn
  19. /// </summary>
  20. InternalLine currentLine;
  21. /// <summary>
  22. /// the points of the current line template, as an ordered list
  23. /// </summary>
  24. List<Point> currentPoints;
  25. //Point lastCursorPosition;
  26. /// <summary>
  27. /// pointer to the active section of the line template, indexing the ending point of the active section
  28. /// </summary>
  29. int index;
  30. public TrajectoryGenerator(MVP_View viewForDebug)
  31. {
  32. programView_debug = viewForDebug;
  33. previousLines = new List<Polyline>();
  34. }
  35. /// <summary>
  36. /// updates the pointer to the template for the line currently being drawn, and resets indices etc.
  37. /// </summary>
  38. /// <param name="newCurrentLine">the new template for the line currently being drawn</param>
  39. public void setCurrentLine(InternalLine newCurrentLine, List<InternalLine> leftLineList)
  40. {
  41. currentLine = newCurrentLine;
  42. if (currentLine != null)
  43. {
  44. currentPoints = currentLine.GetPoints();
  45. }
  46. else
  47. {
  48. currentPoints = null;
  49. }
  50. //lastCursorPosition = currentPoints.ElementAt(0);
  51. index = 1;
  52. if (leftLineList != null)
  53. {
  54. foreach (InternalLine l in leftLineList)
  55. {
  56. Polyline temp = new Polyline();
  57. PointCollection pointCollection = new PointCollection();
  58. foreach (Point p in l.GetPoints())
  59. {
  60. pointCollection.Add(p);
  61. }
  62. temp.Points = pointCollection;
  63. temp.Stroke = System.Windows.Media.Brushes.Red;
  64. temp.StrokeThickness = 1;
  65. programView_debug.AddNewLineRight(temp);
  66. previousLines.Add(temp);
  67. }
  68. }
  69. }
  70. /// <summary>
  71. /// generates the new trajectory back to the template based on the current cursor position
  72. /// </summary>
  73. /// <param name="cursorPosition">the current cursor position</param>
  74. /// <returns>the direction in which to go, as an angle on the drawing plane, in degree format, with 0° being the positive X-Axis, increasing counterclockwise</returns>
  75. public double GenerateTrajectory(Point cursorPosition)
  76. {
  77. if (currentLine != null && currentPoints.Count > 1)
  78. {
  79. Console.WriteLine(cursorPosition);
  80. Console.WriteLine(index + ":" + currentPoints.Count);
  81. Console.WriteLine(currentPoints.ElementAt(index));
  82. //update index to point to current section if one or more section divideing lines have been passed since last call
  83. while (index < (currentPoints.Count - 1) && (SectionDividingLinePassed(cursorPosition, currentPoints.ElementAt(index - 1), currentPoints.ElementAt(index), currentPoints.ElementAt(index + 1)) || ComputeDistance(cursorPosition, currentPoints.ElementAt(index)) < 3))
  84. {
  85. index++;
  86. }
  87. /*if (ComputeDistance(cursorPosition, currentPoints.ElementAt(index)) < 5 && index < (currentPoints.Count - 1))
  88. {
  89. index++;
  90. Console.WriteLine(index);
  91. }*/
  92. //lastCursorPosition = cursorPosition;
  93. //project teh point onto the active line segment to be able to compute distances
  94. Point orthogonalProjection = ComputeOrthogonalProjection(cursorPosition, currentPoints.ElementAt(index - 1), currentPoints.ElementAt(index));
  95. //index of the last reachable actual point
  96. int targetIndex = index - 1;
  97. List<Tuple<Point, Point>> strikeZones = new List<Tuple<Point, Point>>();
  98. //if "far" away from the next actual point of the line, generate an auxiliary point at a constant distance (constantA) on the current line segment
  99. Point auxiliaryPoint = new Point(-1, -1);
  100. if (ComputeDistance(orthogonalProjection, currentPoints.ElementAt(index)) > CONSTANT_A)
  101. {
  102. auxiliaryPoint = MoveAlongLine(orthogonalProjection, currentPoints.ElementAt(index - 1), currentPoints.ElementAt(index), CONSTANT_A);
  103. strikeZones.Add(computeStrikeZone(currentPoints.ElementAt(index - 1), auxiliaryPoint, currentPoints.ElementAt(index), orthogonalProjection, cursorPosition));
  104. //targetIndex--;
  105. }
  106. //aim for the furthest actual point of the line reachable by the descent rate constraints (lower bounds) given by the various strike zones
  107. while (targetIndex < (currentPoints.Count - 1) && allStrikeZonesPassed(strikeZones, cursorPosition, orthogonalProjection, currentPoints.ElementAt(targetIndex + 1)))
  108. {
  109. strikeZones.Add(computeStrikeZone((targetIndex >= 0 ? currentPoints.ElementAt(targetIndex) : new Point(-1, -1)), currentPoints.ElementAt(targetIndex + 1), (targetIndex < currentPoints.Count - 1 ? currentPoints.ElementAt(targetIndex + 1) : new Point(-1, -1)), orthogonalProjection, cursorPosition));
  110. targetIndex++;
  111. }
  112. Console.WriteLine(index + "," + targetIndex);
  113. Point furthestCrossingPoint = new Point(-1, -1); ;
  114. if (targetIndex < index) //auxiliary point created and next actual point not reachable
  115. {
  116. furthestCrossingPoint = ComputeFurthestCrossingPoint(cursorPosition, orthogonalProjection, strikeZones, auxiliaryPoint, currentPoints.ElementAt(targetIndex + 1));
  117. //if such a point exists, use it as target for the new trajectory
  118. if (furthestCrossingPoint.X != -1)
  119. {
  120. Debug_DrawStrikeZones(strikeZones);
  121. Debug_DrawTrajectoryVector(cursorPosition, furthestCrossingPoint);
  122. Debug_DrawOrthogonalProjection(cursorPosition, orthogonalProjection);
  123. Debug_DrawCurrentSection(currentPoints.ElementAt(index - 1), currentPoints.ElementAt(index));
  124. return computeOrientationOfVector(cursorPosition, furthestCrossingPoint);
  125. }
  126. //else use the last reachable actual point
  127. else
  128. {
  129. Debug_DrawStrikeZones(strikeZones);
  130. Debug_DrawTrajectoryVector(cursorPosition, auxiliaryPoint);
  131. Debug_DrawOrthogonalProjection(cursorPosition, orthogonalProjection);
  132. Debug_DrawCurrentSection(currentPoints.ElementAt(index - 1), currentPoints.ElementAt(index));
  133. return computeOrientationOfVector(cursorPosition, auxiliaryPoint);
  134. }
  135. }
  136. else
  137. {
  138. //aim for the furthest (auxiliary) point on the line segment after the last reachable actual point (only if there is such a segment: not if that last reachable point is the last point of the line)
  139. if (targetIndex < (currentPoints.Count - 1))
  140. {
  141. furthestCrossingPoint = ComputeFurthestCrossingPoint(cursorPosition, orthogonalProjection, strikeZones, currentPoints.ElementAt(targetIndex), currentPoints.ElementAt(targetIndex + 1));
  142. }
  143. //if such a point exists, use it as target for the new trajectory
  144. if (furthestCrossingPoint.X != -1)
  145. {
  146. Debug_DrawStrikeZones(strikeZones);
  147. Debug_DrawTrajectoryVector(cursorPosition, furthestCrossingPoint);
  148. Debug_DrawOrthogonalProjection(cursorPosition, orthogonalProjection);
  149. Debug_DrawCurrentSection(currentPoints.ElementAt(index - 1), currentPoints.ElementAt(index));
  150. return computeOrientationOfVector(cursorPosition, furthestCrossingPoint);
  151. }
  152. //else use the last reachable actual point
  153. else
  154. {
  155. Debug_DrawStrikeZones(strikeZones);
  156. Debug_DrawTrajectoryVector(cursorPosition, currentPoints.ElementAt(targetIndex));
  157. Debug_DrawOrthogonalProjection(cursorPosition, orthogonalProjection);
  158. Debug_DrawCurrentSection(currentPoints.ElementAt(index - 1), currentPoints.ElementAt(index));
  159. return computeOrientationOfVector(cursorPosition, currentPoints.ElementAt(targetIndex));
  160. }
  161. }
  162. }
  163. else return -1;
  164. }
  165. /// <summary>
  166. /// prints the trajectory vector on the drawing pane for debugging and calibration purposes
  167. /// </summary>
  168. /// <param name="vectorStartPoint">origin point of the trajectory vector</param>
  169. /// <param name="vectorEndPoint">target point of the trajectory vector</param>
  170. private void Debug_DrawTrajectoryVector(Point vectorStartPoint, Point vectorEndPoint)
  171. {
  172. Polyline temp = new Polyline();
  173. PointCollection pointCollection = new PointCollection();
  174. pointCollection.Add(vectorStartPoint);
  175. pointCollection.Add(vectorEndPoint);
  176. temp.Points = pointCollection;
  177. temp.Stroke = System.Windows.Media.Brushes.Red;
  178. temp.StrokeDashArray = new DoubleCollection { 2, 2 }; //TODO
  179. temp.StrokeThickness = 1;
  180. programView_debug.AddNewLineRight(temp);
  181. previousLines.Add(temp);
  182. }
  183. /// <summary>
  184. /// prints the trajectory vector on the drawing pane for debugging and calibration purposes
  185. /// </summary>
  186. /// <param name="vectorStartPoint">origin point of the trajectory vector</param>
  187. /// <param name="vectorEndPoint">target point of the trajectory vector</param>
  188. private void Debug_DrawOrthogonalProjection(Point cursorPosition, Point orthogonalProjection)
  189. {
  190. Polyline temp = new Polyline();
  191. PointCollection pointCollection = new PointCollection();
  192. pointCollection.Add(cursorPosition);
  193. pointCollection.Add(orthogonalProjection);
  194. temp.Points = pointCollection;
  195. temp.Stroke = System.Windows.Media.Brushes.Red;
  196. temp.StrokeDashArray = new DoubleCollection { 1, 2 }; //TODO
  197. temp.StrokeThickness = 1;
  198. programView_debug.AddNewLineRight(temp);
  199. previousLines.Add(temp);
  200. }
  201. /// <summary>
  202. /// prints the trajectory vector on the drawing pane for debugging and calibration purposes
  203. /// </summary>
  204. /// <param name="vectorStartPoint">origin point of the trajectory vector</param>
  205. /// <param name="vectorEndPoint">target point of the trajectory vector</param>
  206. private void Debug_DrawCurrentSection(Point sectionStartPoint, Point sectionEndPoint)
  207. {
  208. Polyline temp = new Polyline();
  209. PointCollection pointCollection = new PointCollection();
  210. pointCollection.Add(sectionStartPoint);
  211. pointCollection.Add(sectionEndPoint);
  212. temp.Points = pointCollection;
  213. temp.Stroke = System.Windows.Media.Brushes.Red;
  214. temp.StrokeThickness = 2;
  215. programView_debug.AddNewLineRight(temp);
  216. previousLines.Add(temp);
  217. }
  218. /// <summary>
  219. /// first deletes all debug lines from thte last interaction and then prints all strike zones on the drawing pane for debugging and calibration purposes
  220. /// </summary>
  221. /// <param name="strikeZones">list of all strike zones to be drawn</param>
  222. private void Debug_DrawStrikeZones(List<Tuple<Point, Point>> strikeZones)
  223. {
  224. foreach(Polyline l in previousLines)
  225. {
  226. programView_debug.RemoveSpecificLine(l);
  227. }
  228. previousLines.Clear();
  229. foreach (Tuple<Point, Point> t in strikeZones)
  230. {
  231. Polyline temp = new Polyline();
  232. PointCollection pointCollection= new PointCollection();
  233. pointCollection.Add(t.Item1);
  234. pointCollection.Add(t.Item2);
  235. temp.Points = pointCollection;
  236. temp.Stroke = System.Windows.Media.Brushes.DarkGreen;
  237. temp.StrokeDashArray = new DoubleCollection{ 2, 2 }; //TODO
  238. temp.StrokeThickness = 2;
  239. programView_debug.AddNewLineRight(temp);
  240. previousLines.Add(temp);
  241. }
  242. }
  243. /// <summary>
  244. /// computes the orientation of the given vector on the drawing plane
  245. /// </summary>
  246. /// <param name="vectorStartPoint">origin point of the direction vector</param>
  247. /// <param name="vectorEndPoint">target point of the direction vector</param>
  248. /// <returns>the orientation angle, in degree format</returns>
  249. private double computeOrientationOfVector(Point vectorStartPoint, Point vectorEndPoint)
  250. {
  251. double x = vectorEndPoint.X - vectorStartPoint.X;
  252. double y = vectorEndPoint.Y - vectorStartPoint.Y;
  253. return Math.Atan( y / x );
  254. }
  255. /// <summary>
  256. /// computes the furthest point on the given line segment that will still pass all previous strike zones when connecting it with the current cursor position in a straight line
  257. /// </summary>
  258. /// <param name="cursorPosition">the current cursor position</param>
  259. /// <param name="orthogonalProjection">the orthogonal projection of the current cursor position onto the active line segment</param>
  260. /// <param name="strikeZones">list of all strike zones which have to be passed</param>
  261. /// <param name="lineSegmentStartPoint">starting point of the line segment on which the point has to be found</param>
  262. /// <param name="lineSegmentEndPoint">ending point of the line segment on which the point has to be found</param>
  263. /// <returns>the furthest such point or a point with negative coordinates, if there is no such point on the given segment (start and end point excluded)</returns>
  264. private Point ComputeFurthestCrossingPoint(Point cursorPosition, Point orthogonalProjection, List<Tuple<Point, Point>> strikeZones, Point lineSegmentStartPoint, Point lineSegmentEndPoint)
  265. {
  266. Tuple<Point, Point> bsf= new Tuple<Point, Point>(new Point(-1, -1), new Point(-1, -1));
  267. Double bsfAngle = 180;
  268. for (int j = 0; j < strikeZones.Count; j++)
  269. {
  270. double currentAngle = ComputeAngle(orthogonalProjection, cursorPosition, strikeZones.ElementAt(j).Item2);
  271. if (currentAngle < bsfAngle)
  272. {
  273. bsfAngle = currentAngle;
  274. bsf = strikeZones.ElementAt(j);
  275. }
  276. }
  277. Point furthestCrossingPoint = ComputeCrossingPoint(cursorPosition, bsf.Item2, lineSegmentStartPoint, lineSegmentEndPoint);
  278. return furthestCrossingPoint;
  279. }
  280. private double ComputeAngle(Point point1, Point centerPoint, Point point2)
  281. {
  282. return (Math.Abs(computeOrientationOfVector(centerPoint, point1) - computeOrientationOfVector(centerPoint, point2)) % 180);
  283. }
  284. private Point ComputeCrossingPoint(Point line1Point1, Point line1Point2, Point line2Point1, Point line2Point2)
  285. {
  286. if (line2Point1.Equals(line2Point2)) return new Point(-1, -1);
  287. double xCoordinateOfCrossingPoint = ( (line1Point1.X * line1Point2.Y - line1Point1.Y * line1Point2.X) * (line2Point1.X - line2Point2.X) - (line1Point1.X - line1Point2.X) * (line2Point1.X * line2Point2.Y - line2Point1.Y * line2Point2.X) ) / ( (line1Point1.X - line1Point2.X) * (line2Point1.Y - line2Point2.Y) - (line1Point1.Y - line1Point2.Y) * (line2Point1.X - line2Point2.X) );
  288. double yCoordinateOfCrossingPoint = ( (line1Point1.X * line1Point2.Y - line1Point1.Y * line1Point2.X) * (line2Point1.Y - line2Point2.Y) - (line1Point1.Y - line1Point2.Y) * (line2Point1.X * line2Point2.Y - line2Point1.Y * line2Point2.X) ) / ( (line1Point1.X - line1Point2.X) * (line2Point1.Y - line2Point2.Y) - (line1Point1.Y - line1Point2.Y) * (line2Point1.X - line2Point2.X) );
  289. Point crossingPointOfLines = new Point(xCoordinateOfCrossingPoint, yCoordinateOfCrossingPoint);
  290. if (BeyondSection(crossingPointOfLines, line1Point1, line1Point2)) return new Point(-1, -1);
  291. if (BeyondSection(crossingPointOfLines, line1Point2, line1Point1)) return new Point(-1, -1);
  292. if (BeyondSection(crossingPointOfLines, line2Point1, line2Point2)) return new Point(-1, -1);
  293. if (BeyondSection(crossingPointOfLines, line2Point2, line2Point1)) return new Point(-1, -1);
  294. else return crossingPointOfLines;
  295. }
  296. /// <summary>
  297. /// checks if all strike zones are passed by the trajectory given by the straight line from the cursor position to the next target point
  298. /// </summary>
  299. /// <param name="strikeZones">list of all already computed strike zones</param>
  300. /// <param name="cursorPosition">the current cursor position</param>
  301. /// <param name="targetPoint">index of the next target point</param>
  302. /// <returns>true if all strike zones are passed, else false</returns>
  303. private bool allStrikeZonesPassed(List<Tuple<Point, Point>> strikeZones, Point cursorPosition, Point orthogonalProjection, Point targetPoint)
  304. {
  305. Point lastPoint = orthogonalProjection;
  306. foreach (Tuple<Point, Point> s in strikeZones )
  307. {
  308. if (!SectionsCrossing(cursorPosition, targetPoint, s.Item1, s.Item2)) return false; //strike zone not passed
  309. if (SectionsCrossing(cursorPosition, targetPoint, lastPoint, s.Item1)) return false; //line crossed
  310. lastPoint = s.Item1;
  311. }
  312. return true;
  313. }
  314. private bool SectionsCrossing(Point section1StartingPoint, Point section1EndingPoint, Point section2StartingPoint, Point section2EndingPoint)
  315. {
  316. Point crossingPoint = ComputeCrossingPoint(section1StartingPoint, section1EndingPoint, section2StartingPoint, section2EndingPoint);
  317. if (BeyondSection(crossingPoint, section1StartingPoint, section1EndingPoint)) return false;
  318. if (BeyondSection(crossingPoint, section1EndingPoint, section1StartingPoint)) return false;
  319. if (BeyondSection(crossingPoint, section2StartingPoint, section2EndingPoint)) return false;
  320. if (BeyondSection(crossingPoint, section2EndingPoint, section2StartingPoint)) return false;
  321. return true;
  322. }
  323. /// <summary>
  324. /// computes the strike zone for a point using the cursor position, its orthogonal projection onto the active line segment and tunable constants
  325. /// </summary>
  326. /// <param name="targetedPoint">the point to compute the strike zone of</param>
  327. /// <param name="orthogonalProjection">orthogonal projection of the cursor position onto the active line segment</param>
  328. /// <param name="cursorPosition">the current cursor position</param>
  329. /// <returns></returns>
  330. private Tuple<Point, Point> computeStrikeZone(Point lastPoint, Point targetedPoint, Point nextPoint, Point orthogonalProjection, Point cursorPosition)
  331. {
  332. if (lastPoint.X == -1 || nextPoint.X == -1 || ComputeDistance(cursorPosition, orthogonalProjection) < DEADZONE)
  333. {
  334. return new Tuple<Point, Point>(targetedPoint, targetedPoint);
  335. }
  336. double size = ComputeStrikeZoneSize(ComputeDistance(cursorPosition, orthogonalProjection), ComputeDistance(orthogonalProjection, targetedPoint)); //TODO correct distance to targetPoint
  337. double v_x = (lastPoint.X - targetedPoint.X) / ComputeDistance(lastPoint, targetedPoint);
  338. double v_y = (lastPoint.Y - targetedPoint.Y) / ComputeDistance(lastPoint, targetedPoint);
  339. //double u_x = (nextPoint.X - targetedPoint.X) / ComputeDistance(nextPoint, targetedPoint);
  340. //double u_y = (nextPoint.Y - targetedPoint.Y) / ComputeDistance(nextPoint, targetedPoint);
  341. //double tmp_x = v_x + u_x;
  342. //double tmp_y = v_y + u_y;
  343. double tmp_x = v_y;
  344. double tmp_y = v_x;
  345. double tmp_length = Math.Sqrt(tmp_x * tmp_x + tmp_y * tmp_y);
  346. tmp_x = ((tmp_x / tmp_length) * size) + targetedPoint.X;
  347. tmp_y = ((tmp_y / tmp_length) * size) + targetedPoint.Y;
  348. return new Tuple<Point, Point>(targetedPoint, new Point(tmp_x, tmp_y)); //TODO right direction of vector
  349. }
  350. private double ComputeStrikeZoneSize(double v1, double v2)
  351. {
  352. return 25; //TODO
  353. }
  354. /// <summary>
  355. /// moves a point a given distance along a vector defined by two points
  356. /// </summary>
  357. /// <param name="pointToBeMoved">the point to be moved along the line</param>
  358. /// <param name="lineStartPoint">origin point of the direction vector</param>
  359. /// <param name="lineEndPoint">target point of the direction vector</param>
  360. /// <param name="distance">distance by which to move the point</param>
  361. /// <returns>a new point that is located distance away from pointToBeMoved in the direction of the given vector</returns>
  362. private Point MoveAlongLine(Point pointToBeMoved, Point lineStartPoint, Point lineEndPoint, double distance)
  363. {
  364. double xOffset = lineEndPoint.X - lineStartPoint.X;
  365. double yOffset = lineEndPoint.Y - lineStartPoint.Y;
  366. double vectorLength = ComputeDistance(lineStartPoint, lineEndPoint);
  367. xOffset /= vectorLength;
  368. xOffset *= distance;
  369. yOffset /= vectorLength;
  370. yOffset *= distance;
  371. return new Point(pointToBeMoved.X + xOffset, pointToBeMoved.Y + yOffset);
  372. }
  373. /// <summary>
  374. /// computes the euclidean distance between two points
  375. /// </summary>
  376. /// <param name="point1">point 1</param>
  377. /// <param name="point2">point 2</param>
  378. /// <returns>euclidean distance between point1 and point2</returns>
  379. private double ComputeDistance(Point point1, Point point2)
  380. {
  381. return Math.Sqrt( (double) ( Math.Pow((point2.X - point1.X), 2) + Math.Pow((point2.Y - point1.Y), 2) ) );
  382. }
  383. /// <summary>
  384. /// computes the orthogonal projection of a point onto the given line segment
  385. /// </summary>
  386. /// <param name="cursorPosition">the current cursor position</param>
  387. /// <param name="lastPoint">beginning point of the current section</param>
  388. /// <param name="currentPoint">ending point of current section</param>
  389. /// <returns>the orthogonal projection of a point onto the given line segment, or the respective segment end point if the orthogonal projection lies outside the specified segment</returns>
  390. private Point ComputeOrthogonalProjection(Point cursorPosition, Point lastPoint, Point currentPoint)
  391. {
  392. double v_x = cursorPosition.X - lastPoint.X;
  393. double v_y= cursorPosition.Y - lastPoint.Y;
  394. double u_x = currentPoint.X - lastPoint.X;
  395. double u_y = currentPoint.Y - lastPoint.Y;
  396. double factor = (v_x * u_x + v_y * u_y) / (u_x * u_x + u_y * u_y);
  397. double new_x = factor * u_x + lastPoint.X;
  398. double new_y = factor * u_y + lastPoint.Y;
  399. Point orthogonalProjection = new Point(new_x, new_y);
  400. Console.Write(orthogonalProjection);
  401. if (BeyondSection(orthogonalProjection, lastPoint, currentPoint))
  402. {
  403. Console.WriteLine("n");
  404. return currentPoint;
  405. }
  406. if (BeyondSection(orthogonalProjection, currentPoint, lastPoint))
  407. {
  408. Console.WriteLine("l");
  409. return lastPoint;
  410. }
  411. Console.WriteLine("o");
  412. return orthogonalProjection;
  413. }
  414. /// <summary>
  415. /// checks if a Point lies on a given line section or beyond it, works only if pointToTest lies on the line defined by sectionStartingPoint and sectionEndingPoint
  416. /// </summary>
  417. /// <param name="pointToTest">the Point to test</param>
  418. /// <param name="sectionStartingPoint">the starting point of the section</param>
  419. /// <param name="sectionEndingPoint">the ending point of the section</param>
  420. /// <returns>true iff pointToTest lies beyond sectionEndingPoint, on the line defined by sectionStartingPoint and sectionEndingPoint</returns>
  421. private bool BeyondSection(Point pointToTest, Point sectionStartingPoint, Point sectionEndingPoint)
  422. {
  423. //TODO
  424. if(sectionEndingPoint.X >= sectionStartingPoint.X && pointToTest.X > sectionEndingPoint.X)
  425. {
  426. return true;
  427. }
  428. else if(sectionEndingPoint.X <= sectionStartingPoint.X && pointToTest.X < sectionEndingPoint.X)
  429. {
  430. return true;
  431. }
  432. else
  433. {
  434. if (sectionEndingPoint.Y > sectionStartingPoint.Y)
  435. {
  436. if (pointToTest.Y > sectionEndingPoint.Y) return true;
  437. }
  438. else if (sectionEndingPoint.Y <= sectionStartingPoint.Y)
  439. {
  440. if (pointToTest.Y < sectionEndingPoint.Y) return true;
  441. }
  442. }
  443. return false;
  444. }
  445. /// <summary>
  446. /// checks if the angle dividing line between this section and the next one has been passed
  447. /// </summary>
  448. /// <param name="cursorPosition">the current cursor position</param>
  449. /// <param name="lastPoint">beginning point of the current section</param>
  450. /// <param name="currentPoint">ending point of current and beginning point of next section</param>
  451. /// <param name="nextPoint">ending point of next section</param>
  452. /// <returns>true iff cursorPosition is closer to the next section than to the current one</returns>
  453. private bool SectionDividingLinePassed(Point cursorPosition, Point lastPoint, Point currentPoint, Point nextPoint)
  454. {
  455. //compute a point at the same distance to the dividing line as nextPoint, but on the other side of the line
  456. Point auxiliaryPoint = MoveAlongLine(currentPoint, currentPoint, lastPoint, ComputeDistance(currentPoint, nextPoint));
  457. //line passed iff cursorPosition closer to nextPoint than to auxiliaryPoint
  458. return ComputeDistance(cursorPosition, nextPoint) <= ComputeDistance(cursorPosition, auxiliaryPoint);
  459. }
  460. }
  461. }