2D ray intersect triangle test

by Glidias
Detecting 2D intersection edges along tri-polygon, and collinear cases with gradient along triangular slope.
♥0 | Line 135 | Modified 2015-06-05 16:27:37 | MIT License
play

ActionScript3 source code

/**
 * Copyright Glidias ( http://wonderfl.net/user/Glidias )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/iyad
 */

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Vector3D;
    import flash.text.TextField;
    
    /**
     * ...
     * @author Glenn Ko
     */
    [SWF(frameRate="60", backgroundColor="#ffffff")]
    public class LineIntersectTest extends Sprite
    {
      
        private var startPt:Vector3D = new Vector3D(30,60);
        private var endPt:Vector3D = new Vector3D();
        
        private var pt1:Vector3D = new Vector3D(100, 60, 60);
        private var pt2:Vector3D = new Vector3D(100+60, 60, 120);
        private var pt3:Vector3D = new Vector3D(70,180, 100);
        private var r:Number;
        private var s:Number;
        
        private var intersectTimes:Vector.<Number> = new Vector.<Number>(2, true);
        private var intersectZ:Vector.<Number> = new Vector.<Number>(2, true);
        private var debugField:TextField;
        
        public function LineIntersectTest() {
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            debugField = new TextField();
            debugField.autoSize = "left";
            addChild(debugField);
        }
    
        private function onEnterFrame(e:Event):void {
            var gotIntersect:Boolean;
            endPt.x = mouseX;
            endPt.y = mouseY;
            graphics.clear();
            
              _coincident = false;
              
            gotIntersect = IsIntersecting(startPt, endPt, pt1, pt2);
        
            
            var count:int = 0;
            var color:uint =   0;
            if (gotIntersect) {
                color = 0xFF0000;
                intersectTimes[count] = r;
                intersectZ[count] = pt2.z * s - pt1.z * s  + pt1.z;
                count++;
                
            }
            gotIntersect = IsIntersecting(startPt, endPt, pt2, pt3);
            if (gotIntersect) {
                color = 0xFF0000;
                intersectTimes[count] = r;
                intersectZ[count] = pt3.z * s - pt2.z * s  + pt2.z;
                count++;
            }
            
            gotIntersect = IsIntersecting(startPt, endPt, pt3, pt1);
            if (gotIntersect) {
                if (count <2) {
                    color = 0xFF0000;
                    intersectTimes[count] = r;
                    intersectZ[count] = pt1.z * s - pt3.z * s  + pt3.z;
                    count++;
                }
            }
            
            graphics.lineStyle(0, color, 1);
            graphics.moveTo(startPt.x, startPt.y);
            graphics.lineTo(endPt.x, endPt.y);
            
            graphics.moveTo(pt1.x, pt1.y);
            graphics.lineTo(pt2.x, pt2.y);
            graphics.lineTo(pt3.x, pt3.y);
            graphics.lineTo(pt1.x, pt1.y);
            
            var dx:Number = endPt.x - startPt.x;
            var dy:Number  = endPt.y - startPt.y;
            
            var temp:Number = intersectTimes[0];
            var temp2:Number = intersectZ[0];
            
            if (intersectTimes[1] < temp ) {
                intersectTimes[0] = intersectTimes[1];
                intersectZ[0] = intersectZ[1];
                
                intersectTimes[1] = temp;
                intersectZ[1]=temp2;
            }
            
            
            if (color == 0xFF0000) {
                graphics.beginFill(0, 1);
                var ax:Number;
                var ay:Number;
                var bx:Number;
                var by:Number;
                graphics.drawCircle(ax=startPt.x + dx * intersectTimes[0], ay = startPt.y + dy * intersectTimes[0], 2);
                graphics.drawCircle(bx= startPt.x + dx * intersectTimes[1], by = startPt.y + dy * intersectTimes[1], 3);
                
                var rd:Number = (intersectTimes[1] - intersectTimes[0]);
           
               var gradient:Number;
               
               rd  *= Math.sqrt( dx * dx + dy * dy ); 
               
             
               if (_coincident) {
                     
                    gradient = (intersectZ[1] - intersectZ[0]) / rd;
                    debugField.text = "Coincident found (gradient):" + gradient + ", "+(count > 1);
               }
                else if (count > 1) {
                    if (rd> 0) {
                      gradient = (intersectZ[1] - intersectZ[0]) / rd;
                      debugField.text = "penetrate dist:" + rd + ", gradient:"+gradient + ", "+intersectTimes;
                    }
                    else {
                         debugField.text = "Hit a fully vertical wall!:"+intersectTimes[0];
                    }
                }
                else {
                    debugField.text = "Should not happen! Exception occured!";
                }

            
            }
            else {
                debugField.text = "No penetrate";
            }
        }
        
        public function sqDistBetween2DVector(a:Vector3D, b:Vector3D):Number {
            var dx:Number = b.x - a.x;
            var dy:Number = b.y - a.y;
            return dx * dx + dy * dy;
        }
        
        public function rBetween2DVec(a:Vector3D, b:Vector3D, c:Vector3D):Number {
            var dx:Number = b.x - a.x;
            var dy:Number = b.y - a.y;
            var dx2:Number = c.x - a.x;
            var dy2:Number = c.y - a.y;
            return dx * dx2 + dy * dy2;
        }
        

     private var _coincident:Boolean;
        
        public function IsIntersecting(a:Vector3D, b:Vector3D, c:Vector3D, d:Vector3D):Boolean
        {
            var denominator:Number = ((b.x - a.x) * (d.y - c.y)) - ((b.y - a.y) * (d.x - c.x));
            var numerator1:Number = ((a.y - c.y) * (d.x - c.x)) - ((a.x - c.x) * (d.y - c.y));
            var numerator2:Number = ((a.y - c.y) * (b.x - a.x)) - ((a.x - c.x) * (b.y - a.y));

            // Detect coincident lines (has a problem, read below)
            if (denominator == 0) {
                // find between c and d, which is closer to a, clamp to s to 1 and 0, set r to c/d
               s = sqDistBetween2DVector(a, c) < sqDistBetween2DVector(a, d) ? 0 : 1;
               r = s != 0 ? rBetween2DVec(a, b, d)  : rBetween2DVec(a, b, c);
              // throw new Error("DETECT");
               _coincident = true;
                return false;// (r >= 0) && (s >= 0 && s <= 1);
               //  return numerator1 == 0 && numerator2 == 0;
            }


            r = numerator1 / denominator;
            s = numerator2 / denominator;
            // && r <= 1
            return (r >= 0) && (s >= 0 && s <= 1);
        }
    
     }
    
}

Forked