Skip to content

Patterns & Pattern Parts

sewpat.pattern

Pattern package — re-exports every public name from :mod:sewpat.pattern.part.

Importing from sewpat.pattern continues to work unchanged after the split of the old monolithic pattern.py into sub-modules.

SeamPairSpec = tuple['PatternPart | str', str, 'PatternPart | str', str] | tuple['PatternPart | str', str, 'PatternPart | str', str, float] | tuple['PatternPart | str', str, 'PatternPart | str', str, float, float]

Pattern(name: str, parts: list[PatternPart] | None = None, anchor: Point | None = None)

A complete sewing pattern consisting of one or more pattern parts.

Attributes:

Name Type Description
name

Pattern name.

parts list[PatternPart]

Ordered list of all :class:PatternPart objects.

anchor Point

Top-left origin on the page. Defaults to (1.5 cm, 1.5 cm).

reference_square PatternElement | None

Optional scale-verification square added via :meth:add_reference_square.

Initialise a pattern with name, optional parts, and optional page anchor.

add_part(part: PatternPart) -> PatternPart

Append part to this pattern and return it (for chaining).

add_reference_square(origin: Point, edge_length: float = 3 * CM, style: StyleOptions | None = None, part: PatternPart | None = None) -> PatternElement

Add a print-scale verification square, clamped inside the bounding box with 2 mm padding.

Parameters:

Name Type Description Default
origin Point

Preferred top-left corner.

required
edge_length float

Side length. Defaults to 3 cm.

3 * CM
style StyleOptions | None

Defaults to a plain stroke style.

None
part PatternPart | None

Part for boundary clamping; auto-detected for single non-grid non-block parts.

None

get_part(name: str) -> PatternPart

Return the first PatternPart with the given name.

Raises:

Type Description
KeyError

If no part with that name exists.

validate_seam_pairs(pairs: list[SeamPairSpec], *, tolerance_mm: float = 2.0, warn: bool = True) -> SeamValidationResult

Measure and compare seam lengths across pattern parts.

Each entry in pairs is a 4-tuple (part_a, role_a, part_b, role_b) where each part is either a :class:PatternPart object or a name string (including :class:GarmentPart enum values). The method sums all is_outline elements carrying the given role tag and reports the length difference.

Example::

result = pattern.validate_seam_pairs([
    (Part.BLOCK_BACK, "side",     Part.BLOCK_FRONT, "side"),
    (Part.BLOCK_BACK, "shoulder", Part.BLOCK_FRONT, "shoulder", 13.0, 10.0),
])
print(result)

Parameters:

Name Type Description Default
pairs list[SeamPairSpec]

List of 4-, 5-, or 6-tuples (part_a, role_a, part_b, role_b[, max_tol[, min_delta]]).

required
tolerance_mm float

Default upper tolerance in mm. Defaults to 2.0.

2.0
warn bool

Emit a :class:UserWarning for every failing pair when True.

True

Returns:

Name Type Description
A SeamValidationResult

class:SeamValidationResult with one :class:SeamPairResult

SeamValidationResult

per entry in pairs.

Raises:

Type Description
KeyError

If a name string does not match any part in this pattern.

ValueError

If a role produces no is_outline elements in a part.

validate_widths(specs: list[WidthLevelSpec], *, tolerance_mm: float = 5.0, warn: bool = True) -> WidthValidationResult

Check that the combined back + front widths at key levels match measurements.

For each level, the width is measured by intersecting a construction-grid :class:~sewpat.geometry.Segment with the role-tagged seam edges of the back and front pieces. This approach is independent of the pattern's orientation on the page.

Typical expected values for a top block:

  • bust: meas.bust_width / 2
  • waist: meas.waist_width / 2
  • hip: meas.hip_width / 2

Example::

width_check = pattern.validate_widths(
    [
        (Part.BLOCK_BACK, "center_back", "side",
         Part.BLOCK_FRONT, "center_front", "side",
         "Bust",  grid.chest, meas.bust_width / 2),
        (Part.BLOCK_BACK, "center_back", "side",
         Part.BLOCK_FRONT, "center_front", "side",
         "Waist", grid.waist, meas.waist_width / 2),
        (Part.BLOCK_BACK, "center_back", "side",
         Part.BLOCK_FRONT, "center_front", "side",
         "Hip",   grid.hip,   meas.hip_width / 2),
    ],
    tolerance_mm=5.0,
)
print(width_check)

Parameters:

Name Type Description Default
specs list[WidthLevelSpec]

List of 9- or 10-tuples (back_part, back_center_role, back_side_role, front_part, front_center_role, front_side_role, label, grid_segment, expected_mm[, tol_mm]). Each part may be a :class:PatternPart object or a name string. The optional 10th element overrides tolerance_mm for that level.

required
tolerance_mm float

Default tolerance in mm. Defaults to 5.0.

5.0
warn bool

Emit a :class:UserWarning for every failing check when True.

True

Returns:

Name Type Description
A WidthValidationResult

class:WidthValidationResult with one :class:WidthCheckResult

WidthValidationResult

per entry in specs.

Raises:

Type Description
KeyError

If a name string does not match any part in this pattern.

ValueError

If a role has no is_outline elements, or none of them intersect the grid segment.

PatternPart(name: str, elements: list[PatternElement] | None = None, is_construction: bool = False)

Bases: NamedAccessMixin

A collection of pattern elements forming one pattern piece.

Initialise a PatternPart.

Parameters:

Name Type Description Default
name str

Human-readable label for this piece.

required
elements list[PatternElement] | None

Initial list of elements; defaults to an empty list.

None
is_construction bool

When True every appended element is stamped is_construction=True automatically.

False

area_cm2: float | None property

Area of the outline polygon in cm², or None if not yet defined.

centroid: Point | None property

Geometric centroid of the outline polygon, or None if not yet defined.

add_construction_line(geometry: GeometryType, name: str | None = None, style: StyleOptions | None = None) -> PatternElement

Append any geometry as a construction element (never is_outline).

Accepts any geometry type — :class:~sewpat.geometry.Segment, :class:~sewpat.geometry.CubicBezier, :class:~sewpat.geometry.Line, :class:~sewpat.geometry.Ray, :class:~sewpat.geometry.Point, etc. The element is always stamped is_construction=True regardless of whether the host part is a :class:~sewpat.pattern.ConstructionGridPart or a plain :class:PatternPart.

name is applied directly to geometry via set_name (or geometry.name for immutable types like :class:~sewpat.geometry.Point) so it becomes the single source of truth and can be retrieved later via :meth:get_element.

Parameters:

Name Type Description Default
geometry GeometryType

Any geometry object to add as a construction element.

required
name str | None

Optional label applied to geometry before appending.

None
style StyleOptions | None

Defaults to :data:~sewpat.style.STYLE_CONSTRUCTION_GRID.

None

Returns:

Type Description
PatternElement

The newly created :class:PatternElement.

add_dart(dart: Dart, *, stitch_style: StyleOptions | None = None, fold_style: StyleOptions = STYLE_DART_FOLD, precision_style: StyleOptions = STYLE_PRECISION_POINT, notches: bool = True, precision_tip: bool = True, notch_length: float | None = None, notch_width: float | None = None) -> None

Add all visual elements for dart to this part.

Delegates to :func:sewpat.pattern._dart_integration.add_dart; see that function for full documentation.

All created elements are appended to self.elements and can be filtered by element.role: "dart_stitch", "dart_fold", "dart_roof", "dart_tip", "dart_notch".

Style overrides (stitch_style, fold_style, precision_style) and notch geometry (notch_length, notch_width) are forwarded unchanged. Pass notches=False to suppress notch triangles (triangle darts only) or precision_tip=False to suppress tip circles and labels.

add_grainline(start: Point, end: Point, name: str = 'grainline / Fadenlauf', style: StyleOptions | None = None) -> PatternElement

Add a grainline segment, nudging outside endpoints inward along the grain axis.

Each endpoint is nudged toward the opposite one, so the grainline stays perfectly straight even when an endpoint sits on the outline boundary.

Parameters:

Name Type Description Default
start Point

Start point of the grainline.

required
end Point

End point of the grainline.

required
name str

Label for the segment. Defaults to "grainline / Fadenlauf".

'grainline / Fadenlauf'
style StyleOptions | None

Optional style override; defaults to :data:STYLE_GRAINLINE.

None

Returns:

Type Description
PatternElement

The newly created :class:PatternElement.

add_grid_notches(grid_part: PatternPart, role_map: dict[str, list[str]], min_spacing: float = 8.0, length: float = 0.8 * CM, width: float = 0.4 * CM, is_back: bool = False) -> list[PatternElement]

Add notches where outline edges intersect construction lines.

Only elements whose role attribute appears as a key in role_map are considered. For each role the mapped grid-line names are resolved from grid_part and intersected with the role's outline edges.

Delegates to :func:sewpat.pattern._notches.add_grid_notches. See that function for full parameter documentation.

add_info_box(header: str | None = None, notes: list[str] | None = None, offset: tuple[float, float] = (0.0, 3 * CM)) -> PatternElement | None

Add an info box near the centroid of this part.

Parameters:

Name Type Description Default
header str | None

Bold header text. Defaults to the part name.

None
notes list[str] | None

Optional note lines shown below the header.

None
offset tuple[float, float]

(dx, dy) shift from the centroid in mm. Defaults to (0, 30) — 30 mm below the centroid. Pass a negative dy to move the box upward, positive to move it downward, so it clears dart geometry or precision marks.

(0.0, 3 * CM)

Returns:

Type Description
PatternElement | None

The created PatternElement, or None if no centroid exists yet.

add_notches(*points: Point, seam_edge: Segment | CubicBezier | None = None, length: float = 0.8 * CM, width: float = 0.4 * CM, is_back: bool = False) -> None

Add filled-triangle notch marks at points, always pointing inward.

Delegates to :func:sewpat.pattern._notches.add_notches. See that function for full parameter documentation.

add_precision_points(*centers: Point, style: StyleOptions | None = None) -> None

Add a two-circle precision mark at each given point.

Each mark is a :class:~sewpat.element.PrecisionPoint with default radii (2 mm outer, 0.2 mm inner). To use custom radii, construct a :class:~sewpat.element.PrecisionPoint directly and pass its elements to :meth:append or :meth:extend.

Parameters:

Name Type Description Default
*centers Point

Points at which to place precision marks.

()
style StyleOptions | None

Visual style for the circles. Defaults to :data:~sewpat.style.STYLE_PRECISION_POINT.

None

add_seam_allowance(distance: float, outline_elements: list[PatternElement] | None = None, style: StyleOptions | None = None, corner_join: str = 'miter') -> list[PatternElement]

Offset the outline outward by distance mm and add the result as SA elements.

Delegates to :func:sewpat.pattern._sa.add_seam_allowance. See that function for full parameter documentation.

append(geometry: GeometryType, style: StyleOptions | None = None, is_outline: bool = False, is_construction: bool = False, role: str | None = None) -> PatternElement

Wrap geometry in a PatternElement, stamp is_construction, and append it.

The element's name is taken from geometry.name; set it on the geometry object before calling (e.g. seg.set_name("Center Back")). Style defaulting (including the automatic STYLE_CONSTRUCTION_GRID for construction elements with no explicit style) is handled by :class:~sewpat.element.PatternElement itself.

Parameters:

Name Type Description Default
geometry GeometryType

The shape to wrap.

required
style StyleOptions | None

Visual style. Defaults to STYLE_CONSTRUCTION_GRID when is_construction=True and no style is given, or plain StyleOptions() otherwise — both via PatternElement.

None
is_outline bool

Whether this element contributes to the seam-allowance polygon.

False
is_construction bool

Mark as a drafting aid (hidden on final print). Automatically True when the part itself is is_construction=True.

False
role str | None

Optional semantic tag (e.g. "side", "neckline"). Used by :meth:add_grid_notches when a role_map is supplied to select which grid lines should produce notches on this edge.

None

append_split_at_dart(element: PatternElement, dart: Dart) -> list[PatternElement]

Split element at both dart legs and append only the outer parts.

This is the standard pattern-making operation of removing the dart mouth from a seam edge: the section of the edge between dart.leg_a and dart.leg_b is discarded, while the parts outside the dart mouth are appended to this part.

All properties of elementstyle, is_outline, is_construction, role, name — are inherited by every resulting sub-element. There is no need to pass a style separately; simply construct element as you would any other outline element and hand it here instead of calling :meth:append::

sleeve_elem = PatternElement(
    sleeve_back.set_name("Sleeve Back"),
    style=STYLE_STITCH, is_outline=True,
)
block_back.append_split_at_dart(sleeve_elem, shoulder_dart_back)

The method delegates all splitting logic to :meth:PatternElement.split_at_dart.

Parameters:

Name Type Description Default
element PatternElement

Source element whose geometry is split. Must wrap a :class:~sewpat.geometry.Segment or :class:~sewpat.geometry.CubicBezier.

required
dart Dart

:class:~sewpat.geometry.Dart whose leg_a / leg_b define the mouth cut points.

required

Returns:

Type Description
list[PatternElement]

The list of newly appended :class:PatternElement objects

list[PatternElement]

(one or two, depending on where the legs fall).

Raises:

Type Description
TypeError

Propagated from :meth:PatternElement.split_at_dart when the geometry type does not support splitting.

bounding_box() -> tuple[Point, Point] | None

Axis-aligned bounding box of the outline polygon.

Returns:

Type Description
tuple[Point, Point] | None

(min_point, max_point) in mm, or None if no outline exists.

contains_point(point: Point) -> bool

Return True if point lies strictly inside the outline polygon (boundary = False).

extend(elements: list[PatternElement]) -> None

Append multiple PatternElement objects, stamping is_construction from this part.

When a :class:PatternElement wraps a :class:~sewpat.geometry.Dart as its geometry, it is dispatched to :meth:add_dart using the element's style as stitch_style; all other dart options keep their defaults. Use :meth:add_dart directly when you need full control over fold style, notches, etc.

All other :class:PatternElement objects are appended as-is after stamping is_construction. Construction elements with no explicit style receive :data:~sewpat.style.STYLE_CONSTRUCTION_GRID automatically.

get_element(name: str) -> PatternElement

Return the first :class:PatternElement whose geometry carries name.

Prefer snake_case attribute access via :class:NamedAccessMixin (e.g. part.center_back) over calling this method directly. Use this method when the name contains characters that cannot form a valid Python identifier (e.g. spaces, slashes).

Raises:

Type Description
KeyError

If no element with that name exists in this part.

seam_length(elements: list[PatternElement | str]) -> float

Return the total arc length in mm of the given pattern elements.

Each entry may be a :class:~sewpat.element.PatternElement or a str name. When a name is given, all matching elements in this part are summed.

The following geometry types contribute their length:

  • :class:~sewpat.geometry.Segment — Euclidean distance between endpoints.
  • :class:~sewpat.geometry.CubicBezier — arc length via numerical integration.
  • :class:~sewpat.geometry.Circle — full circumference (2 * π * radius).
  • :class:~sewpat.geometry.Rect — full perimeter (2 * (width + height)).
  • :class:~sewpat.geometry.Triangle — full perimeter (sum of three sides).

Geometry types with no meaningful length (:class:~sewpat.geometry.Point, :class:~sewpat.geometry.InfoBox, :class:~sewpat.geometry.Dart, :class:~sewpat.geometry.Ray, :class:~sewpat.geometry.Line) are silently skipped.

Parameters:

Name Type Description Default
elements list[PatternElement | str]

A list of :class:~sewpat.element.PatternElement objects or element name strings.

required

Returns:

Type Description
float

Total arc length in mm as a :class:float.

Raises:

Type Description
KeyError

If a name string matches no element in this part.

TypeError

If an entry is not a :class:~sewpat.element.PatternElement or str.

width_at_y(y: float) -> tuple[float, float]

Return (min_x, max_x) of the outline at horizontal slice y mm.

Intersects the outline polygon with a horizontal line at y and returns the X-extent of the intersection. Typical use-case: measure the garment width at the bust, waist, or hip level.

Parameters:

Name Type Description Default
y float

Y-coordinate of the horizontal slice in mm (pattern coordinates).

required

Returns:

Type Description
float

(min_x, max_x) — leftmost and rightmost X coordinates of the

float

outline at y.

Raises:

Type Description
ValueError

If the part has no outline polygon.

ValueError

If the horizontal slice at y does not intersect the outline.

GarmentPart

Bases: StrEnum

Base enum for pattern-part names.

Subclass this in each garment module to define the parts of that pattern. Because values are plain strings, they can be used anywhere a part name string is expected — Pattern.get_part(), the parts= argument of the export functions, and PatternPart(name=…) — without any changes to the rest of the library.

Example::

class Part(GarmentPart):
    BLOCK_BACK  = "Block Back"
    BLOCK_FRONT = "Block Front"
    GRID        = "Grid"

block_back = PatternPart(name=Part.BLOCK_BACK)
export_pattern_svg_mm(pattern, parts=[Part.GRID, Part.BLOCK_BACK])

OverlayPart(name: str, parent: PatternPart, elements: list[PatternElement] | None = None)

Bases: PatternPart

A pattern piece drafted directly on top of a parent part (same coordinate space).

The overlay is constructed normally — its geometry lives in the same coordinate system as parent, so it can share reference points and edges directly. When drafting is done, call :meth:explode to produce an independent, repositioned :class:PatternPart that can be cut separately.

Parameters:

Name Type Description Default
name str

Name of the overlay piece.

required
parent PatternPart

The pattern part this overlay is drafted on.

required

Example::

pocket = OverlayPart("Tasche", parent=front)
pocket.append(Segment(pocket_top_left, pocket_top_right), is_outline=True)
# … add more geometry …
exploded = pocket.explode(offset=Point(10*CM, 0))
pattern.add_part(pocket)     # visible on the front piece during drafting
pattern.add_part(exploded)   # separate cut piece

Initialise an overlay piece that shares coordinate space with parent.

explode(offset: Point, name: str | None = None) -> PatternPart

Detach this overlay into a standalone :class:PatternPart.

Every element's geometry is translated by offset so the new part sits next to the parent on the page rather than on top of it.

Parameters:

Name Type Description Default
offset Point

Translation applied to all geometry in the exploded part. Typically Point(parent_width + gap, 0) to place it to the right of the parent.

required
name str | None

Name for the exploded part. Defaults to self.name.

None

Returns:

Type Description
PatternPart

A new plain :class:PatternPart with translated geometry.

Block(name: str, elements: list[PatternElement] | None = None)

Bases: PatternPart

A base-block pattern piece derived from balanced measurements.

A block captures the fundamental shape of a garment without personal fitting adjustments or style details. It serves as a reusable starting point for new patterns and can be shown/hidden via the show_blocks flag in the SVG export helpers.

The part is identified by isinstance(part, Block).

Initialise a base-block part with name and optional elements.

ConstructionGrid(anchor: Point, verticals: list[tuple[str, float]] | None = None, horizontals: list[tuple[str, float]] | None = None, extent: float = 1500.0, part_name: str = 'Grid', style: StyleOptions | None = None)

Builds an orthogonal construction grid as a :class:ConstructionGridPart.

Each horizontal/vertical line is labelled with its measurement name so it can be retrieved later via :meth:~sewpat.pattern.PatternPart.get_element.

Parameters:

Name Type Description Default
anchor Point

Top-left origin of the grid.

required
verticals list[tuple[str, float]] | None

(name, x_offset_mm) pairs — guide lines parallel to the y-axis.

None
horizontals list[tuple[str, float]] | None

(name, y_offset_mm) pairs — guide lines parallel to the x-axis.

None
extent float

Half-length of each guide line in mm. Defaults to 1500.

1500.0
part_name str

Name of the produced :class:ConstructionGridPart. Defaults to "Grid".

'Grid'
style StyleOptions | None

Visual style for all guide lines. Defaults to :data:~sewpat.style.STYLE_CONSTRUCTION_GRID.

None

Example::

from sewpat.units import CM

grid = ConstructionGrid(
    anchor=Point(10 * CM, 10 * CM),
    verticals=[("Center Back", 0), ("Side Back", 20 * CM)],
    horizontals=[("Chest", 0), ("Waist", 20 * CM), ("Hip", 36 * CM)],
)
pattern.add_part(grid.build())

Store grid parameters; pass None for verticals/horizontals to get an empty axis.

build() -> ConstructionGridPart

Build and return the grid as a :class:ConstructionGridPart.

ConstructionGridPart(name: str = 'Grid', elements: list[PatternElement] | None = None)

Bases: PatternPart

A :class:PatternPart that represents a construction grid.

Grid elements are kept separate from the main pattern pieces when rendering by default — they are only included when requested explicitly by name via the parts= argument of the export functions.

All elements appended to this part automatically receive is_construction=True, so they are hidden when show_construction=False is passed to the export functions.

Prefer building instances via :class:ConstructionGrid rather than creating them directly.

Initialise a construction-grid part; all elements stamped is_construction=True.

SeamPairResult(part_a: str, role_a: str, length_a: float, part_b: str, role_b: str, length_b: float, delta_mm: float, tolerance_mm: float, ok: bool, min_delta_mm: float | None = None) dataclass

Measurement result for a single matched seam pair.

Attributes:

Name Type Description
part_a str

Name of the first pattern part.

role_a str

Role tag used to select elements in part_a.

length_a float

Total seam length in mm for the matched elements in part_a.

part_b str

Name of the second pattern part.

role_b str

Role tag used to select elements in part_b.

length_b float

Total seam length in mm for the matched elements in part_b.

delta_mm float

Signed difference length_a - length_b in mm. Positive means part_a is longer, negative means part_b is longer.

tolerance_mm float

The upper tolerance applied to this pair: delta_mm must not exceed this value in absolute terms.

min_delta_mm float | None

Optional signed lower bound. When set, delta_mm must also be >= min_delta_mm for the pair to be ok. None means no lower bound is enforced.

ok bool

True when all active bounds are satisfied: abs(delta_mm) <= tolerance_mm and, if set, delta_mm >= min_delta_mm.

SeamValidationResult(pairs: list[SeamPairResult] = list(), all_ok: bool = True, tolerance_mm: float = 2.0) dataclass

Aggregated result of :func:validate_seam_pairs.

Attributes:

Name Type Description
pairs list[SeamPairResult]

One :class:SeamPairResult per checked seam pair, in the order they were supplied.

all_ok bool

True when every pair is within tolerance.

tolerance_mm float

The tolerance value that was used.

__str__() -> str

Human-readable summary, one line per pair.