triangulo rectangulo perimetro para cuadrado como codigo circulo calcular javascript svg

javascript - rectangulo - ¿Cómo puedo calcular el área de una curva de bezier?



perimetro en javascript (4)

Teniendo en cuenta la siguiente ruta (por ejemplo) que describe una curva bezier cúbica SVG: "M300,140C300,40,500,40,500,140", y suponiendo una línea recta que conecta los puntos finales 300,140 a 500,140 (cerrando el área bajo la curva), ¿es posible? ¿Para calcular el área así encerrada?

¿Alguien puede sugerir una fórmula (o JavaScript) para lograr esto?


Dudé en solo hacer un comentario o una respuesta completa. Pero una simple búsqueda en Google de "area bezier curve" da como resultado los primeros tres enlaces (el primero es este mismo post), en:

http://objectmix.com/graphics/133553-area-closed-bezier-curve.html

que proporciona la solución de forma cerrada, utilizando el teorema de la divergencia. Me sorprende que este enlace no haya sido encontrado por el OP.

Copiando el texto en caso de que el sitio web se caiga, y acreditando al autor de la respuesta Kalle Rutanen:

Un problema interesante. Para cualquier curva diferenciable por partes en 2D, el siguiente procedimiento general le da el área dentro de la curva / serie de curvas. Para las curvas polinomiales (curvas de Bezier), obtendrá soluciones de forma cerrada.

Sea g (t) una curva diferenciable por partes, con 0 <= t <= 1. g (t) se orienta en el sentido de las agujas del reloj yg (1) = g (0).

Sea F (x, y) = [x, y] / 2

Entonces div (F (x, y)) = 1 donde div es para divergencia.

Ahora el teorema de la divergencia te da el área dentro de la curva cerrada g (t) como una integral de línea a lo largo de la curva:

int (punto (F (g (t)), perp (g ''(t)) dt, t = 0..1) = (1/2) * int (punto (g (t), perp (g'' (t))) dt, t = 0..1)

perp (x, y) = (-y, x)

donde int es para integración, ''para diferenciación y punto para producto puntual. La integración debe estar formada por las partes correspondientes a los segmentos de curva suave.

Ahora para ejemplos. Tome el grado Bezier 3 y una curva de este tipo con puntos de control (x0, y0), (x1, y1), (x2, y2), (x3, y3). La integral sobre esta curva es:

I: = 3/10 * y1 * x0 - 3/20 * y1 * x2 - 3/20 * y1 * x3 - 3/10 * y0 * x1 - 3/20 * y0 * x2 - 1/20 * y0 * x3 + 3/20 * y2 * x0 + 3/20 * y2 * x1 - 3/10 * y2 * x3 + 1/20 * y3 * x0 + 3/20 * y3 * x1 + 3/10 * y3 * x2

Calcula esto para cada curva en la secuencia y súmalos. La suma es el área encerrada por las curvas (asumiendo que las curvas forman un bucle).

Si la curva consta de una sola curva Bezier, entonces debe ser x3 = x0 e y3 = y0, y el área es:

Área: = 3/20 * y1 * x0 - 3/20 * y1 * x2 - 3/20 * y0 * x1 + 3/20 * y0 * x2 - 3/20 * y2 * x0 + 3/20 * y2 * x1

Espero no haber cometido errores.

-
Kalle Rutanen
http://kaba.hilvi.org


En primer lugar, no estoy tan familiarizado con las curvas de Bézier, pero sé que son funciones continuas. Si se asegura de que su curva cúbica no se interseca, puede integrarla en forma cerrada (me refiero al uso de integrales analíticas) en el dominio adjunto dado ([ab]) y restar el área del triángulo que está formado por el extremo Unión en línea recta y eje x. En caso de intersección con la curva de Bezier y el extremo que une la línea recta, puede dividir en secciones e intentar calcular cada área por separado de manera consistente.

Para mí, los términos de búsqueda adecuados son "integrales de función continua" "integrales" "área bajo una función" "cálculo"

Por supuesto, puede generar datos discretos a partir de su curva bezier fn y obtener datos XY discretos y calcular la integral aproximadamente.


Me gusta la solución en la respuesta aceptada de Phrogz, pero también busqué un poco más y encontré una manera de hacer lo mismo con Paper.js usando la clase CompoundPath y la propiedad del area . Ver mi demo Paper.js .

El resultado (área de superficie = 11856) es exactamente el mismo que con la demostración de Phrogz cuando se usa el umbral 0, ¡pero el procesamiento parece mucho más rápido! Sé que es excesivo cargar Paper.js solo para calcular el área de superficie, pero si está considerando implementar un marco o tiene ganas de investigar cómo Paper.js lo hace ...


Convierta la ruta a un polígono de precisión arbitraria y luego calcule el área del polígono .

Demostración interactiva: Área de camino a través de subdivisión

En su núcleo, la demostración anterior utiliza funciones para subdividir de forma adaptativa la ruta en un polígono y calcular el área de un polígono :

// path: an SVG <path> element // threshold: a ''close-enough'' limit (ignore subdivisions with area less than this) // segments: (optional) how many segments to subdivisions to create at each level // returns: a new SVG <polygon> element function pathToPolygonViaSubdivision(path,threshold,segments){ if (!threshold) threshold = 0.0001; // Get really, really close if (!segments) segments = 3; // 2 segments creates 0-area triangles var points = subdivide( ptWithLength(0), ptWithLength( path.getTotalLength() ) ); for (var i=points.length;i--;) points[i] = [points[i].x,points[i].y]; var doc = path.ownerDocument; var poly = doc.createElementNS(''http://www.w3.org/2000/svg'',''polygon''); poly.setAttribute(''points'',points.join('' '')); return poly; // Record the distance along the path with the point for later reference function ptWithLength(d) { var pt = path.getPointAtLength(d); pt.d = d; return pt; } // Create segments evenly spaced between two points on the path. // If the area of the result is less than the threshold return the endpoints. // Otherwise, keep the intermediary points and subdivide each consecutive pair. function subdivide(p1,p2){ var pts=[p1]; for (var i=1,step=(p2.d-p1.d)/segments;i<segments;i++){ pts[i] = ptWithLength(p1.d + step*i); } pts.push(p2); if (polyArea(pts)<=threshold) return [p1,p2]; else { var result = []; for (var i=1;i<pts.length;++i){ var mids = subdivide(pts[i-1], pts[i]); mids.pop(); // We''ll get the last point as the start of the next pair result = result.concat(mids) } result.push(p2); return result; } } // Calculate the area of an polygon represented by an array of points function polyArea(points){ var p1,p2; for(var area=0,len=points.length,i=0;i<len;++i){ p1 = points[i]; p2 = points[(i-1+len)%len]; // Previous point, with wraparound area += (p2.x+p1.x) * (p2.y-p1.y); } return Math.abs(area/2); } }

// Return the area for an SVG <polygon> or <polyline> // Self-crossing polys reduce the effective ''area'' function polyArea(poly){ var area=0,pts=poly.points,len=pts.numberOfItems; for(var i=0;i<len;++i){ var p1 = pts.getItem(i), p2=pts.getItem((i+-1+len)%len); area += (p2.x+p1.x) * (p2.y-p1.y); } return Math.abs(area/2); }

A continuación se encuentra la respuesta original, que utiliza una técnica diferente (no adaptativa) para convertir la <path> a un <polygon> .

Demostración interactiva: http://phrogz.net/svg/area_of_path.xhtml

En su núcleo, la demostración anterior utiliza funciones para aproximar una ruta con un polígono y calcular el área de un polígono .

// Calculate the area of an SVG polygon/polyline function polyArea(poly){ var area=0,pts=poly.points,len=pts.numberOfItems; for(var i=0;i<len;++i){ var p1 = pts.getItem(i), p2=pts.getItem((i+len-1)%len); area += (p2.x+p1.x) * (p2.y-p1.y); } return Math.abs(area/2); } // Create a <polygon> approximation for an SVG <path> function pathToPolygon(path,samples){ if (!samples) samples = 0; var doc = path.ownerDocument; var poly = doc.createElementNS(''http://www.w3.org/2000/svg'',''polygon''); // Put all path segments in a queue for (var segs=[],s=path.pathSegList,i=s.numberOfItems-1;i>=0;--i) segs[i] = s.getItem(i); var segments = segs.concat(); var seg,lastSeg,points=[],x,y; var addSegmentPoint = function(s){ if (s.pathSegType == SVGPathSeg.PATHSEG_CLOSEPATH){ }else{ if (s.pathSegType%2==1 && s.pathSegType>1){ x+=s.x; y+=s.y; }else{ x=s.x; y=s.y; } var last = points[points.length-1]; if (!last || x!=last[0] || y!=last[1]) points.push([x,y]); } }; for (var d=0,len=path.getTotalLength(),step=len/samples;d<=len;d+=step){ var seg = segments[path.getPathSegAtLength(d)]; var pt = path.getPointAtLength(d); if (seg != lastSeg){ lastSeg = seg; while (segs.length && segs[0]!=seg) addSegmentPoint( segs.shift() ); } var last = points[points.length-1]; if (!last || pt.x!=last[0] || pt.y!=last[1]) points.push([pt.x,pt.y]); } for (var i=0,len=segs.length;i<len;++i) addSegmentPoint(segs[i]); for (var i=0,len=points.length;i<len;++i) points[i] = points[i].join('',''); poly.setAttribute(''points'',points.join('' '')); return poly; }