gtrace.mechanics

gtrace.mechanics

A module providing the Mechanics class: a named body on the bench that takes no part in the trace - a breadboard, a mirror mount, the housing of a beam dump.

A Mechanics is the counterpart of an Optics: something to draw on the layout because it is physically there, without any optical role. It is deliberately not derived from Optics - having no isHit and no hitFrom* is the definition of the class, not an omission - and the trace never sees it. Anything that is to stop or reflect light is an Optics (a beam dump is a mirror of zero reflectivity), and anything that is only to be seen is a Mechanics.

The shapes are held in local coordinates and carried onto the bench by a pose (center and rotationAngle), so that moving the body is a change of two numbers rather than of every vertex, and so that the pose and the geometry cannot fall out of step - the position is written down once. The same reasoning put the AR surface right in 2026-08-03: a second description of where something is, is a place for the two to disagree.

Attributes

__author__

__copyright__

__credits__

__license__

__version__

__maintainer__

__email__

__status__

DEFAULT_LAYER

LAYER_COLOR

_RESIZABLE

_ROUND

_MOUNT_POST_X

_MOUNT_POST_D

_MODEL_REGISTRY

Classes

Mechanics

A named body on the bench that takes no part in the trace.

Functions

point_in_polygon(point, polygon)

Whether a point lies inside a polygon, by ray casting.

_shape_bbox_points(s)

Points that bound one shape, in its own coordinates. An arc is

turned_shape(s, angle[, offset])

A copy of one shape turned about the origin and carried.

rotate_shape(s, angle[, pivot])

A copy of one shape turned about a point.

shape_centre(s)

The middle of the box a shape occupies, in its own coordinates.

host_pose(host)

Where a host stands and which way it is turned.

_turn(p, angle)

A local vector carried into a frame turned by angle.

breadboard(width, height[, pitch, hole_diameter, ...])

A breadboard: a rectangular plate with a grid of mounting holes,

_breadboard_shapes(p)

The shapes of a breadboard, from its parameters. Split out so that

round_breadboard(diameter[, pitch, hole_diameter, ...])

A round breadboard: a disc with the same grid of mounting holes,

_round_breadboard_shapes(p)

The shapes of a round breadboard, from its parameters. The rim,

mirror_mount([scale, knobs])

A one-inch kinematic mirror mount seen from above, drawn after a

mirror_mount_2in([scale, knobs])

A two-inch kinematic mirror mount seen from above: the same

lens_holder([length, thickness])

A lens holder seen from above: a plain rectangle, centred on the

pedestal([post_diameter, base_diameter, ...])

A pedestal pillar post seen from above: concentric circles.

clamping_fork([bore_diameter, length, width, ...])

A clamping fork seen from above: the U that closes on a pedestal,

_mount_shapes(u, knobs, front_w, front_d, gap, back_w, ...)

The shapes every kinematic mount is drawn from, with the

register_model(name, source[, description, prefix])

Put a model into the library, by value.

models()

The library: model name -> description, sorted by name.

model_shapes(name)

Fresh shape objects for a registered model.

model_points(name)

The named points of a registered model, in local coordinates.

model_prefix(name)

What bodies built from a registered model are called, before the

model_params(name)

The builder parameters of a registered model, or None for one

from_model(model, **kwargs)

A Mechanics built from a library model, carrying the model name as

save_models(filename[, names])

Write library models to a JSON file.

load_models(filename)

Merge the models of a JSON file into the library.

Module Contents

gtrace.mechanics.__author__ = 'Yoichi Aso'
gtrace.mechanics.__credits__ = ['Yoichi Aso']
gtrace.mechanics.__license__ = 'BSD'
gtrace.mechanics.__version__ = '0.8.0'
gtrace.mechanics.__maintainer__ = 'Yoichi Aso'
gtrace.mechanics.__email__ = 'asoy01@gmail.com'
gtrace.mechanics.__status__ = 'Beta'
gtrace.mechanics.DEFAULT_LAYER = 'mechanics'
gtrace.mechanics.LAYER_COLOR = (110, 110, 110)
gtrace.mechanics.point_in_polygon(point, polygon)

Whether a point lies inside a polygon, by ray casting.

This exists because a Mechanics is picked by its area: a breadboard is a large rectangle, and the enclosing-circle test the optics use would cover the whole bench around it.

Parameters:
  • point (array-like) – The point, of shape (2,).

  • polygon (sequence of array-like) – The vertices, in order, each of shape (2,). The polygon is closed implicitly; the first vertex need not be repeated.

Return type:

bool

gtrace.mechanics._shape_bbox_points(s)

Points that bound one shape, in its own coordinates. An arc is bounded by the full circle it lies on - looser than the arc itself, but never smaller, which is what a bound must guarantee.

gtrace.mechanics.turned_shape(s, angle, offset=(0.0, 0.0))

A copy of one shape turned about the origin and carried.

The shape itself is never touched: a new primitive comes back, with the same thickness.

A Rectangle survives as a Rectangle only while the turn is nothing at all - a carry alone keeps it, pivot and all. Turned, it comes back as the closed polyline of its four corners, which is what a DXF would write of it either way. A rectangle turned about a pivot of its own is turned about the pivot carried with it, so the corners are its own, not those of the box it was written from.

Parameters:
  • s (gtrace.draw shape) – The shape to turn.

  • angle (float) – How far to turn it, counterclockwise, in radians.

  • offset (array-like, optional) – Where to carry it afterwards. Default the origin.

Return type:

A new shape, of the same class except for a turned rectangle.

Raises:

gtrace.draw.serialize.UnknownShapeError – If the shape is of a kind this does not know.

gtrace.mechanics.rotate_shape(s, angle, pivot=(0.0, 0.0))

A copy of one shape turned about a point.

Turning about a point is turning about the origin and carrying the result back, which is why this and the pose of a body are the same arithmetic. A turned rectangle comes back as the closed polyline of its corners - see turned_shape().

Parameters:
  • s (gtrace.draw shape)

  • angle (float) – Counterclockwise, in radians.

  • pivot (array-like, optional) – The point to turn about. Default the local origin.

Return type:

A new shape.

gtrace.mechanics.shape_centre(s)

The middle of the box a shape occupies, in its own coordinates.

What a shape is turned about when nothing else is said: it is the point the editor already draws a box around, so a turn about it is the one turn that can be seen coming.

gtrace.mechanics.host_pose(host)

Where a host stands and which way it is turned.

An optics is turned by the normal of its HR face and a body by its own angle. That is the only difference between standing on a mirror and standing on a pedestal, so it is written down once here rather than at each of the three places that attach, derive and detach.

Parameters:

host (gtrace.optcomp.Optics or Mechanics)

Returns:

The host’s centre, and its angle in radians.

Return type:

(numpy.ndarray, float)

Raises:

ValueError – If the object has no pose to attach to.

gtrace.mechanics._turn(p, angle)

A local vector carried into a frame turned by angle.

class gtrace.mechanics.Mechanics(shapes=None, center=None, rotationAngle=None, name='Mechanics', layer=DEFAULT_LAYER, model=None, attached_to=None, offset=None, offset_angle=0.0, params=None, points=None, attach_point=None, fix_rotation=True)

Bases: object

A named body on the bench that takes no part in the trace.

The geometry is a list of drawing primitives (gtrace.draw shapes) in local coordinates, placed on the bench by a pose: center is where the local origin lands and rotationAngle how far the body is turned about it. The shapes themselves never change when the body moves.

A body can be attached to an optics, which is what a mirror mount is: something that stands where its mirror stands. An attached body has no pose of its own - center and rotationAngle are derived, on every read, from the host’s pose and the attachment offset. There is no callback to miss and no stored copy to go stale: the 2026-08-03 bugs were all a notification not arriving, and a derived value cannot fail to be notified. The price is that an attached body cannot be moved on its own - which is what “attached” means. detach() bakes the derived pose in and frees it.

Variables:
  • name (str) – Name of the body, unique within a layout.

  • center (numpy.ndarray) – Where the local origin stands on the bench, of shape (2,). Derived from the host while attached, and read-only then.

  • rotationAngle (float) – How far the body is turned about the local origin, in radians, counterclockwise. Derived while attached, like center.

  • shapes (list of gtrace.draw.Shape) – The geometry, in local coordinates.

  • layer (str) – The layer the body is drawn on. Defaults to ‘mechanics’.

  • model (str or None) – The catalogue model the shapes came from, if any. A label, not a reference: the shapes saved with a layout are the truth, and the model name only records where they were taken from, so a library that has moved on cannot silently redraw an old layout.

  • attached_to (gtrace.optcomp.Optics or None) – The optics this body stands on, held by reference, or None for a body standing on its own. The constructor also accepts a name, which OpticalLayout resolves when the body is registered; until then the pose cannot be read.

  • offset (numpy.ndarray) – Where the local origin stands in the host’s frame: the host’s substrate centre, with x along its HR normal. [0, 0] puts the body’s origin at the host’s centre.

  • offset_angle (float) – How far the body is turned relative to the host, in radians.

name = 'Mechanics'
shapes
layer = ''
model = None
params = None
points
attach_point
fix_rotation = True
attached_to = None
_attach_name = None
offset
offset_angle = 0.0
_center
_rotationAngle = 0.0
property center
property rotationAngle
attach(host, offset=None, offset_angle=None, keep_pose=None, attach_point=None, fix_rotation=None)

Stand this body on an optics. From here on its pose is derived from the host’s - move the mirror and the mount comes along, with no notification to miss.

Where it stands on the host is the model’s to say, not the drop point’s: a mirror mount is built around its optic, so the right relative position is unique and drawn into the shapes. The convention that carries it is the local origin - every builder and library model draws its shapes so that the origin is the point meant to coincide with the host’s substrate centre - so attaching with no offset seats the body there, wherever it happened to be lying beforehand.

Parameters:
  • host (gtrace.optcomp.Optics or Mechanics) – What to stand on. A body may stand on another body - a pedestal on a mount, a fork on a pedestal - and the chain follows the optics at the root of it. A cycle is refused.

  • offset (array-like or None, optional) – Where the local origin stands in the host’s frame (its substrate centre, x along the HR normal). None - the default - is [0, 0]: the designed position.

  • offset_angle (float or None, optional) – The turn relative to the host. None is 0: squarely on it.

  • keep_pose (bool or None, optional) – Derive the offset and the angle from where the body stands now instead, so that attaching changes what moves it and not where it is; offset and offset_angle must be left None with it. None - the default - decides by the host: a body standing on an optics goes to the model’s designed place, since a mount’s position on its mirror is unique and drawn into the shapes; a body standing on another body keeps where it is, since which hole of a mount a pedestal sits in is a choice made on the bench and not by the library.

  • attach_point (array-like or None, optional) – Which point of this body is pinned, in local coordinates. None keeps whatever it already had (the origin, unless something else was said). This is also the point the body turns about when its turn is free.

  • fix_rotation (bool or None, optional) – Whether the turn relative to the host is frozen. None keeps the current setting.

Returns:

self

Return type:

Mechanics

Raises:

ValueError – If the host has no pose, or if standing on it would make a cycle.

_refuse_cycle(host)

Refuse standing on something that already stands on this body.

A cycle would make the pose derive from itself, and since it is derived on every read that is not a wrong answer but an unbounded one.

hosts()

What this body stands on, nearest first, ending at the optics the chain hangs from. Empty for a free body.

world_points()

The named points of this part, where they stand on the bench.

Returns:

name -> numpy array of shape (2,).

Return type:

dict

detach()

Free this body, leaving it exactly where it stands: the derived pose is baked into center and rotationAngle. A body that is not attached is left alone.

Returns:

self

Return type:

Mechanics

to_world(p)

Carry a local point onto the bench: turned by rotationAngle and stood at center.

Parameters:

p (array-like) – A local point of shape (2,), or an array of them of shape (N, 2).

Return type:

numpy.ndarray

local_bbox()

The bounding box of the shapes, in local coordinates.

Returns:

The lower-left and upper-right corners, each of shape (2,). A body with no shapes is a point at the local origin.

Return type:

(numpy.ndarray, numpy.ndarray)

outline()

The bounding box of the shapes, carried onto the bench: four corners in world coordinates, counterclockwise.

This is the polygon the body is picked by. A box rather than the exact silhouette, because a grab handle wants to be simple and a little generous; the exact shape belongs to the drawing.

Returns:

Of shape (4, 2).

Return type:

numpy.ndarray

contains(point)

Whether a world point falls on the body - inside its outline().

world_shapes()

The shapes as they stand on the bench: new primitives in world coordinates. The local ones are left untouched.

A rectangle survives as a rectangle only while the body is not turned; a rectangle carries an angle of its own, but a body’s turn is not written into it, so a turned one comes out as the closed polyline of its corners.

_world_shape(s)
draw(cv, drawName=False)

Draw itself into a canvas, on its own layer.

Parameters:
  • cv (gtrace.draw.Canvas) – The canvas to draw into.

  • drawName (bool, optional) – Whether to write the name at the center, on the ‘text’ layer like an optics name. Defaults to False.

translate(trVect)

Move the body by a vector, like Optics.translate.

rotate(angle, center=None)

Turn the body, like Optics.rotate.

Parameters:
  • angle (float) – How far to turn, in radians, counterclockwise.

  • center (array-like or None, optional) – The point to turn about. None - the default - turns the body about its own center, which then stays put.

resize(width=None, height=None)

Rebuild a parametric body at a new size.

Only a body a builder made knows how to do this: a breadboard cut to a new size is re-drilled from its parameters, with the same pitch and the same holes, where scaling the shapes would scale the holes and the grid along with the plate. A body drawn by hand has no parameters, and is refused - its shapes are all anyone knows about it.

A round body has one size, not two. Either name sets its diameter, and a message that gives both is taken at its word: two that disagree are refused rather than resolved by picking one, since a round board asked to be 300 by 400 is a misunderstanding and not a size.

Parameters:
  • width (float or None, optional) – The new size, in metres. None keeps that side as it is.

  • height (float or None, optional) – The new size, in metres. None keeps that side as it is.

Returns:

self

Return type:

Mechanics

property resizable

How resize() can rebuild this body, or None.

'round' for a body with one size - a round board is cut to a diameter - and 'box' for one with two. A front end needs the difference: the rows it offers are Diameter or Width and Height, and a corner dragged on a disc has no opposite corner to hold still.

edit(height=None, **kwargs)

Open a shape editor on this body, in a notebook.

The editor works in the local frame - the one the shapes are written in, with the origin marked, since the origin is what comes to sit at the host’s substrate centre - and edits this body by reference: a layout already holding it draws the new shapes at its next draw.

Returns the widget, so a cell ending in mt.edit() shows it. ShapeEditor itself, for driving without a browser, is in gtrace.draw.viewer.editor.

Parameters:
  • height (int or None, optional) – Height of the editor in pixels, as for a layout widget.

  • **kwargs – Passed to the widget.

Returns:

widget

Return type:

anywidget.AnyWidget

copy()

A new Mechanics with the same pose and a copy of the shape list. The shapes themselves are shared: nothing in gtrace mutates a drawing primitive, and the copy is what save, undo and the clipboard-of-the-future need. An attached body copies as attached, standing on the same host.

gtrace.mechanics.breadboard(width, height, pitch=0.025, hole_diameter=0.006, margin=None, holes=True, **kwargs)

A breadboard: a rectangular plate with a grid of mounting holes, its local origin at the centre of the plate.

The hole grid is laid out the way real boards drill it: symmetric about the centre, the outermost rows a margin in from the edges, everything else on the pitch. The defaults are the metric standard - M6 clearance holes on a 25 mm grid, half a pitch in from the edge.

Parameters:
  • width (float) – Size of the plate, in metres.

  • height (float) – Size of the plate, in metres.

  • pitch (float, optional) – Hole spacing. Defaults to 25 mm.

  • hole_diameter (float, optional) – Diameter of a hole. Defaults to 6 mm.

  • margin (float or None, optional) – Distance from an edge to the first hole row. None - the default - is half a pitch, which is where the standard grid falls.

  • holes (bool, optional) – Whether to draw the grid at all. A board across a whole bench is sometimes wanted as just its outline.

  • **kwargs – Passed to Mechanics: name, center, rotationAngle, layer, attached_to and the rest.

Return type:

Mechanics

gtrace.mechanics._breadboard_shapes(p)

The shapes of a breadboard, from its parameters. Split out so that resize() can re-drill an existing board the same way breadboard() drilled it.

gtrace.mechanics.round_breadboard(diameter, pitch=0.025, hole_diameter=0.006, margin=None, holes=True, **kwargs)

A round breadboard: a disc with the same grid of mounting holes, its local origin at the centre.

A vacuum tank is round, and so is the board that goes in the bottom of it. The grid is the one a rectangular board is drilled with - symmetric about the centre, on the pitch - and the edge decides which of those holes exist: a hole is drilled where it lies a margin in from the rim, and left out where it does not, so the outermost rows come out shorter towards the edge the way a real disc is drilled.

Parameters:
  • diameter (float) – Across the disc, in metres.

  • pitch (float, optional) – Hole spacing. Defaults to 25 mm, as on a rectangular board.

  • hole_diameter (float, optional) – Diameter of a hole. Defaults to 6 mm.

  • margin (float or None, optional) – How far in from the rim a hole must be to be drilled. None - the default - is half a pitch, which is the rectangular board’s rule read round.

  • holes (bool, optional) – Whether to draw the grid at all.

  • **kwargs – Passed to Mechanics: name, center, rotationAngle, layer, attached_to and the rest.

Return type:

Mechanics

gtrace.mechanics._round_breadboard_shapes(p)

The shapes of a round breadboard, from its parameters. The rim, and the holes of the same grid that fall inside it.

gtrace.mechanics._RESIZABLE
gtrace.mechanics._ROUND
gtrace.mechanics.mirror_mount(scale=1.0, knobs=True, **kwargs)

A one-inch kinematic mirror mount seen from above, drawn after a Polaris KA1 style footprint: the front plate the optic sits in, the back plate across the adjustment gap with the two adjuster tips showing in it, the two adjuster knobs on their stems out of the back, and the hole it is bolted down through.

The local origin is the substrate centre of the mounted optic - the point marked on the drawing this is taken from - which sits 3 mm behind the front face of the front plate. attached_to with no offset therefore seats the mount so that a 6 mm thick optic ends flush with that face. The dimensions are the drawing’s, in millimetres, times scale:

  • plate 45.7 wide, front plate 7 deep

  • adjustment gap 3.2, with the two 5 mm adjuster tips showing, 6.4 in from either edge

  • back plate 12.7 deep

  • knobs 15.2 x 8.6 on 6.4-wide, 7.6-long stems, on the adjuster lines

  • the post hole, 4 across, 13.5 behind the origin - the point named ‘post’, which is also where the circle is drawn

Parameters:
  • scale (float, optional) – Multiplies every dimension. 1 - the default - is the one-inch mount; for a two-inch optic see mirror_mount_2in, which is measured rather than scaled.

  • knobs (bool, optional) – Whether to draw the adjuster knobs and their stems.

  • **kwargs – Passed to Mechanics.

Return type:

Mechanics

gtrace.mechanics.mirror_mount_2in(scale=1.0, knobs=True, **kwargs)

A two-inch kinematic mirror mount seen from above: the same schematic as mirror_mount, with its dimensions taken from the Thorlabs KA2A drawing (a three-adjuster 2” mount).

Measured off that drawing: front plate 68.6 wide and 7.0 deep, the 3.2 adjustment gap (the 22.9 overall body minus the two plates), back plate 69.9 wide and 12.7 deep. The adjusters protrude 12.2 behind the back plate (35.1 overall); how that splits into stem and knob, and the knob width, are drawn in the one-inch mount’s proportions, since the drawing does not dimension them.

The adjuster lines are 2.1 inch (53.34 mm) apart, which is measured on the mount rather than read off the drawing - the figure the drawing gives puts the knobs closer together than they are. The knobs sit on those lines, so it is knob to knob.

The local origin is the substrate centre of the mounted optic. The drawing’s optic pocket is 10.3 deep, so a standard 12.7 thick two-inch optic seated against the stop centres 3.95 behind the front face - which is where attached_to with no offset puts the host’s substrate centre. The post hole is drawn as the one-inch mount’s is: 4 across, 13.5 behind the origin, at the point named ‘post’.

Parameters:
  • scale (float, optional) – Multiplies every dimension.

  • knobs (bool, optional) – Whether to draw the adjuster knobs and their stems.

  • **kwargs – Passed to Mechanics.

Return type:

Mechanics

gtrace.mechanics.lens_holder(length=0.03, thickness=0.01, **kwargs)

A lens holder seen from above: a plain rectangle, centred on the substrate centre of the optic it holds.

A holder wraps its lens symmetrically, so the local origin is the middle of the rectangle - attached_to with no offset centres it on the host’s substrate.

Parameters:
  • length (float, optional) – Across the beam, in metres. Defaults to 30 mm, which suits a one-inch optic.

  • thickness (float, optional) – Along the beam. Defaults to 10 mm.

  • **kwargs – Passed to Mechanics.

Return type:

Mechanics

gtrace.mechanics.pedestal(post_diameter=0.0254, base_diameter=0.0318, relief_diameter=0.0102, bore_diameter=0.0044, **kwargs)

A pedestal pillar post seen from above: concentric circles.

A pedestal is what a mount is bolted to and what a clamping fork holds down, so it is the middle of a stack rather than either end of one. Its named point is 'axis', at the local origin: the tapped hole a mount screws into from above, the post a fork closes around, and the point the whole thing turns about.

The dimensions default to Thorlabs’ RS05P8E drawing - a 1 inch post on a 1.25 inch base, with the relief cut and the #8-32 tapped hole - since that is the pedestal the design was drawn against. Measure yours and pass the numbers if it differs.

Parameters:
  • post_diameter (float, optional) – The pillar, in metres. Defaults to 25.4 mm.

  • base_diameter (float, optional) – The flange a clamping fork bears on. Defaults to 31.8 mm.

  • relief_diameter (float, optional) – The relief cut around the tapped hole. Defaults to 10.2 mm; zero leaves it out.

  • bore_diameter (float, optional) – The tapped hole through the middle. Defaults to 4.4 mm, which is a #8-32 thread.

  • **kwargs – Passed to Mechanics.

Return type:

Mechanics

gtrace.mechanics.clamping_fork(bore_diameter=0.026, length=0.0738, width=0.0363, tail_width=0.0234, tip_ahead=0.0038, slot_span=0.0315, slot_width=0.007, slot_near=0.0268, **kwargs)

A clamping fork seen from above: the U that closes on a pedestal, the tapering shank, and the slot its screw goes through.

The origin is the bore centre - the point that comes to sit on the pedestal it holds - and that is its named point, 'bore'. The shank runs from there along -x, so a fork attached with no turn of its own lies behind the post it clamps. 'screw' is the middle of the slot, which is where the bolt into the bench roughly goes.

The smooth waist of the real part is drawn as a straight taper and two arcs: this is a drawing of what the part occupies, not a reproduction of it. The dimensions default to Thorlabs’ CF125 drawing.

Parameters:
  • bore_diameter (float, optional) – The U that closes on the post. Defaults to 26.0 mm, which takes a 25 mm pedestal.

  • length (float, optional) – Prong tips to tail, in metres. Defaults to 73.8 mm.

  • width (float, optional) – Across the prongs. Defaults to 36.3 mm.

  • tail_width (float, optional) – Across the rounded tail. Defaults to 23.4 mm.

  • tip_ahead (float, optional) – From the bore centre to the prong tips, along the fork. Defaults to 3.8 mm. Less than the bore radius, or the U does not close on anything.

  • slot_span (float, optional) – Between the two ends of the slot, centre to centre. Defaults to 31.5 mm.

  • slot_width (float, optional) – Across the slot. Defaults to 7 mm, which passes a 1/4-20 cap screw.

  • slot_near (float, optional) – From the bore centre to the near end of the slot. Defaults to 26.8 mm.

  • **kwargs – Passed to Mechanics.

Return type:

Mechanics

gtrace.mechanics._MOUNT_POST_X = -13.5
gtrace.mechanics._MOUNT_POST_D = 4.0
gtrace.mechanics._mount_shapes(u, knobs, front_w, front_d, gap, back_w, back_d, face_ahead, tip_span, tip_r, stem_d, stem_w, knob_d, knob_w)

The shapes every kinematic mount is drawn from, with the dimensions in millimetres and u carrying them to metres.

The frame is the attachment frame: the origin is the substrate centre of the mounted optic, +x the host’s HR normal. The front face stands face_ahead of the origin; the plates stack backwards from it, the adjuster tips bulge out of the back plate into the gap on the two lines tip_span either side of the centre, and the knobs hang off their stems out of the back. The hole the mount is bolted down through is drawn last, over the plate it is bored in.

gtrace.mechanics._MODEL_REGISTRY
gtrace.mechanics.register_model(name, source, description='', prefix=None)

Put a model into the library, by value.

This is the whole of “save it to the library”: build a shape in a cell - by hand, or starting from breadboard() or mirror_mount() - look at it in the viewer, and register what you settled on. The shapes are copied out as data at this moment, so editing the original afterwards does not quietly edit the library.

A name already registered is overwritten: that is how a definition is updated, and relink_mechanics() is how a layout then chooses to follow it.

Parameters:
  • name (str) – The model name, e.g. ‘POLARIS-K1’.

  • source (Mechanics or sequence of gtrace.draw.Shape) – Where the shapes come from. A Mechanics contributes its layer as well; its pose is ignored - a model is a shape, not a place.

  • description (str, optional) – One line for models() to show.

  • prefix (str or None, optional) – What to call the bodies built from this model, before the number: ‘MT’ gives MT1, MT2. A part is known by what it is - a mount is MT1 whatever catalogue it came from - so the model says it rather than every layout choosing again, and a front end that adds one has the name to hand. None leaves it to whoever is naming, which is ‘H’ in the viewer.

Returns:

name

Return type:

str

gtrace.mechanics.models()

The library: model name -> description, sorted by name.

gtrace.mechanics.model_shapes(name)

Fresh shape objects for a registered model.

Raises:

KeyError – If the library has no such model.

gtrace.mechanics.model_points(name)

The named points of a registered model, in local coordinates.

Raises:

KeyError – If the library has no such model.

gtrace.mechanics.model_prefix(name)

What bodies built from a registered model are called, before the number - ‘MT’ for a mount, ‘FK’ for a fork - or None where the model does not say.

Raises:

KeyError – If the library has no such model.

gtrace.mechanics.model_params(name)

The builder parameters of a registered model, or None for one registered from hand-drawn shapes. A copy; the registry is not handed out to be edited in place.

Raises:

KeyError – If the library has no such model.

gtrace.mechanics.from_model(model, **kwargs)

A Mechanics built from a library model, carrying the model name as its label.

The label is a label: the layout saves the shapes by value, and a library that changes afterwards changes nothing until relink_mechanics() is asked to.

Parameters:
  • model (str) – The model name.

  • **kwargs – Passed to Mechanics: name, center, rotationAngle, layer, attached_to and the rest. The layer defaults to the model’s own.

Return type:

Mechanics

gtrace.mechanics.save_models(filename, names=None)

Write library models to a JSON file.

The file carries exactly what the registry holds - the serialized shapes, the layer, the description and the builder parameters - under a single ‘models’ object, so a saved library is the same data a saved layout embeds and load_models() can take it back without a conversion in between.

Parameters:
  • filename (str) – Name of the file to write.

  • names (sequence of str or None, optional) – Which models to save. None - the default - saves the whole library, the built-in stock included: they are values like any other, and loading them back changes nothing.

Returns:

filename

Return type:

str

Raises:

KeyError – If a name in names is not in the library.

gtrace.mechanics.load_models(filename)

Merge the models of a JSON file into the library.

Name by name, the file wins - exactly the rule register_model already has, since loading a definition is one more way of registering it. Models the file does not mention are left alone, so building a library out of several files is just calling this once per file.

Everything is checked before anything is merged: a file with one unreadable shape in it changes nothing, rather than leaving the library half updated.

Parameters:

filename (str) – A file written by save_models().

Returns:

The names that were merged, in the file’s order.

Return type:

list of str

Raises:

ValueError – If the file is not a model library, or an entry of it does not describe one.