Skip to content

Instantly share code, notes, and snippets.

@scriptify
Created September 20, 2019 10:57
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scriptify/80bcb8f4f3e878c5f064cc48dc905017 to your computer and use it in GitHub Desktop.
Save scriptify/80bcb8f4f3e878c5f064cc48dc905017 to your computer and use it in GitHub Desktop.
Calculates the area of a polygon in 3D space
//determinant of matrix a
function det(a) {
return (
a[0][0] * a[1][1] * a[2][2] +
a[0][1] * a[1][2] * a[2][0] +
a[0][2] * a[1][0] * a[2][1] -
a[0][2] * a[1][1] * a[2][0] -
a[0][1] * a[1][0] * a[2][2] -
a[0][0] * a[1][2] * a[2][1]
);
}
//unit normal vector of plane defined by points a, b, and c
function unit_normal(a, b, c) {
let x = det([[1, a[1], a[2]], [1, b[1], b[2]], [1, c[1], c[2]]]);
let y = det([[a[0], 1, a[2]], [b[0], 1, b[2]], [c[0], 1, c[2]]]);
let z = det([[a[0], a[1], 1], [b[0], b[1], 1], [c[0], c[1], 1]]);
let magnitude = Math.pow(
Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2),
0.5
);
return [x / magnitude, y / magnitude, z / magnitude];
}
// dot product of vectors a and b
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
// cross product of vectors a and b
function cross(a, b) {
let x = a[1] * b[2] - a[2] * b[1];
let y = a[2] * b[0] - a[0] * b[2];
let z = a[0] * b[1] - a[1] * b[0];
return [x, y, z];
}
// area of polygon poly
export default function calculatePolygonArea(poly) {
if (poly.length < 3) {
console.log("not a plane - no area");
return 0;
} else {
let total = [0, 0, 0];
for (let i = 0; i < poly.length; i++) {
var vi1 = poly[i];
if (i === poly.length - 1) {
var vi2 = poly[0];
} else {
var vi2 = poly[i + 1];
}
let prod = cross(vi1, vi2);
total[0] = total[0] + prod[0];
total[1] = total[1] + prod[1];
total[2] = total[2] + prod[2];
}
let result = dot(total, unit_normal(poly[0], poly[1], poly[2]));
return Math.abs(result / 2);
}
}
@dmartini1337
Copy link

Hello Maximilian Torggler,
I recently stumbled over the area measurement problem in the Potree Desktop Viewer. I'm not very firm in Javascript development, but I want to use your improvement to get the right area measurements. Can you please tell me how to change/add these calculation?

Thank you very much,have a nice weekend and greetingz.

Dominik

@scriptify
Copy link
Author

Hello,
do you need a 2D or 3D area measurement? Because our team and me observed that this algorithm didn't really work as expected in 3D space. For that to work, you first need to create a 3D mesh of all points and then calculate the real surface. For that purpose, I created a WASM port of powercrust. This is still very experimental though.

@dmartini1337
Copy link

dmartini1337 commented Apr 12, 2021

Hi,
I want to measure a the spaces and areas of rooftops. Due to the different angles roofs can have, the area measurement in potree does not fit. If I am understanding correctly, the area is calculated only from x and y coordinates in potree?
Isn't it possible to calculate the right area for 3 points in x,y,z very easily? This wouldn't be as convenient as a complete polygon, but it would be a useful start.

I have thought about it furthermore... Isn't It possible to define an vector plane with the first 3 points and then project the other points on this plane (if the points aren't too far away, of course). Then the calculation would be the same as in the x,y plane like potree already do. Mathematically is this not a big problem, but I don't know how to implement this into potree.

And if I understood your code correctly you have already implemented the calculation of the area of the triangle of 3 points.
Maybe you could help me to get the code running in potree, this would be a starting point for me to implement a calculation of more than 3 points, if they are near the first vectore plane.

@dmartini1337
Copy link

This seems to work pretty well, too. https://math.stackexchange.com/questions/3207981/caculate-area-of-polygon-in-3d
Calculated polygons in excel with this formula. If the points aren't to far away from the plane this should work pretty well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment