Padding

This example demonstrates the qtcad.builder.Builder.pad_group operation.

Initialization

from qtcad.builder import Builder
from qtcad.builder import Mask, Polygon

2D Padding

The pad_group works on 2D and 3D groups. We will now demonstrate the former. We use circular shapes here as they better demonstrate the effects of growth parameters on curved surfaces.

from qtcad.builder import Circle

circle_1 = Circle(name="gate_1").centered().translated(-2, 0)
circle_2 = Circle(name="gate_2").centered().translated(2, 0)

gate_mask_2d = Mask("gates")
gate_mask_2d.add_shape(circle_1)
gate_mask_2d.add_shape(circle_2)

builder_2d = (
    Builder(name="padding demo 2d")
    .set_mesh_size(10)
    .add_mask(gate_mask_2d)
    .group_from_mask()
    .add_surface()
)
[15:24:27] INFO     Creating a surface from shape 0 with name       builder.py:2500
                    'gates' from mask 'gates' at z=0
           INFO     Creating new physical group with name 'gates'   builder.py:2580
           INFO     Creating a surface from shape 1 with name       builder.py:2500
                    'gates' from mask 'gates' at z=0
           INFO     Fragmenting...                                fragmenter.py:218

At this point we have two circular 2D “gates”

builder_2d.view(
    surfaces=True,
    volume_labels=False,
    save="figs/before_padding_2d.svg",
)
padding
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd41c3c550>

Now we add padding around the 2D gates. The grow_accuracy and grow_complexity arguments can be used to control the algorithm used to grow the shapes.

Builder.pad_group(group: str | list[str] | Callable[[PhysicalGroup], bool], thickness: float, padding_suffix: str = '_padding', noclip: bool = False, grow_complexity: float = 10.0, grow_accuracy: int = 100, min_curve_nodes: int = 20) Self

[🏗️ Operation] Add a padding layer of thickness around the volumes in volume group with name group_name. The newly created padding volume will be named group_name + padding_suffix and clipped horizontally by the currently selected shapes unless noclip is True.

Parameters:
  • group – The group(s) to pad. See get_group for details on the allowed types.

  • thickness – The padding thickness.

  • padding_suffix – Suffix to append to the group name for the new volume.

  • noclip – If True, no horizontal clipping will occur. Default is False.

  • grow_complexity – See grow().

  • grow_accuracy – See grow().

  • min_curve_nodes – See grow().

First, we can pad both shapes at once by referencing the mask group:

builder_2d.pad_group(
    "gates",
    2,
    noclip=True,
    grow_complexity=5,
)
           INFO     Padding Physical Group 'gates' of dimension 2    builder.py:462
                    with a layer of thickness 2
           INFO     Growing surface (2, 3)...                       builder.py:3493
           INFO     Growing surface (2, 4)...                       builder.py:3493
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'gates_padding'
           INFO     Restored z coordinate to 0                      builder.py:3540

<qtcad.builder.builder.Builder object at 0x75dd41c3c550>

Viewing the result for padding both shapes at once

builder_2d.view(
    surfaces=True,
    volume_labels=False,
    save="figs/final_2d_grouped.svg",
)
padding
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd41c3c550>

Padding Shapes Individually

We will now pad the shapes individually to demonstrate the effect of the control parameters.

  • Higher grow_complexity leads to more complex grown shapes (more facets), but increases runtime (increasing the complexity of the resulting CAD model).

  • Higher grow_accuracy increases the precision of the grown shapes, also at the cost of runtime.

We demonstrate this by comparing three circles:

circle_1 = Circle(name="gate_1").centered().translated(-4, 0)
circle_2 = Circle(name="gate_2").centered().translated(0, 0)
circle_3 = Circle(name="gate_3").centered().translated(4, 0)

gate_mask_indiv = Mask("gates_indiv")
gate_mask_indiv.add_shape(circle_1)
gate_mask_indiv.add_shape(circle_2)
gate_mask_indiv.add_shape(circle_3)

builder_indiv = Builder(name="padding demo 2d individual")
(builder_indiv.add_mask(gate_mask_indiv).group_from_shape().add_surface())
[15:24:28] INFO     Creating a surface from shape 0 with name       builder.py:2500
                    'gate_1' from mask 'gates_indiv' at z=0
           INFO     Creating new physical group with name 'gate_1'  builder.py:2580
           INFO     Creating a surface from shape 1 with name       builder.py:2500
                    'gate_2' from mask 'gates_indiv' at z=0
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name 'gate_2'  builder.py:2580
           INFO     Creating a surface from shape 2 with name       builder.py:2500
                    'gate_3' from mask 'gates_indiv' at z=0
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name 'gate_3'  builder.py:2580

<qtcad.builder.builder.Builder object at 0x75dd41c3ce10>

Now we apply padding with different parameters:

  1. gate_1: Low complexity (2) but high accuracy (1000). This results in a coarse, polygonal padding (few facets).

  2. gate_2: High complexity (20) but low accuracy (1). This may lead to geometric artifacts or imprecision.

  3. gate_3: High complexity (20) and high accuracy (1000). This results in a smooth, accurate circular padding.

(
    builder_indiv.pad_group(
        "gate_1", 1, noclip=True, grow_complexity=0.05, grow_accuracy=1000
    )
    .pad_group("gate_2", 1, noclip=True, grow_complexity=20, grow_accuracy=1)
    .pad_group("gate_3", 1, noclip=True, grow_complexity=20, grow_accuracy=1000)
)
           INFO     Padding Physical Group 'gate_1' of dimension 2   builder.py:462
                    with a layer of thickness 1
           INFO     Growing surface (2, 4)...                       builder.py:3493
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_padding'
           INFO     Restored z coordinate to 0                      builder.py:3540
           INFO     Padding Physical Group 'gate_2' of dimension 2   builder.py:462
                    with a layer of thickness 1
           INFO     Growing surface (2, 7)...                       builder.py:3493
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_padding'
           INFO     Restored z coordinate to 0                      builder.py:3540
           INFO     Padding Physical Group 'gate_3' of dimension 2   builder.py:462
                    with a layer of thickness 1
           INFO     Growing surface (2, 10)...                      builder.py:3493
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_3_padding'
           INFO     Restored z coordinate to 0                      builder.py:3540

<qtcad.builder.builder.Builder object at 0x75dd41c3ce10>

Viewing the result of individual padding

builder_indiv.view(
    surfaces=True, volume_labels=False, save="figs/final_2d_individual.svg"
)
padding
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd41c3ce10>

3D Padding

Setting up the shapes

Here we define the device substrate shape (a simple box)…

substrate = Polygon.box(10, 10, name="substrate").centered()

… and the two “gates”

gate_1 = Polygon.box(10, 1, name="gate_1").centered().translated(0, -2)
gate_2 = gate_1.translated(0, 4).named("gate_2")

Finally we assemble them into masks

box_mask = Mask("substrate")
box_mask.add_shape(substrate)
gate_mask = Mask("gates")
gate_mask.add_shape(gate_1)
gate_mask.add_shape(gate_2)
Polygon(name='gate_2', id=1, hull=[(-5, 1.5), (-5, 2.5), (5, 2.5), (5, 1.5)], holes=[])

Generating the geometry

builder = Builder(name="padding demo")

(
    builder.set_mesh_size(10)
    .add_mask(box_mask)
    .add_mask(gate_mask)
    .group_from_shape()
    .use_mask("substrate")
    .use_shape("substrate")
    .extrude(3)
    .use_mask("gates")
    .extrude(0.4)
)
[15:24:29] INFO     Using mask 'substrate' (implicitly selecting     builder.py:801
                    shapes [Polygon 0 'substrate'])
           INFO     Selected shapes: [Polygon 0 'substrate']         builder.py:854
           INFO     Extruding shape 0 from mask 'substrate' with    builder.py:2794
                    name 'substrate' by 3 at z=0
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate_hull'
           INFO     Creating new physical group with name           builder.py:2580
                    'substrate'
           INFO     Setting z-coordinate to 3                        builder.py:903
           INFO     Using mask 'gates' (implicitly selecting shapes  builder.py:801
                    [Polygon 0 'substrate'])
           INFO     Extruding shape 0 from mask 'gates' with name   builder.py:2794
                    'gate_1' by 0.4 at z=3
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_hull'
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name 'gate_1'  builder.py:2580
           INFO     Extruding shape 1 from mask 'gates' with name   builder.py:2794
                    'gate_2' by 0.4 at z=3
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_hull'
           INFO     Fragmenting...                                fragmenter.py:218
           INFO     Creating new physical group with name 'gate_2'  builder.py:2580
           INFO     Setting z-coordinate to 3.4                      builder.py:903

<qtcad.builder.builder.Builder object at 0x75dd41c3cb90>

At this point we have two “gates” on top of a “substrate”

builder.view(
    surfaces=False,
    volume_labels=True,
    angles=(-45, 0, 45),
    save="figs/before_padding.svg",
)
padding
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd41c3cb90>

Now we add padding around those gates. The first padding will not be clipped, whereas the padding around the second gate will be clipped by the substrate shape we selected beforehand. We also set polygonize=False for the first gate to create a curved padding volume.

(
    builder.use_mask("substrate")
    .use_shape("substrate")
    .pad_group("gate_1", 0.6, noclip=False)
    .pad_group("gate_2", 0.6, noclip=True)
)
[15:24:30] INFO     Using mask 'substrate' (implicitly selecting     builder.py:801
                    shapes [Polygon 0 'substrate'])
           INFO     Selected shapes: [Polygon 0 'substrate']         builder.py:854
           INFO     Padding Physical Group 'gate_1' of dimension 3   builder.py:462
                    with a layer of thickness 0.6 (clipping with
                    shapes with shapes: [Polygon 0 'substrate'])
           INFO     Growing volume (3, 6)...                        builder.py:3290
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:24:31] INFO     Creating new physical group with name           builder.py:2580
                    'gate_1_padding'
           INFO     Padding Physical Group 'gate_2' of dimension 3   builder.py:462
                    with a layer of thickness 0.6
[15:24:32] INFO     Growing volume (3, 11)...                       builder.py:3290
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_padding_bottom'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_padding_side'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_padding_top'
           INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_padding_hull'
           INFO     Fragmenting...                                fragmenter.py:218
[15:24:34] INFO     Creating new physical group with name           builder.py:2580
                    'gate_2_padding'

<qtcad.builder.builder.Builder object at 0x75dd41c3cb90>

Viewing the result

builder.view(surfaces=False, angles=(-45, 0, 45), save="figs/final.svg")
padding
           INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd41c3cb90>

Hiding the padding volume

builder.view(
    True,
    groups=["gate_1", "gate_2", "substrate"],
    surfaces=True,
    volume_labels=True,
    angles=(-90, 0, 90),
    orthographic=True,
    save="figs/padding_removed.svg",
)
padding
[15:24:35] INFO     Saving figure                                   builder.py:1926

<qtcad.builder.builder.Builder object at 0x75dd41c3cb90>

Total running time of the script: (0 minutes 9.579 seconds)

Gallery generated by Sphinx-Gallery