Introductory Example
Overview
The code provided in this section is the introductory example as given on the Github repository's Readme and the documentation's Home tab.
This script:
- Loads printing presets and resources:
- Reads a
.toml
preset file and initializes custom presets with parameters like writing speed, power, and hatching settings. -
Imports a 3D mesh (
example_mesh.stl
) and a marker image (example_marker.png
). -
Sets up alignment configurations:
- Defines
CoarseAligner
andMarkerAligner
nodes for nano-printing alignment, with manual anchor positions. -
Integrates GDS cell data (
gds_file.gds
) to create a customInterfaceAligner
with anchor positions/scan sizes defined by polygons in a GDS file. -
Organizes the printing hierarchy:
- Initializes a
Scene
with upward writing direction and attaches aStructure
(using the mesh and preset). -
Builds a node hierarchy with coarse alignment, scene, interface alignment, and marker alignment.
-
Duplicates and modifies scenes:
-
Clones scenes, translates their positions, and updates their presets/names for multi-scene arrangements.
-
Exports the project:
- Generates a
.nano
file for and validates node hierarchy viaproject.tree()
.
Prerequisites
Files/Directories:
- preset_from_file.toml
(preset configuration).
- example_mesh.stl
(3D structure mesh).
- example_marker.png
(alignment marker image).
- gds_file.gds
(GDSII design for interface alignment).
Python Packages:
- npxpy
installed with key all
: pip install npxpy[all]
.
- shapely
& gdshelpers
(for GDS parsing and geometry operations).
You can download the full example below:
Full Implementation
import npxpy
# Initialize the presets and resources that you want to use in this project.
# You can either load presets directly from a .toml...
preset_from_file = npxpy.Preset.load_single(file_path="preset_from_file.toml")
# ... or initialize it inside of your script.
edit_presets = {
"writing_speed": 220000.0,
"writing_power": 50.0,
"slicing_spacing": 0.8,
"hatching_spacing": 0.3,
"hatching_angle": 0.0,
"hatching_angle_increment": 0.0,
"hatching_offset": 0.0,
"hatching_offset_increment": 0.0,
"hatching_back_n_forth": True,
"mesh_z_offset": 0.0,
}
preset_from_args = npxpy.Preset(name="preset_from_args", **edit_presets)
# Load your resources simply via path to their directories.
stl_mesh = npxpy.Mesh(file_path="./example_mesh.stl", name="stl_structure")
marker = npxpy.Image(file_path="./example_marker.png", name="marker_image")
# Initialize your project and load your presets and resources into it.
project = npxpy.Project(objective="25x", resin="IP-n162", substrate="FuSi")
project.load_presets(preset_from_file, preset_from_args)
project.load_resources(stl_mesh, marker)
# Prepare the nodes of your project as usual.
# Setup alignment nodes
coarse_aligner = npxpy.CoarseAligner(residual_threshold=8)
marker_aligner = npxpy.MarkerAligner(
name="Marker Aligner", image=marker, marker_size=[10, 10]
)
# Set anchors manually...
ca_positions = [
[200.0, 200.0, 0.0],
[200.0, -200.0, 0.0],
[-200.0, -200.0, 0.0],
[-200.0, 200.0, 0.0],
]
ma_positions = [
[0, 200, 0.33],
[200, 0, 0.33],
[0, -200, 0.33],
[-200, 0, 0.33],
]
coarse_aligner.set_coarse_anchors_at(ca_positions)
marker_aligner.set_markers_at(ma_positions)
# ... or incorporate them in a GDS-design and read them in.
import npxpy.gds
gds = npxpy.gds.GDSParser("gds_file.gds")
interface_aligner = gds.get_custom_interface_aligner(
cell_name="cell_with_print_scene",
interface_layer=(1, 0),
signal_type="reflection",
detector_type="confocal",
area_measurement=True,
measure_tilt=True,
)
# Initiale printing scene
scene = npxpy.Scene(name="scene", writing_direction_upward=True)
# Initialize structure with desired preset and mesh defined above.
structure = npxpy.Structure(
name="structure", preset=preset_from_file, mesh=stl_mesh
)
# Arrange hierarchy of all nodes as desired either with .add_child()...
coarse_aligner.add_child(scene.add_child(interface_aligner))
# ...or more conveniently by using .append_node() to append
# consecutively to the lowest node.
scene.append_node(marker_aligner, structure)
# Eventually, add all highest-order nodes of interest
# (here only coarse_aligner) to project.
project.add_child(coarse_aligner)
# After allocating your nodes, you can copy, manipulate and add additional
# instances as you like.
scene_1 = scene.deepcopy_node(copy_children=True)
scene_1.name = "scene_1"
scene_1.translate([254.0, 300.0, 0.0])
# You can access descendants/ancestors as you go via semantically ordered lists.
structure_1 = scene_1.all_descendants[-1]
structure_1.preset = preset_from_args
structure_1.name = "structure_1"
coarse_aligner.add_child(scene_1)
# Checking the node order can be done as well
project.tree()
# Export your project to a .nano-file.
project.nano(project_name="my_project")
In addition, you can regard your project in the viewport.
# Check Project in Viewport
project.viewport()