The vertex-normal fallback compared the cross product's length with
f64::EPSILON, an area-scale threshold, so a valid triangle small enough
fell back to the leaning vertex normal again. Fall back only when the
cross product is zero.
Co-Authored-By: Claude Opus 5 <[email protected]>
The vertex-normal fallback compared the cross product's length with
f32::EPSILON, an area-scale threshold, so a valid facet with 1e-4 edges
(cross product 1e-8) took the leaning vertex normal again. Fall back only
when the cross product is zero.
Co-Authored-By: Claude Opus 5 <[email protected]>
PlotStyleTable::to_text wrote scale_factor with one decimal, and saving
from the plot style panel rewrites the whole loaded table. A table with
apply_factor on and scale_factor=0.25 came back as 0.2, thinning every
scaled lineweight by a fifth.
Write the factor in full, keeping the decimal point on a whole value.
Co-Authored-By: Claude Opus 5 <[email protected]>
In a .lin file the description is optional and the comma goes with it, so
"*PLAIN" followed by "A,.5,-.25" is a complete definition. parse only kept
a header that contained a comma, so such a linetype was dropped silently
and a CENTERLTYPE naming it then reported that it was not loaded.
Take the whole header as the name when there is no comma.
Co-Authored-By: Claude Opus 5 <[email protected]>
build_stl took the facet normal from the first vertex's normal whenever the
mesh had normals. On smoothed meshes (tessellated curved solids, OBJ imports
with vn) that normal leans off the triangle, while STL defines the facet
normal as the triangle's own unit normal.
Use the triangle's own normal, and keep the vertex normal only for a
triangle with no area. Meshes without normals export as before.
Co-Authored-By: Claude Opus 5 <[email protected]>
build_step took the PLANE normal from the first vertex's normal whenever
the mesh had normals. On smoothed meshes (tessellated curved solids, OBJ
imports with vn) that normal leans off the triangle, so the plane missed
two of the face's corners and the first edge was no longer perpendicular
to the placement axis.
Use the triangle's own normal, and keep the vertex normal only for a
triangle with no area. Meshes without normals export as before.
Co-Authored-By: Claude Opus 5 <[email protected]>
With a working plane other than world XY, ROTATE and MIRROR handed a
non-ordinate dimension to acadrust's Entity::apply_transform, which only
translates those dimension types by where the transform sends the origin.
The definition points, plane and angles stayed unturned, so the dimension
jumped back once its block was baked again.
Send both through the existing Affine branch, which ALIGN already uses and
which transforms points, normal and stored angles together. The world-Z
paths are unchanged.
Co-Authored-By: Claude Opus 5 <[email protected]>
Scene meshes store each position as an f32 half plus a low residual so
geometry stays precise at survey coordinates, and the renderer adds the
two back together. STEP export read only the f32 half. Near x = 500000
that half steps in 1/32 units, so a solid at 500000.123 was written as
500000.125, and the edge directions and planes were built from the same
snapped points.
Build each exported vertex from both halves in f64 and derive directions
and the fallback face normal from those. Meshes without a residual export
as before.
Co-Authored-By: Claude Opus 5 <[email protected]>
IMPORTOBJ only computed face normals when the file listed no normals at
all. When a file did list some, a face that omitted its normal indices,
or pointed at an index past the end of the list, kept a zero normal. That
zero reaches the mesh shader, which normalizes it for lighting.
Track which vertices got a normal from the file and give the rest their
face normal. Supplied normals are kept, and a file without normals is
handled as before.
Co-Authored-By: Claude Opus 5 <[email protected]>
Rotating geometry leaves float noise in coordinates: turning the point
(0, 10) by 180 degrees gives X = -1.2246e-15. Rust formats that as
"-0.0000", so Properties showed "-0.0000" (or -0", -0d0'0", -0g) for a
value that is zero at the drawing's precision.
format_length and format_angle now drop the sign when every printed digit
is zero. Values that still show a digit keep it, and scientific notation
is unaffected.
Co-Authored-By: Claude Opus 5 <[email protected]>
ROTATE and MIRROR in the drawing plane moved a linear dimension's points
but left its stored rotation (the axis it measures along) unchanged. A
horizontal dimension rotated 90 degrees then measured its now-vertical
points along X and its value dropped to 0; mirroring about a slanted line
did the same. Polar ARRAY goes through the same path.
Turn the axis by the rotation angle, and reflect it about the mirror line.
A zero-length mirror line still leaves the dimension untouched.
Co-Authored-By: Claude Opus 5 <[email protected]>