Skip to content

ch5_export.md

nathan-carmichael edited this page Mar 11, 2026 · 1 revision

Chapter 5: Profile Export Pipeline

After optimisation, the variable-thickness element mesh must be converted into a clean CAD-ready profile. The export_profile function uses an image-processing approach that is topology-agnostic: it handles beams, trusses, branching structures, and any geometry with holes or disconnected regions.

This chapter describes the algorithm in detail.


Algorithm Overview

The pipeline has six stages:

  1. Filter. Optionally remove elements thinner than a fraction of the maximum thickness.
  2. Rasterise. Draw every active element as a filled rectangle onto a high-resolution binary image.
  3. Clean. Apply morphological operations to close gaps and remove noise.
  4. Trace. Extract all closed boundary contours using skimage.measure.find_contours.
  5. Fit. Convert pixel contours to world coordinates and fit a smoothing spline to each loop.
  6. Export. Write each spline loop as a text file of [X, Y, Z] points for SolidWorks import.

Rasterisation

Each active element is represented by a rectangle centred on the element axis with width equal to the element thickness. For an element connecting nodes (x₁, y₁) and (x₂, y₂) with thickness t and orientation α = atan2(y₂ − y₁, x₂ − x₁), the four corners are:

$$ \begin{bmatrix} x_k \pm p_x \ y_k \pm p_y \end{bmatrix}, \qquad p_x = -\frac{t}{2}\sin\alpha, \quad p_y = \frac{t}{2}\cos\alpha, \quad k \in {1, 2} $$

These corners are mapped to pixel coordinates and rasterised using scikit-image's skimage.draw.polygon, which returns the row and column indices of all pixels inside the polygon. All element masks are combined with a logical OR onto a single boolean image.

The image resolution is controlled by the resolution parameter (pixels per metre, default 50,000). To prevent excessive memory use, the image dimensions are capped at 8000×8000 pixels.

Resolution guidance: For small geometries (e.g. a beam with a few millimetres of arc length), the default resolution may produce an image that is only a few pixels across. Increase resolution (e.g. to 500,000) to capture sufficient detail. For large truss geometries, the default is usually adequate or can be reduced to 5,000 for faster processing.


Morphological Cleanup

Adjacent elements may leave one- or two-pixel gaps at joints due to discretisation. A morphological closing operation (skimage.morphology.closing) with a disk structuring element fills these gaps:

$$ B_{\text{clean}} = (B \oplus S) \ominus S $$

where S is a disk with radius proportional to 10% of the maximum element thickness. The disk radius is capped to prevent excessive computation times on large images — without this cap, a large structuring element on a multi-megapixel image can take minutes to process.

Very small isolated pixel clusters (noise) are removed with skimage.morphology.remove_small_objects.


Boundary Extraction

Scikit-image's find_contours traces all closed contours in the binary image at a threshold of 0.5, returning each contour as a list of [row, col] sub-pixel coordinates. These are converted back to world coordinates using the known image bounds:

$$ x_{\text{world}} = \frac{c}{W - 1},(x_{\max} - x_{\min}) + x_{\min} $$

$$ y_{\text{world}} = \frac{H - 1 - r}{H - 1},(y_{\max} - y_{\min}) + y_{\min} $$

where (r, c) are the row and column pixel coordinates, and W, H are the image width and height.

Note: Unlike MATLAB's bwboundaries, which explicitly classifies boundaries as "outer" or "hole", find_contours returns all contours without classification. The current implementation marks all loops as outer boundaries. Full hole detection would require additional topological analysis.


Spline Fitting

Each boundary loop is parameterised by cumulative arc length s. After removing duplicate consecutive points, a cubic interpolating spline is fitted using scipy.interpolate.interp1d with kind='cubic':

$$ x(s) = \text{interp1d}(s_i,, x_i,, s_{\text{fine}}), \qquad y(s) = \text{interp1d}(s_i,, y_i,, s_{\text{fine}}) $$

where s_fine is a uniform grid with num_spline_points samples.

The spline is closed by appending the first point to the end.

Smoothing note: The MATLAB version uses csaps (smoothing cubic spline) with a smoothing parameter near 1.0. The Python version uses cubic interpolation as a fallback since scipy.interpolate.interp1d provides robust handling of the arc-length-parameterised data. For most geometries the results are visually identical.


File Format

Each loop is exported as a plain-text file with one point per line in the format:

X.XXXXXX Y.YYYYYY 0.000000

The Z coordinate is zero (2-D planar structure). Coordinates are in the units specified by scale_to_mm (default: millimetres).

Files are named <base>_loop_<n>.txt for outer boundaries and <base>_hole_<n>.txt for interior voids. A .npz NumPy archive containing the spline data for all loops is also saved.


SolidWorks Import Workflow

To import the exported profiles into SolidWorks:

  1. Open a new part and select the Front Plane.
  2. InsertCurveCurve Through XYZ Points.
  3. Browse to the exported .txt file and click OK.
  4. Repeat for each loop and hole file.
  5. Create a new sketch on the Front Plane and Convert Entities to pull the curves into the sketch.
  6. Close any open loop endpoints with short sketch lines if needed.
  7. Extrude Boss/Base the outer boundary to the desired width.
  8. Extrude Cut any hole boundaries through the part.

Tip: For beam-type profiles with a single outer loop and no holes, a single Extrude Boss/Base produces the finished part in one operation. For truss-type profiles, import the outer boundary first, extrude, then cut the holes.


Controlling Quality

The key parameters affecting export quality are:

Parameter Effect
resolution Higher values capture thinner elements and sharper corners, at the cost of memory and processing time. For small geometries, this may need to be significantly increased from the default.
smoothing Values very close to 1 (e.g. 0.999999999) preserve fine detail; lower values produce smoother, rounder profiles.
min_thickness_frac For trusses, setting this to 0.10–0.20 removes vanished material and leaves clean load-path outlines.
num_spline_points More points give a denser export file, which may improve CAD import fidelity for complex shapes.

Clone this wiki locally