⚠️ 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>