Land the spilled coins, plane the bench's tenons, and sharpen the support check
Three defects reported from looking at the models, and the first of them says something about the check that was supposed to catch it. Every third coin was lifted to "land on top of the previous one" while its position stayed independently scattered, so it was almost never above anything and simply hovered about 3 mm off the ground. A stacking coin now takes the previous coin's PLACE as well as its height. The tilted ones were lifted by half their thickness plus their circumradius; a coin is a nine-sided prism and can come to rest on a face rather than a corner, so the lift uses the apothem and its own radius, erring towards bedding into the ground rather than floating above it. The support check missed all of that, and the reason is worth writing down: its voxel is the model's extent over the resolution, so at 64 a 0.19 m coin pouch gets a 3 mm voxel -- exactly the size of the gap it existed to find. A check coarser than the defect it hunts is worth very little. At 112 the whole suite still runs in fifteen seconds. Raising it immediately turned up a real fault nobody had seen. The log pile's sawn ends were cut to exactly the body's end radius and placed exactly at its rim, so disc and lathe met along a seam of no width: they touched and never overlapped, and there was nothing joining them but two edges in the same place. The caps are now three percent wider and seated slightly inside, which is two millimetres here and true of a real log anyway, since bark wears back from a cut face. And the bench's through-tenons stood 42 mm proud of the seat -- a block of oak the size of a thumb sticking straight up out of the surface you are meant to sit on. A real through-tenon is wedged and then planed back, so what shows is end grain and a hairline of shoulder. Three millimetres proud, ten housed below. 28 models, 20 547 triangles, all checks pass at resolution 112, 0 floating cases, build clean.
This commit is contained in:
parent
2b6e2b4d02
commit
1888616315
8 changed files with 175 additions and 64 deletions
|
|
@ -111,6 +111,7 @@ export function createModel(overrides: Partial<CoinPouchConfig> = {}) {
|
|||
const coinPieces: BufferGeometry[] = []
|
||||
// Scatter DIRECTION: all one way, because spilled money flows to one side.
|
||||
const spillAngle = random() * Math.PI * 2
|
||||
let previous: { x: number; z: number; top: number } | undefined
|
||||
for (let i = 0; i < count; i += 1) {
|
||||
const t = (i + 0.6) / count
|
||||
// Distance grows with a square root: piled at the pouch, thin further out.
|
||||
|
|
@ -118,11 +119,19 @@ export function createModel(overrides: Partial<CoinPouchConfig> = {}) {
|
|||
const spread = jitter(random, 0.75) * (0.35 + t * 0.65)
|
||||
const angle = spillAngle + spread
|
||||
const thickness = config.coinRadius * (0.13 + random() * 0.06)
|
||||
// The overlapping ones: every third coin lands on top of the previous.
|
||||
const stack = i % 3 === 2 ? thickness * 1.6 : 0
|
||||
// Every third coin lands ON the one before it -- which means taking
|
||||
// that coin's PLACE, not just its height.
|
||||
//
|
||||
// The lift was applied while the position stayed independent, so the
|
||||
// stacking coin was almost never above anything and simply hovered
|
||||
// about 3 mm off the ground. The support check missed it at its default
|
||||
// resolution: the voxel is the model's extent over 64, which on a 0.19 m
|
||||
// pouch is 3 mm -- exactly the size of the gap it had to see.
|
||||
const stacking = i % 3 === 2 && previous !== undefined
|
||||
|
||||
const lower = config.coinRadius * (0.92 + random() * 0.16)
|
||||
const coin = prismGeometry(
|
||||
config.coinRadius * (0.92 + random() * 0.16),
|
||||
lower,
|
||||
config.coinRadius * (0.9 + random() * 0.16),
|
||||
thickness, 9, [0, 0, 0], tint('brass', jitter(random, 0.06), 0.5),
|
||||
)
|
||||
|
|
@ -130,11 +139,26 @@ export function createModel(overrides: Partial<CoinPouchConfig> = {}) {
|
|||
const tilt = random() < 0.22 ? 0.5 + random() * 0.7 : jitter(random, 0.12)
|
||||
coin.rotateX(tilt)
|
||||
coin.rotateY(random() * Math.PI * 2)
|
||||
coin.translate(
|
||||
Math.sin(angle) * distance,
|
||||
floor + thickness / 2 + stack + Math.sin(tilt) * config.coinRadius * 0.5,
|
||||
Math.cos(angle) * distance,
|
||||
)
|
||||
// A tilted disc has to rise by half of (its diameter's projection plus
|
||||
// its own thickness) for its lowest edge to reach the ground, not by
|
||||
// half its thickness alone.
|
||||
// The APOTHEM, not the circumradius, and this coin's own radius rather
|
||||
// than the nominal one. A coin is a nine-sided prism; rolled onto its
|
||||
// edge it can come to rest on a face rather than a corner, so lifting
|
||||
// it by the circumradius leaves it standing on nothing. Erring towards
|
||||
// the smaller radius beds it into the ground instead, which is the
|
||||
// right way to be wrong.
|
||||
const rest = (Math.sin(tilt) * lower * 2 * Math.cos(Math.PI / 9)
|
||||
+ thickness * Math.cos(tilt)) / 2
|
||||
const x = stacking
|
||||
? previous!.x + jitter(random, config.coinRadius * 0.45)
|
||||
: Math.sin(angle) * distance
|
||||
const z = stacking
|
||||
? previous!.z + jitter(random, config.coinRadius * 0.45)
|
||||
: Math.cos(angle) * distance
|
||||
const y = stacking ? previous!.top + rest : floor + rest
|
||||
coin.translate(x, y, z)
|
||||
previous = { x, z, top: y + rest * 0.55 }
|
||||
coinPieces.push(coin)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue