Groups¶
Frozen argument groups (Placement, Facets) for parameters that travel together
Frozen argument groups (Placement, Facets) for parameters that travel together.
-
class pybosl2.groups.Placement(anchor=
Anchor.CENTER, spin=0.0, orient=Anchor.TOP)[source]¶ Bases:
objectWhere a shape sits: its anchor, its spin about Z, and the direction it faces.
The three always travel together (SPEC G-1), so they can be one value that is built once and reused. Frozen, like every group:
with_()returns a new one.A placement reads in two dimensions as well as three. In the plane a shape has an anchor and a spin but nothing to orient – there is no third axis to turn a face towards – so a 2-D constructor honours those two. One placement can therefore serve a 2-D outline and the solid extruded from it, which is the case worth having. What it must not do is quietly honour two of the three: a placement carrying a real
orientasks for something the plane cannot do, so passing one to a 2-D constructor raises rather than silently dropping it (SPEC E-5). The defaultorientis not “a real one” –Placement()andPlacement(anchor=...)are dimension-neutral and pass anywhere.Examples
from pybosl2 import Anchor, Placement, cuboid upright = Placement(anchor=Anchor.BOTTOM) cuboid([40, 30, 20], placement=upright).show()Loading 3-D preview…- anchor : Anchor | Sequence[float]¶
The point on the shape that lands at the origin.
- spin : float¶
Rotation about Z in degrees, applied after anchoring.
- orient : Anchor | Sequence[float]¶
The direction the shape’s top is rotated towards.
-
with_(*, anchor=
None, spin=None, orient=None)[source]¶ Return a copy with the given members replaced.
Examples
>>> from pybosl2 import Anchor, Placement >>> Placement(anchor=Anchor.BOTTOM).with_(spin=45).spin 45.0
- orients()[source]¶
Whether this placement asks for an orientation the plane cannot give.
- Returns:¶
Truewhenorientdiffers from the default, which is what makes a placement three-dimensional. A placement that only anchors and spins reads in either dimension.- Return type:¶
bool
Examples
>>> from pybosl2 import Anchor, Placement >>> Placement(anchor=Anchor.BOTTOM).orients() False >>> Placement(orient=Anchor.RIGHT).orients() True
- as_plane_kwargs()[source]¶
Return the members a 2-D constructor can honour.
- Returns:¶
A mapping with
anchorandspin.orientis absent because the plane has no third axis to turn a face towards;orients()says whether dropping it would lose anything, andresolve_placement_2d()refuses rather than drop it.- Return type:¶
dict[str, Any]
-
class pybosl2.groups.Facets(fn=
None, fa=None, fs=None, res=None)[source]¶ Bases:
objectThe curve-resolution controls, carried as one value.
Mostly internal. SPEC R-1 requires every construction that approximates a curve to accept
fn/fa/fs(orres) and pass them to everything it builds, and the rule is broken most often by a function that simply forgets to forward one of the four. One value is harder to drop than four parameters.Callers wanting to set resolution should reach for
use_defaults()instead, which sets it for a whole block without threading anything through any call (SPEC R-4).Nonein any member means “not given, decide for me” (SPEC D-4).Examples
>>> from pybosl2.groups import Facets >>> Facets(fn=64).as_kwargs() {'fn': 64}- fn : int | None¶
Fixed fragment count for a full circle.
- fa : float | None¶
Minimum fragment angle in degrees.
- fs : float | None¶
Minimum fragment size in millimetres.
- res : int | None¶
Sampling resolution for the SDF backend.
- classmethod ambient()[source]¶
Return the values
use_defaults()currently has in force.
-
classmethod resolved(fn=
None, fa=None, fs=None, res=None)[source]¶ Return the values to actually use: what the caller passed, over the ambient defaults.
This is the one place the rule lives (SPEC R-5: an explicit value always wins over an ambient one).
resolve_facets()andresolve_res()both go through it, so the CSG facet controls and the SDF resolution cannot drift into resolving differently – they were two implementations of one rule before.fn=0passes through unchanged: it is the caller opting out of an ambientfn, andfrag_count()reads anyfnbelow 3 as “use fa/fs” (SPEC R-5).- Parameters:¶
- fn : int | None¶
Caller-supplied fragment count, or
None. Omitted, the ambientuse_defaults(fn=...)value applies;fn=0opts back out to fa/fs.- fa : float | None¶
Caller-supplied fragment angle, or
None. Omitted, the ambientuse_defaults(fa=...)value applies.- fs : float | None¶
Caller-supplied fragment size, or
None. Omitted, the ambientuse_defaults(fs=...)value applies.- res : int | None¶
Caller-supplied SDF resolution, or
None. Omitted, the ambientuse_defaults(res=...)value applies.
- Returns:¶
A
Facetswith each member filled from the ambient default where the caller gave nothing, and stillNonewhere nothing is set anywhere.- Return type:¶
Examples
>>> from pybosl2 import use_defaults >>> from pybosl2.groups import Facets >>> with use_defaults(fn=64): ... Facets.resolved(fa=6).as_kwargs() {'fn': 64, 'fa': 6}
-
class pybosl2.groups.EdgeTreatment(kind=
EdgeTreatmentKind.NONE, size=0.0)[source]¶ Bases:
objectWhat happens to an edge: a rounding of some radius, a chamfer of some size, or nothing.
Rounding and chamfer are mutually exclusive on one edge – an edge is rounded or chamfered, never both – and the library checked that in six places with six different wordings, none of which said what to do instead. As one value the conflict is not checkable, it is unrepresentable: there is one size and one kind, so there is nothing to disagree.
Build one with
rounding()orchamfer()rather than the constructor, so the kind and the size are set together.Examples
from pybosl2 import EdgeTreatment, cuboid cuboid([40, 30, 20], treatment=EdgeTreatment.rounding(4)).show()Loading 3-D preview…- Parameters:¶
- kind : EdgeTreatmentKind¶
- size : float | Sequence[float]¶
- kind : EdgeTreatmentKind¶
Which treatment, or
NONE.
- size : float | Sequence[float]¶
The radius (rounding) or inset (chamfer). Negative rounds outward, as BOSL2’s does. A sequence gives a size per corner, which the 2-D constructors accept.
- classmethod rounding(size)[source]¶
Return a rounding treatment of radius size.
- Parameters:¶
- size : float | Sequence[float]¶
The rounding radius, or one radius per corner.
- Returns:¶
An
EdgeTreatment.- Return type:¶
Examples
>>> from pybosl2 import EdgeTreatment >>> EdgeTreatment.rounding(4).as_kwargs() {'rounding': 4.0}
- classmethod chamfer(size)[source]¶
Return a chamfer treatment of inset size.
- Parameters:¶
- size : float | Sequence[float]¶
The chamfer size, inset from the sides, or one per corner.
- Returns:¶
An
EdgeTreatment.- Return type:¶
Examples
>>> from pybosl2 import EdgeTreatment >>> EdgeTreatment.chamfer(2).as_kwargs() {'chamfer': 2.0}
- classmethod none()[source]¶
Return the treatment that leaves edges sharp.
- Returns:¶
An
EdgeTreatmentthat contributes no arguments.- Return type:¶
-
class pybosl2.groups.EdgeSelection(edges=
Anchor.ALL, excepted=None)[source]¶ Bases:
objectWhich edges a treatment applies to, and which are spared.
The pair travels together on 15 callables and neither member means much alone: edges without except_edges is the common case, and except_edges without edges reads as “all of them but these”, which is what the default makes it. Unlike
EdgeTreatmentthe two are not exclusive – they compose, the second narrowing the first.Both are expressed in the anchor language (SPEC C-10, O-6b), never as strings.
Examples
from pybosl2 import Anchor, EdgeSelection, EdgeTreatment, cuboid top_only = EdgeSelection(edges=Anchor.TOP) cuboid([40, 30, 20], treatment=EdgeTreatment.rounding(4), selection=top_only).show()Loading 3-D preview…- edges : Any¶
The edges to treat. Defaults to every edge.
- excepted : Any¶
The edges to spare, spelled
except_edgesat a call site becauseexceptis a Python keyword (SPEC B2-3).
-
class pybosl2.groups.Texturing(texture=
None, size=None, reps=None, depth=1.0, inset=False)[source]¶ Bases:
objectA surface texture and how it is applied: the five parameters that always travel together.
They travel together on all 11 callables that take more than one of them, which is the cleanest group in the library by that measure. It could not be built until there was something to group – every one of those parameters refused until T37 built the application half of the texture subsystem (SPEC S-34, S-35).
size and reps are alternatives, and the group holds at most one, so the pair cannot disagree (SPEC G-7): give the tile’s size in millimetres, or how many times it repeats.
Examples
from pybosl2 import Texturing, cyl cyl(height=30, radius=12, texturing=Texturing("ribs", reps=[16, 1], depth=1.5)).show()Loading 3-D preview…- Parameters:¶
- texture : Any¶
The texture, by name or already built.
- size : float | Sequence[float] | None¶
Size of one tile as
[around, along]in millimetres.
- reps : int | Sequence[int] | None¶
Repeat counts as
[around, along], instead of size.
- depth : float¶
How far the texture displaces the surface. Negative sinks it in.
- inset : float | bool¶
How far the surface is sunk before the texture is added.
Truemeans one depth.
- pybosl2.groups.resolve_center_anchor(*, center, anchor, centred, uncentred)[source]¶
Fold BOSL2’s
center=shorthand into the anchor language (SPEC G-1, B2-3).center=is a placement option wearing a boolean: True means “sit on the origin”, False means “sit on the shape’s own base”. BOSL2 gives it precedence overanchor=–anchor = center==true ? CENTER : center==false ? uncentred : anchor– and this is the one place that rule is written.It was written in eleven places before T40, in three spellings and two contradicting precedences. Seven gave
centerprecedence, which is right. The other four spelled it inline asuse_anchor = anchor; if use_anchor is None: use_anchor = CENTER if center is None or center else BOTTOM, which letsanchorwin — while their own docstrings said “center: if given, overrides anchor”.cyl(height=10, radius=5, anchor=TOP, center=False)sat on its top face, and the documentation next to it said it would sit on the bottom one. That is E-5’s silent wrong answer, and it survived because the rule had no single home to be right in.Both are named at the call site rather than defaulted, because each backend anchors in its own vocabulary: the CSG backend passes
Anchormembers and the SDF backend passes the raw direction vectors of pybosl2/sdf/_constants.py. One type variable spans all three anchors so the resolver hands back exactly what it was given.- Parameters:¶
- center : bool | None¶
True for a centred anchor, False for uncentred,
Noneto leave anchor be.- anchor : _CenterAnchorT¶
The anchor as passed, used only when center is
None.- centred : _CenterAnchorT¶
What
center=Truemeans for this shape.- uncentred : _CenterAnchorT¶
What
center=Falsemeans –BOTTOMfor the cylinders,BOTTOM_FRONT_LEFTfor the boxes.
- Returns:¶
The anchor to place with.
Nonepropagates, so a constructor whose own default depends on more than this (SPEC D-4) still gets to compute it.- Return type:¶
_CenterAnchorT
-
pybosl2.groups.resolve_placement(placement, anchor, spin, orient, function, *, defaults=
None)[source]¶ Resolve a placement group against the loose members, refusing a call that gives both.
SPEC G-3: the loose spellings survive, and supplying a group and one of its members is an error rather than a silent preference – the same rule a radius and its own diameter follow (SPEC D-5), for the same reason: the call cannot mean two things at once.
- Parameters:¶
- placement : Placement | None¶
The group, or
None.- anchor : Anchor | Sequence[float] | None¶
The loose
anchoras passed.- spin : float | None¶
The loose
spinas passed.- orient : Anchor | Sequence[float] | None¶
The loose
orientas passed.- function : str¶
Name of the calling function, for the error message.
- defaults : Placement | None¶
What the loose members default to, so “given” can be told from “left alone”. Defaults to
Placement’s own defaults.
- Returns:¶
The three values to use.
- Raises:¶
Bosl2ValueError – if placement is given together with any of the loose members.
- Return type:¶
tuple[Anchor | Sequence[float] | None, float | None, Anchor | Sequence[float] | None]
-
pybosl2.groups.resolve_placement_2d(placement, anchor, spin, function, *, defaults=
None)[source]¶ Resolve a placement for a 2-D constructor, which has an anchor and a spin but no orient.
A separate function rather than a flag on
resolve_placement(), because a boolean that selects how many values come back is a second function wearing the first one’s name (SPEC S-19b).- Parameters:¶
- placement : Placement | None¶
The group, or
None.- anchor : _AnchorT¶
The loose
anchoras passed.- spin : _SpinT¶
The loose
spinas passed.- function : str¶
Name of the calling function, for the error message.
- defaults : Placement | None¶
What the loose members default to, so “given” can be told from “left alone”.
- Returns:¶
The anchor and spin to use.
- Raises:¶
Bosl2ValueError – if placement is given together with either loose member (SPEC G-3), or if it carries a real
orient, which the plane cannot honour (SPEC E-5).- Return type:¶
tuple[__SPHINX_IMMATERIAL_TYPE_VAR__V__AnchorT | Anchor | Sequence[float], __SPHINX_IMMATERIAL_TYPE_VAR__V__SpinT | float]
-
pybosl2.groups.resolve_edge_treatment(treatment, rounding, chamfer, function, *, per_corner=
True)[source]¶ Resolve an edge-treatment group against the loose
rounding/chamfer.- Parameters:¶
- treatment : EdgeTreatment | None¶
The group, or
None.- rounding : _RoundingT¶
The loose
roundingas passed.- chamfer : _ChamferT¶
The loose
chamferas passed.- function : str¶
Name of the calling function, for the error message.
- per_corner : bool¶
Whether this constructor takes a size per corner. A 3-D primitive takes one size for the whole solid, so a per-corner group handed to it is refused here rather than left to fail as a
TypeErrorfrom inside the backend (SPEC E-1, E-4).
- Returns:¶
The
roundingandchamferto use, at most one of them set. Where a group decides the answer, the other comes back as0– “off” – rather thanNone, becauseNonemeans “decide for me” and the group has just decided (SPEC D-4).- Raises:¶
Bosl2ValueError – if the group is given beside either loose member (SPEC G-3), if both loose members are given (the rule above), or if a per-corner group is given to a constructor that takes one size.
- Return type:¶
tuple[__SPHINX_IMMATERIAL_TYPE_VAR__V__RoundingT, __SPHINX_IMMATERIAL_TYPE_VAR__V__ChamferT]
- pybosl2.groups.resolve_edge_selection(selection, edges, except_edges, function)[source]¶
Resolve an edge-selection group against the loose
edges/except_edges.- Parameters:¶
- selection : EdgeSelection | None¶
The group, or
None.- edges : Any¶
The loose
edgesas passed.- except_edges : Any¶
The loose
except_edgesas passed.- function : str¶
Name of the calling function, for the error message.
- Returns:¶
The
edgesandexcept_edgesto use.- Raises:¶
Bosl2ValueError – if the group is given beside either loose member (SPEC G-3).
- Return type:¶
tuple[Any, Any]
- pybosl2.groups.resolve_texturing(texturing, texture, tex_size, tex_reps, tex_depth, tex_inset, function)[source]¶
Resolve a texturing group against the loose
tex_*arguments.- Parameters:¶
- texturing : Texturing | None¶
The group, or
None.- texture : Any¶
The loose
textureas passed.- tex_size : float | Sequence[float] | None¶
The loose
tex_sizeas passed.- tex_reps : int | Sequence[int] | None¶
The loose
tex_repsas passed.- tex_depth : float | None¶
The loose
tex_depthas passed.- tex_inset : float | bool | None¶
The loose
tex_insetas passed.- function : str¶
Name of the calling function, for the error message.
- Returns:¶
The
(texture, tex_size, tex_reps, tex_depth, tex_inset)to use.- Raises:¶
Bosl2ValueError – if the group is given beside any loose member (SPEC G-3).
- Return type:¶
tuple[Any, float | Sequence[float] | None, int | Sequence[int] | None, float | None, float | bool | None]