Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Offset #668

Closed
wants to merge 2 commits into from
Closed

Add Offset #668

wants to merge 2 commits into from

Conversation

elalish
Copy link
Owner

@elalish elalish commented Dec 20, 2023

Inspired by and related to #666, this is an Offset function, so a Minkowski only with a sphere (positive or negative). I used convexity to apply fewer edge and vert Booleans.

@elalish elalish self-assigned this Dec 20, 2023
@elalish
Copy link
Owner Author

elalish commented Dec 20, 2023

As @zalo also found, this is basically a fuzz test for the Boolean due to using so many coplanar objects. The outset looks reasonable:
image

but it has a terrible genus, and the inset makes it clearer what is going wrong internally:
image

Most of these shards are due to bad symbolic perturbation (I think). Then there's lots of trouble with CW triangulation, due to self-intersecting polygons - I have a hunch about this problem too. And of course it's highly order-dependent and not infrequently seg-faults, which is the worst part. Since Vec isn't catching it, it must be somewhere unusual.

Anyway, even if this doesn't eventually become our API, it's serving as a good test case.

@zalo
Copy link
Contributor

zalo commented Dec 20, 2023

Nice! The inset parameter makes a lot of sense; I feel silly for not including it.

Do you notice any seams/artifacts between the extruded triangles and the low-resolution spheres? If so, I feel like it might be worth rotating the spheres/cylinders so they have at least one vertex aligned with the adjacent extruding triangle 🤔
A Tessellated Cube normalized to a sphere could have vertices that are well distributed for 90° and 45° angles…

Also, I wonder at the speed difference between hulling two spheres and unioning two spheres and a cylinder… I’ll look at the implementation more carefully tomorrow when I’m on a real PC again 😄

@elalish
Copy link
Owner Author

elalish commented Dec 20, 2023

Yes, there are little dimples - I'm considering tweaking the precision to see if I can just decimate them out. Our spheres are tessellated octahedra, which I think already have the nicely aligned verts you're thinking of. I don't think it's worth rotating though, since having only one vert aligned isn't much better than none.

The idea with unioning these separately is that with the hulls you're effectively unioning the same sphere 6 times (since that vert is part of 6 triangles), where I'm just doing it once. Plus, unioning shapes with identical faces is the slowest part, since you get lots of collisions to check. Still, I'm curious how much difference it makes in practice; would love to see some comparisons!

@zalo
Copy link
Contributor

zalo commented Dec 20, 2023

I added just the Naive NonConvex-Convex method to your branch as a point of comparison:
https://github.com/elalish/manifold/compare/offset...zalo:manifold:offset-comparison?w=1

[ RUN      ] Boolean.Offset
C:\Repositories\manifold\test\boolean_test.cpp(601): error: Expected equality of these values:
  fat.Genus()
    Which is: -57
  cutout.Genus()
    Which is: 5

C:\Repositories\manifold\test\boolean_test.cpp(602): error: Expected equality of these values:
  thin.Genus()
    Which is: -78
  -7

[  FAILED  ] Boolean.Offset (5930 ms)
[ RUN      ] Boolean.OffsetHull
[       OK ] Boolean.OffsetHull (10095 ms)

Seems like it's twice as slow, but it returns the correct Genus 🤔

I believe the issue is that the triangle extrusions probably don't match up perfectly with the edges of the spheres and cylinders.
image

Ah, just saw your reply!

The hulling method gets around this by just sweeping the same low-res sphere everywhere, but of course, that's where all of the slowness comes from.

Perhaps the hull method can be sped up by sweeping just a few vertices of the sphere on triangle faces, but the whole thing on convexEdges/Points?

Perhaps duplicate vertices/faces can be added to a hashmap and checked for in O(1)?

@elalish
Copy link
Owner Author

elalish commented Dec 20, 2023

Yeah, you get the right genus because you aren't unioning barely-touching extrusions like I am. I'm going to focus on fixing the Boolean problems this has revealed.

@zalo
Copy link
Contributor

zalo commented Dec 20, 2023

If you'd like some mesh inspiration from OpenCascade's Offset Operation:
https://zalo.github.io/CascadeStudio/#code=y0ktUchPSytOLQlKTMksLVawVQjOyUxJLdJQgggo6SiY65nqKBgo6CiYGmhac%2BUAdRQXZKQWpYLUghkaJqZQieTSJJCwU36FhjlQEwyXFJWmomjNSS0udoaoDSlKzCvOSSxJ1Yg2AFqjo2AMtE8b2U2xOgoumWlpQG15yakaICt0FKIh5sRqQo2FqA9GN9wfLKyBaqkOio81rQE%3D&gui=q1ZKzs8tyM9LzSvxS8xNVbJSSk4sTk5MSQ3LTC1X0lHyTS3OCEotVrIy0DPUUXJOTM5ItVeyKikqTdVRci%2FKL81LCchJzAOJpSXmFIMFM1PgKoISUzJLgZrN9UxrAQ%3D%3D

It's kind of unfair given the amount of code OpenCascade needs to achieve this (and they don’t even try to handle self intersections), but look at that topology! 😄
SpherelessCubeOffset.stl.txt

EDIT:
This is probably more similar to @pca006132 's technique, where convex edges have cylinder wedges constructed around them, and convex points have special interpolating sphere wedges constructed around them to match the cylinders.

The key insight in OpenCascade is that every "Face" can be reduced to a boundary polygon in some 2D UV space, where it can be delaunay triangulated and lifted back to the 3D space. This means that it's trivial to ensure vertices are sewn together if they share the same boundary polygon edges.

If the final destinations of the extruded triangle vertices are kept track of, then it might be straight-forward to construct these boundaries...

@pca006132
Copy link
Collaborator

Nice work! I have less capacity currently as I am working on a new openscad interpreter (https://github.com/pca006132/sscad). It is basically a minimal implementation of openscad's script, with cleaner code, less dependencies and hopefully faster speed. The goal is to use it in manifoldcad, python (maybe @wrongbad will be interested), and eventually as experimental alternative code backend for openscad. I want to get something working before next year, so I am pretty busy with it. Will have a look at offset and minkowski later after I get something running.

@elalish
Copy link
Owner Author

elalish commented Dec 27, 2023

Closing in favor of #666.

edge.y *= -1;
batch[edgeOffset + idx] =
cylinder.Scale({1, 1, length})
.Transform(RotateUp(edge))
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@starseeker This might help you.

@pca006132 pca006132 deleted the offset branch November 18, 2024 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants