4 ms·
If you look at the source, you'll see that it doesn't really try to split the path into smaller primitives at all. It uses a simple algorithm (https://stackover
by yarcob 6y ago
If you look at the source, you'll see that it doesn't really try to split the path into smaller primitives at all. It uses a simple algorithm (https://stackoverflow.com/a/33852627 https://stackoverflow.com/a/33852627) to calculate the center of mass, and another algorithm to calculate the area (https://stackoverflow.com/a/33670691 https://stackoverflow.com/a/33670691).
Both of these algorithms basically sum up the "signed area" of the polygons. This means that if you circle something twice, it'll count twice, and the sign depends on the direction of the winding.
The confusing part is that when the polygon is drawn, it uses the "non-zero winding rule" to determine which part to fill. So the filled parts of the polygons are all parts that contribute non-zero parts to the area (eg. positive, negative, two time positive etc.).
So the weird behaviour is that the physics simulation doesn't use the same rules as the visualisation!
So the nice thing about these algorithms is that it works for arbitrary complex shapes as long as the path has no self-intersections.
If you want to add support for self-intersecting paths, you need to decide how to deal with intersections. Presumably you'd want the physics to match the visualisation, ie. use the non-zero winding rule also for centroid and area calculations. To do that, you would first need to split the polygon into non-intersecting parts, and then calculate the area separately for each part, and then sum up the absolute values of the individual parts.
- yarcob 6y agoI annotated a screenshot with winding numbers. You'll see that the filled areas correspond to the parts with non-zero winding numbers, but the physics simulation considers the sign and magnitude. https://i.imgur.com/3OLflHc.png https://i.imgur.com/3OLflHc.png
- sgtnoodle 6y agoThanks for tracking down the actual algorithms! It appears that they work by summing the "signed" areas of half-trapezoids formed between each neighboring pair of vectors and an arbitrary axis line, so I'm going to stand by my claim that the code breaks the polygon up into smaller primitives. :-) Good catch with the discrepancy between the physics and the visualization. I wonder if there's a way to engineer a cool structure with a lot of invisible mass. Do you have a notion of how the code actually computes bouyancy? Does it somehow slice the polygon into two at the water line and then compute center and area of both? Once again, it would be interesting to engineer an object that leverages any non-linear behaviors at the water line, perhaps like an object whose mass changes depending on its position and orientation.
- yarcob 6y ago> Do you have a notion of how the code actually computes bouyancy? Weight force (downward) is determined by the full polygon. Buyancy force (upward) is determined by the part below the water line. Lateral/angular motion results from the fact that the forces act on the centroids of the full polygon vs the centroid of the submerged polygon. The script seems to use a JS library named "turf" to clip the polygon at the water line. Here's the line in the source: var pp = turf.bboxClip(p, [-Infinity, yZero, Infinity, Infinity]).geometry.coordinates[0]; As far as I can tell, yZero is the water line, and pp is the part of the polygon that is submerged.