8000 Add Fillet by Trzeth · Pull Request #1229 · elalish/manifold · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add Fillet #1229

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

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from
Draft

Add Fillet #1229

wants to merge 15 commits into from

Conversation

Trzeth
Copy link
Contributor
@Trzeth Trzeth commented Apr 19, 2025

Idea
Figure 1. General idea

Fillet operation means to create rounding corner with selected edges.
Algorithm Input: target mesh, radius of rounding corner and selected edges.
Implement: Main idea is create a properly cylinder and boolean with target mesh to create the rounding corner.

  1. (Figure1. first row) With given radius and tangent planes, the position of cylinder can be calculate.
  2. (Figure1. second row) Height of cylinder is related 1 neighbourhood, this is done by SplitByPlane.
  3. (Unfinished) Boolean to get the intersect edge, and union parts to generate the final output.

Corner cases
Figure 2. Corner cases

There are some corner cases this implement can't handle.

  1. (Fig 2. Case 1) If the request radius is larger than interproximal angle, the position of cylinder can't be calculate.
  2. (Fig 2. Case 2) If the selected edge is part of straight line, the rounding corner lack a transition surface to sharp edge.
Snipaste_2025-04-18_11-55-17

Siemens NX fillet operation

Snipaste_2025-04-19_11-24-48

Blender bevel

As for case 1, most software only deal with adjacent faces, can't handle this case with pure geometric way. But, this can be solve by MinkowskiSum with outward and inward offset.

Snipaste_2025-04-18_11-21-35

Siemens NX fillet operation

Snipaste_2025-04-19_11-23-49

Blender bevel

As for case 2, Blender create transition surface while NX can't handle it.

*/
///@{
static Manifold Fillet(const MeshGL&, double radius,
const std::vector<size_t>& selectedEdges = {});
Copy link
Owner

Choose a reason for hiding this comment

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

So, the API here is tricky - I can see why you're basing this on MeshGL input, since that allows you to select edges, and that's what I did for one of the Smoothing constructors. However, I think I'd prefer to avoid edge-selection APIs as much as we can. I think I'd prefer a Fillet command that fillets all edges beyond a threshold angle, and then it can be non-static. Do you think that's doable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the fillet in pure geometric way won't be that robustness, See corner case 1. It heavily rely on the request radius and adjacent relationship. If so, the result might be out of control.
But I think it would be extremely valuable if there is a full robust fillet method, and i'll keep looking for it.

Copy link
Owner

Choose a reason for hiding this comment

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

Yeah, Manifold's core ethos is robustness - we want find an algorithm that doesn't have edges cases, rather than trying to fix edges cases one by one. In computational geometry, edge cases tend to be the norm, rather than the exception.

@Trzeth
Copy link
Contributor Author
Trzeth commented Apr 24, 2025
Snipaste_2025-04-24_17-48-24

openscad/openscad#5337 Implement roof() without CGAL

Specifically,CGAL::create_interior_straight_skeleton_2 and CGAL::approx_convex_partition_2 around roof_ss.cc .

Might be related and able to handle together?

@elalish
Copy link
Owner
elalish commented Apr 24, 2025

Actually I have a straight skeleton algorithm I implemented in Matlab ages ago that I've been meaning to port if you're interested. It is good for polygon offsets, though I'm not sure how that would relate to polygon fillets or especially to mesh fillets?

@Trzeth
Copy link
Contributor Author
Trzeth commented Apr 25, 2025

Actually I have a straight skeleton algorithm I implemented in Matlab ages ago that I've been meaning to port if you're interested. It is good for polygon offsets, though I'm not sure how that would relate to polygon fillets or especially to mesh fillets?

@elalish
Yes! I would like to see your straight skeleton algorithm if you have time to port!

Besides, I think it might require using Clipper to maintain robustness , as otherwise, construct new point could lead to floating-point precision issues and numerical instability. Do you think my consideration exist?

And yes, it's more relevant to offsets. Since this is a sudden thought, I want to keep offset thread clean so put it here .

@elalish
Copy link
Owner

I don't have time to port it at the moment - it'll probably take me a week just to dredge up the old Matlab script from my archives. If you'd be interested in reading through it and trying to port it to C++, I'll be happy to give pointers. The main thing was using SVD to calculate skeleton verts from sets of three edges, so as to also get a numerical uncertainty. I used this to merge verts, which keeps the numerics stable. A Hilbert curve is a great test case, and shows why degeneracy is so common in the straight skeleton.

@Trzeth
Copy link
Contributor Author
Trzeth commented Apr 25, 2025

Thanks! I'll give it a try.

@pca006132
Copy link
Collaborator

image

Notes about today's meeting. Consider the polygon with a hole in the middle. If we define fillet using rolling ball (blue) directly, we will get two rounded squares at the bottom because the middle section can't fit a ball inside.

The issue here is that this changes the topology in a potentially weird way, so maybe we can try not to remove stuff when removing it can change the contour. With this interpretation, we get the result at the top.

@Trzeth
Copy link
Contributor Author
Trzeth commented Jun 10, 2025

My current thought is to process vertex one by one. If there is no solution in the neighbor, we will find it via adjacent vertex circles overlapping. It can simply be proven. This gives a better result than rolling sphere method ends up nothing, see the second figure.

However, I still need to find a way to search for a solution for adjacent overlapping circles. I'm currently thinking about using an inward offset to find a possible solution area.

What do you think about it? CC @elalish @pca006132

未命名绘图 drawio

未命名绘图-第 3 页 drawio

@elalish
Copy link
Owner
elalish commented Jun 10, 2025

Our Collider BVH should give you an efficient way to search for overlapping circles. How about you focus on writing this up as code here so we can start to test it on real polygons. No need for it to handle every edge case yet, but if it runs, we'll be able to discuss it more easily with examples.

You might consider writing it in such a way that it can incrementally create the fillets, so that if it runs into trouble, we can dump out the intermediate result in a form we can visualize.

@pca006132
Copy link
Collaborator

And what do you mean by adjacent vertex circle overlapping? Can you give a more detailed example? Or explain why the 3 circles in your first figure are different in sizes.

@Trzeth
Copy link
Contributor Author
Trzeth commented Jun 11, 2025
8000

未命名绘图-第 1 页 drawio
Sorry for the unclear description, here is what I'm thinking.

Since we are focusing on 2d convex vertex fillet, I am processing convex vertex one by one, calculating the intersect point and bridge with an arc. See Figure 1, this is when the fillet radius is relatively small.
Assume process vertex one by one, I was worried that the adjacent vertex would create overlapping arcs with a large radius, which would result in a strange two arcs combined shape, see Figure 2. But it can be simply proven if overlap exists, there is no solution in the neighborhood.
See Figure 3, with an increased radius, two circles will end up cutting three edges, after that there is no solution in the neighborhood. So we can rule out e2, that's what I'm trying to say before.

As we rule out e2, we have to find a solution between e1 and e3. The solution might meet the concave vertex and split the shape into two parts, that's what I currently achieved. See Figure 5.

未命名绘图-第 4 页 drawio

But there are also situations where no solution existed between e1 and e3, and need to do a global search for a solution. Last week, I was trying to find it locally but have no idea.
The last meeting @pca006132 suggests to split the polygon into regions and cutting out the no solution part. But I found it hard to properly split it. I tried splitting into a convex polygon, but since the region is partly open, it's hard to get the maximum radius of the region, see Figure 7. Then I was trying to tweak around bisector, but the thought is still unclear.

Another idea is using offset to get a possible solution region nearly, which is also not so clear.

Maybe I should just start coding and get some results at least.

@pca006132
Copy link
Collaborator
pca006132 commented Jun 11, 2025

The last meeting @pca006132 suggests to split the polygon into regions and cutting out the no solution part. But I found it hard to properly split it. I tried splitting into a convex polygon, but since the region is partly open, it's hard to get the maximum radius of the region, see Figure 7. Then I was trying to tweak around bisector, but the thought is still unclear.

No, maybe I should explain it a bit better.

image

Here, the blue area is where the fixed-radius circle can reach. The issue is that it has a different topology than the thing we started with. So we fill in the green area to make the topology the same as the original, and the final result is the colored region.

image

Here, it is mostly similar to the example above. However, the two red regions on the right are not significant in terms of topology, so we can simply remove them.

The question here is can we figure out a simple way to compute this. Maybe we can split the edges, compute if each segment can touch the circle, from this we can find the edges that are in the same blue component. And for the remaining edges, we can check if they connect different blue components, and if yes we keep them.

Assume process vertex one by one, I was worried that the adjacent vertex would create overlapping arcs with a large radius, which would result in a strange two arcs combined shape, see Figure 2. But it can be simply proven if overlap exists, there is no solution in the neighborhood.

I think if you have something like figure 2, this means you can't have a circle that touches both e1 and e2 and fits within the polygon. Similarly for e2 and e3. This means that e2 should go.

@pca006132
Copy link
Collaborator
pca006132 commented Jun 13, 2025

Some trivial stuff related to the algorithm that you may consider:

image

For every oriented edge, we check the red region for other edges. If there are no other edges, we must be able to fit circles inside the red region, so the edge must be kept. Otherwise, there are several cases: tangent--tangent, tangent--point, point--point. For all cases, we need to ensure that no other edges can intersect the circle, or it will be invalid. For tangents, we split the edge and do the check recursively. For points, we add an edge to join them (and split the polygon). For the degenerate case where there is another edge that touches the circle, we ignore that because it doesn't matter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
5D87
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0