Commit graph

2,471 commits

Author SHA1 Message Date
Hakan Seven
7e8fc8ef88 feat: replace rfd Save As with native iced file chooser
Implements a full in-app file browser window for Save As, replacing the
rfd dialog that could not expose the selected filter index on Linux.
The new chooser includes directory navigation, a scrollable file list,
filename input, and a format drop-down (DWG/DXF × 2018/2013/2010/2007/2004/2000/R14).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 16:20:38 +03:00
Hakan Seven
9cd8eff77f fix: replace broken version filters with custom Save As dialog
rfd does not expose the selected filter index, so the old DWG/DXF version
filters had no effect — every file was always saved as AC1032 (R2018).

Replace with a single custom iced Save As window that shows:
- File name text input
- Save-in folder input + Browse button (rfd folder picker)
- Format dropdown: DWG/DXF × 2018/2013/2010/2007/2004/2000/R14
- Save / Cancel buttons

The selected format is passed to save_as_version() which temporarily sets
doc.version before writing, so DwgWriter/DxfWriter emit the correct file
format. Also works in the unsaved-changes Save flow.

Closes #9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 16:12:32 +03:00
Hakan Seven
9974456a5d chore: bump version to 0.1.9
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 15:54:37 +03:00
Hakan Seven
01943c5b8d fix: correct paper-space grip projection and MTEXT attachment point rendering
- Grip points in paper space now use the 2-D linear to_px transform
  (tx/ty/ortho_size) instead of the 3-D view_proj matrix, matching the
  coordinate system used by PaperCanvas
- world_offset is no longer subtracted from paper-space entity grip
  positions — paper-space coordinates are already unoffset (same rule
  as wire tessellation in wires_for_block)
- MTEXT v_offset corrected for all attachment points: CXF glyphs sit
  on the baseline and extend upward, so Top attachment needs v_offset=-h,
  Bottom needs (n_lines-1)*line_h, Middle is the midpoint of the two

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 12:16:46 +03:00
Hakan Seven
3009639741 fix: decode all MTEXT escape codes correctly
Previously \\U+XXXX was in the "strip until ;" list, silently dropping
all Unicode character references (°, ±, ⌀, Ø, €, …).

Changes:
- \\U+XXXX / \\u+XXXX  decode to the actual Unicode character (was stripped)
- \\S upper/lower;     stacked fractions/tolerances render as "upper/lower"
                       or "upper^lower" instead of leaking as literal text
- \\t                  tab → four spaces (was leaking as literal 't')
- Unknown escapes      silently consume the code char (was leaking it)
- \\M+...;             DBCS multibyte — stripped (added to semicolon-arg list)
- \\X                  paragraph-align end marker — stripped cleanly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:51:45 +03:00
Hakan Seven
c5c5ba1b60 fix: correct MTEXT line spacing and preserve blank paragraph separators
Line spacing: DXF code 44 (line_spacing_factor) is a multiplier on
AutoCAD's default baseline-to-baseline distance of 5/3 × text_height.
The renderer was using factor × 1.0 instead of factor × 1.667, making
all MTEXT appear cramped.

Blank paragraphs: split_mtext_lines was filtering out empty strings, so
\\P\\P (double paragraph break used to separate sections) was silently
collapsed. Empty lines in the middle of the block are now preserved;
only leading/trailing blank lines are stripped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:48:06 +03:00
Hakan Seven
fc0aa8698b feat: show Save/Discard/Cancel dialog before closing unsaved tabs or quitting
Opens a floating OS window when the user tries to close a dirty tab or
quit with unsaved changes. The main window stays alive until the dialog
is resolved — Cancel aborts the close entirely. For quit with multiple
dirty tabs the dialog loops through each one individually.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:31:11 +03:00
Hakan Seven
59e7f6b832 docs: switch Linux install instructions from Flatpak to AppImage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 11:02:30 +03:00
Hakan Seven
ce40e5092d docs: rewrite README to document all features added since initial release
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 10:59:41 +03:00
Hakan Seven
9d6efe326a chore: bump version to 0.1.8
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 10:54:36 +03:00
Hakan Seven
fad7b16d5f fix: correct PageSetup paper size when layout origin is non-zero
paper_limits() can return a non-zero origin (e.g. when min_limits has
negative margin values).  PageSetup was using x1/y1 directly instead of
(x1-x0)/(y1-y0), giving wrong dimensions in those cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 10:52:25 +03:00
Hakan Seven
3298ebff91 fix: use PlotSettings paper dimensions for correct paper-space rendering
paper_limits() now reads paper_width/paper_height/plot_rotation from the
Layout object (populated by a patched acadrust from the embedded DWG
PlotSettings). This fixes layouts where min/max_limits do not match the
physical paper size (e.g. A4 portrait content inside A3 landscape limits).

DXF files use codes 44/45/73 from raw_plot_settings_codes; DWG files use
the PlotSettings block embedded in the LAYOUT object. Both fall back to
min/max_limits when paper_width is zero.

Depends on HakanSeven12/acadrust feat/layout-paper-dimensions (PR #21 on
hakanaktt/acadrust); using that fork until the PR is merged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 08:04:35 +03:00
Hakan Seven
cbb37a0909 fix: persist camera in View table and fix pitch clamp for exact top/bottom views
- Save camera to named View table entries (H7CAD_Camera_Model / H7CAD_Camera_<layout>)
  on every navigation change; restore from these entries on file open and tab switch.
  acadrust's DWG writer overrides *Active VPort view_height/view_center with
  zoom-extents values, but leaves the View table untouched, so this survives save.
- Fix pitch recovery: clamp vd.z to [-1, 1] instead of [-0.999, 0.999] so that
  asin(1.0) = π/2 exactly for plan/top views, preventing the subtle tilt on reload.
- Fix IEEE 754 edge case: atan2(+0, -0) = π for plan view direction (0,0,1);
  special-case yaw = 0 when both vd.x and vd.y are near zero.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 07:43:45 +03:00
Hakan Seven
35e487934c fix: correct yaw recovery from view_direction vector
view_dir = rotation * Z = (sin(yaw)*cos(pitch), -cos(yaw)*cos(pitch), sin(pitch))
so yaw = atan2(x, -y), not atan2(x, y).
The sign error caused a 180-degree Z rotation on every save/reload cycle.
Applies to apply_active_vport_camera, apply_sheet_viewport_camera, and
camera_for_viewport.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 07:20:55 +03:00
Hakan Seven
05dd23a8dc fix: increment camera_generation on orbit/pan/zoom to trigger dirty sync
Direct camera.orbit/pan/zoom calls in update.rs bypassed camera_generation
so the Tick handler never detected a change and never wrote the camera back
to the document. Add camera_generation += 1 after each navigation call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 07:16:58 +03:00
Hakan Seven
8f90a68930 feat: restore and persist saved camera position per layout
- On file open and layout tab switch, restore the camera from the
  document's saved view (*Active VPort for model space, sheet viewport
  for paper space) instead of fitting to wire bounds.
- After any zoom/pan/rotate, write the new camera position back to the
  document and mark the file dirty so it is saved with the file.
- Uses last_synced_camera_gen to avoid marking the file dirty on the
  initial camera restore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 07:07:19 +03:00
Hakan Seven
ed94a5b81f fix: correct viewport projection by converting view_target to wire-space
Model entity wires are tessellated with world_offset subtracted for GPU
precision, but view_target/view_center were raw model coordinates.
Subtracting world_offset from view_target aligns both coordinate systems
so model content projects correctly into viewport rectangles in paper space.

Also fixes scale priority (view_height before custom_scale) and adds
view_center DCS offset to the projection, completing the paper-space
viewport rendering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 06:42:06 +03:00
Hakan Seven
6a0b9169d6 fix: identify user viewports by geometry when id is 0 or negative
The acadrust DWG reader never assigns a viewport id (always 0).
Some DXF exporters use id=-1 for all viewports.  In both cases the
previous id > 1 check excluded every viewport from content rendering.

Replace is_user_viewport_id(id) with is_content_viewport(vp) that
uses a geometry heuristic for unknown ids (0 / negative):
  - id=1           → always sheet viewport (excluded)
  - id≥2           → always user viewport  (included)
  - id=0 or id<0   → sheet if center≈(0,0) AND scale≈1.0, else user

This allows DWG files and non-standard DXF files to display model
content inside their paper-space viewports and be entered via
double-click.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 22:06:43 +03:00
Hakan Seven
66a73b00e1 fix: make viewports from external DXF/DWG files visible and enterable
Two root causes prevented paper-space viewports from loading correctly:

1. acadrust's ViewportStatusFlags::from_bits() maps bit 0 → is_on, but
   the real DXF/DWG spec uses bit 15 (0x8000) for "viewport on". Post-load
   fixup in io/mod.rs now corrects this for both DXF and DWG files: when
   bit 0 is clear but bit 15 is set, is_on is forced true and locked is
   derived from bit 14 (0x4000).

2. Some DXF exporters write id=-1 for all viewport entities instead of the
   standard id=1 (sheet) / id≥2 (user) convention. The is_user_viewport_id()
   helper now treats any id ≠ 0 and ≠ 1 as a user viewport, covering both
   the standard id≥2 and the non-standard id=-1 cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 21:57:02 +03:00
Hakan Seven
00e61a1301 fix: correct entity color adaptation for viewport content in paper space
Model-space entities shown through a viewport were tessellated using
paper_bg_color (light), but the interactive viewport pane renders them
on bg_color (dark), causing white/black entities to appear incorrectly.

- model_wires_for_viewport: tessellate with bg_color so the viewport
  pane (dark background) gets correctly adapted entity colors
- viewport_content_wires: re-adapt projected wire colors using
  paper_bg_color before rendering onto the paper canvas

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 21:39:38 +03:00
Hakan
678909bdf7 feat: add local settings for Bash permissions 2026-04-30 10:01:17 +03:00
Hakan
d06db45950 feat: adapt white/black entity colors to background luminance
White entities on light backgrounds (e.g. paper space) render as black;
black entities on dark backgrounds (e.g. model space) render as white.
All other colors pass through unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 10:00:46 +03:00
Hakan Seven
7065bfa935 fix: do not apply world_offset to paper-space entities
Paper-space entities (wires, hatches, wipeouts) live in sheet
coordinates (~mm scale) and do not need the model-space centring
shift.  world_offset was incorrectly subtracted from their coordinates,
displacing all paper-space geometry away from the paper sheet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 21:38:48 +03:00
Hakan Seven
1a19a841e6 fix: correct polyline arc direction, text precision, Face3D edge color, buffer chunking
- fix: polyline arc center sign was inverted (- → +) causing arcs to render on the
  wrong side in LwPolyline and Polyline2D
- fix: store glyph strokes in local space with f64 origin so world_offset subtraction
  uses f64 precision; prevents blocky text at large UTM coordinates
- fix: Face3D fill darkened to 45% so edge wires are visually distinct from fill
- fix: wire batch vertex buffer chunked to 256 MB GPU limit (was panic on large files)
- fix: gpu_face3d_edges changed from Option<WireGpu> to Vec<WireGpu> to support chunks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 20:58:44 +03:00
Hakan Seven
02203dba93 Revert "fix: skip degenerate triangle for 3-corner Face3D"
This reverts commit 517af91245.
2026-04-29 20:34:18 +03:00
Hakan Seven
517af91245 fix: skip degenerate triangle for 3-corner Face3D
acadrust Face3D encodes triangles by setting fourth_corner == third_corner.
The fill builder was emitting a zero-area second triangle for these cases.
Now checks the p2==p3 distance and skips the second triangle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:57:38 +03:00
Hakan Seven
298098e764 perf: dedicated Face3D shader — N draw calls → 2
3DFACE entities previously created one WireGpu buffer per entity,
resulting in N separate draw calls per frame. For files with large
triangle meshes this was the dominant GPU CPU overhead.

New pipeline:
- face3d.wgsl: simple flat-color vertex + fragment shader (MVP only,
  no quad expansion, no pattern distance computation)
- Face3DGpu: batches ALL Face3D entities into a single TriangleList
  buffer (6 vertices per face, per-vertex color) — 1 draw call
- WireGpu::from_batch: merges N Face3D edge wire models into one
  quad-expanded buffer for edge rendering — 1 draw call
- split_face3d_wires: separates face3d from other wires at Primitive
  build time via document handle lookup (O(N), once per epoch)

Hit-testing via WireModel (CPU) is unaffected — face3d wires remain
in entity_wires_arc() and hit_test_wires() as before.

Before: N 3DFACE → N draw calls, N × 96 B/vertex WireVertex
After:  N 3DFACE → 2 draw calls (fill + edges), 28 B/vertex fill

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 21:53:31 +03:00
Hakan Seven
8c3964305b fix: convert grip positions to local space for display and hit-test
Entity grips() return world-space coordinates (raw DXF values). After
the world_offset change the camera view_proj is in local space, so
projecting world-space grips through it gave wrong screen positions and
hit-test failures.

- refresh_selected_grips: subtract world_offset from every grip.world
  so selected_grips are stored in local (camera) space
- Grip drag: cursor/snap positions are already local space; for
  GripApply::Absolute add world_offset back before passing to entity
  so entity coordinates stay in world space. Translate deltas are
  identical in both spaces so no conversion is needed there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:27:46 +03:00
Hakan Seven
5f69d8c3f0 fix: apply world_offset to hatch, solid, and wipeout boundary coordinates
hatch_model_from_dxf(), solid_hatch_model(), and wipeout_boundary_2d()
were converting DXF world-space coordinates directly to f32 without
subtracting world_offset. After the world_offset change moved all wire
geometry to local space, hatches/solids/wipeouts rendered at the wrong
position (displaced by the centroid offset, up to ~4M m for Turkish UTM).

All three functions now accept world_offset and apply it to every
boundary vertex before the f64→f32 cast.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:21:40 +03:00
Hakan Seven
e191315713 fix: restore visibility for large-coordinate DXF files after world_offset regression
Three root causes caused all geometry and UCS arrows to disappear:

1. TruckObject::Lines and TruckObject::Text variants returned world-space
   f32 coordinates without applying world_offset, so fit_all() computed
   bounds spanning from local space to UTM world space (~4 M m), placing
   the camera impossibly far from all visible geometry.

2. Ray/XLine entities with unnormalized direction vectors (common in some
   DXF exporters) produced astronomically large far-point coordinates
   (up to 1e28) that overwhelmed the camera fit even after the offset fix.
   Fixed by normalizing the direction vector before multiplying by
   DISPLAY_EXTENT.

3. Origin-stuck corrupted entities (coordinates ≈ 0 in world space become
   ≈ -world_offset in local space) pulled the fit_all() bounds far from
   the actual drawing. Fixed by computing local_extent_max from EXTMIN/EXTMAX
   (10× safety margin) and skipping points outside that range in fit_all().

Additional hardening: wire_gpu.rs now skips ±inf segments (not just NaN),
and snap_pts/key_vertices in all TruckObject variants are offset-corrected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 18:04:35 +03:00
Hakan Seven
a2fb334966 fix: world_offset precision fix for large-coordinate DXF files (e.g. Turkish UTM)
Subtracts the DXF header extents centroid (world_offset) from all coordinates
in f64 BEFORE casting to f32. This eliminates the ~0.5 m ULP error that occurs
at 4,000,000 m UTM coordinates and caused geometry to disappear on zoom-out.

- Scene: adds world_offset field + compute_and_set_world_offset() method
- tessellate.rs: threads world_offset through all f64→f32 conversions
  (legacy_geometry, dimension_geometry, solid_wire_fallback, multileader)
- truck_tess.rs: to_local() helper already in place from prior session
- mod.rs: tessellate_entity() and entity_aabb() apply world_offset
- update.rs: compute_and_set_world_offset() called after doc load
- cmd_result.rs / solid3d_cmds.rs: pass correct offset to truck tessellators

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 07:41:38 +03:00
Hakan Seven
e38638502e fix: selected wires always visible on top of occluding geometry
Changed selection overlay pipeline from depth_compare=Greater to
depth_compare=Always so selected wires are redrawn at full brightness
after all other passes, making them visible regardless of what is in
front of them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 03:04:31 +03:00
Hakan Seven
c27927c2b3 fix: X-ray ghost pass for selected wires occluded by other geometry
Selected wires are now visible through occluding objects. A second
wire_xray pipeline (depth_compare=Greater, depth_write_enabled=false)
renders 25%-alpha ghost copies of selected wires only where they are
behind the depth buffer, leaving fully-visible portions at full glow
brightness unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 03:01:42 +03:00
Hakan Seven
392f4503d8 feat: complex linetype text elements and ellipse quadrant snaps
Complex linetypes now render embedded text elements (e.g. GAS_LINE's
"GAS" labels): the LtSegment::Text variant is parsed from LIN files,
scaled along with shape/dash segments, and tessellated via
cxf::tessellate_text_ex aligned to the linetype direction.

Full ellipses gain four Quadrant snap hints at ±major/±minor axis
endpoints in addition to the existing Center snap, matching AutoCAD
snap behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:34:51 +03:00
Hakan Seven
7bae75f5d6 feat: dimension extension lines respect DIMEXO offset and DIMEXE overshoot
Extension lines for linear and aligned dimensions now start at
DIMEXO × DIMSCALE distance from the definition point (instead of at the
point itself) and extend DIMEXE × DIMSCALE units past the dimension
line, matching AutoCAD rendering. Both values fall back to 0 when the
dimstyle is not found.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:30:56 +03:00
Hakan Seven
416d6adc99 feat: MultiLeader spline path type via Catmull-Rom tessellation
When path_type == Spline, the leader line is now tessellated as a
Catmull-Rom spline through the bend points (8 segments per span)
instead of connecting them with straight segments. Straight/Invisible
path types are unchanged. Key vertices and tangent geoms still use the
raw control points for snap and tangent snapping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:29:41 +03:00
Hakan Seven
debc4b87a8 feat: dimension arrow size from DIMASZ×DIMSCALE in dimstyle
Arrow size for all dimension types (linear, aligned, radius, diameter,
angular) is now read from the associated DimStyle's dimasz field scaled
by dimscale, instead of being hardcoded at 0.12. Falls back to 0.12
when the style isn't found in the document's dim_styles table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:28:48 +03:00
Hakan Seven
0bb4209e2c fix: closed spline gap, hatch spline boundary, and spline commit grouping
- Spline: if flags.closed/periodic and B-spline endpoints don't meet,
  add an explicit closing Wire segment to eliminate the visual gap.
- Hatch BoundaryEdge::Spline: evaluate the B-spline at 16 uniform
  parameter samples (de Boor via truck BSplineCurve) instead of
  plotting raw control points as a polyline; falls back to control-
  point polyline for degenerate knot/degree inputs.
- Ellipse arc key_vertices and LWPolyline midpoint grips committed
  separately; this commit wraps the spline-related fixes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:26:26 +03:00
Hakan Seven
6fd740e38f feat: ellipse arc endpoint snap and LWPolyline arc midpoint grips
Partial ellipse arcs now populate key_vertices with both endpoints so
Endpoint snap works correctly. LWPolyline arc segments (bulge ≠ 0) get
a diamond grip at the arc midpoint; dragging it recomputes the segment
bulge via circumcircle of start/mid/end, giving interactive arc editing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:22:51 +03:00
Hakan Seven
67022589df feat: render LWPolyline and Polyline2D wide strokes as solid fills
Wide polyline segments (constant_width, per-vertex start/end widths)
now appear as solid-filled quads or arc bands via HatchModel, generated
inline in synced_hatch_models(). Straight segments → trapezoid, arc
segments → arc-band polygon (inner/outer arc). MINSERT confirmed working
via acadrust explode_from_document → array_transforms().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 02:20:28 +03:00
Hakan Seven
c7a7022293 fix: Polyline3D spline vertex flags and AttributeEntity/Definition DXF rotation
Polyline3D tessellation now separates spline-fit curve vertices (flag 8)
from frame control points (flag 16): the curve vertices form the rendered
wire while control points are exposed as key_vertices for snap. Polylines
without spline flags are unchanged.

DXF post-load fixup now also converts AttributeEntity and AttributeDefinition
rotation from degrees to radians (group code 50 bug), matching the existing
LinearDimension fix. Attribute text rendered from DXF files now has correct
orientation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 22:12:56 +03:00
Hakan Seven
5216c247c2 fix: Spline snap points and TextStyle backward/upside-down rendering
Spline entities now expose fit_points (or control_points when no fit
points are defined) as key_vertices, enabling Endpoint and Midpoint
snap to reach spline construction points.

TextStyle is_backward flag is applied by negating the width_factor,
producing horizontally mirrored text. is_upside_down rotates the text
180°. Both tessellate_text_ex and text_local_bounds now handle negative
width_factor without clamping it to zero.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 22:10:32 +03:00
Hakan Seven
045ab96eab fix: resolve ByBlock color, linetype, and lineweight through INSERT chain
Block sub-entities with ByBlock color now inherit their INSERT's resolved
color instead of rendering as the default white. ByBlock linetype inherits
the INSERT's linetype pattern, and ByBlock lineweight inherits the INSERT's
effective line weight.

Implemented via render_style_for_block_sub(), called in tessellate_entity()
when expanding INSERT exploded entities.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 22:07:24 +03:00
Hakan Seven
464bb8905f fix: INSERT Insertion snap point and Hatch boundary snap points
INSERT entities now expose their insertion point as a SnapHint::Insertion
pre-baked snap candidate, enabling OSNAP Insertion to locate block
reference origins. The cross marker is also positioned at the actual
insertion point instead of the origin.

Hatch entities now populate key_vertices from Polyline and Line boundary
edges (with correct elevation Z), enabling Endpoint and Midpoint snapping
to hatch boundary geometry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 22:04:53 +03:00
Hakan Seven
d7f2f860a2
Update image link in README.md 2026-04-26 21:59:19 +03:00
Hakan Seven
cda8078905 docs: add acadrust integration gaps audit
Comprehensive backlog of acadrust entity fields, behaviors, and subsystems
not yet integrated into H7CAD rendering, snap, grip, and properties systems.
Covers tessellation gaps, OCS→WCS transform, ByBlock style resolution,
snap/grip point gaps, text rendering, and DXF reader unit bugs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:58:22 +03:00
Hakan Seven
4504916f97 fix: resolve DXF %%x codes and render MText decoration strokes
Text/MText values now correctly handle DXF special-character sequences:
- %%d → °, %%p → ±, %%c → ⌀, %%nnn → Unicode scalar (resolved in tessellation)
- %%u / %%o toggle underline and overline strokes for TEXT entities

MText decoration codes (\L/\l, \O/\o, \K/\k) were previously consumed
as argument-bearing codes, silently eating the decorated text. Fixed
strip_mtext_codes to keep them as zero-width markers; tessellate_text_ex
now emits actual line strokes (underline, overline, strikethrough).
measure_mtext_chars and word_wrap skip markers so line widths are correct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:57:51 +03:00
Hakan Seven
089612584d chore: bump version to 0.1.7
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 17:08:32 +03:00
Hakan Seven
db653c5a07 fix: derive dimension text rotation from axis geometry
acadrust's DXF reader does not parse group code 53 (text rotation),
so DimensionBase.text_rotation is always zero for DXF-loaded files.
Fall back to the natural axis-aligned rotation computed from geometry:
Linear dimensions use d.rotation (radians), Aligned dimensions use
atan2 of the second-first vector.  Normalize to (-π/2, π/2] so text
never appears upside-down.  Explicit non-zero overrides stored by the
DWG reader are preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 17:08:12 +03:00
Hakan Seven
19bb846c50 fix: dimension line geometry and DXF rotation unit mismatch
append_linear_dimension() applied the same perp offset to both d1 and d2,
but only d2 is guaranteed to be at the definition_point level; d1 must be
projected independently onto the dimension line, otherwise non-collinear
first/second points produce a parallelogram instead of a rectangle.

Fix: compute dim_line_pos = def.dot(perp) and project each endpoint
separately so the dimension line is always parallel to axis.

Additionally, the acadrust DXF reader stores LinearDimension.rotation from
group code 50 (degrees) without converting to radians, while DWG and our
own annotation commands store it in radians.  Add a post-load fixup in
load_file() that converts the rotation to radians for DXF files so
tessellation can call cos/sin uniformly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 16:57:23 +03:00