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 in(first.type != ShapeType.unknown  && second.type != ShapeType.unknown)
243 in(first.type != ShapeType.triangle && second.type != ShapeType.triangle)
244 do
245 {
246     import std.conv : to;
247     import std.math : abs, sqrt;
248 
249     first.begin = first.begin + firstPos;
250     second.begin = second.begin + secondPos;
251 
252     if (first.type == ShapeType.line || first.type == ShapeType.rectangle)
253         first.end = first.end + firstPos;
254 
255     if (second.type == ShapeType.line || second.type == ShapeType.rectangle)
256         second.end = second.end + secondPos;
257 
258     switch(first.type)
259     {
260         case ShapeType.point:
261 
262             switch(second.type)
263             {
264                 case ShapeType.point:
265                     return first.begin == second.begin;
266 
267                 case ShapeType.line: 
268                     return pointLineImpl(first.begin, second.to!(Vecf[]));
269 
270                 case ShapeType.rectangle:
271                     return pointRectImpl(first.begin, second.to!(Vecf[]));
272 
273                 case ShapeType.circle:
274                     return pointCircleImpl(first.begin, second.begin, second.radius);
275 
276                 case ShapeType.polygon:
277                     return isPolygonAndPoint(second.data, first.begin);
278 
279                 case ShapeType.multi:
280                     foreach(shape; second.shapes) {
281                         if (isCollide(first, shape,vecf(0,0), second.begin))
282                             return true;
283                     }
284 
285                     return false;
286 
287                 default:
288                     return false;
289             }
290 
291         case ShapeType.line:
292 
293             switch(second.type)
294             {
295                 case ShapeType.point:
296                     return pointLineImpl(second.begin, first.to!(Vecf[]));
297 
298                 case ShapeType.line:
299                     return lineLineImpl(first.to!(Vecf[]), second.to!(Vecf[]));
300 
301                 case ShapeType.rectangle:
302                     return lineRectImpl(first.to!(Vecf[]), second.to!(Vecf[]));
303 
304                 case ShapeType.circle:
305                     return lineCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
306 
307                 case ShapeType.polygon:
308                     return isPolygonAndLine(second.data, first.to!(Vecf[]));
309 
310                 case ShapeType.multi:
311                     foreach(shape; second.shapes) {
312                         if (isCollide(first,shape,vecf(0,0),second.begin))
313                             return true;
314                     }
315 
316                     return false;
317 
318                 default:
319                     return false;
320             }
321 
322         case ShapeType.rectangle:
323             
324             switch(second.type)
325             {
326                 case ShapeType.point:
327                     return pointRectImpl(second.begin, first.to!(Vecf[]));
328 
329                 case ShapeType.line:
330                     return lineRectImpl(second.to!(Vecf[]), first.to!(Vecf[]));
331 
332                 case ShapeType.rectangle:
333                     const a = first.begin;
334                     const b = first.end;
335                     const c = second.begin;
336                     const d = second.end;
337 
338                     return
339                     (
340                         a.x + (b.x-a.x) >= c.x && 
341                         a.x <= c.x + (d.x-c.x) && 
342                         a.y + (b.y - a.y) >= c.y && 
343                         a.y <= c.y + (d.y - c.y)
344                     );
345 
346                 case ShapeType.circle:
347                     return rectCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
348 
349                 case ShapeType.polygon:
350                     return isPolygonAndRect(second.data, first.to!(Vecf[]));
351 
352                 case ShapeType.multi:
353                     foreach(shape; second.shapes) {
354                         if (isCollide(first, shape,vecf(0,0),second.begin))
355                             return true;
356                     }
357 
358                     return false;
359 
360                 default:
361                     return false;
362             }
363 
364         case ShapeType.circle:
365             switch(second.type)
366             {
367                 case ShapeType.point:
368                     return pointCircleImpl(second.begin, first.begin, first.radius);
369 
370                 case ShapeType.line:
371                     return lineCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
372 
373                 case ShapeType.rectangle:
374                     return rectCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
375 
376                 case ShapeType.circle:
377                     immutable dist = first.begin - second.begin;
378 
379                     return dist.length <= first.radius + second.radius;
380 
381                 case ShapeType.polygon:
382                     return isPolygonAndCircle(second.data, first.begin, first.radius);
383 
384                 case ShapeType.multi:
385                     foreach(shape; second.shapes) {
386                         if (isCollide(first,shape,vecf(0,0),second.begin))
387                             return true;
388                     }
389 
390                     return false;
391 
392                 default:
393                     return false;
394             }
395 
396         case ShapeType.polygon:
397             switch(second.type)
398             {
399                 case ShapeType.point:
400                     return isPolygonAndPoint(first.data, second.begin);
401 
402                 case ShapeType.line:
403                     return isPolygonAndLine(first.data, second.to!(Vecf[]));
404 
405                 case ShapeType.rectangle:
406                     return isPolygonAndRect(first.data, second.to!(Vecf[]));
407 
408                 case ShapeType.circle:
409                     return isPolygonAndCircle(first.data, second.begin, second.radius);
410 
411                 case ShapeType.polygon:
412                     return isPolygonsCollision(first.data, second.data);
413 
414                 case ShapeType.multi:
415                     foreach(shape; second.shapes) {
416                         if (isCollide(shape, first, second.begin, vecf(0,0)))
417                             return true;
418                     }
419 
420                     return false;
421 
422                 default:
423                     return false;
424             }
425 
426         case ShapeType.multi:
427             foreach(shape; first.shapes) {
428                 if (isCollide(shape, second,first.begin,vecf(0,0)))
429                     return true;
430             }
431 
432             return false;
433 
434         default:
435             return false;
436     }
437 }
438 
439 unittest
440 {
441     assert(
442         isCollide(
443             Shapef.Rectangle(vecf(32,32),vecf(64,64)),
444             Shapef.Line(vecf(48,48),vecf(96,96))
445         )   
446     );
447 
448     assert(
449         isCollide(
450             Shapef.Rectangle(vecf(32,32),vecf(64,64)),
451             Shapef.Rectangle(vecf(48,48),vecf(72,72))
452         )
453     );
454 
455     assert(
456         isCollide(
457             Shapef.Line(vecf(32,32),vecf(64,64)),
458             Shapef.Line(vecf(64,32),vecf(32,64))
459         )
460     );
461 }
462 
463 /++
464 Checks collision between polygon and point.
465 
466 Params:
467     first = Polygon vertices.
468     second = Point position.
469 +/
470 bool isPolygonAndPoint(Vecf[] first, Vecf second) @safe nothrow pure
471 {
472     bool collision = false;
473 
474     int next = 0;
475     for(int current = 0; current < first.length; current++)
476     {
477         next = current + 1;
478 
479         if (next == first.length) next = 0;
480 
481         Vecf vc = first[current];
482         Vecf vn = first[next];
483 
484         if(((vc.y >= second.y && vn.y <= second.y) || (vc.y <= second.y && vn.y >= second.y)) &&
485             (second.x < (vn.x - vc.x) * (second.y - vc.y) / (vn.y - vc.y) + vc.x)) {
486             collision = !collision;
487         }
488     }
489 
490     return collision;
491 }
492 
493 /++
494 Checks collision between polygon and line.
495 
496 Params:
497     first = Polygon vertices.
498     second = Line vertices.
499 +/
500 bool isPolygonAndLine(Vecf[] first, Vecf[] second) @safe nothrow pure
501 {
502     int next = 0;
503     for(int current = 0; current < first.length; current++)
504     {
505         next = current + 1;
506 
507         if (next == first.length) next = 0;
508 
509         Vecf vc = first[current];
510         Vecf vn = first[next];
511 
512         bool hit = lineLineImpl(second, [vc, vn]);
513 
514         if (hit) return true;
515     }
516 
517     return false;
518 }
519 
520 /++
521 Check collision between polygon and rectangle.
522 
523 Params:
524     first = Polygon vertices.
525     second = Rectangle vertices.
526 +/
527 bool isPolygonAndRect(Vecf[] first, Vecf[] second) @safe nothrow pure
528 {
529     int next = 0;
530     for(int current = 0; current < first.length; current++)
531     {
532         next = current + 1;
533 
534         if (next == first.length) next = 0;
535 
536         Vecf vc = first[current];
537         Vecf vn = first[next];
538 
539         bool hit = lineRectImpl([vc, vn], second);
540 
541         if (hit) return true;
542     }
543 
544     return false;
545 }
546 
547 /++
548 Check collision between polygon and circle.
549 
550 Params:
551     first = Polygon vertices.
552     second = The position of the center of the circle.
553     r = Circle radius.
554 +/
555 bool isPolygonAndCircle(Vecf[] first, Vecf second, float r) @safe nothrow pure
556 {
557     int next = 0;
558     for(int current = 0; current < first.length; current++)
559     {
560         next = current + 1;
561 
562         if (next == first.length) next = 0;
563 
564         Vecf vc = first[current];
565         Vecf vn = first[next];
566 
567         bool hit = lineCircleImpl([vc, vn], second, r);
568 
569         if (hit) return true;
570     }
571 
572     return false;
573 }
574 
575 /++
576 Checking the collision of two polygons.
577 
578 Params:
579     first = First polygon vertices.
580     second = Second polygon vertices.
581 +/
582 bool isPolygonsCollision(Vecf[] first, Vecf[] second) @safe nothrow pure
583 {
584     int next = 0;
585     for(int current = 0; current < first.length; current++)
586     {
587         next = current + 1;
588 
589         if (next == first.length) next = 0;
590 
591         Vecf vc = first[current];
592         Vecf vn = first[next];
593 
594         bool hit = isPolygonAndLine(second, [vc, vn]);
595         if (hit) return true;
596 
597         hit = isPolygonAndPoint(first, second[0]);
598         if (hit) return true;
599     }
600 
601     return false;
602 }
603 
604 unittest
605 {
606     Vecf[]  first = [
607                         vecf(32, 32),
608                         vecf(64, 48),
609                         vecf(64, 128),
610                         vecf(32, 112)
611                     ];
612 
613     assert(isPolygonAndPoint(first, vecf(33, 33)));
614     assert(isPolygonAndLine(first, [vecf(16, 16), vecf(48, 48)]));
615     assert(isPolygonAndRect(first, [vecf(16, 16), vecf(128, 128)]));
616     assert(isPolygonAndCircle(first, vecf(128, 128), 64));
617     assert(isPolygonsCollision(first,   [
618                                             vecf(48, 48),
619                                             vecf(64, 64),
620                                             vecf(32, 64),
621                                             vecf(32, 32),
622                                             vecf(32, 48)
623                                         ]));
624 }
625 
626 /++
627 Gives the place of collision of a line and a point.
628 
629 Params:
630     point = Point vector.
631     line = Line vectors.
632 
633 Returns:
634     Place of collision.
635 +/
636 const(Vecf) placePointLineImpl(const Vecf point, const Vecf[] line) @safe nothrow pure
637 {
638     import tida.each;
639 
640     if (point == line[0] ||
641        point == line[1])
642       return point;
643 
644     Vecf result = vecfNaN;
645 
646     foreach(x,y; LineNoThrowImpl(line[0], line[1])) {
647         if (cast(int) point.x == x &&
648            cast(int) point.y == y) {
649             result = vecf(x, y);
650             break;
651         }
652     }
653 
654     return result;
655 }
656 
657 /++
658 Gives the place of collision of a point and a rectangle.
659 
660 Params:
661     point = Point vector.
662     rectangle = rectangle vectors.
663 
664 Returns:
665     Place of collision.
666 +/
667 const(Vecf) placePointRectImpl(const Vecf point, const Vecf[] rectangle) @safe nothrow pure
668 {
669     Vecf place = rectangle[0] - point;
670 
671     if( place.x < 0 || place.y < 0 ||
672         place.x > (rectangle[1] - rectangle[0]).x ||
673         place.y > (rectangle[1] - rectangle[0]).y) {
674         return vecfNaN;
675     } else {
676         return rectangle[0] + place;
677     }
678 }
679 
680 /++
681 Gives the place of collision of a point and a circle.
682 
683 Params:
684     point = Point vector.
685     circlePos = Cirlce position.
686     circleRadius = Circle radius.
687 
688 Returns:
689     Place of collision.
690 +/
691 const(Vecf) placePointCircleImpl(const Vecf point, const Vecf circlePos, const float circleRadius) @safe nothrow pure
692 {
693     return point.distance(circlePos) > circleRadius ? vecfNaN : point;
694 }
695 
696 /++
697 Gives the place of collision of a line and a line.
698 
699 Params:
700     first = Line vector.
701     second = Line vectors.
702 
703 Returns:
704     Place of collision.
705 +/
706 const(Vecf) placeLineLineImpl(const Vecf[] first, const Vecf[] second) @safe nothrow pure
707 {
708     const a = first[0];
709     const b = first[1];
710     const c = second[0];
711     const d = second[1];
712 
713     const denominator = ((b.x - a.x) * (d.y - c.y)) - ((b.y - a.y) * (d.x - c.x));
714 
715     const numerator1  = ((a.y - c.y) * (d.x - c.x)) - ((a.x - c.x) * (d.y - c.y));
716     const numerator2  = ((a.y - c.y) * (b.x - a.x)) - ((a.x - c.x) * (b.y - a.y));
717 
718     const r = numerator1 / denominator;
719     const s = numerator2 / denominator;
720 
721     if((r >= 0 && r <= 1) && (s >= 0 && s <= 1))
722         return first[0] - ((first[1] - first[0]) * r);
723     else
724         return vecfNaN;
725 }
726 
727 /++
728 Gives the place of collision of a line and a rectangle.
729 
730 Params:
731     a = Line vector.
732     b = Rectangle vectors.
733 
734 Returns:
735     Place of collision.
736 +/
737 const(Vecf) placeLineRectImpl(const Vecf[] a, const Vecf[] b) @safe nothrow pure
738 {
739     import tida.each;
740 
741     if (b[0] == a[0] ||
742       b[0] == a[1] ||
743       b[1] == a[0] ||
744       b[1] == a[1])
745       return a[0];
746 
747     Vecf result = vecfNaN;
748 
749     foreach(x,y; LineNoThrowImpl(a[0], a[1])) {
750         if (x > b[0].x &&
751            x < b[1].x   &&
752            y > b[0].y &&
753            y < b[1].y)
754         {
755            return vecf(x, y);
756         }
757     }
758 
759     return result;
760 }
761 
762 /++
763 Gives the place of collision of a line and a circle.
764 
765 Params:
766     line = line vector.
767     circlePos = Circle position.
768     circleRadius = Circle radius.
769 
770 Returns:
771     Place of collision.
772 +/
773 const(Vecf) placeLineCircleImpl(const Vecf[] line, const Vecf circlePos, const float circleRadius) @safe nothrow pure
774 {
775     import tida.each;
776 
777     Vecf place = vecfNaN;
778 
779     foreach(x, y; LineNoThrowImpl(line[0], line[1])) {
780         if(!(place = placePointCircleImpl(vecf(x, y), circlePos, circleRadius)).isVecfNaN)
781             return place;
782     }
783 
784     return vecfNaN;
785 }
786 
787 /++
788 Gives the place of collision of a rectangle and a rectangle.
789 
790 Params:
791     a = Rectangle vector.
792     b = Rectangle vectors.
793     isRecurse = Used only for recursion.
794 
795 Returns:
796     Place of collision.
797 +/
798 const(Vecf) placeRectRectImpl(const Vecf[] a, const Vecf[] b,bool isRecurse = false) @safe nothrow pure
799 {
800     if (lineRectImpl([a[0], a[0] + vecf(a[1].x, 0)], b))
801         return placeLineRectImpl([a[0], a[0] + vecf(a[1].x, 0)], b);
802     if (lineRectImpl([a[0] + vecf(a[1].x, 0), a[1]], b))
803         return placeLineRectImpl([a[0] + vecf(a[1].x, 0), a[1]], b);
804     if (lineRectImpl([a[0], a[0] + vecf(0, a[1].y)], b))
805         return placeLineRectImpl([a[0], a[0] + vecf(0, a[1].y)], b);
806     if (lineRectImpl([a[0] + vecf(0, a[1].y), a[1]], b))
807         return placeLineRectImpl([a[0] + vecf(0, a[1].y), a[1]], b);
808 
809     if(!isRecurse)
810         return placeRectRectImpl(b, a, true);
811     else
812         return vecfNaN;
813 }
814 
815 /++
816 Gives the place of collision of a rectangle and a circle.
817 
818 Params:
819     a = Rectangle vectors.
820     circlePos = Circle position.
821     circleRadius = Circle radius.
822 
823 Returns:
824     Place of collision.
825 +/
826 const(Vecf) placeRectCircleImpl(const Vecf[] a, const Vecf circlePos, const float circleRadius) @safe nothrow pure
827 {
828     if (lineCircleImpl([a[0], a[0] + vecf(a[1].x, 0)], circlePos, circleRadius))
829         return placeLineCircleImpl([a[0], a[0] + vecf(a[1].x, 0)], circlePos, circleRadius);
830     if (lineCircleImpl([a[0] + vecf(a[1].x, 0), a[1]], circlePos, circleRadius))
831         return placeLineCircleImpl([a[0] + vecf(a[1].x, 0), a[1]], circlePos, circleRadius);
832     if (lineCircleImpl([a[0], a[0] + vecf(0, a[1].y)], circlePos, circleRadius))
833         return placeLineCircleImpl([a[0], a[0] + vecf(0, a[1].y)], circlePos, circleRadius);
834     if (lineCircleImpl([a[0] + vecf(0, a[1].y), a[1]], circlePos, circleRadius))
835         return placeLineCircleImpl([a[0] + vecf(0, a[1].y), a[1]], circlePos, circleRadius);
836 
837     Vecf place = vecfNaN;
838     Vecf[] line =   [
839                         circlePos - vecf(0, circleRadius),
840                         circlePos + vecf(0, circleRadius)
841                     ];
842 
843     if(!(place = placeLineRectImpl(line, a)).isVecfNaN) return place;
844     line =  [
845                 circlePos - vecf(circleRadius, 0),
846                 circlePos + vecf(circleRadius, 0)
847             ];
848 
849     return placeLineRectImpl(line, a);
850 }
851 
852 /++
853 Gives the place of collision of a circle and a circle.
854 
855 Params:
856     fPos = First circle position.
857     fRadius = First circle radius.
858     fPos = Second circle position.
859     fRadius = Second circle radius.
860 
861 Returns:
862     Place of collision.
863 +/
864 const(Vecf) placeCircleCircleImpl(	const Vecf fPos, 
865                                     const float fRadius, 
866                                     const Vecf sPos,
867                                     const float sRadius)
868 @safe nothrow pure
869 {
870     //immutable dist = first.begin - second.begin;
871     //return dist.length <= first.radius + second.radius;
872 
873     if((fPos - sPos).length <= fRadius + sRadius) {
874         return Vecf((fPos.x * sRadius + sPos.x * fRadius) / (fRadius + sRadius),
875                     (fPos.y * sRadius + sPos.y * fRadius) / (fRadius + sRadius));
876     } else {
877         return vecfNaN;
878     }
879 }
880 
881 /++
882 Finds the point of contact between two forms.
883 
884 Params:
885     first = First shape.
886     second = Second shape.
887     firstPos = First shape position.
888     secondPos = Second shape position.
889 
890 Returns:
891     point of contact between two forms.
892 +/
893 const(Vecf) placeofTangents(Shape!float first, 
894                             Shape!float second, 
895                             Vecf firstPos = vecf(0, 0), 
896                             Vecf secondPos = vecf(0, 0))
897 @safe nothrow pure
898 in(first.type != ShapeType.unknown  && second.type != ShapeType.unknown)
899 in(first.type != ShapeType.triangle && second.type != ShapeType.triangle)
900 do
901 {
902     first.begin = first.begin + firstPos;
903     second.begin = second.begin + secondPos;
904 
905     if (first.type == ShapeType.line || first.type == ShapeType.rectangle)
906         first.end = first.end + firstPos;
907 
908     if (second.type == ShapeType.line || second.type == ShapeType.rectangle)
909         second.end = second.end + secondPos;
910 
911     switch (first.type)
912     {
913         case ShapeType.point:
914             switch(second.type) {
915                 case ShapeType.point:
916                     return first.begin == second.begin ? first.begin : vecfNaN;
917 
918                 case ShapeType.line:
919                     return placePointLineImpl(first.begin, second.to!(Vecf[]));
920 
921                 case ShapeType.rectangle:
922                     return placePointRectImpl(first.begin, second.to!(Vecf[]));
923 
924                 case ShapeType.circle:
925                     return placePointCircleImpl(first.begin, second.begin, second.radius);
926 
927                 case ShapeType.polygon:
928                     return placePolygonAndPoint(second.data, first.begin);
929 
930                 case ShapeType.multi:
931                     Vecf place = vecfNaN;
932 
933                     foreach(shape; second.shapes) {
934                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
935                             return place;
936                     }
937 
938                     return vecfNaN;
939 
940                 default:
941                     return vecfNaN;
942             }
943 
944         case ShapeType.line:
945             switch(second.type)
946             {
947                 case ShapeType.point:
948                     return placePointLineImpl(second.begin, first.to!(Vecf[]));
949 
950                 case ShapeType.line:
951                     return placeLineLineImpl(first.to!(Vecf[]), second.to!(Vecf[]));
952 
953                 case ShapeType.rectangle:
954                     return placeLineRectImpl(second.to!(Vecf[]), first.to!(Vecf[]));
955 
956                 case ShapeType.circle:
957                     return placeLineCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
958 
959                 case ShapeType.polygon:
960                     return placePolygonAndLine(second.data, first.to!(Vecf[]));
961 
962                 case ShapeType.multi:
963                     Vecf place = vecfNaN;
964 
965                     foreach(shape; second.shapes) {
966                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
967                             return place;
968                     }
969 
970                     return vecfNaN;
971 
972                 default:
973                     return vecfNaN;
974             }
975 
976         case ShapeType.rectangle:
977             switch(second.type)
978             {
979                 case ShapeType.point:
980                     return placePointRectImpl(second.begin, first.to!(Vecf[]));
981 
982                 case ShapeType.line:
983                     return placeLineRectImpl(second.to!(Vecf[]), first.to!(Vecf[]));
984 
985                 case ShapeType.rectangle:
986                     return placeRectRectImpl(first.to!(Vecf[]), second.to!(Vecf[]));
987 
988                 case ShapeType.circle:
989                     return placeRectCircleImpl(first.to!(Vecf[]), second.begin, second.radius);
990 
991                 case ShapeType.polygon:
992                     return placePolygonAndRect(second.data, first.to!(Vecf[]));
993 
994                 case ShapeType.multi:
995                     Vecf place = vecfNaN;
996 
997                     foreach(shape; second.shapes) {
998                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
999                             return place;
1000                     }
1001 
1002                     return vecfNaN;
1003 
1004                 default:
1005                     return vecfNaN;
1006             }
1007 
1008         case ShapeType.circle:
1009             switch(second.type)
1010             {
1011                 case ShapeType.point:
1012                     return placePointCircleImpl(second.begin, first.begin, first.radius);
1013 
1014                 case ShapeType.line:
1015                     return placeLineCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
1016 
1017                 case ShapeType.rectangle:
1018                     return placeRectCircleImpl(second.to!(Vecf[]), first.begin, first.radius);
1019 
1020                 case ShapeType.circle:
1021                     return placeCircleCircleImpl(first.begin, first.radius, second.begin, second.radius);
1022 
1023                 case ShapeType.polygon:
1024                     return placePolygonAndCircle(second.data, first.begin, first.radius);
1025 
1026                 case ShapeType.multi:
1027                     Vecf place = vecfNaN;
1028 
1029                     foreach(shape; second.shapes) {
1030                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
1031                             return place;
1032                     }
1033 
1034                     return vecfNaN;
1035 
1036                 default:
1037                     return vecfNaN;
1038             }
1039 
1040         case ShapeType.polygon:
1041             switch(second.type)
1042             {
1043                 case ShapeType.point:
1044                     return placePolygonAndPoint(first.data, second.begin);
1045 
1046                 case ShapeType.line:
1047                     return placePolygonAndLine(first.data, second.to!(Vecf[]));
1048 
1049                 case ShapeType.rectangle:
1050                     return placePolygonAndRect(first.data, second.to!(Vecf[]));
1051 
1052                 case ShapeType.circle:
1053                     return placePolygonAndCircle(first.data, second.begin, second.radius);
1054 
1055                 case ShapeType.polygon:
1056                     return placePolygonsCollision(first.data, second.data);
1057 
1058                 case ShapeType.multi:
1059                     Vecf place = vecfNaN;
1060 
1061                     foreach(shape; second.shapes) {
1062                         if(!((place = placeofTangents(first, shape,vecf(0,0), second.begin)).isVecfNaN))
1063                             return place;
1064                     }
1065 
1066                     return vecfNaN;
1067 
1068                 default:
1069                     return vecfNaN;
1070             }
1071 
1072         case ShapeType.multi:
1073             Vecf place = vecfNaN;
1074 
1075             foreach(shape; first.shapes) {
1076                 if(!((place = placeofTangents(shape, second, first.begin, 
1077                                                 vecf(0, 0))).isVecfNaN))
1078                     return place;
1079             }
1080 
1081             return vecfNaN;
1082 
1083         default:
1084             return vecfNaN;
1085     }
1086 }
1087 
1088 /++
1089 The point of contact between the polygon and the point.
1090 
1091 Params:
1092     first = Polygon vertexs.
1093     second = Point position.
1094 
1095 Returns:
1096     Point of contact between shapes.
1097 +/
1098 Vecf placePolygonAndPoint(Vecf[] first, Vecf second) @safe nothrow pure
1099 {
1100     int next = 0;
1101     for(int current = 0; current < first.length; current++)
1102     {
1103         next = current + 1;
1104 
1105         if (next == first.length) next = 0;
1106 
1107         Vecf vc = first[current];
1108         Vecf vn = first[next];
1109 
1110         if(((vc.y >= second.y && vn.y <= second.y) || (vc.y <= second.y && vn.y >= second.y)) &&
1111             (second.x < (vn.x - vc.x) * (second.y - vc.y) / (vn.y - vc.y) + vc.x)) {
1112             return second;
1113         }
1114     }
1115 
1116     return vecfNaN;
1117 }
1118 
1119 /++
1120 The point of contact between the polygon and the line.
1121 
1122 Params:
1123     first = Polygon vertexs.
1124     second = line position.
1125 
1126 Returns:
1127     Point of contact between shapes.
1128 +/
1129 Vecf placePolygonAndLine(Vecf[] first, Vecf[] second) @safe nothrow pure
1130 {
1131     int next = 0;
1132     for(int current = 0; current < first.length; current++)
1133     {
1134         next = current + 1;
1135 
1136         if (next == first.length) next = 0;
1137 
1138         Vecf vc = first[current];
1139         Vecf vn = first[next];
1140 
1141         Vecf place = placeLineLineImpl(second, [vc, vn]);
1142         if(!place.isVecfNaN) return place;
1143     }
1144 
1145     return vecfNaN;
1146 }
1147 
1148 /++
1149 The point of contact between the polygon and the rectangle.
1150 
1151 Params:
1152     first = Polygon vertexs.
1153     second = Rectangle vertexs.
1154 
1155 Returns:
1156     Point of contact between shapes.
1157 +/
1158 Vecf placePolygonAndRect(Vecf[] first, Vecf[] second) @safe nothrow pure
1159 {
1160     int next = 0;
1161     for(int current = 0; current < first.length; current++)
1162     {
1163         next = current + 1;
1164 
1165         if (next == first.length) next = 0;
1166 
1167         Vecf vc = first[current];
1168         Vecf vn = first[next];
1169 
1170         Vecf place = placeLineRectImpl([vc, vn], second);
1171         if(!place.isVecfNaN) return place;
1172     }
1173 
1174     return vecfNaN;
1175 }
1176 
1177 /++
1178 The point of contact between the polygon and the circle.
1179 
1180 Params:
1181     first = Polygon vertexs.
1182     second = Circle position.
1183     r = Circle radius.
1184 
1185 Returns:
1186     Point of contact between shapes.
1187 +/
1188 Vecf placePolygonAndCircle(Vecf[] first, Vecf second, float r) @safe nothrow pure
1189 {
1190     int next = 0;
1191     for(int current = 0; current < first.length; current++)
1192     {
1193         next = current + 1;
1194 
1195         if (next == first.length) next = 0;
1196 
1197         Vecf vc = first[current];
1198         Vecf vn = first[next];
1199 
1200         Vecf place = placeLineCircleImpl([vc, vn], second, r);
1201         if(!place.isVecfNaN) return place;
1202     }
1203 
1204     return vecfNaN;
1205 }
1206 
1207 /++
1208 The point of contact between the polygon and the polygon.
1209 
1210 Params:
1211     first = First polygon vertexs.
1212     second = Second polygon vertexs.
1213 
1214 Returns:
1215     Point of contact between shapes.
1216 +/
1217 Vecf placePolygonsCollision(Vecf[] first, Vecf[] second) @safe nothrow pure
1218 {
1219     int next = 0;
1220     for (int current = 0; current < first.length; current++)
1221     {
1222         next = current + 1;
1223 
1224         if (next == first.length) next = 0;
1225 
1226         Vecf vc = first[current];
1227         Vecf vn = first[next];
1228 
1229         Vecf place = placePolygonAndLine(second, [vc, vn]);
1230         if(!place.isVecfNaN) return place;
1231 
1232         place = placePolygonAndPoint(first, second[0]);
1233         if (!place.isVecfNaN) return place;
1234     }
1235 
1236     return vecfNaN;
1237 }