1 /++
2 Collision checker and collision points between forms.
3 
4 Macros:
5     LREF = <a href="#$1">$1</a>
6     HREF = <a href="$1">$2</a>
7 
8 Authors: $(HREF https://github.com/TodNaz,TodNaz)
9 Copyright: Copyright (c) 2020 - 2021, TodNaz.
10 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT)
11 +/
12 module tida.collision;
13 
14 import tida.shape, tida.vector;
15 
16 /++
17 Checks if there is a collision between the lines.
18 
19 Params:
20     first = First line vertexs.
21     second = Second line vertexs.
22 +/
23 bool lineLineImpl(const Vecf[] first, const Vecf[] second) @safe nothrow pure
24 {
25     const a = first[0];
26     const b = first[1];
27     const c = second[0];
28     const d = second[1];
29 
30     const denominator = ((b.x - a.x) * (d.y - c.y)) - ((b.y - a.y) * (d.x - c.x));
31 
32     const numerator1  = ((a.y - c.y) * (d.x - c.x)) - ((a.x - c.x) * (d.y - c.y));
33     const numerator2  = ((a.y - c.y) * (b.x - a.x)) - ((a.x - c.x) * (b.y - a.y));
34 
35     if (denominator == 0) return numerator1 == 0 && numerator2 == 0;
36 
37     const r = numerator1 / denominator;
38     const s = numerator2 / denominator;
39 
40     return (r >= 0 && r <= 1) && (s >= 0 && s <= 1);
41 }
42 
43 /++
44 Checks if there is a collision between a point and a line.
45 
46 Params:
47     point = Point position.
48     line = Line vertexs.
49 +/
50 bool pointLineImpl(const Vecf point, const Vecf[] line) @safe nothrow pure
51 {
52     import tida.each;
53 
54     if (point == line[0] ||
55        point == line[1])
56       return true;
57 
58     bool result = false;
59 
60     foreach(x,y; LineNoThrowImpl(line[0], line[1])) {
61         if (cast(int) point.x == x &&
62            cast(int) point.y == y) {
63             result = true;
64             break;
65         }
66     }
67 
68     return result;
69 }
70 
71 /++
72 Checks if there is a collision between a point and a rectange.
73 
74 Params:
75     a = Point position.
76     b = Rectangle vertexs.
77 +/
78 bool pointRectImpl(const Vecf a, const Vecf[] b) @safe nothrow pure
79 {
80     return a.x > b[0].x &&
81            a.y > b[0].y &&
82            a.x < b[1].x &&
83            a.y < b[1].y;
84 }
85 
86 /++
87 Checks if there is a collision between a line and a rectangle.
88 
89 Params:
90     a = Line vertexs.
91     b = Rectangle vertexs.
92 +/
93 bool lineRectImpl(const Vecf[] a, const Vecf[] b) @safe nothrow pure
94 {
95     import tida.each;
96 
97     if (b[0] == a[0] ||
98       b[0] == a[1] ||
99       b[1] == a[0] ||
100       b[1] == a[1])
101       return true;
102 
103     bool result = false;
104 
105     foreach(x,y; LineNoThrowImpl(a[0], a[1])) {
106         if (x > b[0].x &&
107            x < b[1].x   &&
108            y > b[0].y &&
109            y < b[1].y) 
110         {
111            result = true;
112            break;
113         }
114     }
115 
116     return result;
117 }
118 
119 /++
120 Checks if there is a collision between a point and a Circle.
121 
122 Params:
123     a = Point position.
124     circlePos = Circle position.
125     circleRadius = Circle radius.
126 +/
127 bool pointCircleImpl(const Vecf a, const Vecf circlePos, const float circleRadius) @safe nothrow pure
128 {
129     return a.distance(circlePos) <= circleRadius;
130 }
131 
132 /++
133 Checks if there is a collision between a line and a Circle.
134 
135 Params:
136     a = Line vertexs.
137     circlePos = Circle position.
138     circleRadius = Circle radius.
139 +/
140 bool lineCircleImpl(const Vecf[] a, const Vecf circlePos, const float circleRadius) @safe nothrow pure
141 {
142     bool inside1 = pointCircleImpl(a[0], circlePos, circleRadius);
143     bool inside2 = pointCircleImpl(a[1], circlePos, circleRadius);
144     if (inside1 || inside2) return true;
145 
146     float len = a.length;
147 
148     float dot = (   (circlePos.x - a[0].x) * (a[1].x - a[0].x)) +
149                 (   (circlePos.y - a[0].y) * (a[1].y - a[0].y)) / (len * len);
150 
151     const closest = a[0] + ((a[1] - a[0]) * dot);
152 
153     bool onSegment = pointLineImpl(closest, a);
154     if (onSegment) return true;
155 
156     const dist = closest - circlePos;
157     len = dist.length;
158 
159     return (len <= circleRadius);
160 }
161 
162 /++
163 Checks if there is a collision between a rectangle and a circle.
164 
165 Params:
166     a = Rectange vertexs.
167     circlePos = Circle position.
168     circleRadius = Circle radius.
169 +/
170 bool rectCircleImpl(const Vecf[] a, const Vecf circlePos, const float circleRadius) @safe nothrow pure
171 {
172     Vecf temp = circlePos;
173 
174     if (circlePos.x < a[0].x) temp.x = a[0].x; else
175     if (circlePos.x > a[1].x) temp.y = a[1].y;
176 
177     if (circlePos.y < a[0].y) temp.y = a[0].y; else
178     if (circlePos.y > a[1].y) temp.y = a[1].y;
179 
180     immutable dist = circlePos - temp;
181     immutable len = dist.length;
182 
183     return len <= circleRadius;
184 }
185 
186 bool trianglePointImpl(const Vecf[3] a, const Vecf b) @safe nothrow pure
187 {
188     import std.math : abs;
189 
190     const area = abs (  (a[1].x - a[0].x) * (a[2].y - a[0].y) -
191                         (a[2].x - a[0].x) * (a[1].y - a[0].y) );
192     const(float)[] areas =
193     [
194         abs( (a[0].x - b.x) * (a[1].y - b.y) - (a[1].x - b.x) * (a[0].y - b.y) ),
195         abs( (a[1].x - b.x) * (a[2].y - b.y) - (a[2].x - b.x) * (a[1].y - b.y) ),
196         abs( (a[2].x - b.x) * (a[0].y - b.y) - (a[0].x - b.x) * (a[2].y - b.y) )
197     ];
198 
199     return (areas[0] + areas[1] + areas[2]) == area;
200 }
201 
202 bool triangleLineImpl(const Vecf[3] a, const Vecf[2] b) @safe nothrow pure
203 {
204     import tida.each;
205 
206     bool iscollision = false;
207 
208     foreach(x, y; LineNoThrowImpl(b[0], b[1]))
209     {
210         if (trianglePointImpl(a, vecf(x, y))) {
211             iscollision = true;
212             break;
213         }
214     }
215 
216     return iscollision;
217 }
218 
219 /++
220 A function to check the intersection of two shapes. It does not give an intersection point,
221 it gives a state that informs if there is an intersection.
222 
223 Params:
224     first = First shape.
225     second = Second shape.
226     firstPos = Position first shape.
227     secondPos = Position second shape.
228 
229 Returns:
230     Gives a state indicating if there is an intersection.
231 
232 Example:
233 ---
234 isCollide(Shape.Rectangle(vecf(32,32),vecf(48,48)),
235                  Shape.Line(vecf(48,32),vecf(32,48)));
236 ---
237 +/
238 bool isCollide(	Shape!float first, 
239                 Shape!float second, 
240                 Vecf firstPos = vecf(0,0),
241                 Vecf secondPos = vecf(0,0)) @safe nothrow pure
242 {
243     import std.conv : to;
244     import std.math : abs, sqrt;
245 
246     first.begin = first.begin + firstPos;
247     second.begin = second.begin + secondPos;
248 
249     if (first.type == ShapeType.line || first.type == ShapeType.rectangle)
250         first.end = first.end + firstPos;
251 
252     if (second.type == ShapeType.line || second.type == ShapeType.rectangle)
253         second.end = second.end + secondPos;
254 
255     switch(first.type)
256     {
257         case ShapeType.point:
258 
259             switch(second.type)
260             {
261                 case ShapeType.point:
262                     return first.begin == second.begin;
263 
264                 case ShapeType.line: 
265                     return pointLineImpl(first.begin, second.to!(Vecf[]));
266 
267                 case ShapeType.rectangle:
268                     return pointRectImpl(first.begin, second.to!(Vecf[]));
269 
270                 case ShapeType.circle:
271                     return pointCircleImpl(first.begin, second.begin, second.radius);
272 
273                 case ShapeType.polygon:
274                     return isPolygonAndPoint(second.data, first.begin);
275 
276                 case ShapeType.multi:
277                     foreach(shape; second.shapes) {
278                         if (isCollide(first, shape,vecf(0,0), second.begin))
279                             return true;
280                     }
281 
282                     return false;
283 
284                 default:
285                     return false;
286             }
287 
288         case ShapeType.line:
289 
290             switch(second.type)
291             {
292                 case ShapeType.point:
293                     return pointLineImpl(second.begin, first.to!(Vecf[]));
294 
295                 case ShapeType.line:
296                     return lineLineImpl(first.to!(Vecf[]), second.to!(Vecf[]));
297 
298                 case ShapeType.rectangle:
299                     return lineRectImpl(first.to!(Vecf[]), second.to!(Vecf[]));
300 
301                 case ShapeType.circle:
302                     return lineCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
303 
304                 case ShapeType.polygon:
305                     return isPolygonAndLine(second.data, first.to!(Vecf[]));
306 
307                 case ShapeType.multi:
308                     foreach(shape; second.shapes) {
309                         if (isCollide(first,shape,vecf(0,0),second.begin))
310                             return true;
311                     }
312 
313                     return false;
314 
315                 default:
316                     return false;
317             }
318 
319         case ShapeType.rectangle:
320             
321             switch(second.type)
322             {
323                 case ShapeType.point:
324                     return pointRectImpl(second.begin, first.to!(Vecf[]));
325 
326                 case ShapeType.line:
327                     return lineRectImpl(second.to!(Vecf[]), first.to!(Vecf[]));
328 
329                 case ShapeType.rectangle:
330                     const a = first.begin;
331                     const b = first.end;
332                     const c = second.begin;
333                     const d = second.end;
334 
335                     return
336                     (
337                         a.x + (b.x-a.x) >= c.x && 
338                         a.x <= c.x + (d.x-c.x) && 
339                         a.y + (b.y - a.y) >= c.y && 
340                         a.y <= c.y + (d.y - c.y)
341                     );
342 
343                 case ShapeType.circle:
344                     return rectCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
345 
346                 case ShapeType.polygon:
347                     return isPolygonAndRect(second.data, first.to!(Vecf[]));
348 
349                 case ShapeType.multi:
350                     foreach(shape; second.shapes) {
351                         if (isCollide(first, shape,vecf(0,0),second.begin))
352                             return true;
353                     }
354 
355                     return false;
356 
357                 default:
358                     return false;
359             }
360 
361         case ShapeType.circle:
362             switch(second.type)
363             {
364                 case ShapeType.point:
365                     return pointCircleImpl(second.begin, first.begin, first.radius);
366 
367                 case ShapeType.line:
368                     return lineCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
369 
370                 case ShapeType.rectangle:
371                     return rectCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
372 
373                 case ShapeType.circle:
374                     immutable dist = first.begin - second.begin;
375 
376                     return dist.length <= first.radius + second.radius;
377 
378                 case ShapeType.polygon:
379                     return isPolygonAndCircle(second.data, first.begin, first.radius);
380 
381                 case ShapeType.multi:
382                     foreach(shape; second.shapes) {
383                         if (isCollide(first,shape,vecf(0,0),second.begin))
384                             return true;
385                     }
386 
387                     return false;
388 
389                 default:
390                     return false;
391             }
392 
393         case ShapeType.polygon:
394             switch(second.type)
395             {
396                 case ShapeType.point:
397                     return isPolygonAndPoint(first.data, second.begin);
398 
399                 case ShapeType.line:
400                     return isPolygonAndLine(first.data, second.to!(Vecf[]));
401 
402                 case ShapeType.rectangle:
403                     return isPolygonAndRect(first.data, second.to!(Vecf[]));
404 
405                 case ShapeType.circle:
406                     return isPolygonAndCircle(first.data, second.begin, second.radius);
407 
408                 case ShapeType.polygon:
409                     return isPolygonsCollision(first.data, second.data);
410 
411                 case ShapeType.multi:
412                     foreach(shape; second.shapes) {
413                         if (isCollide(shape, first, second.begin, vecf(0,0)))
414                             return true;
415                     }
416 
417                     return false;
418 
419                 default:
420                     return false;
421             }
422 
423         case ShapeType.multi:
424             foreach(shape; first.shapes) {
425                 if (isCollide(shape, second,first.begin,vecf(0,0)))
426                     return true;
427             }
428 
429             return false;
430 
431         default:
432             return false;
433     }
434 }
435 
436 unittest
437 {
438     assert(isCollide(
439             Shapef.Rectangle(vecf(32,32),vecf(64,64)),
440             Shapef.Line(vecf(48,48),vecf(96,96))
441         ));
442 
443 
444     assert(isCollide(
445         Shapef.Rectangle(vecf(32,32),vecf(64,64)),
446         Shapef.Rectangle(vecf(48,48),vecf(72,72))
447     ));
448 
449     assert(isCollide(
450         Shapef.Line(vecf(32,32),vecf(64,64)),
451         Shapef.Line(vecf(64,32),vecf(32,64))
452     ));
453 }
454 
455 /++
456 Checks collision between polygon and point.
457 
458 Params:
459     first = Polygon vertices.
460     second = Point position.
461 +/
462 bool isPolygonAndPoint(Vecf[] first, Vecf second) @safe nothrow pure
463 {
464     bool collision = false;
465 
466     int next = 0;
467     for(int current = 0; current < first.length; current++)
468     {
469         next = current + 1;
470 
471         if (next == first.length) next = 0;
472 
473         Vecf vc = first[current];
474         Vecf vn = first[next];
475 
476         if(((vc.y >= second.y && vn.y <= second.y) || (vc.y <= second.y && vn.y >= second.y)) &&
477             (second.x < (vn.x - vc.x) * (second.y - vc.y) / (vn.y - vc.y) + vc.x)) {
478             collision = !collision;
479         }
480     }
481 
482     return collision;
483 }
484 
485 /++
486 Checks collision between polygon and line.
487 
488 Params:
489     first = Polygon vertices.
490     second = Line vertices.
491 +/
492 bool isPolygonAndLine(Vecf[] first, Vecf[] second) @safe nothrow pure
493 {
494     int next = 0;
495     for(int current = 0; current < first.length; current++)
496     {
497         next = current + 1;
498 
499         if (next == first.length) next = 0;
500 
501         Vecf vc = first[current];
502         Vecf vn = first[next];
503 
504         bool hit = lineLineImpl(second, [vc, vn]);
505 
506         if (hit) return true;
507     }
508 
509     return false;
510 }
511 
512 /++
513 Check collision between polygon and rectangle.
514 
515 Params:
516     first = Polygon vertices.
517     second = Rectangle vertices.
518 +/
519 bool isPolygonAndRect(Vecf[] first, Vecf[] second) @safe nothrow pure
520 {
521     int next = 0;
522     for(int current = 0; current < first.length; current++)
523     {
524         next = current + 1;
525 
526         if (next == first.length) next = 0;
527 
528         Vecf vc = first[current];
529         Vecf vn = first[next];
530 
531         bool hit = lineRectImpl([vc, vn], second);
532 
533         if (hit) return true;
534     }
535 
536     return false;
537 }
538 
539 /++
540 Check collision between polygon and circle.
541 
542 Params:
543     first = Polygon vertices.
544     second = The position of the center of the circle.
545     r = Circle radius.
546 +/
547 bool isPolygonAndCircle(Vecf[] first, Vecf second, float r) @safe nothrow pure
548 {
549     int next = 0;
550     for(int current = 0; current < first.length; current++)
551     {
552         next = current + 1;
553 
554         if (next == first.length) next = 0;
555 
556         Vecf vc = first[current];
557         Vecf vn = first[next];
558 
559         bool hit = lineCircleImpl([vc, vn], second, r);
560 
561         if (hit) return true;
562     }
563 
564     return false;
565 }
566 
567 /++
568 Checking the collision of two polygons.
569 
570 Params:
571     first = First polygon vertices.
572     second = Second polygon vertices.
573 +/
574 bool isPolygonsCollision(Vecf[] first, Vecf[] second) @safe nothrow pure
575 {
576     int next = 0;
577     for(int current = 0; current < first.length; current++)
578     {
579         next = current + 1;
580 
581         if (next == first.length) next = 0;
582 
583         Vecf vc = first[current];
584         Vecf vn = first[next];
585 
586         bool hit = isPolygonAndLine(second, [vc, vn]);
587         if (hit) return true;
588 
589         hit = isPolygonAndPoint(first, second[0]);
590         if (hit) return true;
591     }
592 
593     return false;
594 }
595 
596 unittest
597 {
598     Vecf[]  first = [
599                         vecf(32, 32),
600                         vecf(64, 48),
601                         vecf(64, 128),
602                         vecf(32, 112)
603                     ];
604 
605     assert(isPolygonAndPoint(first, vecf(33, 33)));
606 
607     assert(isPolygonAndLine(first, [vecf(16, 16), vecf(48, 48)]));
608 
609     assert(isPolygonAndRect(first, [vecf(16, 16), vecf(128, 128)]));
610 
611     assert(isPolygonAndCircle(first, vecf(128, 128), 64));
612 
613     assert(isPolygonsCollision(first,   [
614                                             vecf(48, 48),
615                                             vecf(64, 64),
616                                             vecf(32, 64),
617                                             vecf(32, 32),
618                                             vecf(32, 48)
619                                         ]));
620 }
621 
622 /++
623 Gives the place of collision of a line and a point.
624 
625 Params:
626     point = Point vector.
627     line = Line vectors.
628 
629 Returns:
630     Place of collision.
631 +/
632 const(Vecf) placePointLineImpl(const Vecf point, const Vecf[] line) @safe nothrow pure
633 {
634     import tida.each;
635 
636     if (point == line[0] ||
637        point == line[1])
638       return point;
639 
640     Vecf result = vecfNaN;
641 
642     foreach(x,y; LineNoThrowImpl(line[0], line[1])) {
643         if (cast(int) point.x == x &&
644            cast(int) point.y == y) {
645             result = vecf(x, y);
646             break;
647         }
648     }
649 
650     return result;
651 }
652 
653 /++
654 Gives the place of collision of a point and a rectangle.
655 
656 Params:
657     point = Point vector.
658     rectangle = rectangle vectors.
659 
660 Returns:
661     Place of collision.
662 +/
663 const(Vecf) placePointRectImpl(const Vecf point, const Vecf[] rectangle) @safe nothrow pure
664 {
665     Vecf place = rectangle[0] - point;
666 
667     if( place.x < 0 || place.y < 0 ||
668         place.x > (rectangle[1] - rectangle[0]).x ||
669         place.y > (rectangle[1] - rectangle[0]).y) {
670         return vecfNaN;
671     } else {
672         return rectangle[0] + place;
673     }
674 }
675 
676 /++
677 Gives the place of collision of a point and a circle.
678 
679 Params:
680     point = Point vector.
681     circlePos = Cirlce position.
682     circleRadius = Circle radius.
683 
684 Returns:
685     Place of collision.
686 +/
687 const(Vecf) placePointCircleImpl(const Vecf point, const Vecf circlePos, const float circleRadius) @safe nothrow pure
688 {
689     return point.distance(circlePos) > circleRadius ? vecfNaN : point;
690 }
691 
692 /++
693 Gives the place of collision of a line and a line.
694 
695 Params:
696     first = Line vector.
697     second = Line vectors.
698 
699 Returns:
700     Place of collision.
701 +/
702 const(Vecf) placeLineLineImpl(const Vecf[] first, const Vecf[] second) @safe nothrow pure
703 {
704     const a = first[0];
705     const b = first[1];
706     const c = second[0];
707     const d = second[1];
708 
709     const denominator = ((b.x - a.x) * (d.y - c.y)) - ((b.y - a.y) * (d.x - c.x));
710 
711     const numerator1  = ((a.y - c.y) * (d.x - c.x)) - ((a.x - c.x) * (d.y - c.y));
712     const numerator2  = ((a.y - c.y) * (b.x - a.x)) - ((a.x - c.x) * (b.y - a.y));
713 
714     const r = numerator1 / denominator;
715     const s = numerator2 / denominator;
716 
717     if((r >= 0 && r <= 1) && (s >= 0 && s <= 1))
718         return first[0] - ((first[1] - first[0]) * r);
719     else
720         return vecfNaN;
721 }
722 
723 /++
724 Gives the place of collision of a line and a rectangle.
725 
726 Params:
727     a = Line vector.
728     b = Rectangle vectors.
729 
730 Returns:
731     Place of collision.
732 +/
733 const(Vecf) placeLineRectImpl(const Vecf[] a, const Vecf[] b) @safe nothrow pure
734 {
735     import tida.each;
736 
737     if (b[0] == a[0] ||
738       b[0] == a[1] ||
739       b[1] == a[0] ||
740       b[1] == a[1])
741       return a[0];
742 
743     Vecf result = vecfNaN;
744 
745     foreach(x,y; LineNoThrowImpl(a[0], a[1])) {
746         if (x > b[0].x &&
747            x < b[1].x   &&
748            y > b[0].y &&
749            y < b[1].y)
750         {
751            return vecf(x, y);
752         }
753     }
754 
755     return result;
756 }
757 
758 /++
759 Gives the place of collision of a line and a circle.
760 
761 Params:
762     line = line vector.
763     circlePos = Circle position.
764     circleRadius = Circle radius.
765 
766 Returns:
767     Place of collision.
768 +/
769 const(Vecf) placeLineCircleImpl(const Vecf[] line, const Vecf circlePos, const float circleRadius) @safe nothrow pure
770 {
771     import tida.each;
772 
773     Vecf place = vecfNaN;
774 
775     foreach(x, y; LineNoThrowImpl(line[0], line[1])) {
776         if(!(place = placePointCircleImpl(vecf(x, y), circlePos, circleRadius)).isVecfNaN)
777             return place;
778     }
779 
780     return vecfNaN;
781 }
782 
783 /++
784 Gives the place of collision of a rectangle and a rectangle.
785 
786 Params:
787     a = Rectangle vector.
788     b = Rectangle vectors.
789     isRecurse = Used only for recursion.
790 
791 Returns:
792     Place of collision.
793 +/
794 const(Vecf) placeRectRectImpl(const Vecf[] a, const Vecf[] b,bool isRecurse = false) @safe nothrow pure
795 {
796     if (lineRectImpl([a[0], a[0] + vecf(a[1].x, 0)], b))
797         return placeLineRectImpl([a[0], a[0] + vecf(a[1].x, 0)], b);
798     if (lineRectImpl([a[0] + vecf(a[1].x, 0), a[1]], b))
799         return placeLineRectImpl([a[0] + vecf(a[1].x, 0), a[1]], b);
800     if (lineRectImpl([a[0], a[0] + vecf(0, a[1].y)], b))
801         return placeLineRectImpl([a[0], a[0] + vecf(0, a[1].y)], b);
802     if (lineRectImpl([a[0] + vecf(0, a[1].y), a[1]], b))
803         return placeLineRectImpl([a[0] + vecf(0, a[1].y), a[1]], b);
804 
805     if(!isRecurse)
806         return placeRectRectImpl(b, a, true);
807     else
808         return vecfNaN;
809 }
810 
811 /++
812 Gives the place of collision of a rectangle and a circle.
813 
814 Params:
815     a = Rectangle vectors.
816     circlePos = Circle position.
817     circleRadius = Circle radius.
818 
819 Returns:
820     Place of collision.
821 +/
822 const(Vecf) placeRectCircleImpl(const Vecf[] a, const Vecf circlePos, const float circleRadius) @safe nothrow pure
823 {
824     if (lineCircleImpl([a[0], a[0] + vecf(a[1].x, 0)], circlePos, circleRadius))
825         return placeLineCircleImpl([a[0], a[0] + vecf(a[1].x, 0)], circlePos, circleRadius);
826     if (lineCircleImpl([a[0] + vecf(a[1].x, 0), a[1]], circlePos, circleRadius))
827         return placeLineCircleImpl([a[0] + vecf(a[1].x, 0), a[1]], circlePos, circleRadius);
828     if (lineCircleImpl([a[0], a[0] + vecf(0, a[1].y)], circlePos, circleRadius))
829         return placeLineCircleImpl([a[0], a[0] + vecf(0, a[1].y)], circlePos, circleRadius);
830     if (lineCircleImpl([a[0] + vecf(0, a[1].y), a[1]], circlePos, circleRadius))
831         return placeLineCircleImpl([a[0] + vecf(0, a[1].y), a[1]], circlePos, circleRadius);
832 
833     Vecf place = vecfNaN;
834     Vecf[] line =   [
835                         circlePos - vecf(0, circleRadius),
836                         circlePos + vecf(0, circleRadius)
837                     ];
838 
839     if(!(place = placeLineRectImpl(line, a)).isVecfNaN) return place;
840     line =  [
841                 circlePos - vecf(circleRadius, 0),
842                 circlePos + vecf(circleRadius, 0)
843             ];
844 
845     return placeLineRectImpl(line, a);
846 }
847 
848 /++
849 Gives the place of collision of a circle and a circle.
850 
851 Params:
852     fPos = First circle position.
853     fRadius = First circle radius.
854     fPos = Second circle position.
855     fRadius = Second circle radius.
856 
857 Returns:
858     Place of collision.
859 +/
860 const(Vecf) placeCircleCircleImpl(	const Vecf fPos, 
861                                     const float fRadius, 
862                                     const Vecf sPos,
863                                     const float sRadius)
864 @safe nothrow pure
865 {
866     //immutable dist = first.begin - second.begin;
867     //return dist.length <= first.radius + second.radius;
868 
869     if((fPos - sPos).length <= fRadius + sRadius) {
870         return Vecf((fPos.x * sRadius + sPos.x * fRadius) / (fRadius + sRadius),
871                     (fPos.y * sRadius + sPos.y * fRadius) / (fRadius + sRadius));
872     } else {
873         return vecfNaN;
874     }
875 }
876 
877 /++
878 Finds the point of contact between two forms.
879 
880 Params:
881     first = First shape.
882     second = Second shape.
883     firstPos = First shape position.
884     secondPos = Second shape position.
885 
886 Returns:
887     point of contact between two forms.
888 +/
889 const(Vecf) placeofTangents(Shape!float first, 
890                             Shape!float second, 
891                             Vecf firstPos = vecf(0, 0), 
892                             Vecf secondPos = vecf(0, 0))
893 @safe nothrow pure
894 in(first.type != ShapeType.unknown  && second.type != ShapeType.unknown)
895 in(first.type != ShapeType.triangle && second.type != ShapeType.triangle)
896 do
897 {
898     first.begin = first.begin + firstPos;
899     second.begin = second.begin + secondPos;
900 
901     if (first.type == ShapeType.line || first.type == ShapeType.rectangle)
902         first.end = first.end + firstPos;
903 
904     if (second.type == ShapeType.line || second.type == ShapeType.rectangle)
905         second.end = second.end + secondPos;
906 
907     switch (first.type)
908     {
909         case ShapeType.point:
910             switch(second.type) {
911                 case ShapeType.point:
912                     return first.begin == second.begin ? first.begin : vecfNaN;
913 
914                 case ShapeType.line:
915                     return placePointLineImpl(first.begin, second.to!(Vecf[]));
916 
917                 case ShapeType.rectangle:
918                     return placePointRectImpl(first.begin, second.to!(Vecf[]));
919 
920                 case ShapeType.circle:
921                     return placePointCircleImpl(first.begin, second.begin, second.radius);
922 
923                 case ShapeType.polygon:
924                     return placePolygonAndPoint(second.data, first.begin);
925 
926                 case ShapeType.multi:
927                     Vecf place = vecfNaN;
928 
929                     foreach(shape; second.shapes) {
930                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
931                             return place;
932                     }
933 
934                     return vecfNaN;
935 
936                 default:
937                     return vecfNaN;
938             }
939 
940         case ShapeType.line:
941             switch(second.type)
942             {
943                 case ShapeType.point:
944                     return placePointLineImpl(second.begin, first.to!(Vecf[]));
945 
946                 case ShapeType.line:
947                     return placeLineLineImpl(first.to!(Vecf[]), second.to!(Vecf[]));
948 
949                 case ShapeType.rectangle:
950                     return placeLineRectImpl(second.to!(Vecf[]), first.to!(Vecf[]));
951 
952                 case ShapeType.circle:
953                     return placeLineCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
954 
955                 case ShapeType.polygon:
956                     return placePolygonAndLine(second.data, first.to!(Vecf[]));
957 
958                 case ShapeType.multi:
959                     Vecf place = vecfNaN;
960 
961                     foreach(shape; second.shapes) {
962                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
963                             return place;
964                     }
965 
966                     return vecfNaN;
967 
968                 default:
969                     return vecfNaN;
970             }
971 
972         case ShapeType.rectangle:
973             switch(second.type)
974             {
975                 case ShapeType.point:
976                     return placePointRectImpl(second.begin, first.to!(Vecf[]));
977 
978                 case ShapeType.line:
979                     return placeLineRectImpl(second.to!(Vecf[]), first.to!(Vecf[]));
980 
981                 case ShapeType.rectangle:
982                     return placeRectRectImpl(first.to!(Vecf[]), second.to!(Vecf[]));
983 
984                 case ShapeType.circle:
985                     return placeRectCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
986 
987                 case ShapeType.polygon:
988                     return placePolygonAndRect(second.data, first.to!(Vecf[]));
989 
990                 case ShapeType.multi:
991                     Vecf place = vecfNaN;
992 
993                     foreach(shape; second.shapes) {
994                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
995                             return place;
996                     }
997 
998                     return vecfNaN;
999 
1000                 default:
1001                     return vecfNaN;
1002             }
1003 
1004         case ShapeType.circle:
1005             switch(second.type)
1006             {
1007                 case ShapeType.point:
1008                     return placePointCircleImpl(second.begin, first.begin, first.radius);
1009 
1010                 case ShapeType.line:
1011                     return placeLineCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
1012 
1013                 case ShapeType.rectangle:
1014                     return placeRectCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
1015 
1016                 case ShapeType.circle:
1017                     return placeCircleCircleImpl(first.begin, first.radius, second.begin, second.radius);
1018 
1019                 case ShapeType.polygon:
1020                     return placePolygonAndCircle(second.data, first.begin, first.radius);
1021 
1022                 case ShapeType.multi:
1023                     Vecf place = vecfNaN;
1024 
1025                     foreach(shape; second.shapes) {
1026                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
1027                             return place;
1028                     }
1029 
1030                     return vecfNaN;
1031 
1032                 default:
1033                     return vecfNaN;
1034             }
1035 
1036         case ShapeType.polygon:
1037             switch(second.type)
1038             {
1039                 case ShapeType.point:
1040                     return placePolygonAndPoint(first.data, second.begin);
1041 
1042                 case ShapeType.line:
1043                     return placePolygonAndLine(first.data, second.to!(Vecf[]));
1044 
1045                 case ShapeType.rectangle:
1046                     return placePolygonAndRect(first.data, second.to!(Vecf[]));
1047 
1048                 case ShapeType.circle:
1049                     return placePolygonAndCircle(first.data, second.begin, second.radius);
1050 
1051                 case ShapeType.polygon:
1052                     return placePolygonsCollision(first.data, second.data);
1053 
1054                 case ShapeType.multi:
1055                     Vecf place = vecfNaN;
1056 
1057                     foreach(shape; second.shapes) {
1058                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
1059                             return place;
1060                     }
1061 
1062                     return vecfNaN;
1063 
1064                 default:
1065                     return vecfNaN;
1066             }
1067 
1068         case ShapeType.multi:
1069             Vecf place = vecfNaN;
1070 
1071             foreach(shape; first.shapes) {
1072                 if(!((place = placeofTangents(shape, second, first.begin, 
1073                                                 vecf(0, 0))).isVecfNaN))
1074                     return place;
1075             }
1076 
1077             return vecfNaN;
1078 
1079         default:
1080             return vecfNaN;
1081     }
1082 }
1083 
1084 /++
1085 The point of contact between the polygon and the point.
1086 
1087 Params:
1088     first = Polygon vertexs.
1089     second = Point position.
1090 
1091 Returns:
1092     Point of contact between shapes.
1093 +/
1094 Vecf placePolygonAndPoint(Vecf[] first, Vecf second) @safe nothrow pure
1095 {
1096     int next = 0;
1097     for(int current = 0; current < first.length; current++)
1098     {
1099         next = current + 1;
1100 
1101         if (next == first.length) next = 0;
1102 
1103         Vecf vc = first[current];
1104         Vecf vn = first[next];
1105 
1106         if(((vc.y >= second.y && vn.y <= second.y) || (vc.y <= second.y && vn.y >= second.y)) &&
1107             (second.x < (vn.x - vc.x) * (second.y - vc.y) / (vn.y - vc.y) + vc.x)) {
1108             return second;
1109         }
1110     }
1111 
1112     return vecfNaN;
1113 }
1114 
1115 /++
1116 The point of contact between the polygon and the line.
1117 
1118 Params:
1119     first = Polygon vertexs.
1120     second = line position.
1121 
1122 Returns:
1123     Point of contact between shapes.
1124 +/
1125 Vecf placePolygonAndLine(Vecf[] first, Vecf[] second) @safe nothrow pure
1126 {
1127     int next = 0;
1128     for(int current = 0; current < first.length; current++)
1129     {
1130         next = current + 1;
1131 
1132         if (next == first.length) next = 0;
1133 
1134         Vecf vc = first[current];
1135         Vecf vn = first[next];
1136 
1137         Vecf place = placeLineLineImpl(second, [vc, vn]);
1138         if(!place.isVecfNaN) return place;
1139     }
1140 
1141     return vecfNaN;
1142 }
1143 
1144 /++
1145 The point of contact between the polygon and the rectangle.
1146 
1147 Params:
1148     first = Polygon vertexs.
1149     second = Rectangle vertexs.
1150 
1151 Returns:
1152     Point of contact between shapes.
1153 +/
1154 Vecf placePolygonAndRect(Vecf[] first, Vecf[] second) @safe nothrow pure
1155 {
1156     int next = 0;
1157     for(int current = 0; current < first.length; current++)
1158     {
1159         next = current + 1;
1160 
1161         if (next == first.length) next = 0;
1162 
1163         Vecf vc = first[current];
1164         Vecf vn = first[next];
1165 
1166         Vecf place = placeLineRectImpl([vc, vn], second);
1167         if(!place.isVecfNaN) return place;
1168     }
1169 
1170     return vecfNaN;
1171 }
1172 
1173 /++
1174 The point of contact between the polygon and the circle.
1175 
1176 Params:
1177     first = Polygon vertexs.
1178     second = Circle position.
1179     r = Circle radius.
1180 
1181 Returns:
1182     Point of contact between shapes.
1183 +/
1184 Vecf placePolygonAndCircle(Vecf[] first, Vecf second, float r) @safe nothrow pure
1185 {
1186     int next = 0;
1187     for(int current = 0; current < first.length; current++)
1188     {
1189         next = current + 1;
1190 
1191         if (next == first.length) next = 0;
1192 
1193         Vecf vc = first[current];
1194         Vecf vn = first[next];
1195 
1196         Vecf place = placeLineCircleImpl([vc, vn], second, r);
1197         if(!place.isVecfNaN) return place;
1198     }
1199 
1200     return vecfNaN;
1201 }
1202 
1203 /++
1204 The point of contact between the polygon and the polygon.
1205 
1206 Params:
1207     first = First polygon vertexs.
1208     second = Second polygon vertexs.
1209 
1210 Returns:
1211     Point of contact between shapes.
1212 +/
1213 Vecf placePolygonsCollision(Vecf[] first, Vecf[] second) @safe nothrow pure
1214 {
1215     int next = 0;
1216     for (int current = 0; current < first.length; current++)
1217     {
1218         next = current + 1;
1219 
1220         if (next == first.length) next = 0;
1221 
1222         Vecf vc = first[current];
1223         Vecf vn = first[next];
1224 
1225         Vecf place = placePolygonAndLine(second, [vc, vn]);
1226         if(!place.isVecfNaN) return place;
1227 
1228         place = placePolygonAndPoint(first, second[0]);
1229         if (!place.isVecfNaN) return place;
1230     }
1231 
1232     return vecfNaN;
1233 }