Collision/intersection line-ellipse and line-rectangle javascript
Hola, espero que les guste y sirva esta publicación.
Estaba trabajando para un proyecto en javascript, y necesitaba dibujar una línea desde un punto hacia el punto de colisión con un elipse o un rectángulo. Empecé a googlear, y no tuve suerte. Pude conseguir algunos scripts pero en otros lenguajes de programación, y hechos para otros fines, por lo que tuve que adaptarlos.
Aquí les dejo el script + una demo:
Código
/**
* http://programando-soft.blogspot.com
*
* Luciano Rasente
*/
/**
* =====================================
* Requeriments
* ======================================
*/
function point(_x, _y) {
return {x: _x, y: _y};
}
/*
Common vector2 operations
Author: Tudor Nita | cgrats.com
Version: 0.51
*/
function Vec2(x_,y_)
{
this.x = x_;
this.y = y_;
this.isVector = true;
/* vector * scalar */
this.mulS = function (value){ return new Vec2(this.x*value, this.y*value); };
/* vector * vector */
this.mulV = function(vec_) { return new Vec2(this.x * vec_.x, this.y * vec_.y); };
/* vector / scalar */
this.divS = function(value) { return new Vec2(this.x/value,this.y/value); };
/* vector + scalar */
this.addS = function(value) { return new Vec2(this.x+value,this.y+value); };
/* vector + vector */
this.addV = function(vec_) { return new Vec2(this.x+vec_.x,this.y+vec_.y); };
/* vector - scalar */
this.subS = function(value) { return new Vec2(this.x-value, this.y-value); };
/* vector - vector */
this.subV = function(vec_) { return new Vec2(this.x-vec_.x,this.y-vec_.y); };
/* vector absolute */
this.abs = function() { return new Vec2(Math.abs(this.x),Math.abs(this.y)); };
/* dot product */
this.dot = function(vec_) { return (this.x*vec_.x+this.y*vec_.y); };
/* vector length */
this.length = function() { return Math.sqrt(this.dot(this)); };
/* distance between vectors */
this.dist = function(vec_) { return (vec_.subV(this)).length(); };
/* vector length, squared */
this.lengthSqr = function() { return this.dot(this); };
/*
vector linear interpolation
interpolate between two vectors.
value should be in 0.0f - 1.0f space
*/
this.lerp = function(vec_, value) {
return new Vec2(
this.x+(vec_.x-this.x)*value,
this.y+(vec_.y-this.y)*value
);
};
/* normalize THIS vector */
this.normalize = function() {
var vlen = this.length();
this.x = this.x/ vlen;
this.y = this.y/ vlen;
};
}
/**
* =====================================
* Script
* ======================================
*/
/**
* Gets the intersection between a line and a rectangle.
* @param ex Ellipse x
* @param ey Ellipse y
* @param ew Ellipse width
* @param ew Ellipse height
* @param x1 Line begin x
* @param y1 Line begin y
* @param x2 Line end x
* @param y2 Line end y
* @returns {x: , y: } or null.
*/
function getEllipseIntersection(ex, ey, ew, eh, x1, y1, x2, y2) {
var x0 = ex,
y0 = ey,
w0 = ew,
h0 = eh;
// If the ellipse or line segment are empty, return no intersections.
if(w0 == 0 || h0 == 0 || (x0 == x1 && y0 == y1)) {
return null;
}
// Translate so the ellipse is centered at the origin.
var cx = x0 + w0/2; // X en el centro del elipse
var cy = y0 + h0/2; // Y en el centro del elipse
x0 -= cx;
y0 -= cy;
x1 -= cx;
y1 -= cy;
x2 -= cx;
y2 -= cy;
// Get the semimajor and semiminor axes.
var a = w0 / 2;
var b = h0 / 2;
// Calculate the quadratic parameters.
var A = (x2 - x1) * (x2 - x1) / a / a +
(y2 - y1) * (y2 - y1) / b / b;
var B = 2 * x1 * (x2 - x1) / a / a +
2 * y1 * (y2 - y1) / b / b;
var C = x1 * x1 / a / a + y1 * y1 / b / b - 1;
// Make a list of t values.
var values = [];
// Calculate the discriminant.
var discriminant = B * B - 4 * A * C;
if (discriminant == 0)
{
// One real solution.
values.push(-B / 2 / A);
}
else if (discriminant > 0)
{
// Two real solutions.
values.push((-B + Math.sqrt(discriminant)) / 2 / A);
values.push((-B - Math.sqrt(discriminant)) / 2 / A);
}
// Convert the t values into points.
var points = [];
for(var i = 0; i < values.length; i++)
{
var t = values[i];
// If the points are on the segment (or we
// don't care if they are), add them to the list.
if ((t >= 0) && (t <= 1))
{
var x = x1 + (x2 - x1) * t + cx;
var y = y1 + (y2 - y1) * t + cy;
points.push({x: x, y: y});
}
}
// Return the points.
return points[0];
}
/**
* Gets the intersection between a line and a rectangle.
* @param rx Rectangle x
* @param ry Rectangle y
* @param rw Rectangle width
* @param rw Rectangle height
* @param x0 Line begin x
* @param y0 Line begin y
* @param x1 Line end x
* @param y1 Line end y
* @returns {x: , y: } or null.
*/
function getRectIntersection(rx, ry, rw, rh, x0, y0, x1, y1) {
var p1 = point(x0, y0),
p2 = point(x1, y1);
var tl = point(rx, ry),
tr = point(rx+rw, ry),
bl = point(rx, ry+rh),
br = point(rx+rw, ry+rh);
var result =
getLineIntersection(p1, p2, tl, tr) ||
getLineIntersection(p1, p2, tl, bl) ||
getLineIntersection(p1, p2, tr, br) ||
getLineIntersection(p1, p2, bl, br) ||
null;
return result;
}
/**
* Gets the intersection between two lines.
* Line point: {x: , y: }
*
* @param a1 Line A begin point
* @param a2 Line A end point
* @param b1 Line B begin point
* @param b2 Line B end point
*/
function getLineIntersection(a1, a2, b1, b2) {
if(typeof Vec2 === 'undefined') {
throw "Vec2 is not defined";
}
if(typeof a1.isVector === 'undefined') {
a1 = new Vec2(a1.x, a1.y);
a2 = new Vec2(a2.x, a2.y);
b1 = new Vec2(b1.x, b1.y);
b2 = new Vec2(b2.x, b2.y);
}
var b = a2.subV(a1);
var d = b2.subV(b1);
var bDotDPerp = b.x * d.y - b.y * d.x;
// if b dot d == 0, it means the lines are parallel so have infinite intersection points
if (bDotDPerp == 0) {
return null;
}
var c = b1.subV(a1);
var t = (c.x * d.y - c.y * d.x) / bDotDPerp;
if (t < 0 || t > 1)
{
return null;
}
var u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1)
{
return null;
}
return a1.addV(b.mulS(t));
}
Comentarios
Publicar un comentario