January 18, 2025

About

Methods for representing shape data using Deep Neural Networks have recently begun to be proposed, such as BrepGen, which generates data that directly represents shapes in Brep format, and DeepCAD, which generates sequences of CAD commands to describe such data.

DeepCAD Generation Network Architecture from their paper[1]

Checking Core Part of Shape Generation

Top Flow of the Code

It is a simple process of generating CAD data (STEP files) from a CADSequence class object via Open CASCADE Technology.

https://github.com/ChrisWu1997/DeepCAD/blob/f7b350790a3bce0267a5345339fd09be0250c8cb/utils/export2step.py#L43-L45

cad_seq = CADSequence.from_dict(data)
cad_seq.normalize()
out_shape = create_CAD(cad_seq)

How it Composes shape as an object

Shapes are constructed through combinations of Boolean operations between shapes. Each shape is described using the common sketch-and-extrude method.

https://github.com/ChrisWu1997/DeepCAD/blob/master/cadlib/visualize.py#L25


def create_CAD(cad_seq: CADSequence):
    """create a 3D CAD model from CADSequence. Only support extrude with boolean operation."""
    body = create_by_extrude(cad_seq.seq[0])
    for extrude_op in cad_seq.seq[1:]:
        new_body = create_by_extrude(extrude_op)
        if extrude_op.operation == EXTRUDE_OPERATIONS.index("NewBodyFeatureOperation") or \
                extrude_op.operation == EXTRUDE_OPERATIONS.index("JoinFeatureOperation"):
            body = BRepAlgoAPI_Fuse(body, new_body).Shape()
        elif extrude_op.operation == EXTRUDE_OPERATIONS.index("CutFeatureOperation"):
            body = BRepAlgoAPI_Cut(body, new_body).Shape()
        elif extrude_op.operation == EXTRUDE_OPERATIONS.index("IntersectFeatureOperation"):
            body = BRepAlgoAPI_Common(body, new_body).Shape()
    return body


def create_by_extrude(extrude_op: Extrude):
    """create a solid body from Extrude instance."""
    profile = copy(extrude_op.profile) # use copy to prevent changing extrude_op internally
    profile.denormalize(extrude_op.sketch_size)

    sketch_plane = copy(extrude_op.sketch_plane)
    sketch_plane.origin = extrude_op.sketch_pos

    face = create_profile_face(profile, sketch_plane)
    normal = gp_Dir(*extrude_op.sketch_plane.normal)
    ext_vec = gp_Vec(normal).Multiplied(extrude_op.extent_one)
    body = BRepPrimAPI_MakePrism(face, ext_vec).Shape()
    if extrude_op.extent_type == EXTENT_TYPE.index("SymmetricFeatureExtentType"):
        body_sym = BRepPrimAPI_MakePrism(face, ext_vec.Reversed()).Shape()
        body = BRepAlgoAPI_Fuse(body, body_sym).Shape()
    if extrude_op.extent_type == EXTENT_TYPE.index("TwoSidesFeatureExtentType"):
        ext_vec = gp_Vec(normal.Reversed()).Multiplied(extrude_op.extent_two)
        body_two = BRepPrimAPI_MakePrism(face, ext_vec).Shape()
        body = BRepAlgoAPI_Fuse(body, body_two).Shape()
    return body

Sketch

How is the sketch in the sketch-and-extrude process structured?
The sketch is defined by an object created from the Profile class within the Extrude class. Furthermore, this Profile class consists of a list of multiple Loop class objects, as shown below.

In other words, a Loop consists of multiple curves that together form a closed region.

https://github.com/ChrisWu1997/DeepCAD/blob/master/cadlib/sketch.py#L211

class Loop(SketchBase):
    """Sketch loop, a sequence of connected curves."""
    @staticmethod
    def from_dict(stat):
        all_curves = [construct_curve_from_dict(item) for item in stat['profile_curves']]
        this_loop = Loop(all_curves)
        this_loop.is_outer = stat['is_outer']
        return this_loop

...

class Profile(SketchBase):
    """Sketch profile,a closed region formed by one or more loops. 
    The outer-most loop is placed at first."""
    @staticmethod
    def from_dict(stat):
        all_loops = [Loop.from_dict(item) for item in stat['loops']]
        return Profile(all_loops)


class Extrude(object):
    """Single extrude operation with corresponding a sketch profile.
    NOTE: only support single sketch profile. Extrusion with multiple profiles is decomposed."""
    def __init__(self, profile: Profile, sketch_plane: CoordSystem,
                 operation, extent_type, extent_one, extent_two, sketch_pos, sketch_size):
        """
        Args:
            profile (Profile): normalized sketch profile
            sketch_plane (CoordSystem): coordinate system for sketch plane
            operation (int): index of EXTRUDE_OPERATIONS, see macro.py
            extent_type (int): index of EXTENT_TYPE, see macro.py
            extent_one (float): extrude distance in normal direction (NOTE: it's negative in some data)
            extent_two (float): extrude distance in opposite direction
            sketch_pos (np.array): the global 3D position of sketch starting point
            sketch_size (float): size of the sketch
        """
        self.profile = profile # normalized sketch
        self.sketch_plane = sketch_plane
        self.operation = operation
        self.extent_type = extent_type
        self.extent_one = extent_one
        self.extent_two = extent_two

Lines (Curves)

The curve mentioned above belongs to one of three classes—line, circle, or circular arc—each of which inherits from the CurveBase class.

https://github.com/ChrisWu1997/DeepCAD/blob/master/cadlib/curves.py#L9

def construct_curve_from_dict(stat):
    if stat['type'] == "Line3D":
        return Line.from_dict(stat)
    elif stat['type'] == "Circle3D":
        return Circle.from_dict(stat)
    elif stat['type'] == "Arc3D":
        return Arc.from_dict(stat)
    else:
        raise NotImplementedError("curve type not supported yet: {}".format(stat['type']))

Thoughts

The approach of constructing the final geometry by combining very simple shapes may currently face challenges in representing complex shapes. However, this simple composition aligns well with the research objective of clearly defining what is possible and to what extent. I believe the approach they have demonstrated will have a significant impact on future research and development. Evaluating the generation of 3D shapes based on “accuracy” is particularly intriguing, and further advancements in this area are highly anticipated. Additionally, their code is remarkably refined and elegant, making it truly impressive.

Reference

[1] https://arxiv.org/abs/2105.09492

[2] https://github.com/ChrisWu1997/DeepCAD/tree/master

[3] https://arxiv.org/abs/2401.15563