fix: Transformation nodes must create new scope

In VRML 1, transformations like translations and rotations
  accumulate within a scope as they are encountered, and one
  can even have multiple translations with shapes interleaved
  between them. This accumulation is not possible in VRML97.
  Therefore, it's necessary to insert new scopes in the translated
  file every time a new transformation is encountered. This
  commit makes sure that happens.
This commit is contained in:
Glen Whitney 2024-02-14 00:00:09 -08:00
parent a6a6e60894
commit b6c5c6d0a5
2 changed files with 32 additions and 16 deletions

View File

@ -1,6 +1,6 @@
{ {
name: 'vrml1to97', name: 'vrml1to97',
version: '0.3.1', version: '0.3.2',
description: 'JavaScript converter from VRML 1 to VRML97', description: 'JavaScript converter from VRML 1 to VRML97',
scripts: { scripts: {
test: 'echo "Error: no test specified" && exit 1', test: 'echo "Error: no test specified" && exit 1',

View File

@ -91,6 +91,7 @@ function addWorldParameter(name: string, value: string, tree: Tree): void
matches := (str: string, pat: RegExp) => pat.test(str) matches := (str: string, pat: RegExp) => pat.test(str)
operator matches operator matches
GroupNode := /(?:Transform)?Separator|Group|Switch|WWWAnchor/ GroupNode := /(?:Transform)?Separator|Group|Switch|WWWAnchor/
TransformNode := /^(?:Rotation|Scale|Transform|Translation)$/
SetNode := /IndexedFaceSet|IndexedLineSet|PointSet/ SetNode := /IndexedFaceSet|IndexedLineSet|PointSet/
LightNode := /Light$/ LightNode := /Light$/
@ -161,6 +162,8 @@ function parse(stream: Lexer, tree: DefTree = {}): DefTree
switch role switch role
matches GroupNode matches GroupNode
role = 'Child' role = 'Child'
matches TransformNode
role = 'Transform'
'ShapeHints' 'ShapeHints'
role = 'Dummy' // will fill in when we parse the ShapeHints role = 'Dummy' // will fill in when we parse the ShapeHints
'Coordinate3' 'Coordinate3'
@ -193,6 +196,19 @@ function parse(stream: Lexer, tree: DefTree = {}): DefTree
addChild clause, tree addChild clause, tree
'Shape' 'Shape'
addShape clause, [], tree addShape clause, [], tree
'Transform'
// VRML97 doesn't allow just the transform part of
// a Transform to be USEd (the whole node must be), so
// we have to recreate the transform. FIXME: dedupe code
content := known[next.value][1..]
{children, ...context} := tree
restOfTree := parse stream, context
if remainingKids := restOfTree.children
newChild := `Transform {\n ${renderList content}\n `
+ `children [\n ${renderList remainingKids}`
+ "] }\n"
addChild newChild, tree
return tree
{} {}
mergeTree role, tree mergeTree role, tree
else else
@ -203,20 +219,24 @@ function parse(stream: Lexer, tree: DefTree = {}): DefTree
{ht: 'word', nt: 'obrace'} {ht: 'word', nt: 'obrace'}
switch held.value switch held.value
matches GroupNode matches GroupNode
parent := {children, ...context} := tree
held.value.endsWith('Separator') ? 'Transform' : 'Group'
{children, Translation, Rotation, ...context} := tree
subTree := parse stream, context subTree := parse stream, context
if newKids := subTree.children if newKids := subTree.children
newChild .= `${parent} {\n ` newChild :=
if 'Rotation' in subTree `Group { children [\n ${renderList newKids} ] }\n`
newChild += renderList subTree.Rotation
newChild += "\n "
if 'Translation' in subTree
newChild += renderList subTree.Translation
newChild += "\n "
newChild += `children [\n ${renderList newKids} ] }\n`
addChild newChild, tree addChild newChild, tree
matches TransformNode
content := toksUntilClose stream
if (lastDefinition
and tree._definitions?[lastDefinition][0] is 'Transform')
tree._definitions[lastDefinition].push ...content
{children, ...context} := tree
restOfTree := parse stream, context
if remainingKids := restOfTree.children
newChild := `Transform {\n ${renderList content}\n `
+ `children [\n ${renderList remainingKids} ] }\n`
addChild newChild, tree
return tree // used the rest of the tree, so done
'ShapeHints' 'ShapeHints'
subTree := parse stream subTree := parse stream
hints: Tree := {} hints: Tree := {}
@ -228,10 +248,6 @@ function parse(stream: Lexer, tree: DefTree = {}): DefTree
mergeTree hints, tree mergeTree hints, tree
if lastDefinition and tree._definitions if lastDefinition and tree._definitions
tree._definitions[lastDefinition] = [hints] tree._definitions[lastDefinition] = [hints]
'Rotation'
tree.Rotation = toksUntilClose stream
'Translation'
tree.Translation = toksUntilClose stream
'Coordinate3' 'Coordinate3'
tree.Coordinate = toksUntilClose stream tree.Coordinate = toksUntilClose stream
'Normal' 'Normal'