@@ -370,16 +370,14 @@ static void testRotatedPointsAgainstRect(
370370 Real *minDistSqr
371371);*/
372372static Real fast_hypot (
373- Real x1,
374- Real x2,
375- Real y1,
376- Real y2
373+ Real x,
374+ Real y
377375);
378376static void testSphereAgainstRect (
379- const Coord2D * pts, // an array of 4
377+ const Coord2D pts[] , // an array of 4
380378 const CollideInfo *a,
381379 // Real angle,
382- Real &distance
380+ Real &distSqr
383381);
384382
385383static Bool xy_collideTest_Rect_Rect (const CollideInfo *a, const CollideInfo *b, CollideLocAndNormal *cinfo);
@@ -572,17 +570,33 @@ static void testRotatedPointsAgainstRect(
572570}*/
573571
574572// -----------------------------------------------------------------------------
575- static Real fast_hypot (Real x1 , Real x2, Real y1, Real y2 )
573+ static Real fast_hypot (Real x , Real y )
576574{
577575 // Fast approximation of Boundary length, generally if one line has the length of only 10% or less of the other line, we take the longest line as the boundary.
578576 // Has an error rate of approx 0.5%.
579577 // Example: A line of dx = 5, and dy = 0.5, would give h = 5.025, we take dx directly
580- Real dx = fabs (x1 - x2);
581- Real dy = fabs (y1 - y2);
578+ /* Real dSqr = x*x + y*y;
579+ Real curGuess = 1.0f;
580+ Real tolerance = 0.1f;
581+ while(fabs( (curGuess * curGuess) / dSqr - 1.0) > tolerance)
582+ curGuess = ((dSqr/curGuess) + curGuess) * 0.5;
583+ return curGuess;*/
584+
585+ Real dx = fabs (x);
586+ Real dy = fabs (y);
582587
583588 // Longest line and shortest between x and y
584- Real a = max (dx, dy);
585- Real b = min (dx, dy);
589+ Real a, b;
590+ if (dx > dy)
591+ {
592+ a = dx;
593+ b = dy;
594+ }
595+ else
596+ {
597+ a = dy;
598+ b = dx;
599+ }
586600 // Real maxTolerance = 0.1f * dmax;
587601 // Real distTolerance = max(20.0f, 0.5f * maxTolerance);
588602
@@ -599,102 +613,73 @@ static Real fast_hypot(Real x1, Real x2, Real y1, Real y2)
599613
600614// -----------------------------------------------------------------------------
601615static void testSphereAgainstRect (
602- const Coord2D * pts, // an array of 4
616+ const Coord2D pts[] , // an array of 4
603617 const CollideInfo *a,
604618 // Real angle,
605- Real &distance
619+ Real &distSqr
606620)
607621{
608622 // Get two points that are closest to the facing direction
609623 // DEBUG_LOG(("Source Points: x: %f y: %f", a->position.x, a->position.y));
610- Real x1, x2, y1, y2;
611- x1 = x2 = y1 = y2 = 0 .0f ;
624+ Real dx1, dx2, dy1, dy2;
625+ // x1 = x2 = y1 = y2 = 0.0f;
626+ Real minDist = 1e10 ;
627+ Real secondMinDist = 0 .0f ;
628+ Int minIdx = -1 ;
629+ Int secondMinIdx = -1 ;
612630
613- Real dist[4 ];
614- Coord2D points[4 ];
615- for (Int i = 0 ; i < 4 ; ++i, ++pts)
631+ Real derivative[4 ][2 ];
632+ for (Int i = 0 ; i < 4 ; ++i)
616633 {
617- /* if(x1 != 0.0f && x2 != 0.0f)
618- break;
619- Real dir = atan2(pts->y - a->position.y, pts->x - a->position.x);
620- Real relAngle = stdAngleDiff(dir, angle);
621- DEBUG_LOG(( "Angle: %f", angle ));
622- DEBUG_LOG(( "Dir: %f", dir ));
623- DEBUG_LOG(( "Rel Angle: %f", relAngle ));
624- if(fabs(relAngle) <= PI/2)
625- {
626- switch(i)
627- {
628- // tl
629- case 0:
630- DEBUG_LOG(( "Top Left" ));
631- break;
632- // tr
633- case 1:
634- DEBUG_LOG(( "Top Right" ));
635- break;
636- // bl
637- case 2:
638- DEBUG_LOG(( "Bottom Left" ));
639- break;
640- // br
641- case 3:
642- DEBUG_LOG(( "Bottom Right" ));
643- break;
644- }
645- if(x1 == 0.0f && y1 == 0.0f)
646- {
647- x1 = pts->x;
648- y1 = pts->y;
649- DEBUG_LOG(("Point 1: x: %f y: %f", x1, y1));
650- }
651- else
652- {
653- x2 = pts->x;
654- y2 = pts->y;
655- DEBUG_LOG(("Point 2: x: %f y: %f", x2, y2));
656- }
657- }*/
658- points[i].x = pts->x ;
659- points[i].y = pts->y ;
660- dist[i] = sqr (pts->x - a->position .x ) + sqr (pts->y - a->position .y );
661- }
634+ derivative[i][0 ] = pts[i].x - a->position .x ;
635+ derivative[i][1 ] = pts[i].y - a->position .y ;
662636
663- Real minDist;
664- Int minIdx;
665- Int lastMinIdx = -1 ;
666- while ( TRUE )
667- {
668- minDist = HUGE_DIST_SQR;
669- minIdx = 4 ;
670- for (Int idx = 0 ; idx < 4 ; idx++)
637+ Real curDistSqr = sqr (derivative[i][0 ]) + sqr (derivative[i][1 ]);
638+ if (minDist > curDistSqr)
671639 {
672- if (minDist > dist[idx] && idx != lastMinIdx)
673- {
674- minDist = dist[idx];
675- minIdx = idx;
676- }
640+ minDist = curDistSqr;
641+ minIdx = i;
677642 }
678- if (x1 == 0 .0f && y1 == 0 .0f )
643+ if ( minDist >= secondMinDist ||
644+ (secondMinDist > curDistSqr && curDistSqr > minDist) )
679645 {
680- x1 = points[minIdx].x ;
681- y1 = points[minIdx].y ;
682- lastMinIdx = minIdx;
646+ secondMinDist = curDistSqr;
647+ secondMinIdx = i;
683648 }
684- else
649+ // Get the second last min idx if the last min idx is not yet registered.
650+
651+
652+ if (i == 3 )
685653 {
686- x2 = points[minIdx].x ;
687- y2 = points[minIdx].y ;
688- break ;
654+ dx1 = derivative[minIdx][0 ];
655+ dy1 = derivative[minIdx][1 ];
656+ dx2 = derivative[secondMinIdx][0 ];
657+ dy2 = derivative[secondMinIdx][1 ];
658+
659+ Bool polarity_x1 = dx1 >= 0 ;
660+ Bool polarity_x2 = dx2 >= 0 ;
661+ Bool polarity_y1 = dy1 >= 0 ;
662+ Bool polarity_y2 = dy2 >= 0 ;
663+
664+ if ( polarity_x1 == polarity_x2 && polarity_y1 == polarity_y2 )
665+ {
666+ distSqr = sqr (derivative[minIdx][0 ]) + sqr (derivative[minIdx][1 ]);
667+ return ;
668+ }
689669 }
690670 }
691671
692672 DEBUG_ASSERTCRASH (minIdx <= 3 , (" Hmm, this should not be possible." ));
693-
673+
694674 // Get the Triangle length of all 3 points
695- Real boundary_h = fast_hypot (x1, x2, y1, y2);
696- Real boundary_1 = fast_hypot (x1, a->position .x , y1, a->position .y );
697- Real boundary_2 = fast_hypot (x2, a->position .x , y2, a->position .y );
675+ Real boundary_h = fast_hypot (pts[minIdx].x - pts[secondMinIdx].x , pts[minIdx].y - pts[secondMinIdx].y );
676+ // Real boundary_1 = fast_hypot(dx1, dy1);
677+ // Real boundary_2 = fast_hypot(dx2, dy2);
678+ // Real sqr_boundary_h = sqr(boundary_h);
679+ // Real sqr_boundary_1 = sqr(boundary_1);
680+ // Real sqr_boundary_h = sqr((*pts)[minIdx].x - (*pts)[lastMinIdx].x) + sqr((*pts)[minIdx].y - (*pts)[lastMinIdx].y);
681+ Real sqr_boundary_1 = sqr (dx1) + sqr (dy1);
682+ Real sqr_boundary_2 = sqr (dx2) + sqr (dy2);
698683
699684 // Real boundary_h = sqrtf(sqr(x1 - x2) + sqr(y1 - y2));
700685 // Real boundary_1 = sqrtf(sqr(x1 - a->position.x) + sqr(y1 - a->position.y));
@@ -704,23 +689,21 @@ static void testSphereAgainstRect(
704689 // Real boundary_1 = Hypot(fabs(x1 - a->position.x), fabs(y1 - a->position.y));
705690 // Real boundary_2 = Hypot(fabs(x2 - a->position.x), fabs(y2 - a->position.y));
706691
707- // Heron's formula
708- Real semiPeri = (boundary_h + boundary_1 + boundary_2) * 0.5 ;
709- Real Area = sqrtf (semiPeri * (semiPeri - boundary_h) * (semiPeri - boundary_1) * (semiPeri - boundary_2));
710- distance = Area * 2 / boundary_h;
692+ // Heron's formula (Not reliable for accounting the edges)
693+ // Real semiPeri = (boundary_h + boundary_1 + boundary_2) * 0.5;
694+ // Real Area = sqrtf(semiPeri * (semiPeri - boundary_h) * (semiPeri - boundary_1) * (semiPeri - boundary_2));
695+ // distSqr = sqr( Area * 2 / boundary_h) ;
711696
712- // Fast Hypothenus formula h = ((sqrt(2) - 1) * a) + b 1.41421356237
697+ // Law of Cosines (Demonstration)
713698 // sqr(boundary_1) = sqr(boundary_2) + sqr(boundary_h) - (2 * boundary_2 * boundary_h * cos(angle_1)); // b^2 = a^2 + c^2 - 2ac cos B
714- // boundary_1 * sin(angle_2) = boundary_2 * sin(angle_1)
715699
716- /* Real cosAngle_1 = (boundary_2_Sqr + boundary_h_Sqr - boundary_1_Sqr) * 0.5 / (boundary_2 * boundary_h);
717- Real angle_1 = (Real)Acos(cosAngle_1);
718- //Real sinAngle_2 = boundary_2 / boundary_1 * (Real)Sin(angle_1);
719- //Real angle_2 = (Real)Asin(sinAngle_2);
700+ // Converting formula to count for Radius
701+ // Real cosAngle_1 = (sqr(boundary_2) + sqr(boundary_h) - sqr(boundary_1)) * 0.5 / (boundary_2 * boundary_h));
702+ // Real boundary_h1 = cosAngle_1 * boundary_2;
720703
721- // After we got an angle we can calculate the radius required.
722- use boundary_2
723- Real angle_h = PI/2 - angle_1; */
704+ // Formula Summarization
705+ Real boundary_h1 = (sqr_boundary_2 + sqr (boundary_h) - sqr_boundary_1) * 0.5 / boundary_h;
706+ distSqr = sqr_boundary_2 - sqr (boundary_h1);
724707}
725708
726709// -----------------------------------------------------------------------------
@@ -799,11 +782,9 @@ static Bool xy_collideTest_Rect_Circle(const CollideInfo *a, const CollideInfo *
799782
800783 Coord2D pts[4 ];
801784 rectToFourPoints (a, pts);
785+ testSphereAgainstRect (pts, b, distSqr);
802786
803- Real distance = 0 .0f ;
804- testSphereAgainstRect (pts, b, distance);
805-
806- // DEBUG_LOG(("Radius: %f Distance: %f", b->geom.getMajorRadius(), distance));
787+ // DEBUG_LOG(("Radius: %f Distance: %f", b->geom.getMajorRadius(), distSqr));
807788
808789 /* Real circ_l = b->position.x - b->geom.getMajorRadius();
809790 Real circ_r = b->position.x + b->geom.getMajorRadius();
@@ -817,7 +798,7 @@ static Bool xy_collideTest_Rect_Circle(const CollideInfo *a, const CollideInfo *
817798 if (circ_r >= rect_l && circ_l <= rect_r &&
818799 circ_b >= rect_t && circ_t <= rect_b)
819800 */
820- if (distance <= b->geom .getMajorRadius ())
801+ if (distSqr <= sqr ( b->geom .getMajorRadius () ))
821802 {
822803 if (cinfo)
823804 {
@@ -846,7 +827,7 @@ static Bool xy_collideTest_Rect_Circle(const CollideInfo *a, const CollideInfo *
846827 // cinfo->distSqr = minDistSqr;
847828 // }
848829 if (cinfo->getDistance )
849- cinfo->distSqr = sqr (distance) ;
830+ cinfo->distSqr = distSqr ;
850831 }
851832 return true ;
852833 }
0 commit comments