forked from: 2D ray intersect triangle test
forked from 2D ray intersect triangle test (diff: 22)
Try when starting from inside terrain triangle. The normalized ratio r multiplier of a given slope diagonal's length, based on gradient is: r = sqrt(1+gradient*gradient); This is used to determine the perimeter travel time when walking along terrain triangles given a specific direction.
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/eECN
*/
// forked from Glidias's 2D ray intersect triangle test
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(150,65);
private var endPt:Vector3D = new Vector3D();
private var backPt: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;
if (intersectTimes[0] < 0) { // start dot from inside instead mod
intersectZ[0] -= intersectTimes[0]/(intersectTimes[1]-intersectTimes[0])*(intersectZ[1] - intersectZ[0]);
intersectTimes[0] = 0;
}
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;
if (_coincident) {
gradient = ( - 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!:"+[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
// (r >= 0) &&
return (s >= 0 && s <= 1);
}
}
}