Internal fix: make expandPath not assume path has associated sweep (#4386)

* Add a test that shows current error within `expandPath`

* Make `expandPath` not assume there is an associated sweep artifact

* Look at this (photo)Graph *in the voice of Nickelback*

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Frank Noirot
2024-11-05 21:32:05 -08:00
committed by GitHub
parent 7bad60dfa3
commit 984420c155
3 changed files with 103 additions and 11 deletions

View File

@ -49,6 +49,26 @@ sketch002 = startSketchOn(extrude001, seg02)
extrude002 = extrude(5, sketch002) extrude002 = extrude(5, sketch002)
` `
const exampleCodeNo3D = `sketch003 = startSketchOn('YZ')
|> startProfileAt([5.82, 0], %)
|> angledLine([180, 11.54], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001) - 90,
8.21
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
sketch004 = startSketchOn('-XZ')
|> startProfileAt([0, 14.36], %)
|> line([15.49, 0.05], %)
|> tangentialArcTo([0, 0], %)
|> tangentialArcTo([-6.8, 8.17], %)
`
const sketchOnFaceOnFaceEtc = `sketch001 = startSketchOn('XZ') const sketchOnFaceOnFaceEtc = `sketch001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line([4, 8], %) |> line([4, 8], %)
@ -83,6 +103,7 @@ extrude004 = extrude(3, sketch004)
const codeToWriteCacheFor = { const codeToWriteCacheFor = {
exampleCode1, exampleCode1,
sketchOnFaceOnFaceEtc, sketchOnFaceOnFaceEtc,
exampleCodeNo3D,
} as const } as const
type CodeKey = keyof typeof codeToWriteCacheFor type CodeKey = keyof typeof codeToWriteCacheFor
@ -236,6 +257,69 @@ describe('testing createArtifactGraph', () => {
await GraphTheGraph(theMap, 2000, 2000, 'exampleCode1.png') await GraphTheGraph(theMap, 2000, 2000, 'exampleCode1.png')
}, 20000) }, 20000)
}) })
describe(`code with sketches but no extrusions or other 3D elements`, () => {
let ast: Program
let theMap: ReturnType<typeof createArtifactGraph>
it(`setup`, () => {
// putting this logic in here because describe blocks runs before beforeAll has finished
const {
orderedCommands,
responseMap,
ast: _ast,
} = getCommands('exampleCodeNo3D')
ast = _ast
theMap = createArtifactGraph({ orderedCommands, responseMap, ast })
})
it('there should be two planes, one for each sketch path', () => {
const planes = [...filterArtifacts({ types: ['plane'] }, theMap)].map(
(plane) => expandPlane(plane[1], theMap)
)
expect(planes).toHaveLength(2)
planes.forEach((path) => {
expect(path.type).toBe('plane')
})
})
it('there should be two paths, one on each plane', () => {
const paths = [...filterArtifacts({ types: ['path'] }, theMap)].map(
(path) => expandPath(path[1], theMap)
)
expect(paths).toHaveLength(2)
paths.forEach((path) => {
if (err(path)) throw path
expect(path.type).toBe('path')
})
})
it(`there should be 1 solid2D, just for the first closed path`, () => {
const solid2Ds = [...filterArtifacts({ types: ['solid2D'] }, theMap)]
expect(solid2Ds).toHaveLength(1)
})
it('there should be no extrusions', () => {
const extrusions = [...filterArtifacts({ types: ['sweep'] }, theMap)].map(
(extrusion) => expandSweep(extrusion[1], theMap)
)
expect(extrusions).toHaveLength(0)
})
it('there should be 8 segments, 4 + 1 (close) from the first sketch and 3 from the second', () => {
const segments = [...filterArtifacts({ types: ['segment'] }, theMap)].map(
(segment) => expandSegment(segment[1], theMap)
)
expect(segments).toHaveLength(8)
})
it('screenshot graph', async () => {
// Ostensibly this takes a screen shot of the graph of the artifactGraph
// but it's it also tests that all of the id links are correct because if one
// of the edges refers to a non-existent node, the graph will throw.
// further more we can check that each edge is bi-directional, if it's not
// by checking the arrow heads going both ways, on the graph.
await GraphTheGraph(theMap, 2000, 2000, 'exampleCodeNo3D.png')
}, 20000)
})
}) })
describe('capture graph of sketchOnFaceOnFace...', () => { describe('capture graph of sketchOnFaceOnFace...', () => {
@ -457,7 +541,10 @@ async function GraphTheGraph(
`./src/lang/std/artifactMapGraphs/${imageName}` `./src/lang/std/artifactMapGraphs/${imageName}`
) )
// chop the top 30 pixels off the image // chop the top 30 pixels off the image
const originalImg = PNG.sync.read(fs.readFileSync(originalImgPath)) const originalImgExists = fs.existsSync(originalImgPath)
const originalImg = originalImgExists
? PNG.sync.read(fs.readFileSync(originalImgPath))
: null
// const img1Data = new Uint8Array(img1.data) // const img1Data = new Uint8Array(img1.data)
// const img1DataChopped = img1Data.slice(30 * img1.width * 4) // const img1DataChopped = img1Data.slice(30 * img1.width * 4)
// img1.data = Buffer.from(img1DataChopped) // img1.data = Buffer.from(img1DataChopped)
@ -468,10 +555,10 @@ async function GraphTheGraph(
const newImageDataChopped = newImageData.slice(30 * newImage.width * 4) const newImageDataChopped = newImageData.slice(30 * newImage.width * 4)
newImage.data = Buffer.from(newImageDataChopped) newImage.data = Buffer.from(newImageDataChopped)
const { width, height } = originalImg const { width, height } = originalImg ?? newImage
const diff = new PNG({ width, height }) const diff = new PNG({ width, height })
const imageSizeDifferent = originalImg.data.length !== newImage.data.length const imageSizeDifferent = originalImg?.data.length !== newImage.data.length
let numDiffPixels = 0 let numDiffPixels = 0
if (!imageSizeDifferent) { if (!imageSizeDifferent) {
numDiffPixels = pixelmatch( numDiffPixels = pixelmatch(

View File

@ -36,9 +36,12 @@ interface solid2D {
} }
export interface PathArtifactRich { export interface PathArtifactRich {
type: 'path' type: 'path'
/** A path must always lie on a plane */
plane: PlaneArtifact | WallArtifact plane: PlaneArtifact | WallArtifact
/** A path must always contain 0 or more segments */
segments: Array<SegmentArtifact> segments: Array<SegmentArtifact>
sweep: SweepArtifact /** A path may not result in a sweep artifact */
sweep?: SweepArtifact
codeRef: CommonCommandProperties codeRef: CommonCommandProperties
} }
@ -587,13 +590,15 @@ export function expandPath(
{ keys: path.segIds, types: ['segment'] }, { keys: path.segIds, types: ['segment'] },
artifactGraph artifactGraph
) )
const sweep = getArtifactOfTypes( const sweep = path.sweepId
? getArtifactOfTypes(
{ {
key: path.sweepId, key: path.sweepId,
types: ['sweep'], types: ['sweep'],
}, },
artifactGraph artifactGraph
) )
: undefined
const plane = getArtifactOfTypes( const plane = getArtifactOfTypes(
{ key: path.planeId, types: ['plane', 'wall'] }, { key: path.planeId, types: ['plane', 'wall'] },
artifactGraph artifactGraph

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB