--- jupyter: description: 'The convex hull, the smallest enclosing circle and the rectangle of least area around a part in planex2d, exact with arcs: the round stock and the blank of an L-shaped bracket turned on the sheet.' --- # Hull and enclosing shapes Three measurements in `planex.measurements` find what encloses a part: | Measurement | Gives | |---|---| | `ConvexHull()` | The convex hull as a face, exact with arcs; a spline by its approximation | | `EnclosingCircle()` | The smallest circle around the part, with its `face`, `center`, `center_hv` and `radius` | | `EnclosingRectangle()` | The rectangle of least area around the part, at any angle, with its `face`, `center`, `center_hv`, `length` and `width` (length ≥ width) and the `angle` of its longer side from $h$, in degrees | A measurement is a function of a part, and `part.Measure(f)` evaluates it (see [Part analysis](analysis.md)). The radius of the enclosing circle is the round stock that a turned part needs, `part.Measure(px.measurements.EnclosingCircle())["radius"]`, and the length and width of the enclosing rectangle are the blank that a flat part is cut from. Unlike the bounding box, the rectangle may lie at any angle. ```python import math import planex as px import planex.measurements as pm ``` ```python nbsphinx="hidden" from docs_figures import Row ``` ## An L-shaped bracket The example is an L-shaped bracket with legs of 60 and 40, each 10 wide and with its outer corner rounded to a radius of 10, turned by 30° on the sheet (Figure 1a). ```python outline = px.QuickSketch().Line(60).Turn(90).Line(10).Turn(90).Line(50).Turn(-90).Line(30).Turn(90).Line(10).Close() bracket = outline.Face().Filleted((0, 0), 10).Rotated((0, 0), 30) hull = bracket.Measure(pm.ConvexHull()) circle = bracket.Measure(pm.EnclosingCircle()) blank = bracket.Measure(pm.EnclosingRectangle()) ``` The hull bridges the inside of the L with a straight line from the end of one leg to the end of the other and keeps the rounded corner (Figure 1b). Before the turn, it is the polygon through (0, 0), (60, 0), (60, 10), (10, 40) and (0, 40), of area 1650, less what the fillet takes off the corner: ```python print("hull area", hull.mass, "exact", 1650 - (1 - math.pi / 4) * 10**2) ``` The smallest circle passes through the ends of the two legs, and the line between them is its diameter, $\sqrt{60^2 + 40^2}$ (Figure 1c). The rectangle of least area lies along the legs, 60 by 40, at the bracket's angle of 30° (Figure 1d): ```python print("circle radius", circle["radius"], "exact", math.hypot(60, 40) / 2) print("blank", round(blank["length"], 9), "by", round(blank["width"], 9), "at", round(blank["angle"], 9), "degrees") ``` ```python nbsphinx="hide-input" Row((bracket, "The bracket, turned by 30°"), (bracket, "The convex hull", {"dashed": [hull]}), (bracket, "The smallest circle", {"dashed": [circle["face"]], "marks": [circle["center_hv"]]}), (bracket, "The rectangle of least area", {"dashed": [blank["face"]]}), caption="An L-shaped bracket and what encloses it") ``` See [Boxes, crossings and open ends](queries.md) for the bounding box along the axes.