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: |
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: |
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
|
required |
tolerance_mm
|
float
|
Default upper tolerance in mm. Defaults to |
2.0
|
warn
|
bool
|
Emit a :class: |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
SeamValidationResult
|
class: |
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 |
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
|
required |
tolerance_mm
|
float
|
Default tolerance in mm. Defaults to |
5.0
|
warn
|
bool
|
Emit a :class: |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
WidthValidationResult
|
class: |
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 |
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 |
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: |
None
|
Returns:
| Type | Description |
|---|---|
PatternElement
|
The newly created :class: |
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'
|
style
|
StyleOptions | None
|
Optional style override; defaults to :data: |
None
|
Returns:
| Type | Description |
|---|---|
PatternElement
|
The newly created :class: |
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]
|
|
(0.0, 3 * CM)
|
Returns:
| Type | Description |
|---|---|
PatternElement | None
|
The created PatternElement, or |
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: |
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 |
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 |
False
|
role
|
str | None
|
Optional semantic tag (e.g. |
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 element — style, 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: |
required |
dart
|
Dart
|
:class: |
required |
Returns:
| Type | Description |
|---|---|
list[PatternElement]
|
The list of newly appended :class: |
list[PatternElement]
|
(one or two, depending on where the legs fall). |
Raises:
| Type | Description |
|---|---|
TypeError
|
Propagated from :meth: |
bounding_box() -> tuple[Point, Point] | None
¶
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: |
required |
Returns:
| Type | Description |
|---|---|
float
|
Total arc length in mm as a :class: |
Raises:
| Type | Description |
|---|---|
KeyError
|
If a name string matches no element in this part. |
TypeError
|
If an entry is not a :class: |
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
|
|
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 |
required |
name
|
str | None
|
Name for the exploded part. Defaults to |
None
|
Returns:
| Type | Description |
|---|---|
PatternPart
|
A new plain :class: |
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
|
|
None
|
horizontals
|
list[tuple[str, float]] | None
|
|
None
|
extent
|
float
|
Half-length of each guide line in mm. Defaults to |
1500.0
|
part_name
|
str
|
Name of the produced :class: |
'Grid'
|
style
|
StyleOptions | None
|
Visual style for all guide lines. Defaults to
:data: |
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 |
tolerance_mm |
float
|
The upper tolerance applied to this pair: |
min_delta_mm |
float | None
|
Optional signed lower bound. When set, |
ok |
bool
|
|
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: |
all_ok |
bool
|
|
tolerance_mm |
float
|
The tolerance value that was used. |
__str__() -> str
¶
Human-readable summary, one line per pair.