2bba18d0f710d8a33a7e31ca43d017393b1cf87b
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
978c1075ad |
fix(task-5): cut faces on the real chord, cross sections that see features, a section with no dashed cut edge
Three defects, all of them the same mistake in three places: the cut face was built from something other than the geometry it claims to show. 1. A prismatic cut face removed a feature by its BOUNDING BOX. `Hole.removal_box` is a square, so the gap punched in the cut face was the full diameter wherever the plane passed. On the plan's 80x50x8 plate with a Ho10 hole at (40, 25): a plane at y=29.9 grazes the hole (true chord 1.990) and the section still showed an 8 mm gap through solid metal - 560.0 mm2 hatched against a true 624.08, a 64 mm2 error in the hatched area AND a wrong drawn outline. `Slot` had the same obround-as-box. Features now answer `cut_spans(part, p1, unit)` with their own exact chord: `_circle_chord` for a hole, the union of two circles and a rotated rectangle for a slot, the polygon's own crossings for a pocket, and an exact slab clip of `removal_box` as the default. `_box_span` (the corner projection, which is the box's shadow and not a chord at all) is gone. 2. A transverse revolved section ignored every feature and the honesty rule never fired. A cross section through a DIN 6885-1 keyway came out as a plain hatched disc with `omitted == ()` - the commonest mechanical cross section there is, hatched straight over the 12x5 keyway. The face is now built by `_transverse_face`: its radii come from `radial_profile` (so a groove, an undercut, a bore or an ISO 6410 internal thread is in the face already, which the raw segment diameters could not report), a non-axisymmetric feature is asked for its own `cross_section` notch record, and one the plane really passes through with no such record is listed in `omitted` with its reason rather than hatched over. `Keyway._notch` is the one calculation the end view and the cut face both come out of. 3. A section drew its own cut boundary as a HIDDEN (dashed) line, because the longitudinal branch reused `silhouette_prims` and the silhouette draws the bore dashed - correct for an un-cut view, wrong for a section, where that line IS the hatch loop's boundary. ISO 128-50 bounds a surface lying in the cutting plane with a continuous wide line and ISO 128-3 leaves hidden detail out of a sectional view; via ROLE_LAYER['hidden'] this would also have put the cut boundary on the HIDDEN layer in Task 7. New `section_profile_prims` emits the cut outline all-continuous, and `half=True` keeps the dashed bore on the -Y half only, which is the half a half section does not cut. And the claim the last commit made without earning it: the hatched area and the drawn outline are now literally one calculation. The longitudinal loop is the *emitted* outline flattened (`_flatten_path`), so a chamfer or fillet that substitutes a silhouette corner is cut out of the hatch exactly where it is drawn - a 2 mm 45 deg chamfer takes its 2 mm2 off the 1000 mm2 half face instead of being hatched over. Eleven new tests, every one of them red on the parent commit: the hole chord at 0/4/4.9 mm off centre, a tangent plane leaving the face whole, the 45 deg slot, the keyway cross section against its own analytic area, the feature a cross section cannot project, the feature the plane misses, the groove read off the profile, the continuous cut boundary, the half section's dashed half, and the chamfered cut face. No new ActiveX member is called: all three fixes are pure geometry in the backend-free `engineering/mech` package. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd |
||
|
|
457c53644f |
fix(task-3): keyway end-view arc, the machined face, and the chamfer's segment bound
Three defects in the feature catalogue, all faithfully transcribed from the plan text and all wrong in shipped code. 1. Keyway.prims(view="side") emitted the arc the keyway REMOVES. `Arc` is CCW start -> end, and the emitted (right wall -> left wall) is the ~31 degree cap over the slot opening, not the ~329 degrees of shaft that survives it. Measured live on AutoCAD 2026 (Documents.Add scratch doc, closed in a finally): ModelSpace.AddArc(center, radius, start_rad, end_rad) -- angles in RADIANS, CCW start -> end -- gives ArcLength 8.098 mm for the emitted 74.534 -> 105.466 deg and 86.150 mm for the reversed 105.466 -> 74.534 deg, against a 94.248 mm full circle at r = 15; StartPoint/EndPoint of the emitted arc are exactly the notch walls at x = +/-4. Swapped, so the arc now runs left wall -> right wall the long way round, and the side view's bbox goes from (-4, 11, 4, 15) to (-15, -15, 15, 14.457). 2. Hole and Pocket cut the plate from OPPOSITE faces in the same view frame: Hole ran z = 0 -> depth, Pocket z = thickness -> thickness - depth, and neither takes a face parameter. A plate carrying both showed the pocket milled from one side and the blind hole drilled from the other, silently -- omission() returns None for both, so nothing reported it. The frame comment now names the machined face (v = thickness, the face the front view looks at), and Hole drills from it: the blind floor, the counterbore step and the through bore all hang down from there, as Pocket already did. 3. Chamfer.validate bounded the axial leg against the whole part, never against the segment the chamfer sits on. A shallow lead-in passed validation and was drawn straight through a shoulder at a radius that segment does not have (size 30 at 10 deg on a 15 mm end segment: radial 5.29 < 10 so the radial guard was happy, yet `before` landed at x = 45, two segments away). New helper _anchor_segment names the segment a corner actually cuts into -- at a step, the adjacent one carrying the larger radius -- and the leg is bounded by its length, refused by name with the step it would have crossed. Tests: the keyway test asserted only primitive counts and two x coordinates, so it passed with the arc reversed; it now pins the sweep, the endpoints and the bbox. The hole test exercised only a through hole, which is symmetric; added a blind-hole-and-pocket test that pins both to the same face, and a counterbore test. Added three chamfer tests (two refusals, one that must still be accepted). Each fix was mutation-checked: reverting it fails its test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd |
||
|
|
ac6c4075ba |
feat(task-3): the feature catalogue and its standards tables
engineering/mech/features.py is the nineteen typed features of spec section 5,
each answering the same four questions - is my placement legal, what do I
contribute to this view, to a cut face, and what dimension do I want - plus the
five structural hooks the view engine needs: removal_box, radial_edit,
corner_edit, outline_edit and omission. Pure arithmetic; a test asserts emitted
primitive tuples, not a screenshot.
Nothing restates a table the repository already owns: Keyway takes its width
and depth from engineering.keyway (DIN 6885-1) and is refused by name outside
that table's bore range; GearTeeth takes its outline from engineering.gear's
involute generator and is refused when its tip diameter disagrees with the
segment it sits on.
standards/threads.py transcribes ISO 261 Table 1 and Table 2 - first-choice
M1.6-M64 plus second-choice M14/M18/M22/M27/M33/M39/M45/M52/M60 - and computes
ISO 724's basic minor and pitch diameters from ISO 68-1's own formula, pinned
against the published values (M20x2.5 -> 17.294 / 18.376). The remaining
second-choice diameters, every third-choice diameter and fine pitches below M8
are not transcribed and are refused by name, never interpolated. The drawing
rules are ISO 6410: minor at 0.8 x major, a thread-length limit line across the
major, a three-quarter circle in the end view, and an internal thread whose
section hatch runs to the major diameter.
standards/{undercuts,rings,centres,orings}.py ship DIN 509, DIN 471/472,
DIN 332-1 and ISO 3601-2 with their SOURCE, their row-key contract and an
**empty** row set. That is deliberate and is the track's table rule taken at its
word: a row that could not be verified against the standard is not shipped,
because a wrong relief depth or groove diameter is a wrong workshop drawing
while a narrow table is merely narrow. Every lookup is refused by name and says
what to transcribe and where; the features accept explicit dimensions so the
geometry is fully exercised, and DIN 332 form R is refused outright rather than
approximated by the straight 60 degree cone of forms A and B. Filling any of
these tables later is a data edit with no code change, and a shape test already
fails any row that lands without a column the drawing code reads.
Three deviations from the plan text, each measured rather than assumed
(the merge agent should keep exactly one copy of the first):
1. standards/__init__.py (Task 1, on main) refused a registration with no rows
("registered no rows"), which would have made the four not-transcribed
tables impossible to register at all - and registering them is what keeps a
later transcription a data edit. register() now refuses a rows argument that
is not a dict and accepts an empty one; two tests in tests/test_mech_standards.py
pin both halves. No existing test asserted the old refusal.
2. ORingGroove's housing kind is carried by `housing`, not `kind`. A dataclass
field named `kind` overwrites the discriminator _Base.to_dict() writes:
measured, Probe(id='og').to_dict() == {'kind': 'radial', 'id': 'og'}, so
feature_from_dict would then refuse its own payload as an unknown feature
kind and no part carrying an O-ring groove could round-trip through XDATA.
A new test pins the round trip.
3. The plan's end-chamfer test asserted after == (75.0, 10.0) - the corner
itself - and before == (72.0, 8.268), a point on neither surface. The real
edit is before (72.0, 10.0) on the cylinder and after (75.0, 8.268) on the
end face, consistent with the 45-degree start chamfer the same file pins.
The test was corrected to the measured geometry; the behaviour is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
|