⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{draft task}}
In order to represent evolutions of contents over time, the [http://www.w3.org/TR/SMIL/ SMIL] standard provides a solution to record the animation of data. Smil animations can be added to any kind of contents formated in XML.
- [[wp:Synchronized_Multimedia_Integration_Language|SMIL on Wikipedia]] and [http://www.w3.org/TR/SMIL/smil-animation.html#q35 at W3]
The task is to create an utility that given the first Smiled XML file, would return the following ones:
<?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>
At t = 0 second here is the expected output:
<?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>
At t = 2 second here is the expected output:
<?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>
Go
{{libheader|etree}}
package main
import (
"fmt"
"github.com/beevik/etree"
"log"
"os"
"strconv"
"strings"
)
type animData struct {
element *etree.Element
attrib string
from string
to string
begin float64
dur float64
}
func check(err error) {
if err != nil {
log.Fatal(err)
}
}
func (ad *animData) AtTime(t float64) string {
beg := ad.begin
end := beg + ad.dur
if t < beg || t > end {
log.Fatalf("time must be in interval [%g, %g]", beg, end)
}
fromSplit := strings.Fields(ad.from)
toSplit := strings.Fields(ad.to)
le := len(fromSplit)
interSplit := make([]string, le)
for i := 0; i < le; i++ {
fromF, err := strconv.ParseFloat(fromSplit[i], 64)
check(err)
toF, err := strconv.ParseFloat(toSplit[i], 64)
check(err)
interF := (fromF*(end-t) + toF*(t-beg)) / ad.dur
interSplit[i] = fmt.Sprintf("%.2f", interF)
}
return strings.Join(interSplit, " ")
}
func main() {
doc := etree.NewDocument()
check(doc.ReadFromFile("smil.xml"))
smil := doc.SelectElement("smil")
if smil == nil {
log.Fatal("'smil' element not found")
}
x3d := smil.SelectElement("X3D")
if x3d == nil {
log.Fatal("'X3D' element not found")
}
doc.SetRoot(x3d) // remove 'smil' element
var ads []*animData
for _, a := range doc.FindElements("//animate") {
attrib := a.SelectAttrValue("attributeName", "?")
from := a.SelectAttrValue("from", "?")
to := a.SelectAttrValue("to", "?")
beginS := a.SelectAttrValue("begin", "?")
durS := a.SelectAttrValue("dur", "?")
if attrib == "?" || from == "?" || to == "?" ||
beginS == "?" || durS == "?" {
log.Fatal("an animate element has missing attribute(s)")
}
begin, err := strconv.ParseFloat(beginS[:len(beginS)-1], 64)
check(err)
dur, err := strconv.ParseFloat(durS[:len(durS)-1], 64)
check(err)
p := a.Parent()
if p == nil {
log.Fatal("an animate element has no parent")
}
pattrib := p.SelectAttrValue(attrib, "?")
if pattrib == "?" {
log.Fatal("an animate element's parent has missing attribute")
}
ads = append(ads, &animData{p, attrib, from, to, begin, dur})
p.RemoveChild(a) // remove 'animate' element
}
ts := []float64{0, 2}
for _, t := range ts {
for _, ad := range ads {
s := ad.AtTime(t)
ad.element.CreateAttr(ad.attrib, s)
}
doc.Indent(2)
fmt.Printf("At time = %g seconds:\n\n", t)
doc.WriteTo(os.Stdout)
fmt.Println()
}
}
{{out}}
At time = 0 seconds:
<?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.00 1.00 2.00"/>
<Appearance>
<Material diffuseColor="0.00 0.60 1.00"/>
</Appearance>
</Shape>
</Scene>
</X3D>
At time = 2 seconds:
<?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.80 1.20 1.80"/>
<Appearance>
<Material diffuseColor="0.20 0.56 0.80"/>
</Appearance>
</Shape>
</Scene>
</X3D>
Phix
include builtins\xml.e
constant 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>
"""
function scan_all(sequence s, fmt)
for i=1 to length(s) do
{{s[i]}} = scanf(s[i],fmt)
end for
return s
end function
function animate_contents(sequence doc, atom t)
sequence a = xml_get_nodes(doc,"animate")
if a={} then
for i=1 to length(doc[XML_CONTENTS]) do
doc[XML_CONTENTS][i] = animate_contents(doc[XML_CONTENTS][i],t)
end for
else
for i=1 to length(doc[XML_CONTENTS]) do
if doc[XML_CONTENTS][i][XML_TAGNAME]="animate" then
string name = xml_get_attribute(doc[XML_CONTENTS][i],"attributeName"),
vfrm = xml_get_attribute(doc[XML_CONTENTS][i],"from"),
v_to = xml_get_attribute(doc[XML_CONTENTS][i],"to"),
sbeg = xml_get_attribute(doc[XML_CONTENTS][i],"begin"),
sdur = xml_get_attribute(doc[XML_CONTENTS][i],"dur")
sequence from = scan_all(split(vfrm),"%f"),
to_s = scan_all(split(v_to),"%f")
atom {{begin}} = scanf(sbeg,"%fs"),
{{durat}} = scanf(sdur,"%fs"),
fj = begin+durat-t,
tj = t-begin
-- plenty more error handling possible here...
if tj<0 or fj<0 or length(from)!=length(to_s) then ?9/0 end if
for j=1 to length(from) do
from[j] = sprintf("%.2f",(from[j]*fj+to_s[j]*tj)/durat)
end for
doc = xml_set_attribute(doc,name,join(from," "))
doc[XML_CONTENTS][i..i] = "" -- remove 'animate'
exit
end if
end for
end if
return doc
end function
function animate(sequence doc, atom t)
doc[XML_CONTENTS] = doc[XML_CONTENTS][XML_CONTENTS][1] -- remove smil
doc[XML_CONTENTS] = animate_contents(doc[XML_CONTENTS],t)
return doc
end function
sequence doc = xml_parse(xml)
if doc[XML_DOCUMENT]!="document"
or doc[XML_CONTENTS][XML_TAGNAME]!="smil"
or length(doc[XML_CONTENTS][XML_CONTENTS])!=1
or doc[XML_CONTENTS][XML_CONTENTS][1][XML_TAGNAME]!="X3D" then
?9/0
end if
printf(1,"At time = 0:\n\n")
puts(1,xml_sprint(animate(doc,0)))
printf(1,"\nAt time = 2:\n\n")
puts(1,xml_sprint(animate(doc,2)))
{{out}}
At time = 0:
<?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.00 1.00 2.00" />
<Appearance>
<Material diffuseColor="0.00 0.60 1.00" />
</Appearance>
</Shape>
</Scene>
</X3D>
At time = 2:
<?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.80 1.20 1.80" />
<Appearance>
<Material diffuseColor="0.20 0.56 0.80" />
</Appearance>
</Shape>
</Scene>
</X3D>
Tcl
{{works with|Tcl|8.6}} {{libheader|tDOM}}
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]
{{out|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>