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