Process SMIL directives in XML data
In order to represent evolutions of contents over time, the SMIL standard provides a solution to record the animation of data. Smil animations can be added to any kind of contents formated in XML.
The task is to create an utility that given the first Smiled XML file, would return the following ones:
<lang xml><?xml version="1.0" ?> <smil> <X3D>
<Scene> <Viewpoint position="0 0 8" orientation="0 0 1 0"/> <PointLight color='1 1 1' location='0 2 0'/> <Shape> <Box size='2 1 2'> <animate attributeName="size" from="2 1 2" to="1 2 1" begin="0s" dur="10s"/> </Box> <Appearance> <Material diffuseColor='0.0 0.6 1.0'> <animate attributeName="diffuseColor" from="0.0 0.6 1.0" to="1.0 0.4 0.0" begin="0s" dur="10s"/> </Material> </Appearance> </Shape> </Scene>
</X3D> </smil></lang>
At t = 0 second here is the expected output:
<lang xml><?xml version="1.0" ?> <X3D>
<Scene> <Viewpoint position="0 0 8" orientation="0 0 1 0"/> <PointLight color='1 1 1' location='0 2 0'/> <Shape> <Box size='2 1 2'/> <Appearance> <Material diffuseColor='0.0 0.6 1.0'/> </Appearance> </Shape> </Scene>
</X3D></lang>
At t = 2 second here is the expected output:
<lang xml><?xml version="1.0" ?> <X3D>
<Scene> <Viewpoint position="0 0 8" orientation="0 0 1 0"/> <PointLight color='1 1 1' location='0 2 0'/> <Shape> <Box size='1.8 1.2 1.8'/> <Appearance> <Material diffuseColor='0.2 0.56 0.8'/> </Appearance> </Shape> </Scene>
</X3D></lang>
Tcl
<lang tcl>package require Tcl 8.6 package require tdom
- Applies a time-based interpolation to generate a space-separated list
proc interpolate {time info} {
dict with info {
scan $begin "%fs" begin scan $dur "%fs" dur
} if {$time < $begin} {
return $from
} elseif {$time > $begin+$dur} {
return $to
} set delta [expr {($time - $begin) / $dur}] return [lmap f $from t $to {expr {$f + ($t-$f)*$delta}}]
}
- Applies SMIL <transform> elements to their container
proc applySMILtransform {sourceDocument time} {
set doc [dom parse [$sourceDocument asXML]] foreach smil [$doc selectNodes //smil] {
foreach context [$smil selectNodes {//*[animate]}] { set animator [$context selectNodes animate] set animated [$context selectNodes @[$animator @attributeName]] $context removeChild $animator $context setAttribute [$animator @attributeName] \ [interpolate $time [lindex [$animator asList] 1]] } if {[$smil parentNode] eq ""} { set reparent 1 } else { [$smil parentNode] replaceChild $smil [$smil firstChild] }
} if {[info exist reparent]} {
set doc [dom parse [[$smil firstChild] asXML]]
} return $doc
}
set t [expr {[lindex $argv 0] + 0.0}] set result [applySMILtransform [dom parse [read stdin]] $t] puts {<?xml version="1.0" ?>} puts -nonewline [$result asXML -indent 2]</lang>
- Demonstration:
Note that input.smil contains the source document from the task description.
$ tclsh8.6 applySmil.tcl 0 < input.smil <?xml version="1.0" ?> <X3D> <Scene> <Viewpoint position="0 0 8" orientation="0 0 1 0"/> <PointLight color="1 1 1" location="0 2 0"/> <Shape> <Box size="2.0 1.0 2.0"/> <Appearance> <Material diffuseColor="0.0 0.6 1.0"/> </Appearance> </Shape> </Scene> </X3D> $ tclsh8.6 applySmil.tcl 2 < input.smil <?xml version="1.0" ?> <X3D> <Scene> <Viewpoint position="0 0 8" orientation="0 0 1 0"/> <PointLight color="1 1 1" location="0 2 0"/> <Shape> <Box size="1.8 1.2 1.8"/> <Appearance> <Material diffuseColor="0.2 0.5599999999999999 0.8"/> </Appearance> </Shape> </Scene> </X3D>