Unexpected Results from BRepFill_Filling() with Non-Planar Offset Wire

Artem K

CAD practitioner
Hello everyone,

I've managed to construct offsets for non-planar helix-like lines. This is because MakeOffset() doesn't work with non-planar curves.
My method involved using Geom_OffsetCurve() and creating arcs at the end of two parallel curves to put it simply.
The result is an offset wire with a certain radius.

Here's an illustration of the result with the input curve on the inside and the output wire on the outside:

1684438304925.png

I implemented this using PythonOCC and the following is my code:

Code:
def make_offset(input_curve, radius):

# Calculate the two parallel curves using Geom_OffsetCurve
    parallel_1 = Geom_OffsetCurve(input_curve, radius, gp_Dir(0, 0, 1))
    parallel_2 = Geom_OffsetCurve(input_curve, radius, gp_Dir(0, 0, -1))

# Close the parallel curves with arcs of the same radius
    parallel_1_start = parallel_1.Value(parallel_1.FirstParameter())
    parallel_2_start = parallel_2.Value(parallel_2.FirstParameter())
    parallel_1_end = parallel_1.Value(parallel_1.LastParameter())
    parallel_2_end = parallel_2.Value(parallel_2.LastParameter())

# Get tangent vectors for the parallel curves
    vec1 = get_tangent_vector(input_curve, input_curve.FirstParameter())
    vec2 = get_tangent_vector(input_curve, input_curve.LastParameter())

# Make arcs from two points and vector
    arc1 = GC_MakeArcOfCircle(parallel_1_start, vec1.Reversed(), parallel_2_start).Value()
    arc2 = GC_MakeArcOfCircle(parallel_2_end, vec2, parallel_1_end).Value()

# Fill offset
    fill = BRepFill_Filling()
    fill.Add(BRepBuilderAPI_MakeEdge(parallel_1).Edge(), GeomAbs_C0)
    fill.Add(BRepBuilderAPI_MakeEdge(arc1).Edge(), GeomAbs_C0)
    fill.Add(BRepBuilderAPI_MakeEdge(parallel_2).Edge(), GeomAbs_C0)
    fill.Add(BRepBuilderAPI_MakeEdge(arc2).Edge(), GeomAbs_C0)
    fill.Build()
    face = fill.Face()

# Make a wire from the parallel curves and arcs
    wire_builder = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(arc2).Edge())
    wire_builder.Add(BRepBuilderAPI_MakeEdge(parallel_1).Edge())
    wire_builder.Add(BRepBuilderAPI_MakeEdge(arc1).Edge())
    wire_builder.Add(BRepBuilderAPI_MakeEdge(parallel_2).Edge())
    wire = wire_builder.Wire()

return wire, face

However, I'm encountering a challenge when trying to fill this wire using BRepFill_Filling(). The output face appears curved and exhibits noticeable dips and rises.

I've attached images to better illustrate this issue:

1684439349001.png1684439239129.png

1684439510328.png

Ideally, I want to achieve a more planar face that doesn't have these curves.

Here's an example of what I'm aiming for:

1684439687566.png



Could I be doing something wrong, or is it simply impossible to achieve the result I'm aiming for?

I would greatly appreciate any guidance or suggestions on this matter.
 

Quaoar

Administrator
Staff member
Can you attach the brep file for the face you got with constrained filling?
 

Quaoar

Administrator
Staff member
Have you tried GeomPlate algorithm? It is the GeomPlate_BuildPlateSurface class.

1684442993061.png

It looks a little bit smoother in the result.
 

Attachments

  • plate.brep
    96.6 KB · Views: 2
Last edited:

Artem K

CAD practitioner
Thank you for your help. I managed to use GeomPlate_BuildPlateSurface(), and the results look great.

May I take advantage of your kindness and ask one more question?

Are there methods in OCCT to delete additional edges that lie on a plane from this shape, or methods to simplify it?
1684479947169.png
This result is due to many boolean operations, and this complex shape decreases the time for every subsequent operation.
 

Quaoar

Administrator
Staff member
Is this material removal simulation? How good is it with OpenCascade's Booleans? I bet it shouldn't be super fast :)

You can try ShapeUpgrade_UnifySameDomain for removing imprinted edges and this way maximize analytical faces in the shape.
 

Artem K

CAD practitioner
Thank you.
I see you're aware of it. Yes, you are right. It isn't particularly fast (achieving only up to 5-6 operations per second per thread), but it's faster than other Python frameworks, especially in the BRep approach.
And I know that Python is not the best language for this task.😁
 

Quaoar

Administrator
Staff member
I'm curious how far have you managed to get with this BOP-based approach. Never tried to implement something like this myself but I heard that other people used some other shape representation techniques, such as dexels, voxels, ad-hoc wireframes to give such an algorithm a somewhat better FPS. It's a hell of work :-\
 

Artem K

CAD practitioner
Right. Not many scientists simulate volume removal processes because it requires specific knowledge, abilities, and resources. To the best of my knowledge, many current approaches use dexels or voxels because they are stable, accurate enough, and can be fast with an adequate level of interpolation and element sizes. We are at the stage of developing and stabilizing a method for determining the volume of material removed in 3D CNC milling using the BRep approach.
 

Quaoar

Administrator
Staff member
Interesting. Our take on rough milling volume estimation was/is based on feature recognition. We first identify all prismatic features (not to mention holes as they are easy to process), and then try to construct their corresponding negative volumes by extruding those features' outlines towards the bounding box representing the stock shape (see animation attached).

But this does not imply constructing any cutting trajectories as the final goal is just to estimate the fabrication cost based on the material wastage and tooling, including setups. What you're doing looks more advanced to me.
 

Attachments

  • nv-milling_02.gif
    nv-milling_02.gif
    102.3 KB · Views: 6

Artem K

CAD practitioner
It appears you have some theory on how to convert these primitives into costs.

We don't construct trajectories, instead, we use the completed CNC program from CAM systems and simulate the milling process to calculate the total removal volume along the entire trajectory, and then remove this volume from the stock model.

If you can achieve a better Material Removal Rate (MRR), you become more efficient.
( small demo attached).
Untitled video - Made with Clipchamp.gif
 
Last edited:

blobfish

CAD community veteran
Hello everyone,

I've managed to construct offsets for non-planar helix-like lines. This is because MakeOffset() doesn't work with non-planar curves.
My method involved using Geom_OffsetCurve() and creating arcs at the end of two parallel curves to put it simply.
The result is an offset wire with a certain radius.

Here's an illustration of the result with the input curve on the inside and the output wire on the outside:

View attachment 594

I implemented this using PythonOCC and the following is my code:

Code:
def make_offset(input_curve, radius):

# Calculate the two parallel curves using Geom_OffsetCurve
    parallel_1 = Geom_OffsetCurve(input_curve, radius, gp_Dir(0, 0, 1))
    parallel_2 = Geom_OffsetCurve(input_curve, radius, gp_Dir(0, 0, -1))

# Close the parallel curves with arcs of the same radius
    parallel_1_start = parallel_1.Value(parallel_1.FirstParameter())
    parallel_2_start = parallel_2.Value(parallel_2.FirstParameter())
    parallel_1_end = parallel_1.Value(parallel_1.LastParameter())
    parallel_2_end = parallel_2.Value(parallel_2.LastParameter())

# Get tangent vectors for the parallel curves
    vec1 = get_tangent_vector(input_curve, input_curve.FirstParameter())
    vec2 = get_tangent_vector(input_curve, input_curve.LastParameter())

# Make arcs from two points and vector
    arc1 = GC_MakeArcOfCircle(parallel_1_start, vec1.Reversed(), parallel_2_start).Value()
    arc2 = GC_MakeArcOfCircle(parallel_2_end, vec2, parallel_1_end).Value()

# Fill offset
    fill = BRepFill_Filling()
    fill.Add(BRepBuilderAPI_MakeEdge(parallel_1).Edge(), GeomAbs_C0)
    fill.Add(BRepBuilderAPI_MakeEdge(arc1).Edge(), GeomAbs_C0)
    fill.Add(BRepBuilderAPI_MakeEdge(parallel_2).Edge(), GeomAbs_C0)
    fill.Add(BRepBuilderAPI_MakeEdge(arc2).Edge(), GeomAbs_C0)
    fill.Build()
    face = fill.Face()

# Make a wire from the parallel curves and arcs
    wire_builder = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(arc2).Edge())
    wire_builder.Add(BRepBuilderAPI_MakeEdge(parallel_1).Edge())
    wire_builder.Add(BRepBuilderAPI_MakeEdge(arc1).Edge())
    wire_builder.Add(BRepBuilderAPI_MakeEdge(parallel_2).Edge())
    wire = wire_builder.Wire()

return wire, face

However, I'm encountering a challenge when trying to fill this wire using BRepFill_Filling(). The output face appears curved and exhibits noticeable dips and rises.

I've attached images to better illustrate this issue:

View attachment 596View attachment 595

View attachment 597

Ideally, I want to achieve a more planar face that doesn't have these curves.

Here's an example of what I'm aiming for:

View attachment 598



Could I be doing something wrong, or is it simply impossible to achieve the result I'm aiming for?

I would greatly appreciate any guidance or suggestions on this matter.
I don't know how you derived the offset curves, but I am thinking:
create the surface first by sweeping a line along helix, making sure things are bigger than the finished face.
project helix onto surface making a pcurve.
create offset edges in 2d parametric space.
use the offset edges.

as a prototype test, I created something like your helix and a cross section line. I swept the line along the helix using frenet. The result looks close to your original edges. I didn't create the offset curves as I described above, I just extruded your face edges and trimmed back my swept surface. See attached file.
 

Attachments

  • blobfishFace.brep
    34.1 KB · Views: 4
Top