Printy3D

Tools

Structural analysis

Voxel finite-element tools that estimate whether a print will hold up: under its own weight, standing or held, with stress heatmaps and break-risk points. One more turns a texture into relief.

Each runs as {"recipe": "tool", "tool": "structural.<name>", "params": {…}} and computes exactly one analysis. The numbers are in job.result.result; meshes come back as OBJ artifacts (heatmap, result_obj, result_parts_obj_zip).

Common parameters#

Every structural tool except structural.relief takes these. The model is voxelized, given a material, supported and loaded.

up_axis0 | 1 | 2default 1

Which axis points up: 0 = X, 1 = Y, 2 = Z.

voxel_size_mmnumberdefault 00–100

Voxel size of the analysis grid; 0 chooses it automatically.

support_gap_voxelsintegerdefault 31–100

The gap, in voxels, the engine allows when it decides which voxels are supported.

materialpreset | objectdefault "generic"

A preset name or your own values; see below. Every result echoes the material used.

target_safety_factornumberdefault 2.01–100

The safety factor a part should reach; results report how much of it falls short.

load_gnumberdefault 1.00–1000

Gravity multiplier: 1 is the part's own weight, 3 three times it.

Materials#

presetE (MPa)νρ (g/cm³)Yield (MPa)Stress metricSource
generic20000.301.1050von_misesengine default
pla32000.311.2450von_misespublished, conservative
formlabs_grey_v526750.351.1862max_principaldatasheet
mimaki_mh10022000.351.1745max_principalinferred (ABS-like; Mimaki publishes no mechanical data)

Or send the values yourself:

params.material
{ "youngs_modulus_mpa": 2400, "poisson_ratio": 0.35, "density_g_cm3": 1.2,
  "yield_strength_mpa": 40, "stress_metric": "von_mises" }
youngs_modulus_mpanumberrequired> 0, ≤ 1,000,000

Stiffness.

poisson_rationumberrequired0 to < 0.5

Poisson's ratio.

density_g_cm3numberrequired> 0, ≤ 30

Density, for the weight.

yield_strength_mpanumberrequired> 0, ≤ 100,000

Stress at which the material fails.

stress_metric"von_mises" | "max_principal"default "von_mises"

How stress is compared with the yield strength.

Support and load#

structural.heatmap and structural.fragility also take a point support and a point load:

support_fracnumberdefault -1−1 to 1

Where the part is held: −1 at its feet (as it stands), 0.5 at the waist.

support_point, support_radius_mm[x, y, z], numberdefault —, 6.0radius 0.5–1000

Hold the part at this point instead, over this radius.

load_point, load_radius_mm[x, y, z], numberdefault —, 6.0radius 0.5–1000

Apply a force at this point, over this radius.

load_dir[x, y, z]

Direction of the force; default straight down (minus the up axis).

load_force_nnumberdefault 10.00–1,000,000

The force in newtons.

Every result on this path reports the grid (grid, solid_voxels), the part (volume_mm3, mass_g, center_of_mass_voxel, bounding_box_mm), its islands (num_components, floating_parts, components_voxel) and an overhang summary, beside the tool's own block.

structural.components#

Lists the separate islands of the mesh and can remove the ones you do not want, such as floating specks.

params
{ "remove": { "max_dim_mm": 2, "logic": "or", "keep_main": true } }
weldbooleandefault true

Weld coincident vertices first, so touching triangles count as one island.

weld_mmnumberdefault 0.001> 0, ≤ 10

Weld distance.

min_facesintegerdefault 1≥ 1

Smallest island reported.

exportbooleandefault false

Return every island as its own mesh.

removeobject

Remove islands that match; the cleaned mesh is returned. Each criterion is 0 (off) unless set.

remove.max_dim_mmnumberdefault 00–10,000

Islands whose largest dimension is at most this.

remove.volume_mm3numberdefault 0≥ 0

Islands with at most this volume.

remove.facesintegerdefault 0≥ 0

Islands with at most this many faces.

remove.bbox_mm[x, y, z]

Islands that fit inside a box of this size.

remove.logic"or" | "and"default "or"

Whether an island must match any criterion or all of them.

remove.keep_mainbooleandefault true

Never remove the largest island.

Result: components_mesh with count, reported, exported, welded, total_faces, total_vertices, a list of islands and, with a remove rule, cleanup. The common fields above are not reported by this tool.

Islands
remove max_dim_mm 2
Components and cleanup. structural.components lists the model's separate islands. With a remove rule (here: islands smaller than 2 mm across) it also returns the cleaned mesh. Left, islands in one colour each; right, the cleaned result. Model: Rubber Duck Toy, Poly Haven, https://polyhaven.com/a/rubber_duck_toy, CC0 1.0 (loose fragments: Printy3D (generated), CC0 1.0)

structural.fea#

Solves the voxelized part under gravity (load_g) resting on its floor, and reports displacement and stress. It can also return a thickened or a graded-hollow version.

params
{ "material": "pla", "grid_cell_budget": 200000, "thicken": { "enabled": true, "max_mm": 1.5 } }
grid_cell_budgetintegerdefault 80,0001,000–12,000,000

Cap on the total grid cells (not only solid ones). More cells, finer and slower; at 80,000 a solve takes seconds.

solver"amgcg_gpu" | "gpu" | "mgcg" | "amgcg" | "cpu"default "amgcg_gpu"

The linear solver. A GPU solver falls back to the CPU on a GPU error, and fea.solver reports the solver requested, not the one that ran.

tolnumberdefault 0.0001> 0, ≤ 1

Convergence tolerance.

max_itersintegerdefault 50001–1,000,000

Iteration cap.

bandintegerdefault 00–1000

The engine's band setting for the solve (0 = off).

fixed_axisintegerdefault -1−1 to 2

−1 clamps the floor automatically; 0, 1 or 2 fixes the part on that axis like a cantilever.

nonlinearobject

{enabled: false, model: 1, load_steps: 10, newton_iters: 30, newton_tol: 0.0001, gpu: false}: a nonlinear solve in load steps with Newton iterations.

thickenobject

{enabled: false, max_mm: 1.0}: also return the part thickened, by at most max_mm, where it is too weak.

hollow_gradedobject

{enabled: false, wall_min_mm: 0.6, wall_max_mm: 2.0}: also return the part hollowed with a wall between the two values. No drain holes are added.

Result: fea with structural_guidance, solver, converged, iters, residual, max_disp_mm, max_von_mises_mpa, mean_von_mises_mpa, p95_von_mises_mpa, a note, and blocks for nonlinear, thickening and hollow_graded when enabled. Meshes: the thickened or hollowed part, and the deformed shape.

Input
thicken enabled, max 1 mm
FEA thickening. With thicken enabled, structural.fea also returns a mesh thickened (up to max_mm) where the solve found the part too weak. Left, the input; right, the thickened result. Model: Bracket with hook, Printy3D (generated), CC0 1.0
Input (solid)
hollow_graded 0.6–2.0 mm
Graded hollowing. hollow_graded hollows the part with a wall between wall_min_mm and wall_max_mm, thicker where stress is higher. No drain holes are added. Model: Marble Bust 01, Poly Haven, https://polyhaven.com/a/marble_bust_01, CC0 1.0
Input
Deformed (movement x 380)
Deformed shape. With nonlinear on, structural.fea solves the part under its own weight times load_g and returns the deformed shape as an extra piece, when the solve converges. The real movement here is tiny (max_disp_mm 0.011), so this picture multiplies it by 380 to make the direction visible: the long beam and hook sag. Model: Bracket with hook, Printy3D (generated), CC0 1.0

structural.heatmap#

A stress heatmap of the surface for the support and load you describe.

params
{ "support_frac": 0.5, "normalize": "p99" }
normalize"p99" | "max"default "p99"

Scales the engine's relative stress map to a high percentile of the surface stress or to its maximum. It does not change the heatmap artifact, which is always coloured against the material's yield stress (color_normalized_by: yield_strength): red means yield, so a safe part reads blue whichever value you send. relative_scale_mpa in the result reports the relative map's scale.

percentilenumberdefault 0.99> 0, ≤ 1

The percentile used by p99.

sample_radiusintegerdefault 41–12

How many voxels around each surface point are sampled.

Plus the common parameters and support and load. Result: heatmap with max_von_mises_mpa, p95_von_mises_mpa, mean_von_mises_mpa, surface_color_scale_mpa, color_normalized_by, load_g and a note. Artifact: heatmap.

support_frac -1 (feet), yield scale
support_frac 0.5 (waist), yield scale
Feet, own scale (from measure_all)
Waist, own scale (from measure_all)
How the part is held. support_frac -1 supports the part at its feet, as it stands; 0.5 holds it at the waist. The tool's map is coloured against the material's yield stress (red = 50 MPa on this run), so this safe part reads blue either way, which is the correct answer. To see where the stress goes, the other two images show the same holds from structural.measure_all, each on its own scale: standing, the legs are hottest and the sleeve is mild; held at the waist, the hand and sleeve turn red as well. Colours (jet): blue = low, red = high. Model: Garden Gnome, Poly Haven, https://polyhaven.com/a/garden_gnome, CC0 1.0

structural.fragility#

The safety factor across the part and the points most likely to break.

sample_radiusintegerdefault 81–20

How many voxels around each surface point are sampled.

Plus the common parameters and support and load. Result: fragility with min_safety_factor, max_von_mises_mpa, break_risk_fraction, below_target_fraction, a hotspot, risk_point_count and a verdict in words; the API adds verdict_code: pass, marginal, likely_to_break or unknown. Meshes: the safety-factor heatmap and the risk points.

Surface map
Risk points
Fragility. structural.fragility returns a surface map of how close each point is to its strength, and the points most likely to break. The map is scaled to the load at which the part first reaches yield: green is safe, red is where it would go first. Left, the map; right, the risk points over the model. This solid figure holds its own weight comfortably (minimum safety factor 13,327). Model: Garden Gnome, Poly Haven, https://polyhaven.com/a/garden_gnome, CC0 1.0

structural.measure_all#

Four fixed scenarios in one job: standing_vonmises, standing_maxprincipal, held_waist_vonmises and held_waist_maxprincipal. It runs four solves, so it takes longer than one heatmap.

sample_radiusintegerdefault 41–12

How many voxels around each surface point are sampled.

Plus the common parameters. Result: measure_all.scenarios, one entry per scenario with scenario, metric, support, min_safety_factor, max_stress_mpa, break_risk_fraction, below_target_fraction, hotspot_mm and verdict. One heatmap per scenario.

standing, von Mises
standing, max principal
held at waist, von Mises
held at waist, max principal
Four scenarios. structural.measure_all runs four fixed scenarios: standing and held at the waist, each with von Mises and maximum principal stress. One heatmap per scenario. Colours (jet): blue = low, red = high stress, per scenario. Model: Garden Gnome, Poly Haven, https://polyhaven.com/a/garden_gnome, CC0 1.0

structural.relief#

Turns the model's own texture into real relief: the surface is subdivided, displaced by a height derived from the texture, then repaired into a closed solid. It takes up_axis but none of the other common parameters.

params
{ "mode": "emboss", "amount_mm": 1.5 }
mode"emboss" | "deboss" | "signed"default "emboss"

emboss pushes the surface out by the relief height, deboss presses it in, signed does both around the middle of the height range.

amount_mmnumberdefault 1.0> 0, ≤ 100

The largest displacement.

min_feature_mmnumberdefault 0.5> 0, ≤ 100

The wall left under a deboss; deeper dents are clamped (counted in deboss_clamped).

input_is_heightbooleandefault false

Use the texture's grey levels as the height directly. Off, the engine derives a relief from the image with strength and compress.

strengthnumberdefault 3.0> 0, ≤ 100

How steep the image's detail is made before the height is built. The result is rescaled to amount_mm, so this changes the relief's character, not its depth.

compressnumberdefault 6.0> 0, ≤ 100

Bas-relief compression: flattens large height differences while keeping detail.

up_onlybooleandefault false

Displace only surfaces facing up (along up_axis).

max_edge_mmnumberdefault 00–100

Subdivide until edges are at most this long before displacing; 0 chooses automatically.

fixbooleandefault true

Repair the displaced surface into a closed solid.

fix_resolutionintegerdefault 4,000,000100,000–100,000,000

Grid cells of that repair.

up_axis0 | 1 | 2default 1

Which axis points up.

Result: relief_engrave with vertices, mode, amount_mm, min_feature_mm, deboss_clamped, max_applied_mm, subdiv_max_edge_mm and grid_voxel_mm. Meshes: the repaired relief and the raw displaced surface.

emboss
deboss
signed
Relief modes. structural.relief turns the model's own texture into surface relief. emboss pushes the surface out by the relief height, deboss presses it in, signed does both around the middle of the height range. Model: Relief tile, Printy3D (generated), CC0 1.0; texture Checkered Pavement Tiles, Poly Haven, https://polyhaven.com/a/checkered_pavement_tiles, CC0 1.0
0.5 mm
1 mm
2 mm
Relief depth. amount_mm is the largest displacement of the surface. Model: Relief tile, Printy3D (generated), CC0 1.0; texture Checkered Pavement Tiles, Poly Haven, https://polyhaven.com/a/checkered_pavement_tiles, CC0 1.0
1.5
3
6
Relief strength. When the texture is not itself a height map, the engine derives the relief from it: strength sets how steep the image's detail is made, and compress flattens large height differences like a bas-relief. The result is then rescaled to amount_mm, so strength changes the relief's character, not its depth: about 1 mm at every value here. On this painted vase, higher values soften the small sharp marks; the differences are small. The figure varies strength at the default compress (6). Model: Vase, Artec 3D (artec3d.com), CC BY 3.0 (creativecommons.org/licenses/by/3.0), scaled to 120 mm and processed with Printy3D