Datalogi 0 GB 2003 DIKU Flight Simulator - Rune Højsgaard
Datalogi 0 GB 2003 DIKU Flight Simulator - Rune Højsgaard
Datalogi 0 GB 2003 DIKU Flight Simulator - Rune Højsgaard
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Datalogi</strong> 0 <strong>GB</strong> <strong>2003</strong><br />
<strong>DIKU</strong> <strong>Flight</strong> <strong>Simulator</strong><br />
Espen <strong>Højsgaard</strong> <strong>Rune</strong> <strong>Højsgaard</strong> Sune J. Jensen<br />
1
Indhold<br />
1 Sammenfatning 6<br />
1.1 Vores løsning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
1.1.1 Resultat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
1.1.2 Forløb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
2 Problemorienteret analyse 7<br />
2.1 Modelbeskrivelse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />
2.1.1 Notationsmuligheder / -begrænsninger . . . . . . . . . . . . . . . . 7<br />
2.2 Strålesporing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />
2.2.1 Kameramodel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />
2.2.2 Lys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />
2.2.3 Effektivitet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />
2.3 Brugergrænseflade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />
2.3.1 Fejlmeddelelser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />
2.3.2 Løbende respons . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />
3 Objekt orienteret design 13<br />
3.1 Designovervejelser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />
3.1.1 Vigtige designbeslutninger . . . . . . . . . . . . . . . . . . . . . . . 13<br />
3.2 Diagrammer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />
4 Programmeringsovervejelser 17<br />
4.1 Strålesporing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
4.1.1 Før sporingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
4.1.2 Selve sporingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />
4.2 Tidskompleksitet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />
4.2.1 Beregning af skæring med objekter . . . . . . . . . . . . . . . . . . 18<br />
4.2.2 Kompleksitet for en enkelt stråle . . . . . . . . . . . . . . . . . . . 18<br />
4.2.3 Antal sporede stråler . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />
5 Programbeskrivelse 20<br />
5.1 Læsevejledning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
5.2 Kommentarer i koden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
5.3 Sceneopstiller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />
6 Afprøvning 22<br />
6.1 Strategi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />
6.1.1 Krævede attributter . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />
6.1.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />
6.1.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />
6.1.4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />
6.1.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />
2
6.1.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />
6.1.7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />
6.1.8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />
6.1.9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />
6.1.10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />
6.1.11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />
6.1.12 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />
6.2 Opstilling og udførsel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />
6.3 Konklusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />
7 Brugervejledning 29<br />
7.1 Det kan Fotograf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
7.2 Systemkrav . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
7.3 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />
7.4 Afvikling af programmet . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
7.5 Meddelelser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
7.5.1 Fejlmeddelelser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
8 Litteratur 31<br />
A Klasser og arv 32<br />
B Associationsdiagram 33<br />
C CRC-kort 33<br />
C.1 Element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />
C.2 Fotograf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />
C.3 Kamera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36<br />
C.4 Kugle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />
C.5 Mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />
C.6 Plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />
C.7 Punkt3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />
C.8 Scene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41<br />
C.9 Sceneopstiller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42<br />
C.10 Sol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />
C.11 Stråle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />
C.12 Trekant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />
C.13 XMLParseError . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />
D Grænseflader 47<br />
D.1 Klassen Element . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />
D.2 Klassen Fotograf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />
D.3 Klassen Kamera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />
D.4 Klassen KameraI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />
3
D.5 Klassen Kugle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />
D.6 Klassen Mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />
D.7 Klassen Plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49<br />
D.8 Klassen Punkt3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />
D.9 Klassen Scene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />
D.10 Klassen SceneI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />
D.11 Klassen Sceneopstiller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />
D.12 Klassen Sol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />
D.13 Klassen Stråle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
D.14 Klassen Trekant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
D.15 Klassen XMLParseError . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
E Kildekode 54<br />
E.1 Element.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />
E.2 Fotograf.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />
E.3 Kamera.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />
E.4 KameraI.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />
E.5 Kugle.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />
E.6 Mesh.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />
E.7 Plan.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />
E.8 Punkt3D.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64<br />
E.9 Scene.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />
E.10 SceneI.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />
E.11 Sceneopstiller.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68<br />
E.12 Sol.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />
E.13 Stråle.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />
E.14 Trekant.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />
E.15 XMLParseError.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83<br />
F Afprøvningsdata 84<br />
F.1 Afprøvning 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84<br />
F.2 Afprøvning 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84<br />
F.3 Afprøvning 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />
F.4 Afprøvning 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />
F.5 Afprøvning 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86<br />
F.6 Afprøvning 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />
F.7 Afprøvning 7 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />
F.8 Afprøvning 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88<br />
F.9 Afprøvning 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88<br />
F.10 Afprøvning 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />
F.11 Afprøvning 11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />
F.12 Afprøvning 12 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />
F.13 Afprøvning 13 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />
4
F.14 Afprøvning 14 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />
F.15 Afprøvning 15 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91<br />
F.16 Afprøvning 16 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />
F.17 Afprøvning 17 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />
F.18 Afprøvning 18 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93<br />
F.19 Afprøvning 19 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93<br />
F.20 Afprøvning 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />
F.21 Afprøvning 21 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />
F.22 Afprøvning 22 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />
F.23 Afprøvning 23 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />
F.24 Afprøvning 24 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />
F.25 Afprøvning 25 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />
F.26 Afprøvning 26 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />
F.27 Afprøvning 27 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />
F.28 Afprøvning 28 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />
F.29 Afprøvning 29 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />
F.30 Afprøvning 30 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99<br />
F.31 Afprøvning 31 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99<br />
F.32 Afprøvning 32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
F.33 Afprøvning 33 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />
F.34 Afprøvning 34 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />
F.35 Afprøvning 35 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />
F.36 Afprøvning 36 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102<br />
F.37 Afprøvning 37 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102<br />
F.38 Afprøvning 38 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />
F.39 Afprøvning 39 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103<br />
F.40 Afprøvning 40 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104<br />
F.41 Afprøvning 41 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />
F.42 Afprøvning 42 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />
F.43 Afprøvning 43 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />
F.44 Afprøvning 44 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />
F.45 Afprøvning 45 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107<br />
F.46 Afprøvning 46 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />
F.47 Afprøvning 47 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108<br />
5
1 Sammenfatning<br />
Dette er en besvarelse af den karaktergivende opgave på kurset <strong>Datalogi</strong> 0 <strong>GB</strong> <strong>2003</strong>, Københavns<br />
Universitet [1]. Læseren forventes at have læst opgaveformuleringen samt - som<br />
minimum - at have samme forudsætninger som en elev, der har fulgt kurset.<br />
Formålet med opgaven var at udvikle et program, der implementerer en simpel flysimulator<br />
ved brug af strålesporing.<br />
1.1 Vores løsning<br />
Vores ambition var at lave et godt objektorienteret design af den minimumsløsning, som<br />
opgaveteksten beskriver. Dette design skulle muliggøre nem tilføjelse af nye former og<br />
samtidig gøre det muligt senere at implementere mere avancerede lys- og kameramodeller.<br />
Det var vores mål, at det resulterende program korrekt skulle implementere de principper,<br />
der er beskrevet i opgaven, således at den udleverede scenebeskrivelse kunne omsættes<br />
fejlfrit til billeder.<br />
1.1.1 Resultat<br />
Resultatet er blevet et design, der til fulde lever op til førnævnte ambitioner og som i sin<br />
struktur og navngivning bruger logiske analogier til den „virkelige verden“.<br />
Programmet lever ligeledes op til vores og opgaveformuleringens krav, hvilket afprøvningen<br />
bekræfter.<br />
1.1.2 Forløb<br />
Opgaveforløbet har været præget af, at dette er vores første objektorienterede design og vi<br />
har derfor brugt meget tid på designet i forhold til programmets størrelse. Processen har<br />
dog været lærerig og resultatet må have en vis kvalitet, da selve kodningen kun tog lidt<br />
mere end én dag.<br />
Alt i alt har det været en interessant opgave og vi er tilfredse med resultatet.<br />
6
2 Problemorienteret analyse<br />
Formålet med denne opgave er - som beskrevet i opgaveformuleringen [1] - at fremstille<br />
et program, der kan kan generere farvebilleder ud fra en modelbeskrivelse. Teknikken, der<br />
skal bruges, er strålesporing og de grundlæggende principper for denne teknik er beskrevet<br />
i opgaveformuleringen.<br />
Vi vil i dette afsnit diskutere såvel modelbeskrivelsen som strålesporingen, da ingen af<br />
dem er fuldstændigt afklaret i opgaveteksten. Endvidere vil vi diksutere hvilken brugergrænseflade<br />
programmet have.<br />
2.1 Modelbeskrivelse<br />
Der er i opgaveteksten fastlagt en notation, der er baseret på XML. Denne notation inkluderer<br />
tags til beskrivelse af de elementer, som der skal laves billeder af, samt tags til lyskilder<br />
og til billedspecifik information.<br />
Da opgaveteksten ikke stiller krav til, hvordan programmet håndterer syntaktisk forkert<br />
XML, vil vi blot vedtage, at hvis det er tilfældet, så skal programmet skal meddele det til<br />
brugeren og så afslutte.<br />
Vi vil i det følgende undersøge om notationen er tilstrækkelig samt afdække det semantiske<br />
grundlag for notationen.<br />
2.1.1 Notationsmuligheder / -begrænsninger<br />
Den givne notation indeholder følgende grundelementer: scene, pilotsyn, sol, kugle, plan<br />
og mesh. De sidste tre beskriver ting, der kan ses på de genererede billeder, mens de første<br />
tre er lidt mere uhåndgribelige. Vi vil starte med at diskutere de tags de har til fælles.<br />
Derefter vil vi diskutere de seks grundelementer hver for sig.<br />
Fælles tags De forskellige grundelementer deler to tags: punkt og farve. Disse skal leve<br />
op til nogle regler, som vi vil gennemgå her.<br />
punkt punkt-tagget lader brugeren specificere et sæt koordinater i tilknytning til et<br />
id. Et sådant koordinatsæt bruges til at beskrive to ting i notationen: punkter og vektorer.<br />
For begge gælder, at brugeren skal angive alle tre koordinater, da vi mener det vil gøre<br />
modelbeskrivelserne uoverskuelige, hvis man kan udelade et koordinat og i stedet lade det<br />
få en standard-værdi.<br />
For vektorer vil vi pålægge endnu et krav: mindst én af koordinaterne skal være forskellig<br />
fra nul. Dette skyldes at vektorer i notationen bruges til at angive retninger og nulvektoren<br />
har ikke én, men alle retninger.<br />
farve farve-tagget bruges til at angive en farve i R<strong>GB</strong>-systemet. I den model vi bruger,<br />
er der 8 bit til hver af værdierne, hvilket medfører at værdieren skal være heltal i intervallet<br />
[0;255]. Som for punkt-tagget vil vi kræve at alle tre værdier skal angives.<br />
7
scene Scene-tagget pålægger notationen en enkelt begrænsning, da det er dokumentets<br />
rod. Begrænsningen er, at der kun kan være et scenetag - i hvert fald på yderste niveau -<br />
hvormed det er udelukket at der kan være flere scener i samme fil. Vi vil ikke gøre noget<br />
for at undgå den begrænsning, da vi mener at det er mest hensigtsmæssigt, kun at have<br />
en model i hver fil.<br />
pilotsyn Pilotsyn-tagget er vigtigt, da det fastlægger hvilke billeder, der skal laves af<br />
modellen. De pilotsyn, der kan laves med den givne notation, tager udgangspunkt i den<br />
model, der beskrives i opgaveformuleringen: et øjepunkt, et stedpunkt, to vektorer - der<br />
fastlægger vandret og lodret - samt en billedopløsning. Den model udelukker andet end<br />
plane synsflader, men da vores teori kun beskriver denne type, er det fuldt tilstrækkeligt.<br />
Tolkning af pilotsyn Det er i opgaveformuleringen ikke fastlagt, hvordan stedpunktet<br />
og vektorerne skal fortolkes, men der er på kursets hjemmeside blevet publiceret et<br />
dokument [3], der klarlægger dette. Stedpunktet er det nederste venstre hjørne af „filmen“<br />
og vektorerne fastlægger herudfra, hvilken retning der er op og hvilken der er til højre.<br />
Der er i notationen ikke noget, der forhindrer brugeren i at definere disse vektorer på<br />
en måde, så de ikke opfylder denne model. Desværre har vi ikke det fornødne matematiske<br />
kendskab til at kontrollere, at vektorerne lever op til modellens krav og vi kan derfor ikke<br />
implementere et fejltjek på dette - bortset fra tjek for at ingen af dem er nulvektoren,<br />
hvilket ikke har nogen mening.<br />
Et andet aspekt i modellen, der er interessant, er hvis brugeren placerer øjepunktet i det<br />
rektangel, som udgør „filmen“. Hvis øjepunktet kommer til at falde sammen med et punkt,<br />
hvorigennem der skal spores en stråle, vil strålen ikke have nogen retning og altså ikke være<br />
en stråle men et punkt. Der er ikke noget i vejen for at „spore“ et punkt i modellen, og vi<br />
vil derfor ikke forsøge at begrænse brugerens placering af øjepunktet.<br />
Som det sidste vil vi slå fast, at opløsningen - bredde og højde - skal være heltal større<br />
end nul, da de angiver et antal felter.<br />
sol Sol-tagget angiver placering og farve af lyskilderne i scenen. Da vores teori kun<br />
beskriver strålesporing med en lyskilde, så vil vi kun tillade et sol-tag i en scene. Solens farve<br />
skal følge de generelle regler for farver, men derudover er der ikke nogen begrænsninger,<br />
da den givne lysmodel tillader alle farver.<br />
Former De sidste tre tags - især mesh - gør det muligt at beskrive særdeles komplicerede<br />
objekter og vi mener derfor at notationen med hensyn til modellering af fysiske former er<br />
fuldt tilstrækkelig. Det vil godt nok være en ganske omstændig proces at skulle beskrive<br />
selv de mest trivielle hverdagsting, hvis brugeren ikke har mulighed for at bruge et designværktøj,<br />
men det er muligt. Endvidere kan selv en simpel model illustrere et koncept, der<br />
kan være svært at visualisere for sit indre øje, hvorfor den simple notation også er brugbar<br />
uden et designværktøj.<br />
8
Fælles for det tre former - som de tre tags kan beskrive - er, at vi ikke vil udvide<br />
notationen med mulighed for f.eks. refleksion og gennemsigtighed. Selvom sådanne egenskaber<br />
formentlig ville gøre billederne mere interessante, så ligger det udover vores teoretiske<br />
grundlag at indføre den slags effekter.<br />
Herunder vil vi kort gennemgå hver af de tre former og de begrænsninger, vi mener det<br />
er nødvndigt at pålægge dem.<br />
kugle En kugle defineres ved sit centrum, sin radius og sin farve. Centrum og farve<br />
skal leve op til de ting vi nåede frem til i starten af afsnittet. Radius skal være større end<br />
nul, da negativ radius ikke har nogen mening og da vi ikke mener at brugeren skulle have<br />
grund til at definere et enkelt punkt.<br />
mesh Et mesh er en samling af trekanter. Vi mener ikke at det har nogen mening<br />
at en trekant definerer et linjestykke eller et punkt og for at undgå det, vil vi kræve at<br />
alle punkterne i et mesh er forskellige og at en trekant bliver defineret ved tre forskellige<br />
punkter, der alle skal angives.<br />
plan En plan defineres ved et stedpunkt, to vektorer og en farve. Udover at skulle<br />
leve op til de fælles krav, så vil vi også kræve at de to vektorer ikke er parallelle, da der i<br />
så fald ikke udspændes en plan, men en linje, hvilket vi ikke mener har nogen mening.<br />
Dette kan undersøges, da to parallelle vektorer, a og b, vil opfylde følgende<br />
a = t · b ⇔ a 2 = t 2 · b 2 ⇔ |a| 2 = t 2 · | b| 2 ⇔ t = ± |a|<br />
Så hvis de to vektorer opfylder a = |a|<br />
| b| · b eller a = − |a|<br />
| b| · b, så er de parallelle.<br />
2.2 Strålesporing<br />
Vi skal som sagt bruge strålesporing til at lave billederne med. Teknikken går ud på at<br />
følge lysets vej fra solen til øjet - bare den modsatte vej. I dette afsnit vil vi afklare de<br />
uklarheder, som vi mener der er i opgaveteksten.<br />
2.2.1 Kameramodel<br />
Som beskrevet i opgaveformuleringen [1, afs. 3], defineres der i modelbeskrivelsen en synsflade<br />
(eller flere) med et tilhørende øjepunkt og der knyttes endvidere en opløsning til hver<br />
synsflade. Opløsningen definerer hvor mange referencefelter synsfladen skal deles op i. Processen<br />
med at generere et billede, består i at bestemme hvilken farve hvert referencefelt skal<br />
have. Der er flere måder hvorpå farven i referencefelt kan bestemmes. Man kan f.eks. spore<br />
en stråle der går fra øjepunktet og igennem midten af referencefeltet, eller man kan spore<br />
en række stråler gennem refenrencefeltet og så bestemme farven som et vægtet gennemsnit<br />
af de fundne farve.<br />
9<br />
| b|
Hvis man kun sporer en enkelt stråle igennem et referencefelt, er det sandsynligt at man<br />
vil opleve en del alialisering, dvs. hakkede kanter o.l. Denne effekt skyldes at et referencefelt<br />
har en hvis fysisk udstrækning og det er ikke så sandsynligt at alle punkter i feltet vil have<br />
samme farve. Farven i enkelt punkt kan derfor ikke forventes at være repræsentativ for hele<br />
feltet.<br />
Alialisering vil formentlig kunne mindskes ved at spore flere stråler igennem et referencefelt,<br />
da det så er mere sandsynligt at den fundne farve er repræsentativ for feltet.<br />
Desværre har vi ikke noget grundlag for at vide hvor og hvor mange stråler, der skal spores<br />
for at opnå mindre alialisering og vi vil derfor nøjes med at spore en enkelt stråle igennem<br />
midten af hvert referencefelt.<br />
2.2.2 Lys<br />
Lysmodellen - der beskrives i opgaven - tager én lyskilde i betragtning og tager ikke højde<br />
for refleksion eller andre fænomener, der - udover en solens direkte lys - kunne belyse et<br />
punkt. På trods af denne simple model, så er der alligevel nogle apekter, som ikke dækkes<br />
fuldt i opgaveformuleringen.<br />
Skygge Opgaveteksten beskriver hvordan man beregner farven i et punkt - hvis lyset<br />
altså rammer punktet. For det tilfælde at lyset fra lyskilden aldrig når til punktet, så ligger<br />
punktet i skygge, og skal derfor være sort. I den „virkelige“ verden er der som bekendt ikke<br />
sort i skyggen, men i vores lysmodel er det det eneste naturlige valg, da der ikke kan komme<br />
lys fra andre retninger end solen.<br />
Intet ramt Et andet spørgsmål der skal afklares er, hvilken farve der skal være, hvis<br />
vi sporer en stråle der ikke rammer noget i modellen. Man kunne lade brugeren vælge en<br />
baggrundsfarve, hvilket f.eks. kunne bruges til at lave en blå himmel uden at skulle beskrive<br />
den. Denne mulighed er ikke understøttet i den givne notation, så vi vælger i stedet at lade<br />
„farven“ i sådanne tilfælde være sort, da der aldrig vil komme lys fra den retning.<br />
Solen bag flader Opgaveteksten forholder sig ikke til det tilfælde, hvor en flade befinder<br />
sig mellem øjepunktet og solen. Det kunne f.eks. være at solen var placeret i en kugle eller<br />
at der var en plan imellem. I det tilfælde bør fladen - efter vores opfattelse - ikke få en farve,<br />
da vi ikke bruger gennemsigtige flader. Desværre har vi ikke fået matematiske værktøjer -<br />
og er ikke selv i stand til lave dem - til at bestemme om øjepunkt og sol befinder sig på<br />
hver sin side af fladen og vi er derfor ikke i stand til at implementere det aspekt.<br />
Det har den uhensigtsmæssige konsekvens, at en flade er synlig, selvom øjepunktet og<br />
synsfladen ligger i samme flades skygge.<br />
2.2.3 Effektivitet<br />
Vi forventer at strålesporing er en tidskrævende proces og det er derfor vigtigt at overveje,<br />
om der er måder at effektivisere processen på. Opgaveteksten fremhæver f.eks. udregningen<br />
10
af cosinus til vinklen mellem en flades normalvektor og en stråle, som et sted hvor der kan<br />
spares beregninger 1 [1, s. 8].<br />
Simpel omsluttende form En metode vi forestiller os kan gøre strålesporingen hurtigere,<br />
er at beregne en simpel omsluttende form for hver af de mere komplekse former.<br />
Man kunne f.eks. ved et mesh, som består af en række trekanter, beregne en kugle ved<br />
indlæsningen af modellen, der lige præcis indeholdt alle trekanterne. Ved strålesporingen<br />
kunne man så bruge kuglen til at teste om meshet blev ramt, hvilket ville være nemmere<br />
end at skulle undersøge alle trekanterne for sig. Det ville man selvfølgelig skulle gøre i de<br />
tilfælfe, hvor strålen ramte kuglen, men i de fleste tilfælde tror vi at det ville være en fordel.<br />
Desværre kender vi ikke algoritmer til at beregne en sådan omsluttende form, og må<br />
derfor se bort fra idéen, men i en videreudvikling af programmet, ville det nok være værd<br />
at undersøge.<br />
Frasortering af dele En anden metode, som vi mener ville gøre processen hurtigere,<br />
er fjerne de dele af scenen, som er helt uden for synsfeltet. Dette ville kunne gøres før<br />
generereringen af et billede og ville mindske det antal former, som skulle testes for skæring<br />
med hver stråle.<br />
En måde at gøre det på, kunne være at definere en (uendelig) pyramide ud fra øjepunktet<br />
og fire stråler; en gennem hvert hjørne af synsfladen. Herefter kunne man under<br />
genereringen af billedet, se bort fra alle objekter, der lå uden for pyramiden.<br />
Igen er vi desværre begrænset af vores kendskab til rumgeometrien, men ligesom med<br />
de omsluttende former, ville det være en oplagt tilføjelse til en senere udgave.<br />
2.3 Brugergrænseflade<br />
I dette afsnit vil vi undersøge, hvordan programmets grænseflade til brugeren skal være.<br />
Programmet behøver ikke en interaktiv grænseflade, da brugeren kan specificere alt<br />
programmet skal/kan bruge i en XML-fil. Men der er flere sammenhænge, hvor det vigtigt<br />
at programmet melder tilbage til brugeren. F.eks. hvis brugeren har lavet en fejl i XMLfilen.<br />
2.3.1 Fejlmeddelelser<br />
Da vi ikke stiller et designværktøj til rådighed for brugeren, så er der rigelig mulighed for<br />
at brugeren kan lave fejl. Det er derfor vigtigt, at der kommer fejlmeldinger til brugeren,<br />
som kan hjælpe hende med lokalisere fejlen.<br />
Da den givne notation inkluderer en id-attribut til de fleste tags, vil det være oplagt at<br />
bruge id’et til at fortælle brugeren, hvor der er fejl. Hvis der f.eks. ikke er angivet en farve<br />
til en plan kaldet „jord“, så vælger vi at give brugeren meddelelsen<br />
<br />
1ved at udnytte sammenhængen a •b = cos (a, <br />
b) · |a| · | b| 11
jord (plan)->farve<br />
Farve skal angives<br />
På den måde kan brugeren se id’et og typen på det tag hun skal kigge efter.<br />
2.3.2 Løbende respons<br />
For at undgå at brugeren tror at programmet er gået i stå, vil vi give brugeren besked,<br />
hver gang en ny del-proces sættes igang og når de afsluttes igen.<br />
Da vi som sagt forventer, at strålesporing er en tidskrævende proces, mener vi at det<br />
især er vigtigt, at brugeren løbene får respons fra programmet, når et billede bliver lavet.<br />
Vi vælger derfor at vise brugeren hvor langt genereringen af et givet billede er, ved at skrive<br />
et stjerne for hver 10%. Givet et pilotsyn ”syn1” skal beskeden - når et sted mellem 70%<br />
og 80% er færdig - se ud som følger:<br />
Laver billede "syn1": *******<br />
12
3 Objekt orienteret design<br />
Ud fra opgaveteksten og ovenstående overvejelser, har vi lavet et objektorienteret design.<br />
Dette er sket med udgangspunkt i Erics OOD kogebog [2] samt Perdita [4].<br />
I det følgende afsnit vil vi diskutere designet. I tilæg til teksten har vi i appendiks B<br />
placeret et associationsdiagram, i app. A et diagram med klasserne og deres grænseflader<br />
og i app. C har vi placeret de CRC-kort vi er nået frem til. Især de to første giver et godt<br />
overblik over designet og bør derfor studeres sammen med teksten.<br />
3.1 Designovervejelser<br />
Vi har valgt en overordnet struktur som går ud på at der er en Fotograf som sætter en<br />
Sceneopstiller til at indlæse scenespecifikationerne fra en XML-fil, og opbygge en Scene<br />
(ved at fylde den med en Sol, og en mængde Elementer og Kameraer). Når en Scene er<br />
opbygget aktiverer Fotografen Kameraerne ét ad gangen. Når et Kamera bliver aktiveret<br />
skyder det Stråler gennem et antal reference-punkter, ind i Scenen. Scenen indeholder<br />
en liste over hvilke Elementer (inkluderer de forskellige figur klasser, som pt. er Kugle,<br />
Trekant, Mesh og Plan), som findes i Scenen, og gennemgår dem alle, for at finde ud<br />
af hvilket af Elementerne som er det første en given Stråle skærer. Når en Stråles første<br />
skærings3DPunkt er defineret, skydes der endnu en stråle, denne gang fra den Sol som findes<br />
i Scenen, til skærings3DPunktet mellem den første Stråle og Elementet. Alt afhængig af<br />
vinklen mellem Strålen fra Solen og skærings3DPunktet, og farven af Elementet, findes en<br />
farve som den første Stråle antager, og vender tilbage til Kameraet med. Kameraet tildeler<br />
så det referendepunkt som Strålen blev skudt ud igennem, den farve som Strålen kom<br />
tilbage med. Når alle referencepunkterne er bearbejdede, gemmer kameraet resultatet i en<br />
fil.<br />
3.1.1 Vigtige designbeslutninger<br />
I løbet af anden iteration i henhold til [2], foretog vi nogle af de vigtigste designmæssige<br />
beslutninger. I første iteration var klassen Scene, i tilgift til til de ansvar klassen stadig<br />
har, blevet gjort ansvarlig for både at indlæse XML, opbygge scenen og gemme billedet<br />
i en fil. fordelen ved en sådan monolith er at der skal flyttes meget lidt data: En central<br />
klasse tager sig af hovedparten af beregninger og databearbejdning, resten af klasserne<br />
indeholder mere eller mindre statisk data, og nogle få funktioner. Nogle af Problemerne<br />
med den løsning er bl.a. at man får et program med meget høj kobling, og derfor kan selv<br />
små ændringer i dele af programmet, få uoverskuelige konsekvenser. Det betyder også at<br />
en høj modularitet er stort set uopnåelig.<br />
Vi valgte at løse problemet ved hjælp af to tiltag: for det første valgte vi at overlade<br />
ansvaret for at gemme billedet, til klassen Kamera. Et logisk tiltag, da det er denne klasse<br />
som genererer billedet. For det andet besluttede vi at oprette en ny klasse ved navn<br />
Sceneopstiller, som fik ansvaret for at læse XML-filen, oprette scenen og tilføje figurer til<br />
Scenen.<br />
13
XML til intern kobling Efter anden Iteration blev vi opmærksomme på at vi blot havde<br />
flyttet en del af problemet: klassen Sceneopstiller havde stadig en meget høj kobling. Efter<br />
at have analyseret problemet besluttede vi os dog for at beholde Sceneopstiller uforandret.<br />
Det beror på at vi kom frem til at de fleste koblinger mellem Sceneopstiller og andre klasser,<br />
går ud på at Sceneopstiller instansierer klasserne med data fra XML-filen som argumenter,<br />
og derefter ophører al kontakt. Problemet er naturligvis at man er nødt til at ændre i<br />
Sceneopstiller, hvis man ændrer på en af figurerne eller tilføjer en ny figur. Vi erkendte<br />
at figurerne alle er så forskellige, at det ville være meget omstændigt at prøve at definere<br />
en eller anden fælles skabelon som de alle skulle overholde. Samtidig mener vi at det er<br />
hensigtsmæssigt at holde XML-indlæsningen og sceneopbygningen samlet i én klasse, for<br />
at holde koblingen mellem intern og ekstern representation af figurer samlet, så vi kun<br />
behøver at rette ét sted, hvis en figur ændres eller tilføjes. Et kompromis hvor hensigten<br />
har været at fremme enkelthed og modularitet.<br />
Grænseflader og generalisering Efter 2. iteration havde vi 3 grænseflader (SceneI,<br />
SceneopstillerI, KameraI) og 1 abstrakt klasse (Element). I løbet af 3. iteration gennemgik<br />
vi hver af dem, og overvejede deres berettigelse.<br />
SceneI giver god mening at have som grænseflade, man kunne nemt forestille sig tilfælde,<br />
hvor det ville være hensigtsmæssigt at implementere en ny Scene klasse. Det kunne f.eks<br />
være hvis man ønskede en model som understøttede flere lyskilder eller implementerede<br />
en smartere metode til at finde en Stråles første skærings3DPunkt. Samtidig gør både<br />
Sceneopstiller og Kamera klasserne brug af grænsefladen. Alt i alt besluttede vi at beholde<br />
SceneI.<br />
SceneopstillerI har bestemt også merit. En af årsagerne til at vi valgte at holde XMLindlæsningen<br />
og sceneopbygningen samlet i én klasse, var jo netop at det gav absolut<br />
mest mening at udskifte det hele på én gang. Efter nogen granskning kom vi dog frem til<br />
at der simpelthen ikke var tilstrækkeligt med efterspørgsel, til at det kunne berettige en<br />
grænseflade: den eneste klasse som ville gøre brug af grænsefladen var Fotograf, og Fotograf<br />
ville næppe nogensinde komme til at sende (og modtage) mere end én besked (muligvis<br />
i en senere udgave, samme type besked flere gange), til Sceneopstiller, under en kørsel.<br />
Meget væsentligt i vore overvejelser var også det faktum at der under kørsel aldrig ville<br />
blive instansieret mere en én Sceneopstiller. SceneopstillerI blev altså strøget.<br />
KameraI er et grænsetilfælde, fordi den har merit men ikke er videre efterspurgt (ligesom<br />
SceneopstillerI), og fordi vi alligevel har besluttet os for at beholde den. Der kunne være<br />
mange grunde til at lave kameraer med udvidet funktionalitet, f.eks et kamera som efter at<br />
have genereret et billede, skiftede position og gentog processen. Kamera bliver instansieret<br />
af Sceneopstiller (bag om grænsefladen), og derefter er det kun Fotograf som benytter sig af<br />
grænsefladen (og kun én gang pr. Kamera). Det der gjorde at vi alligevel besluttede os for<br />
at grænsefladen er berettiget, er at den i høj grad kunne blive relevant i en situation hvor<br />
der findes en række forskellige kameraer, som har forskellige egenskaber. I et sådant tilfælde<br />
ville enkapsuleringen Kamera, gøre programmet langt mere overskueligt og funktionelt ([4]<br />
opfordrer i høj grad til brug af enkapsulation).<br />
14
Element ville være meget velegnet som grænseflade. Uanset deres geometriske egenskaber,<br />
er det de samme data vi ønsker fra alle de forskellige figurer: skæringspunkt og farve.<br />
Netop med figurene er der dog endu en faktor at tage med i overvejelserne: der er nogle<br />
mekaniske beregninger som skal udføres for alle figurer uden undtagelse, mht. skæring med<br />
strålen fra solen, og den resulterende farve. De beregninger gør at det er attraktivt at gøre<br />
Element til en abstrakt klasse i stedet for en grænseflade. Det er fordi vi så har mulighed<br />
for at genbruge kode som står i Element, i stedet for at skrive koden i hver enkelt af<br />
figur-klasserne (kode genbrug anbefales også på det kraftigste i [4]), og giver yderligere den<br />
fordel at man kun behøver at rette èt sted, hvis der senere skal ændres i koden. Desuden<br />
fremmes det mål, som opgaveteksten lægger vægt på, om at nye former nemt skal kunne<br />
tilføjes til designet. For at tilføje en ny form til designet, skal den blot nedarve fra Element<br />
- og opfylde dennes kontrakt - og en XML-til-intern kobling skal tilføjes til Sceneopstiller.<br />
Bekvemmelsesklasser Efter at designfasen var overstået, og vi var begyndt at kode,<br />
måtte vi erkende at det ville være hensigtsmæssigt med nogle simple datastrukturer, som<br />
skulle bruges som argumenter, af de forskellige klasser. Vi oprettede to forskellige klasser:<br />
3DPunkt og Stråle. Begge indeholder data som kan inspiceres og evt. ændres, men ingen<br />
af dem sender selv meddelelser til andre objekter, og de har som sådan ingen faste associationer<br />
med nogle bestemte klasser, ud over at klasserne bruger dem som datastrukturer<br />
og argumenter. Det afspejler vi i diagrammerne ved ikke tegne nogle associationer mellem<br />
disse to klasser og resten af klasserne, på associationsdiagrammet, og ved at udelade disse<br />
to i sekvensdiagrammet, alt sammen for overskuelighedens skyld.<br />
Mens vi kodede valgte vi også at introducere en klasse XMLParseError, som kastes ved<br />
fejl i indlæsningen af XML-filen. Denne stammer fra den udleverede XML-indlæser.<br />
3.2 Diagrammer<br />
Her følger en kort beskrivelse af hvert diagram, og begrundelsen for at tage dem med.<br />
associationsdiagrammet er resultatet af vores arbejde med [2]. Det viser alle programmets<br />
klasser, og deres indbyrdes forhold. Associationerne er holdt på et generelt<br />
niveau, for at gøre det nemt at overskue diagrammet, men vi har dog inkluderet<br />
metoderne for hver klasse, så man nemt og hurtigt kan referere til dem. Dette diagram<br />
er tegnet før programmet er kodet/da vi begyndte at kode programmet, og vi<br />
har hovedsaligt kodet ud fra dette diagram.<br />
nedarvningsdiagrammet er genereret efter at programmet er kodet, og er med for at<br />
give et overblik over hvilke klasser som nedarver fra hvilke. Desuden viser vi klassernes<br />
grænseflader på dette diagram, da det formentlig er rart at have et overblik over disse<br />
når man skal arbejde med programmet. Vi har særligt tænkt på folk som evt. skulle<br />
vedligeholde eller udvide programmet.<br />
CRC-kortene stammer fra vores designfase og viser ansvarsfordelingen og de tilhørende<br />
kollaboratører. Det er værd at bemærke at vi ikke har flyttet ansvaret „beregn skæring<br />
15
med stråle“ op i den generelle klasse Element, da denne er abstrakt. I stedet står<br />
ansvaret på hver af dens underklasser. Dette skyldes at implementationen af dette<br />
ansvar ikke kan generaliseres.<br />
16
4 Programmeringsovervejelser<br />
Det er vores opfattelse, at ovenfor gennemgåede design kan implementeres som det er.<br />
Vi vil derfor ikke beskæftige os yderligere med programmets overordnede struktur i dette<br />
afsnit. I stedet vil vi diskutere strålesporingsalgoritmen og dennes tidskompleksitet.<br />
4.1 Strålesporing<br />
Der er i opgaveteksten [1, s.7] skitseret en algoritme til strålesporing. Vi vil følge denne<br />
algoritme og i det følgende vil vi gennemgå de enkelte trin og løse evt. problemer.<br />
4.1.1 Før sporingen<br />
I vores design er det et Kamera-objekt, der skal stå for opdelingen af „filmen“ i referencefelter<br />
og for at skabe de Stråle-objekter, der skal spores. Da vi skal bruge den udleverede klasse<br />
Kanvas til at skabe billedet, vil det være hensigtsmæssigt, hvis vores kamera opererer med<br />
et koordinatsytem, der direkte svarer til det Kanvas bruger. Dette (todimensionale) koordinatsystem<br />
har omdrejningsretning med uret og svarer derfor ikke til det koordinatsystem,<br />
som fastlægges af „filmens“ stedpunkt og dens to vektorer.<br />
For at opnå korrespondance mellem de to koordinatsystemer beregner vi koordinatsættet<br />
til „filmens“ øverste venstre hjørne ved at lægge lodret-vektoren til stedpunktet. Derefter<br />
vender vi lodret-vektoren om. Som det sidste skalerer vi lodret-vektoren og vandret-vektoren,<br />
så de henholdsvis får samme længde som højden og bredden af et referencefelt. Hvis vi<br />
kalder det nye stedpunkt for ¯s, den nye lodret-vektor for l og den nye vandret-vektor for<br />
v, så har vi nu følgende korrespondance mellem et koordinatsæt (i, j) i Kanvas, til et<br />
koordinatsæt i scenen:<br />
(x, y, z) = ¯s + (i + 0, 5) · v + (j + 0, 5) · l i, j ∈ N<br />
At der skal lægges 0,5 til kanvas-koordinaterne skyldes, at vi i de problemorienterede analyse<br />
besluttede at strålerne skulle gå midt igennem referencefelterne.<br />
Når vi har oprettet et Kanvas-objekt, er vi klar til at begynde strålesporingen.<br />
4.1.2 Selve sporingen<br />
For hvert referencefelt skal vi nu gennemgå følgende trin:<br />
1. Vi skal oprette en Stråle med udgangspunkt i øjepunktet og med retning mod midten<br />
af referencefeltet.<br />
2. Scene-objektet skal finde ud af hvilke Element-objekter, strålen skærer og hvilket den<br />
skærer nærmest. Hvis Strålen ikke skærer nogen Elementer, så skal referencefeltet<br />
være sort.<br />
3. Dernæst skal Sol-objektet lave en Stråle, der starter i solen og har retning mod det<br />
fundne skæringspunkt.<br />
17
4. Scene-objektet skal finde det nærmeste skæringspunkt til solstrålen.<br />
5. Det sidst fundne skæringspunkt skal sammenlignes med det første. Hvis de ikke er<br />
ens, så skal referencefeltet være sort.<br />
6. Det ramte Element skal ud fra solstrålen bestemme sin farve i det ramte punkt.<br />
7. Den fundne farve skal tildeles referencefeltet.<br />
Disse trin er trivielle at implementere, men punkt 5 kræver noget omtanke. Da vi arbejder<br />
med brudne tal kan der være visse præcisionproblemer. Det kan tænkes at selvom det med<br />
uendelig præcision ville være det samme punkt, der blev fundet ved udregning af skæring<br />
med både kamera- og solstråle, så kan præcisionsproblemerne betyde at det ikke er tilfældet<br />
i computerens repræsentation af de to skæringspunkter. Sammenligningen af de to punkter<br />
må derfor være tolerant overfor mindre unøjagtigheder. Vi har ikke noget grundlag for at<br />
vælge, hvor stor en differens der er acceptabel, og det må derfor bero på eksperimenter<br />
under konstruktionen af programmet.<br />
4.2 Tidskompleksitet<br />
Der er to parametre det er interessant at undersøge tidskompleksiteten for strålesporingen<br />
i forhold til. Den første er antallet af objekter i scenen, den anden er det ønskede billedes<br />
opløsning. Da der i vores algoritme er en én til én korrespondance mellem antallet af pixels<br />
og antallet af sporede stråler fra kameraet, så er det i realiteten kun betydningen af antallet<br />
af objekter, der skal undersøges.<br />
Vi vil i den sammenhæng ikke betragte et mesh som et objekt. I stedet vil vi tælle de<br />
trekanter, der indgår i meshet, som objekter.<br />
4.2.1 Beregning af skæring med objekter<br />
For både trekant, kugle og plan gælder, at udregningen af skæringspunkt(er) med en stråle<br />
er uafhængig af antallet af objekter i scenen. Disse udregninger bidrager derfor kun med<br />
konstanter til tidskompleksiteten i forhold til antallet af objekter.<br />
4.2.2 Kompleksitet for en enkelt stråle<br />
Den variable størrelse for sporingen af en stråle i en scene er hvor mange objekter, der<br />
skal testes for skæring. Da disse skæringsudregninger er konstante i forhold til antallet af<br />
objekter, så er tidskompleksiteten for sporingen af en enkelt stråle lineært afhængig af<br />
antallet af objekter, n, dvs. O(n).<br />
4.2.3 Antal sporede stråler<br />
For hver stråle fra kameraet er der to muligheder: strålen rammer noget eller den rammer<br />
ikke noget. Hvis strålen rammer noget skal der spores endnu en stråle, ellers er vi<br />
18
færdige. Dvs. at tidskompleksiteten i begge tilfælde - henholdsvis værste- og bedstetidskompleksiteten<br />
- afhænger lineært af tidskompleksiteten for sporing af to stråler. Derfor<br />
er afviklingstiden i forhold til antallet af objekter, n, i scenen asymptotisk tæt begrænset<br />
af funktionen f(n) = n, hvorfor vi har Θ(n).<br />
19
5 Programbeskrivelse<br />
Dette er beskrivelsen af det færdige program. Læseren forventes at være på samme niveau,<br />
som en studerende på <strong>DIKU</strong>, der har fulgt Dat0<strong>GB</strong>-kurset til ende.<br />
Programmet følger det design, vi har beskrevet i afsnit 3 og de overvejelser vi har<br />
gjort i forrige afsnit. Kildekoden kan ses i appendiks E. Koden er velkommenteret og<br />
implementationsdetaljer må søges der. Alle klasserne og deres grænseflader er beskrevet i<br />
appendiks D.<br />
Følgende liste er forslag til relevante klasser i forbindelse med forskellige opgaver.<br />
• I forbindelse med tilføjelse af en ny form, f.eks. en kasse, er det relevant at se på<br />
klasserne Element (app. D.1) og Sceneopstiller (app. D.11). Se desuden nedenstående<br />
afsnit om Sceneopstiller.<br />
• Programmet kan bruges som modul i et andet program, se Fotograf afsnit D.2. I sin<br />
nuværende form forudsætter dette dog, at hovedprogrammet sikrer sig at XML-filen<br />
er gyldig, da vores program ellers kalder System.exit-metoden.<br />
• Ved implementation af nye kameramodeller, der f.eks. implementerer anti-alialisering,<br />
er klasserne KameraI (app. D.4)og Sceneopstiller (app. D.11) gode steder at starte.<br />
5.1 Læsevejledning<br />
Koden i hver klasse er delt op i følgende dele:<br />
1. Evt. konstruktører er placeret først.<br />
2. Dernæst kommer klassens metoder i alfabetisk rækkefølge (undtaget dem der falder<br />
under næste punkt).<br />
3. Klassens accessors og mutators er samlet næstsidst.<br />
4. Sidst kommer klassens attributter.<br />
Vi har tilstræbt at bruge danske navne på såvel variable som metoder, men har i få tilfælde<br />
- hvor vi skønnede det naturligt - brugt engelske navne.<br />
5.2 Kommentarer i koden<br />
Hver metode er ledsaget af en forudgående beskrivelse af formålet. De løbende kommentarer<br />
i selve metoderne tilstræber at give en overordnet forklaring af fremgangsmåden.<br />
Klasserne indeholder en kort beskrivelse af deres formål, men en uddybning af denne<br />
information må søges i appendiks D.<br />
20
5.3 Sceneopstiller<br />
Klassen Sceneopstiller er lavet med udgangspunkt i Søren Sjørups XMLReadWrite, der er<br />
stillet til rådighed i.f.m. opgaven. Denne kan hentes på kurset hjemmeside. Sceneopstiller<br />
er stærkt modificeret og kommenteringen lader en del tilbage at ønske, hvilket bunder i<br />
oplæggets sparsomme kommentering.<br />
Det er hver at bemærke, at Sceneopstiller bruger backtracking - ved hjælp af XML-<br />
ParseError - til at opbygge sine fejlmeddelelser. Ved brug af de generelle indlæsningsfunktioner<br />
er det derfor vigtigt at følge denne struktur, således at en konsistent fejlmelding kan<br />
gives til brugeren.<br />
21
6 Afprøvning<br />
Da vi nu har implementeret programmet og ved at det syntaktisk er korrekt, vil vi afprøve<br />
om det semantisk lever op til opgaveformuleringens krav samt til vores egne krav fra den<br />
problemorienterede analyse.<br />
Det bliver i opgaven præciseret [1, afs. 5] at det er den eksterne afprøvning, der skal<br />
dokumenteres. Vi vil derfor ikke gå ind i den interne afprøvning, men blot konstatere, at<br />
vi under konstruktionen af programmet løbende har foretaget intern afprøvning.<br />
6.1 Strategi<br />
Da det eneste input, som programmet får, er XML, så vil vi opdele kravene til programmet<br />
ud fra de tags, der er i den givne notation. For hvert tag vil vi undersøge, hvilke ækvivalensklasser<br />
man kan dele de mulige variationer op i og hvordan det kan kontrolleres at<br />
programmet lever op til kravet og herunder om det er muligt at vælge grænsetilfælde. For<br />
hver ækvivalensklasse vil vi skrive en parentes med nummeret på den relevante afprøvning.<br />
For de fleste tags vil der være to overordnede ækvivalensklasser: korrekt brug og forkert<br />
brug. Vi vil for disse tags behandle hver af disse ækvivalensklasser for sig.<br />
Generelt vil vi ikke beskæftige os med syntaktisk forkert XML, da kravet blot er at<br />
programmet skal kunne indlæse en scenespecifikation skrevet i XML. Som besluttet i den<br />
problemorienterede analyse, så skal en syntaktisk forkert scenebeskrivelse blot afvises af<br />
programmet.<br />
Vi vil starte med et generelt afsnit, der gælder for de tags, der har krævede attributter.<br />
6.1.1 Krævede attributter<br />
For de tags, hvor der er et antal attributter der er krævede, er der to typer fejl: en eller<br />
flere manglende attributter eller fejl i en eller flere af disse. Hver af disse udgør en ækvivalensklasse<br />
for det relevante tag.<br />
Manglende attribut(ter) Test af programmets reaktion på manglende attributter er<br />
ens for de forskellige tags og vi diskuterer det derfor samlet her og vil ikke nævne det under<br />
de respektive tags (bortset fra en reference til den relevante afprøvning).<br />
Vi vil betragte de tilfælde, hvor en attribut er navngivet forkert, som om de ikke er<br />
angivet.<br />
Der er ikke noget oplagt grænsetilfælde for test af manglende attributter, da de alle er<br />
påkrævede uden nogen særlig vægtning e.l. Udeladelse af én enkelt af attributterne anser<br />
vi derfor for en repræsentativ test af denne ækvivalensklasse.<br />
6.1.2 <br />
scene-tagget er rod-elementet i dokumentet og har ikke nogen krævede attributter. Der er<br />
derfor to ækvivalensklasser i forbindelse med scene-tagget: roden er scene (afpr. 1) eller<br />
22
oden er noget andet (afpr. 2). Sidstnævnte mulighed skal resultere i en fejlmeddelelse.<br />
Det er ikke muligt at vælge grænsetilfælde, da det er enten eller.<br />
6.1.3 <br />
For pilotsynet er det semantiske krav til beskrivelsen, at alle dets attributter skal være<br />
specificeret og det selvfølgelig korrekt.<br />
Korrekt pilotsyn Et korrekt angivet pilotsyn skal have den effekt, at der bliver lavet et<br />
tilsvarende billede, som efter kørslen ligger i en fil. Filen skal have det navn som er angivet<br />
i id-attributten og påhæftet endelsen .ppm. Endvidere skal programmet under kørslen give<br />
en løbende respons på processen. (afpr. 1)<br />
Kontrollen af at programmet lever op til dette krav beror på et visuelt skøn af det<br />
producerede billede samt at outputtet er som beskrevet.<br />
Forkert pilotsyn Et forkert angivet pilotsyn skal resultere i en fejlmeddelelse til brugeren,<br />
der angiver hvad fejlen er. Forkerte pilotsyn er dem, hvor der mangler en eller flere attributter<br />
(afpr. 3) eller hvor en eller flere af disse er angivet forkert.<br />
Forkert(e) attribut(ter) Fire af pilotsyn-taggets attributter består af punkt-tags<br />
og de vil blive diskuteret og afprøvet separat. Tilbage er id, hoejde og bredde. id kan<br />
ikke angives forkert 2 . De to andre skal være heltal større end nul. Dette giver følgende<br />
ækvivalensklasser til test af forkert højde og bredde<br />
• Værdien er ikke et tal. En test-værdi, der nærmest er en grænseværdi, vil være en<br />
blanding af tal og bogstaver. (hoejde: afpr. 4, bredde: afpr. 5)<br />
• Værdien er et brudent tal. En grænseværdi kunne være et brudent tal, hvor decimaldelen<br />
var nul (f.eks. 0.0). (hoejde: afpr. 6, bredde: afpr. 7)<br />
• Værdien er et heltal mindre end eller lig nul. Gænseværdien her er nul. (hoejde: afpr.<br />
8, bredde: afpr. 9)<br />
6.1.4 <br />
Det overordnede krav for sol-tagget er, at der kun må være en sol i scenen.<br />
Som med pilotsyn, så skal alle sol-taggets attributter specificeres og det korrekt.<br />
Korrekt sol Da solen i sig selv ikke er synlig, kan en korrekt angivet sol kun kontrolleres,<br />
hvis der er objekter i synsfeltet og hvis solens farve er lys nok. Kontrollen beror på et visuelt<br />
skøn af det producerede billede. (afpr. 1)<br />
2 id’et kan indeholde tegn som det underliggende filsystem ikke kan håndtere. Dette har dog ikke noget<br />
med vores program at gøre<br />
23
Forkert sol Manglende attributter er en fejl og dette testes som beskrevet i starten af<br />
afsnittet. (afpr. 10)<br />
sol-tagget har kun en attribut, der ikke testes for håndtering af forkert brug et andet<br />
sted, nemlig id og id kan ikke angives forkert.<br />
6.1.5 <br />
Kugle har fire attributter, hvoraf de to bliver beskrevet og testet i anden sammenhæng.<br />
Tilbage er test af id og radius. Id kan ikke angives forkert. Radius skal være et tal større<br />
end nul.<br />
Korrekt kugle En korrekt angivet kugle kan kun kontrolleres visuelt. (afpr. 1)<br />
Forkert kugle Alle kugle-taggets attributter er krævede, hvorfor de generelle betragtninger<br />
i starten af afnittet er relevante for kugle (afpr. 11). Specifikt for kugle er det kun<br />
radius, der skal testes. Vi mener der er følgende to ækvivalensklasser for forkert angivelse<br />
af kugle<br />
• radius er ikke et tal. En form for grænsetilfælde vil være en blanding af tal og<br />
bogstaver. (afpr. 12)<br />
• radius er nul eller derunder. Grænsetilfældet er nul. (afpr. 13)<br />
6.1.6 <br />
Plan har fem krævede attributter, hvoraf de fire bliver diskuteret og testet andetsteds. Den<br />
sidste er id og den kan ikke være forkert.<br />
De to af plans attributter afhænger af hinanden, nemlig de to retningsvektorer, der ikke<br />
må have samme retning.<br />
Korrekt plan En korrekt plan kan kun bekræftes visuelt. (afpr. 1)<br />
Forkert plan Hvis de to retningsvektorer er parallelle, så skal programmet komme med<br />
en fejl. Der er ikke noget grænsetilfælde, da det er et enten eller spørgsmål. (afpr. 14)<br />
(manglende attributter: afpr. 15)<br />
6.1.7 <br />
Mesh har fire attibutter, hvoraf kun id - der ikke kan angives forkert - ikke testes i anden<br />
sammenhæng. Alle mesh’s attributter er krævede.<br />
To af mesh’s attributter er afhængige af hinanden, nemlig punkter og trekanter. Der<br />
må ikke være referencer i trekanter til punkt-tags, der ikke er defineret.<br />
Korrekt mesh Et korrekt mesh kan kun bekræftes visuelt. (afpr. 1)<br />
24
Forkert mesh Ugyldige referencer i trekanter skal resultere i en fejlmeddelelse. Det er<br />
ikke muligt at vælge grænsetilfælde. (afpr. 16) (manglende attributter: afpr. 17)<br />
6.1.8 <br />
Punkt har to betydninger i notationen: punkt og vektor. Kravende til de to er ens, bortset<br />
fra at vektorer ikke må være nulvektoren. Alle punkts attributter er krævede. Et punkts<br />
id kan kun være forkert i konteksten.<br />
Korrekt punkt/vektor Et korrekt punkt/vektor kan kun kontrolleres i forbindelse med<br />
de tags, der har en visuel effekt. Kontrollen består af et visuelt skøn. (afpr. 1)<br />
Forkert punkt/vektor Et forkert punkt eller vektor skal resultere i en fejlmeddelelse.<br />
De tre attributter x, y og z, har samme krav: de skal være tal. Dette giver kun en ækvivalensklasse<br />
med forkert data, nemlig de tilfælde hvor det ikke er tal (x: afpr. 18, y: afpr.<br />
19, z: afpr. 20). En (form for) grænseværdi er en blanding af tal og bogstaver.<br />
For vektor er der desuden det tilfælde, hvor de fire attributter hver for sig er ok, men<br />
hvor x, y og z alle er nul. (afpr. 21)<br />
(manglende attributter: afpr. 22)<br />
6.1.9 <br />
Farve har tre attributter, der alle er påkrævede. De tre attributter skal være heltal i intervallet<br />
[0;255].<br />
Korrekt farve En korrekt farve kan kun testes i forbindelse med de tags, der kan ses på<br />
det genererede billede. (afpr. 1)<br />
Forkert farve En forkert angivet farve skal resultere i en fejlmeddelelse. Der er fire<br />
ækvivalensklasser (for forkert data) for hver af de tre attributter:<br />
• Værdien er ikke et tal. Grænseværdien er en blanding af tal og bogstaver. (r: afpr.<br />
23, g: afpr. 24, b: afpr. 25)<br />
• Værdien er et brudent tal. Grænseværdien er et brudent tal, hvor decimaldelen er<br />
nul. (r: afpr. 26, g: afpr. 27, b: afpr. 28)<br />
• Værdien er et heltal, der er mindre end nul. Grænseværdien er -1. (r: afpr. 29, g: afpr.<br />
30, b: afpr. 31)<br />
• Værdien er et heltal, der er større end 255. Grænseværdien er 256. (r: afpr. 32, g:<br />
afpr. 33, b: afpr. 34)<br />
(manglende attributter: afpr. 35)<br />
25
6.1.10 <br />
trekanter har en krævet tag: antal_trekanter. Dennes værdi skal svare til det antal trekantattributter,<br />
der er angivet.<br />
Korrekt trekanter Et korrekt angivet trekanter-tag kan kun testes i forbindelse med<br />
mesh-tagget. Kontrollen er visuel. (afpr. 1)<br />
Forkert trekanter Hvis antal_trekanter er angivet forkert, skal der komme en fejlmeddelelse.<br />
Der er fire ækvivalensklasser for forkerte værdier af antal_trekanter:<br />
• Værdien er ikke et tal. Grænseværdien er en blanding af tal og bogstaver. (afpr. 36)<br />
• Værdien er et brudent tal. Grænseværdien er et brudent tal, hvor decimaldelen er<br />
nul. (afpr. 37)<br />
• Værdien er et heltal, der er mindre end nul. Grænseværdien er -1. (afpr. 38)<br />
• Værdien er et heltal, der ikke svarer til antallet af trekant-attributter. (afpr. 39)<br />
(manglende attribut: afpr. 40)<br />
6.1.11 <br />
trekant har tre krævede attributter. De må ikke være ens og skal være heltal større end<br />
eller lig nul.<br />
Korrekt trekant En korrekt trekant kan kun testes i forbindelse med et mesh-tag. Kontrollen<br />
er visuel. (afpr. 1)<br />
Forkert trekant En forkert trekant har to eller flere attributter med samme værdi.<br />
Grænseværdien er to ens attributter. (afpr. 41)<br />
(manglende attributter: afpr. 42)<br />
6.1.12 <br />
punkter har en krævet tag: antal_punkter. Dennes værdi skal svare til det antal punktattributter,<br />
der er angivet.<br />
Korrekt punkter Et korrekt angivet punkter-tag kan kun testes i forbindelse med meshtagget.<br />
Kontrollen er visuel. (afpr. 1)<br />
26
Forkert punkter Hvis antal_punkter er angivet forkert, skal der komme en fejlmeddelelse.<br />
Der er fire ækvivalensklasser for forkerte værdier af antal_punkter:<br />
• Værdien er ikke et tal. Grænseværdien er en blanding af tal og bogstaver. (afpr. 43)<br />
• Værdien er et brudent tal. Grænseværdien er et brudent tal, hvor decimaldelen er<br />
nul. (afpr. 44)<br />
• Værdien er et heltal, der er mindre end nul. Grænseværdien er -1. (afpr. 45)<br />
• Værdien er et heltal, der ikke svarer til antallet af trekant-attributter. (afpr. 46)<br />
(manglende attribut: afpr. 47)<br />
6.2 Opstilling og udførsel<br />
Herunder følger de nævnte afprøvninger. Inddata samt forventet og faktisk uddata er placeret<br />
i appendiks F og de respektive kolonner i nedenstående tabel, refererer til afsnit i dette<br />
appendiks. Den sidste kolonne i tabellen angiver om afprøvningen forløb som forventet.<br />
Nr. Inddata Forventet uddata Faktisk uddata Kommentar √ /÷<br />
√<br />
1 F.1 F.1 F.1 obligatorisk<br />
√<br />
2 F.2 F.2 F.2<br />
√<br />
3 F.3 F.3 F.3<br />
√<br />
4 F.4 F.4 F.4<br />
√<br />
5 F.5 F.5 F.5<br />
√<br />
6 F.6 F.6 F.6<br />
√<br />
7 F.7 F.7 F.7<br />
√<br />
8 F.8 F.8 F.8<br />
√<br />
9 F.9 F.9 F.9<br />
√<br />
10 F.10 F.10 F.10<br />
√<br />
11 F.11 F.11 F.11<br />
√<br />
12 F.12 F.12 F.12<br />
√<br />
13 F.13 F.13 F.13<br />
√<br />
14 F.14 F.14 F.14<br />
√<br />
15 F.15 F.15 F.15<br />
√<br />
16 F.16 F.16 F.16<br />
√<br />
17 F.17 F.17 F.17<br />
√<br />
18 F.18 F.18 F.18<br />
√<br />
19 F.19 F.19 F.19<br />
√<br />
20 F.20 F.20 F.20<br />
27
Nr. Inddata Forventet uddata Faktisk uddata Kommentar √ /÷<br />
√<br />
21 F.21 F.21 F.21<br />
√<br />
22 F.22 F.22 F.22<br />
√<br />
23 F.23 F.23 F.23<br />
√<br />
24 F.24 F.24 F.24<br />
√<br />
25 F.25 F.25 F.25<br />
√<br />
26 F.26 F.26 F.26<br />
√<br />
27 F.27 F.27 F.27<br />
√<br />
28 F.28 F.28 F.28<br />
√<br />
29 F.29 F.29 F.29<br />
√<br />
30 F.30 F.30 F.30<br />
√<br />
31 F.31 F.31 F.31<br />
√<br />
32 F.32 F.32 F.32<br />
√<br />
33 F.33 F.33 F.33<br />
√<br />
34 F.34 F.34 F.34<br />
√<br />
35 F.35 F.35 F.35<br />
√<br />
36 F.36 F.36 F.36<br />
√<br />
37 F.37 F.37 F.37<br />
√<br />
38 F.38 F.38 F.38<br />
√<br />
39 F.39 F.39 F.39<br />
√<br />
40 F.40 F.40 F.40<br />
√<br />
41 F.41 F.41 F.41<br />
√<br />
42 F.42 F.42 F.42<br />
√<br />
43 F.43 F.43 F.43<br />
√<br />
44 F.44 F.44 F.44<br />
√<br />
45 F.45 F.45 F.45<br />
√<br />
46 F.46 F.46 F.46<br />
√<br />
47 F.47 F.47 F.47<br />
6.3 Konklusion<br />
Som det ses af ovenstående tabel, så klarer den endelige udgave af vores program sig<br />
igennem afprøvningen. Det er dog ikke resultatet af første afprøvning, der ses ovenfor. Især<br />
afprøvning 1 afslørede flere betydelige fejl.<br />
Heriblandt en fejl i Trekant klassen, der bevirkede at omkring halvdelen af billedet<br />
„syn2.ppm“ blot var vandrette grå og sorte streger. Fejlen skyldtes at den implementerede<br />
algoritme til projicering på en plan ikke brugte den numeriske værdi af plankonstanterne,<br />
hvorfor trekanterne ikke nødvendigvis blev projiceret ind på den plan, hvor deres projektion<br />
havde størst areal.<br />
De resterende afprøvninger afslørede ikke vitale fejl i programmet, men var med til at<br />
trimme fejlmeldingen fra programmet, hvilket fra brugerens synspunkt må siges at være<br />
væsentligt.<br />
28
7 Brugervejledning<br />
Dette er brugervejledningen til strålesporeren Fotograf. Det forudsættes at læseren kan<br />
lave scenebeskrivelser som beskrevet i [1]. Endvidere forudsættes kendskab til hvordan man<br />
bruger en kommandofortolker.<br />
7.1 Det kan Fotograf<br />
Fotograf er et Java-program, der kan lave billeder af tredimensionale modeller og gemme<br />
dem i ppm-formatet. I sin nuværende form kan du bruge Fotograf til at lave billeder,<br />
hvor der indgår kugler, planer og trekanter. Selvom det ikke lyder af meget, så kan du<br />
faktisk lave ret flotte billeder med de tre former.<br />
Men før du kan lave dit første billede, skal du først have installeret Fotograf på dit<br />
system.<br />
7.2 Systemkrav<br />
For at du kan køre Fotograf, skal en Java-fortolker være installeret på dit system. Javafortolkere<br />
til de fleste platforme kan hentes på internet-adressen http://java.sun.com/getjava/<br />
og der kan du også finde information om hvordan de installeres og sættes op.<br />
7.3 Installation<br />
Installation af Fotograf kræver lidt kendskab til, hvordan dit system fungerer. Du skal<br />
nemlig sørge for, at den såkaldte classpath indeholder stien til den mappe, hvor du har<br />
placeret filerne til Fotograf.<br />
Hvis du ikke ved hvordan du gør det, kan du stadig køre Fotograf; det er bare lidt<br />
mere besværligt: når der i vejledningen står at du skal indtaste noget i kommandolinjen,<br />
så skal du indtaste lidt mere end der står. Hvis der f.eks. står at du skal indtaste:<br />
java Fotograf<br />
så skal du i stedet indtaste<br />
java -classpath Fotograf<br />
hvor du i stedet for skal indtaste den rigtige sti, uden de kantede<br />
parenteser. På et Windowssystem kunne kommandoen f.eks. se sådan her ud:<br />
java -classpath c:\Programmer\Fotograf Fotograf<br />
I resten af vejledningen er udganspunktet at din classpath er sat som beskrevet.<br />
29
7.4 Afvikling af programmet<br />
Når du har lavet en scenbeskrivelse og gemt den i en fil (f.eks scene.xml), så er du klar<br />
til at køre Fotograf. Hvis den aktive mappe i din kommandofortolker er samme mappe<br />
som din scenebeskrivelse ligger i, så kører du Fotograf ved at skrive:<br />
java Fotograf scene.xml<br />
Fotograf vil nu gå i gang med at læse din scenebeksrivelse. Hvis scenebeskrivelsen er<br />
korrekt, så vil der for hvert pilotsyn blive lavet et billede med samme navn som pilotsynet,<br />
påhæftet endelsen .ppm. Disse billeder vil blive lagt i samme mappe som Fotograf.<br />
7.5 Meddelelser<br />
Når Fotograf kører, så vil det løbende udskrive meddelelser om hvor langt det er kommet.<br />
Mens den laver et billede vil den udskrive en stjerne for hver 10% den bliver færdig<br />
med; så kan du se at programmet stadig arbejder.<br />
7.5.1 Fejlmeddelelser<br />
Fotograf er lavet så det kan hjælpe dig med at finde fejl i din scenebeskrivelse. Hvis<br />
Fotograf opdager en fejl, så udskriver den så præcis en meddelelse den kan om, hvad<br />
fejlen er. Hvis du f.eks. har glemt at give solen en farve, så vil Fotograf skrive:<br />
Indlæser scene.xml ...<br />
Der er en fejl i scene.xml:<br />
(scene)->solen (sol)->farve<br />
En farve skal angives<br />
Programmet afsluttes<br />
De ting, der står i parentes, er navne på tags og det der står før parentesen er det id du<br />
har givet tagget. Så ud fra ovenstående meddelelse, så ved du at du skal kigge efter et<br />
-tag, hvor id’et er ”solen”.<br />
30
Litteratur<br />
[1] <strong>DIKU</strong> <strong>Flight</strong> <strong>Simulator</strong> 2004. http://www.diku.dk/undervisning/<strong>2003</strong>f/dat0gb/samling.ps,<br />
april <strong>2003</strong>.<br />
[2] Eric Jul. Erics OOD. http://www.diku.dk/undervisning/<strong>2003</strong>f/dat0gb/kogebog.html,<br />
marts <strong>2003</strong>.<br />
[3] Søren Sjørup. Pilotsyn. http://www.diku.dk/undervisning/<strong>2003</strong>f/dat0gb/pilotsyn.ps,<br />
maj <strong>2003</strong>.<br />
[4] Perdita Stevens. Using UML: Software engineering with objects and components.<br />
Addison-Wesley, updated edition edition, 2000.<br />
31
A Klasser og arv<br />
32
B Associationsdiagram<br />
C CRC-kort<br />
Herunder følger vores CRC-kort i alfabetisk rækkefølge.<br />
33
C.1 Element<br />
34
C.2 Fotograf<br />
35
C.3 Kamera<br />
36
C.4 Kugle<br />
37
C.5 Mesh<br />
38
C.6 Plan<br />
39
C.7 Punkt3D<br />
40
C.8 Scene<br />
41
C.9 Sceneopstiller<br />
42
C.10 Sol<br />
43
C.11 Stråle<br />
44
C.12 Trekant<br />
45
C.13 XMLParseError<br />
46
D Grænseflader<br />
I det følgende vil vi gennemgå klasserne og deres grænseflader i alfabetisk rækkefølge.<br />
D.1 Klassen Element<br />
Element er en abstrakt klasse, der repræsenterer en form i scenen, f.eks. en kugle. Den<br />
implementerer en enkelt metode til bestemmelse af farven i et punkt, da denne metode vil<br />
være ens for alle former.<br />
Denne struktur understøtter ikke textures, da formerne ikke har mulighed for at give<br />
en bestemt farve alt efter hvor de skærer den relevante stråle.<br />
Bump-mapping er muligt, da klassen forudsætter at underklasserne implementerer<br />
findNormal.<br />
Følgende er klassens grænseflade:<br />
• Color findFarve( Stråle stråle )<br />
Returnerer farven i det punkt, hvor den givne stråle rammer elementet. Hvis strålen<br />
ikke rammer, returneres null.<br />
• abstract Punkt3D findNormal( Stråle stråle )<br />
Denne metode skal returnere normalvektoren til overfladen i det punkt, hvor den<br />
givne stråle rammer.<br />
• abstract Punkt3D findSkæring( Stråle stråle )<br />
Metoden skal returnere det nærmeste skæringspunkt med den givne stråle. Hvis der<br />
ikke er en skæring skal null returneres.<br />
• abstract Color hentFarve( )<br />
Skal returnere elementets grundfarve.<br />
D.2 Klassen Fotograf<br />
Fotograf-klassen er hovedklassen i programmet. Den indeholder programmets eneste statiske<br />
metode, der opretter en ny fotograf.<br />
Hvis andre programmer skal bruge dette modul som et undermodul, så kan der ses bort<br />
fra main-metoden og man kan blot oprette en fotograf og give ham navnet på filen med<br />
modelbeskrivelsen.<br />
Fotograf har grænsefladen:<br />
• static void main( String[] args )<br />
Metoden undersøger om der er ét argument. I bekræftende fald oprettes en ny fotograf,<br />
der får dette ene argument. Hvis der ikke er præcis ét argument udskrives en<br />
fejlmeddelelse og programmet afsluttes.<br />
• void udførOpgave( String filnavn )<br />
Fotografen producerer de billeder som er beskrevet i modelbeskrivelsen i filen filnavn.<br />
47
D.3 Klassen Kamera<br />
Dette er vores implementation af grænsefladen KameraI. Kameraet sporer kun en stråle<br />
for hver pixel og alialisering er derfor sandsynlig.<br />
Grænsefladen er (se også KameraI afs. D.4):<br />
• Kamera( Punkt3D øjepunkt, Punkt3D stedpunkt,<br />
Punkt3D vandret, Punkt3D lodret, int opløsning_vandret,<br />
int opløsning_lodret, SceneI scene, String navn )<br />
Konstruktør, der opretter et kamera efter de principper, der er diskuteret i afsnit<br />
2.2.1. Når tagBillede kaldes, tager kameraet et billede af scene og gemmer det i<br />
navn påhæftet endelsen .ppm.<br />
• void tagBillede( )<br />
Se KameraI for en beskrivelse.<br />
D.4 Klassen KameraI<br />
Dette er et interface for et kamera. Et kameras opgave er at tage et billede af en model og<br />
at gemme dette billede i en fil.<br />
• void tagBillede( )<br />
Fortæller kameraet at det skal lave og gemme sit billede.<br />
D.5 Klassen Kugle<br />
Kugle er en underklasse af Element og er en repræsentation af en kugleform.<br />
Se Element for en forklaring af metoderne i klassen - kun konstruktøren beskrives her.<br />
• Kugle( Punkt3D centrum, double radius, Color farve )<br />
Konstruktør, der opretter en kugle med argumenterne som karakteristika.<br />
• Punkt3D findNormal( Stråle stråle )<br />
Se Element.<br />
• Punkt3D findSkæring( Stråle stråle )<br />
Se Element.<br />
• Punkt3D hentFarve( )<br />
Se Element.<br />
48
D.6 Klassen Mesh<br />
Mesh repræsenterer en samling af trekanter, dvs. det er en form, der kan placeres i en<br />
scene og den er derfor en underklasse af Element. Mesh er konstrueret, så det kan opbygges<br />
efterhånden som punkter og trekanter bliver indlæst.<br />
En beskrivelse af de metoder, der er pålagt af Element skal ses i den klasses beskrivelse.<br />
Resten er beskrevet her:<br />
• Mesh( Color farve )<br />
Laver et tomt mesh med den angivne farve.<br />
• Punkt3D findNormal( Stråle stråle )<br />
Se Element.<br />
• Punkt3D findSkæring( Stråle stråle )<br />
Se Element.<br />
• Punkt3D hentFarve( )<br />
Se Element.<br />
• void tilføjPunkt( int id, Punkt3D punkt )<br />
Tilføjer punktet til meshet. id er den reference som bruges ved tilføjTrekant.<br />
Metoden kaster fejlen XMLParseError, hvis der allerede er et punkt med samme<br />
koordinatsæt.<br />
• void tilføjTrekant( int p1, int p2, int p3 )<br />
Tilføjer en trekant til meshet, hvor p1, p2 og p3 refererer til punkter tilføjet med<br />
metoden tilføjPunkt.<br />
D.7 Klassen Plan<br />
Plan er en underklasse af Element og er en repræsentation af en plan. Da Trekant skal<br />
bruge plankonstanterne, er der public-adgangsmetoder til disse.<br />
Se desuden Element for en forklaring af visse af metoderne i klassen - resten beskrives<br />
her.<br />
• Plan( Punkt3D stedpunkt, Punkt3D vektor1, Punkt3D vektor2, Color farve )<br />
Opretter den plan der udspændes af de to vektorer ud fra stedpunktet.<br />
• Punkt3D findNormal( Stråle stråle )<br />
Se Element.<br />
• Punkt3D findSkæring( Stråle stråle )<br />
Se Element.<br />
• Punkt3D hentFarve( )<br />
Se Element.<br />
49
• double hentA( )<br />
Returnerer koefficienten A i den generelle ligning for en plan: Ax + By + Cz + D = 0.<br />
• double hentB( )<br />
Returnerer koefficienten B i den generelle ligning for en plan: Ax+By +Cz +D = 0.<br />
• double hentC( )<br />
Returnerer koefficienten C i den generelle ligning for en plan: Ax + By + Cz + D = 0.<br />
• double hentD( )<br />
Returnerer koefficienten D i den generelle ligning for en plan: Ax+By +Cz +D = 0.<br />
D.8 Klassen Punkt3D<br />
Som navnet antyder er der her tale om en klasse, der repræsenterer et punkt eller en vektor<br />
i tre dimensioner. Klassen skelner ikke selv mellem punkt og vektor, da det i forskellige<br />
sammenhænge kan være praktisk at betragte et koordinatsæt det ene eller det andet.<br />
Metoderne i klassen implementerer forskellige ofte brugte udregninger fra rumgeometrien.<br />
Klassens grænseflade er som følger:<br />
• Punkt3D( double x, double y, double z )<br />
Konstruktør til oprettelse af et punkt/vektor med de givne koordinater.<br />
• boolean erNulVektor( )<br />
Returnerer true, hvis vektoren er nulvektoren ellers false.<br />
• boolean erEns( Punkt3D punkt )<br />
Sammenligner punkt’s koordinater med egne koordinater og returnerer true hvis de<br />
er ens, ellers false.<br />
• double findCos( Punkt3D punkt )<br />
Returnerer cosinus til vinklen mellem de to vektorer. Bruger sammenhængen A•B =<br />
cos (A, B) · |A| · |B|.<br />
Hvis en af vektorerne er nulvektoren returneres NaN.<br />
• Punkt3D findDif( Punkt3D punkt )<br />
Returnerer differensvektoren.<br />
• double findDist( Punkt3D punkt )<br />
Returnerer afstanden til det givne punkt.<br />
• Punkt3D findKrydsprodukt( Punkt3D punkt )<br />
Returnerer krydsproduktet med den givne vektor.<br />
50
• double findLængde( )<br />
Returnerer vektorens længde.<br />
• double findSkalarprodukt( Punkt3D punkt )<br />
Returnerer skalarproduktet med punkt.<br />
• Punkt3D findSkaleret( double t )<br />
Returnerer denne vektor skaleret med t.<br />
• Punkt3D findSum( Punkt3D punkt )<br />
Returnerer sumvektoren.<br />
• Punkt3D findVektorTil( Punkt3D punkt )<br />
Returnerer vektoren fra dette punkt til det givne punkt.<br />
• double hentX( )<br />
Returnerer punktets x-koordinat.<br />
• double hentY( )<br />
Returnerer punktets y-koordinat.<br />
• double hentZ( )<br />
Returnerer punktets z-koordinat.<br />
• void saetX( double x )<br />
Sætter punktets x-koordinat.<br />
• void saetY( double y )<br />
Sætter punktets y-koordinat.<br />
• void saetZ( double z )<br />
Sætter punktets z-koordinat.<br />
D.9 Klassen Scene<br />
Scene er vores implementation af grænsefladen SceneI. Den implementere en simpel strålesporingsmodel,<br />
med kun én lyskilde. Konstruktionen af Scene er sådan, at man kan tilføje<br />
de forskellige dele efterhånden som de bliver indlæst fra modelbeskrivelsen.<br />
Kun konstruktøren beskrives her, da de andre metoder opfylder kontrakten fra grænsefladen<br />
SceneI.<br />
• Scene( )<br />
Konstruktør, der opretter en tom scene.<br />
• void findFarve( Stråle stråle )<br />
Se SceneI.<br />
51
• void tilføj( Element e )<br />
Se SceneI.<br />
• void tilføjSol( Sol s )<br />
Se SceneI.<br />
D.10 Klassen SceneI<br />
Denne grænseflade beskriver, de metoder en scene skal implementere.<br />
• void findFarve( Stråle stråle )<br />
Metoden skal bruge strålesporing til at bestemme strålens farve. stråle’s farve sættes<br />
til den fundne farve.<br />
• void tilføj( Element e )<br />
Skal tilføje elementet til scenen.<br />
• void tilføjSol( Sol s )<br />
Skal tilføje den givne sol til scenen. Kan kaste XMLParseError hvis scenen ikke kan<br />
håndtere flere sole.<br />
D.11 Klassen Sceneopstiller<br />
Denne klasse står for at oversætte en modelbeskrivelse til den interne repræsentation af<br />
scene og kameraer. Dvs. den kobler XML til den interne repræsentation.<br />
Klassen er - som foreslået i opgaveteksten [1, app. C] - baseret på XMLReadWrite af<br />
Søren Sjørup (zoren@diku.dk).<br />
Følgende er klassens interface:<br />
• Sceneopstiller( )<br />
Konstruktør, der opretter en ny sceneopstiller.<br />
• Vector opstilScene( String filnavn )<br />
Indlæser modelbeskrivelsen af filnavn og opretter den tilsvarende scene. Den Vector,<br />
der returneres, indeholder de KameraI-objekter der var defineret i filen.<br />
D.12 Klassen Sol<br />
Solen repræsenteres af denne klasse.<br />
• Sol( Punkt3D position, Color farve )<br />
Konstruktør, der opretter en ny sol med den givne position og farve.<br />
• Stråle belys( Punkt3D punkt )<br />
Returnerer en stråle, med samme farve og udgangspunkt som solen, og med retning<br />
mod det givne punkt. Kaster NullPointerException hvis punkt er null.<br />
52
D.13 Klassen Stråle<br />
Repræsentation af en stråle - i form af et begyndelsespunkt, en retningsvektor og en farve<br />
- med følgende grænseflade:<br />
• Stråle( Punkt3D start, Punkt3D retning, Color farve )<br />
Konstruktør, der laver en ny stråle med de givne attributter.<br />
• Color hentFarve( )<br />
Returnerer strålens farve.<br />
• Punkt3D hentRetning( )<br />
Returnerer strålens retning.<br />
• Punkt3D hentStart( )<br />
Returnerer strålens begyndelsespunkt.<br />
• void saetFarve( Color farve )<br />
Sætter strålens farve til den givne.<br />
• void saetRetning( Punkt3D retning )<br />
Sætter strålens retning til den givne.<br />
• void saetStart( Punkt3D start )<br />
Sætter strålens begyndelsespunkt til det givne.<br />
D.14 Klassen Trekant<br />
Trekant er en underklasse af Element og er en repræsentation af en trekant ;-).<br />
Se Element for en forklaring af metoderne i klassen - kun konstruktøren beskrives her.<br />
• Trekan( Punkt3D p1, Punkt3D p2, Punkt3D p3 )<br />
• Punkt3D findNormal( Stråle stråle )<br />
Se Element.<br />
• Punkt3D findSkæring( Stråle stråle )<br />
Se Element.<br />
• Punkt3D hentFarve( )<br />
Se Element.<br />
D.15 Klassen XMLParseError<br />
Instanser af denne klasse kastes når der opstår en fejl pga. modelbeskrivelsen.<br />
• XMLParseError( String fejl )<br />
Konstruktør, der opretter en ny XMLParseError med fejl som meddelelse.<br />
53
E Kildekode<br />
Dette appendiks indeholder kildekoden til det udviklede program. Klasserne er listet i<br />
alfabetisk rækkefølge.<br />
Se forsiden for en reference til kildekoden i elektronisk form på <strong>DIKU</strong>’s system.<br />
E.1 Element.java<br />
/∗<br />
∗ Denne k l a s s e r e p r æ s e n t e r e r e t element ( en form ) i en scene .<br />
∗<br />
∗ Klassen implementerer en g e n e r i s k f a r v e u d r e g n i n g s f u n k t i o n<br />
∗ findFarve .<br />
∗<br />
∗ Underklasser er a n s v a r l i g e f o r at implementere en<br />
∗ funktion , der kan f o r t æ l l e om en s t r å l e skærer<br />
∗ e l e m e n t e t og hvor d e t s k e r .<br />
∗<br />
∗ Endvidere s k a l u n d e r k l a s s e r kunne g i v e<br />
∗ normalvektoren t i l e t skæringspunkt med en g i v e n<br />
∗ s t r å l e .<br />
∗<br />
∗/<br />
import java . awt . Color ;<br />
public abstract class Element {<br />
// Farveudregningsfunktion , der f i n d e r f a r v e n i<br />
// skæringen med en g i v e n s o l s t r å l e<br />
//<br />
//Metoden f o r u d s æ t t e r at s o l s t r å l e n skærer e l e m e n t e t<br />
public Color f i n d F a r v e ( S t r å l e s o l s t r å l e ) {<br />
// Find normalvektoren i s k æ r i n g s p u n k t e t<br />
Punkt3D normal = findNormal ( s o l s t r å l e ) ;<br />
}<br />
// Hvis der i k k e er en normal , er d e t f o r d i<br />
// s o l s t r å l e n i k k e rammer e l e m e n t e t<br />
//−> ingen f a r v e<br />
i f ( normal == null )<br />
return null ;<br />
// Find c o s i n u s t i l komplimentærvinklen<br />
// mellem s o l s t r å l e n og normalvektoren<br />
double cosV = Math . abs ( normal . findCos ( s o l s t r å l e . hentRetning ( ) ) ) ;<br />
// Find f a r v e n i p u n k t e t<br />
Color f a r v e = hentFarve ( ) ;<br />
// Skab den nye f a r v e<br />
return new Color ( ( int ) ( cosV∗ f a r v e . getRed ( ) ) ,<br />
( int ) ( cosV∗ f a r v e . getGreen ( ) ) ,<br />
( int ) ( cosV∗ f a r v e . getBlue ( ) )<br />
) ;<br />
// A b s t r a c t metode der s k a l bestemme normalvektoren<br />
// t i l s k æ r i n g s p u n k t e t med en g i v e n s t r å l e<br />
protected abstract Punkt3D findNormal ( S t r å l e s o l s t r å l e ) ;<br />
//Metoden f o r t æ l l e r om den g i v n e s t r å l e rammer<br />
54
}<br />
// e l e m e n t e t og e v t . hvor .<br />
//<br />
// n u l l r e t u r n e r e s h v i s der i k k e er en skæring<br />
public abstract Punkt3D findSkæring ( S t r å l e s t r å l e ) ;<br />
// A b s t r a c t a c c e s s o r t i l e l e m e n t e t s f a r v e<br />
protected abstract Color hentFarve ( ) ;<br />
E.2 Fotograf.java<br />
/∗<br />
∗ Fotografens opgave er at modtage opgaver og<br />
∗ s ø r g e f o r at de b l i v e r u d f ø r t<br />
∗/<br />
import java . u t i l . Vector ;<br />
import java . u t i l . Enumeration ;<br />
public class Fotograf {<br />
// I n d g a n g s f u n k t i o n<br />
public s t a t i c void main ( S t r i n g [ ] a r g s ) {<br />
// Uforudsete u n d t a g e l s e r s k a l f a n g e s inden de når brugeren<br />
try {<br />
//Ét argument<br />
i f ( a r g s . l e n g t h != 1) {<br />
System . out . p r i n t l n ( "\nDer s k a l være e t argument ! " ) ;<br />
System . out . p r i n t l n ( "\nProgrammet a f s l u t t e s " ) ;<br />
System . e x i t ( 1 ) ;<br />
return ;<br />
}<br />
}<br />
(new Fotograf ( ) ) . udførOpgave ( a r g s [ 0 ] ) ;<br />
}<br />
catch ( Throwable t ) {<br />
System . out . p r i n t l n ( "\nDer opstod en ukendt f e j l ! " ) ;<br />
S t r i n g f e j l = t . g e t L o c a l i z e d M e s s a g e ( ) ;<br />
i f ( f e j l != null )<br />
System . out . p r i n t l n ( " f e j l b e s k e d : "+ f e j l ) ;<br />
System . out . p r i n t l n ( "\nProgrammet<br />
System . e x i t ( 1 ) ;<br />
a f s l u t t e s " ) ;<br />
}<br />
}<br />
/∗<br />
∗ Metode der f å r f o t o g r a f e n t i l at<br />
∗ udføre opgaven i f i l e n f i l n a v n<br />
∗/<br />
public void udførOpgave ( S t r i n g f i l n a v n ) {<br />
//Gør scenen k l a r<br />
Vector kameraer = (new S c e n e o p s t i l l e r ( ) ) . o p s t i l S c e n e ( f i l n a v n ) ;<br />
}<br />
//Tag b i l l e d e r n e<br />
for ( Enumeration e = kameraer . elements ( ) ; e . hasMoreElements ( ) ; ) {<br />
( ( KameraI ) e . nextElement ( ) ) . t a g B i l l e d e ( ) ;<br />
}<br />
E.3 Kamera.java<br />
/∗<br />
∗ Repræsenterer e t kamera i form a f e t øjepunkt , en f i l m<br />
55
∗ ( s t e d p u n k t og vandret− og l o d r e t v e k t o r ) , en o p l ø s n i n g<br />
∗ og navnet på b i l l e d e t .<br />
∗<br />
∗ S t e d p u n k t e t i k o n s t r u k t ø r e n er n e d e r s t e v e n s t r e hjørne ,<br />
∗ men i den i n t e r n e r e p r æ s e n t a t i o n er d e t ø v e r s t e v e n s t r e .<br />
∗ Lodret−v e k t o r e n b l i v e r vendt t i l v a r e n d e .<br />
∗<br />
∗ Se KameraI<br />
∗/<br />
import java . awt . Color ;<br />
import java . i o . IOException ;<br />
import K2 . ∗ ;<br />
public class Kamera implements KameraI {<br />
// Konstruktør<br />
//<br />
// Forudsætter k o r r e k t e argumenter !<br />
public Kamera ( Punkt3D øjepunkt , Punkt3D stedpunkt ,<br />
Punkt3D vandret , Punkt3D l o d r e t ,<br />
int opløsning_vandret , int o p l ø s n i n g _ l o d r e t ,<br />
SceneI scene , S t r i n g navn<br />
) {<br />
this . øjepunkt = øjepunkt ;<br />
this . stedpunkt = stedpunkt . findSum ( l o d r e t ) ;<br />
// Vektorerne t i l p a s s e s h e n h o l d s v i s bredden<br />
// og højden a f e t r e f e r e n c e f e l t<br />
this . vandret = vandret . f i n d S k a l e r e t ( 1 . 0 / opløsning_vandret ) ;<br />
this . l o d r e t = l o d r e t . f i n d S k a l e r e t ( −1.0/ o p l ø s n i n g _ l o d r e t ) ;<br />
this . opløsning_vandret = opløsning_vandret ;<br />
this . o p l ø s n i n g _ l o d r e t = o p l ø s n i n g _ l o d r e t ;<br />
this . navn = navn ;<br />
this . s c e n e = s c e n e ;<br />
}<br />
/∗<br />
∗ Metode der opbygger e t b i l l e d e a f<br />
∗ scenen og gemmer d e t i en f i l<br />
∗/<br />
public void t a g B i l l e d e ( ) {<br />
// Udskriv respons t i l brugeren<br />
System . out . p r i n t ( "\ nLaver b i l l e d e \""+hentNavn ()+" \ " : " ) ;<br />
System . out . f l u s h ( ) ;<br />
// Opret e t kanvas t i l at tegne på<br />
Kanvas kanvas = new Kanvas ( hentOpløsning_lodret ( ) ,<br />
hentOpløsning_vandret ( ) ,<br />
Color .BLACK<br />
) ;<br />
//Vi v i l u d s k r i v e l øbende respons ( pr . 10 procent )<br />
//Hvor mange p i x e l s er en procent ?<br />
int procent = hentOpløsning_vandret ( ) ∗ hentOpløsning_lodret ( ) / 1 0 ;<br />
int o k P i x e l s = 0 ; // a n t a l f æ r d i g e p i x e l s<br />
int okProcent = 0 ; // o k P i x e l s i procent<br />
int tmp_int = 0 ; // a r b e j d s v a r<br />
// Skyd en s t r å l e pr . p i x e l ind i scenen<br />
for ( int i = hentOpløsning_vandret ( ) ; i > 0 ; i −−) {<br />
for ( int j = hentOpløsning_lodret ( ) ; j > 0 ; j −−) {<br />
// Find midten a f r e f e r e n c e f e l t e t<br />
Punkt3D vandSkal = hentVandret ( ) . f i n d S k a l e r e t ( i − 0 . 5 ) ;<br />
Punkt3D l o d S k a l = hentLodret ( ) . f i n d S k a l e r e t ( j − 0 . 5 ) ;<br />
Punkt3D midt = vandSkal . findSum ( l o d S k a l . findSum ( hentStedpunkt ( ) ) ) ;<br />
56
}<br />
}<br />
//Lav en s t r å l e f r a ø j e p u n k t e t gennem p u n k t e t<br />
S t r å l e s t r å l e = new S t r å l e ( hentØjepunkt ( ) ,<br />
hentØjepunkt ( ) . f i n d V e k t o r T i l ( midt ) ,<br />
null<br />
) ;<br />
//Send s t r å l e n t i l scenen<br />
s c e n e . f i n d F a r v e ( s t r å l e ) ;<br />
//Sæt f a r v e n på p i x e l e n<br />
kanvas . s e t P i x e l ( i − 1 , j − 1 , s t r å l e . hentFarve ( ) ) ;<br />
// Respons<br />
tmp_int = ++o k P i x e l s / procent ; // f i n procent f æ r d i g<br />
i f ( tmp_int > okProcent ) {<br />
okProcent = tmp_int ;<br />
System . out . p r i n t ( "∗" ) ;<br />
System . out . f l u s h ( ) ;<br />
}<br />
}<br />
System . out . p r i n t l n ( " f æ r d i g " ) ;<br />
System . out . f l u s h ( ) ;<br />
//Gem b i l l e d e t<br />
try {<br />
kanvas . skrivPPM ( navn ) ;<br />
// Fotæl at b i l l e d e t er gemt<br />
System . out . p r i n t l n ( "\ t \""+hentNavn ()+"\" e r gemt i "<br />
+hentNavn ()+" . ppm"<br />
) ;<br />
System . out . f l u s h ( ) ;<br />
} catch ( IOException e ) {<br />
// Fortæl brugeren om problemet og a f s l u t<br />
System . out . p r i n t l n ( "\nDer opstod en f e j l under "<br />
+" s k r i v n i n g e n a f f i l e n "+hentNavn ()+" . ppm"<br />
) ;<br />
System . out . p r i n t l n ( "\nProgrammet a f s l u t t e s . " ) ;<br />
System . e x i t ( 1 ) ;<br />
}<br />
// Accessors og mutators<br />
private Punkt3D hentØjepunkt ( ) {<br />
return øjepunkt ;<br />
}<br />
private Punkt3D hentStedpunkt ( ) {<br />
return stedpunkt ;<br />
}<br />
private Punkt3D hentVandret ( ) {<br />
return vandret ;<br />
}<br />
private Punkt3D hentLodret ( ) {<br />
return l o d r e t ;<br />
}<br />
private int hentOpløsning_vandret ( ) {<br />
return opløsning_vandret ;<br />
}<br />
private int hentOpløsning_lodret ( ) {<br />
return o p l ø s n i n g _ l o d r e t ;<br />
}<br />
private S t r i n g hentNavn ( ) {<br />
return navn ;<br />
}<br />
private SceneI hentScene ( ) {<br />
return s c e n e ;<br />
}<br />
57
}<br />
// P r i v a t e a t t r i b u t t e r<br />
private Punkt3D øjepunkt = null ;<br />
private Punkt3D stedpunkt = null ;<br />
private Punkt3D vandret = null , l o d r e t = null ;<br />
private int opløsning_vandret , o p l ø s n i n g _ l o d r e t ;<br />
private S t r i n g navn = null ;<br />
private SceneI s c e n e ;<br />
E.4 KameraI.java<br />
/∗<br />
∗ D e f i n e r e r i n t e r f a c e t f o r e t kamera .<br />
∗<br />
∗ Et kamera s k a l t a g e e t b i l l e d e a f en scene<br />
∗ og gemme d e t i en f i l<br />
∗/<br />
public interface KameraI {<br />
/∗<br />
∗ Metoden der f å r kameraet t i l at t a g e<br />
∗ e t b i l l e d e og gemme d e t<br />
∗/<br />
public void t a g B i l l e d e ( ) ;<br />
}<br />
E.5 Kugle.java<br />
/∗<br />
∗ Repræsenterer en k u g l e i form a f e t centrum , en r a d i u s og en f a r v e .<br />
∗<br />
∗ O b j e k t e t s t å r f o r at beregne skæring med s t r å l e r<br />
∗ samt b e r e g n i n g a f normalvektorer i skæringer .<br />
∗<br />
∗/<br />
import java . awt . Color ;<br />
public class Kugle extends Element {<br />
// Konstruktør<br />
//<br />
// Forudsætter g y l d i g e ( i k k e n u l l ) argumenter<br />
public Kugle ( Punkt3D centrum , double radius , Color f a r v e ) {<br />
this . centrum = centrum ;<br />
this . r a d i u s = r a d i u s ;<br />
this . f a r v e = f a r v e ;<br />
}<br />
/∗<br />
∗ Metode t i l at bestemme en normalvektoren<br />
∗ i e t skæringspunkt med en s t r å l e .<br />
∗<br />
∗ Hvis der i k k e er e t skæringspunkt , så er<br />
∗ der ingen normal −> n u l l<br />
∗<br />
∗/<br />
protected Punkt3D findNormal ( S t r å l e s o l s t r å l e ) {<br />
// f i n d skæring<br />
Punkt3D skæring = findSkæring ( s o l s t r å l e ) ;<br />
// Hvis der i k k e er en skæring , er der ingen normal<br />
i f ( skæring == null ) return null ;<br />
58
}<br />
Punkt3D normal = hentCentrum ( ) . f i n d D i f ( skæring ) ;<br />
return normal ;<br />
/∗<br />
∗ Metode , der f i n d e r en e v t . skæring med<br />
∗ en g i v e n s t r å l e .<br />
∗<br />
∗ n u l l r e t u r n e r e s , h v i s der ingen skæring er<br />
∗/<br />
public Punkt3D findSkæring ( S t r å l e s t r å l e ) {<br />
// Hvis s t r å l e n i k k e er d e f i n e r e t , skærer den<br />
// i k k e k u g l e n<br />
i f ( s t r å l e == null )<br />
return null ;<br />
// Skæringspunkter f i n d e s med udgangspunkt<br />
// i at s t r å l e n er en l i n j e<br />
// Find k o e f f i c i e n t e r n e i 2 . g r a d s l i g n i n g e n<br />
Punkt3D s t r å l e R e t = s t r å l e . hentRetning ( ) ,<br />
s t r å l e S t a r t = s t r å l e . h e n t S t a r t ( ) ,<br />
d i f V e k t o r = s t r å l e S t a r t . f i n d D i f ( hentCentrum ( ) ) ;<br />
;<br />
double xDif = d i f V e k t o r . hentX ( ) ; // x_0 − x_c<br />
double yDif = d i f V e k t o r . hentY ( ) ; // y_0 − y_c<br />
double z D i f = d i f V e k t o r . hentZ ( ) ; // z_0 − z_c<br />
double a = Math . pow( s t r å l e R e t . hentX ( ) , 2 . 0 )<br />
+ Math . pow( s t r å l e R e t . hentY ( ) , 2 . 0 )<br />
+ Math . pow( s t r å l e R e t . hentZ ( ) , 2 . 0 )<br />
;<br />
double b = 2∗( s t r å l e R e t . hentX ( ) ∗ xDif<br />
+ s t r å l e R e t . hentY ( ) ∗ yDif<br />
+ s t r å l e R e t . hentZ ( ) ∗ z D i f<br />
) ;<br />
double c = Math . pow( xDif , 2 . 0 )<br />
+ Math . pow( yDif , 2 . 0 )<br />
+ Math . pow( zDif , 2 . 0 )<br />
− Math . pow( hentRadius ( ) , 2 . 0 )<br />
;<br />
//Udregn d i s k r i m i n a n t e n d<br />
double d = Math . pow(b , 2 . 0 ) − 4∗a∗ c ;<br />
//Er der en l ø s n i n g ?<br />
i f ( d < 0 . 0 ) // nope<br />
return null ;<br />
else {// én e l l e r to l ø s n i n g e r<br />
// beregn begge t−værdier<br />
double t1 = (−b + Math . s q r t ( d ) ) / (2∗ a ) ;<br />
double t2 = (−b − Math . s q r t ( d ) ) / (2∗ a ) ;<br />
// Find den nærmeste , der er en d e l a f s t r å l e n<br />
double t ;<br />
i f ( t1 < 0 . 0 && t2 < 0 . 0 ) // begge er u b r u g e l i g e<br />
return null ;<br />
else i f ( t1 < 0 . 0 ) // t1 er u b r u g e l i g<br />
t = t2 ;<br />
else i f ( t2 < 0 . 0 ) // t2 er u b r u g e l i g<br />
t = t1 ;<br />
else // t a g den nærmeste<br />
t = ( t1 < t2 ) ? t1 : t2 ;<br />
return new Punkt3D ( s t r å l e S t a r t . hentX()+ t ∗ s t r å l e R e t . hentX ( ) ,<br />
s t r å l e S t a r t . hentY()+ t ∗ s t r å l e R e t . hentY ( ) ,<br />
59
}<br />
}<br />
}<br />
s t r å l e S t a r t . hentZ ()+ t ∗ s t r å l e R e t . hentZ ( )<br />
) ;<br />
// Accessors og mutators<br />
private double hentRadius ( ) {<br />
return r a d i u s ;<br />
}<br />
private Punkt3D hentCentrum ( ) {<br />
return centrum ;<br />
}<br />
protected Color hentFarve ( ) {<br />
return f a r v e ;<br />
}<br />
// P r i v a t e a t t r i b u t t e r<br />
private Punkt3D centrum = null ;<br />
private Color f a r v e = null ;<br />
private double r a d i u s ;<br />
E.6 Mesh.java<br />
/∗<br />
∗ Repræsenterer e t t r e k a n t s g i t t e r .<br />
∗/<br />
import java . awt . Color ;<br />
import java . u t i l . Comparator ;<br />
import java . u t i l . I t e r a t o r ;<br />
import java . u t i l . Vector ;<br />
import java . u t i l . TreeMap ;<br />
import java . u t i l . Enumeration ;<br />
public class Mesh extends Element {<br />
// Konstruktør<br />
//<br />
// Forudsætter g y l d i g t ( i k k e n u l l ) argument<br />
public Mesh ( Color f a r v e ) {<br />
this . f a r v e = f a r v e ;<br />
}<br />
/∗<br />
∗ Metode , der f i n d e r en e v t . skæring med<br />
∗ en g i v e n s t r å l e .<br />
∗<br />
∗ n u l l r e t u r n e r e s , h v i s der ingen skæring er<br />
∗<br />
∗ Metoden s æ t t e r e n d i v e r e v a r i a b l e n sidstRamt<br />
∗ t i l den s i d s t ramte t r e k a n t f o r e f f e k t i v i t e t<br />
∗<br />
∗/<br />
public Punkt3D findSkæring ( S t r å l e s t r å l e ) {<br />
//Gennemløb t r e k a n t e r n e og f i n d e v t . nærmeste skæring<br />
Punkt3D skæring = null ;<br />
Trekant t r e k a n t = null ;<br />
Punkt3D tmpSk = null ; // Arbejdsvar<br />
double s k D i s t = 0 ; // Afstand mellem s t r å l e og skæring<br />
for ( Enumeration e = t r e k a n t e r . elements ( ) ; e . hasMoreElements ( ) ; tmpSk = null ) {<br />
t r e k a n t = ( Trekant ) e . nextElement ( ) ;<br />
tmpSk = t r e k a n t . findSkæring ( s t r å l e ) ;<br />
// Find den skæring der s k a l gemmes<br />
60
}<br />
}<br />
i f ( ( tmpSk == null && skæring == null ) | | tmpSk == null )<br />
continue ;<br />
else i f ( skæring == null<br />
| | ( s k D i s t > s t r å l e . h e n t S t a r t ( ) . f i n d D i s t ( tmpSk ) )<br />
) {<br />
skæring = tmpSk ;<br />
s k D i s t = s t r å l e . h e n t S t a r t ( ) . f i n d D i s t ( skæring ) ;<br />
sidstRamt = t r e k a n t ;<br />
}<br />
return skæring ;<br />
/∗<br />
∗ Metode t i l at bestemme en normalvektoren<br />
∗ i e t skæringspunkt med en s t r å l e .<br />
∗<br />
∗ Hvis der i k k e er e t skæringspunkt , så er<br />
∗ der ingen normal −> n u l l<br />
∗<br />
∗ Metoden f o r u d s æ t t e r at der er s k e t en<br />
∗ forudgående s t r å l s p o r i n g<br />
∗/<br />
protected Punkt3D findNormal ( S t r å l e s o l s t r å l e ) {<br />
return sidstRamt . findNormal ( s o l s t r å l e ) ;<br />
}<br />
/∗<br />
∗ Metode t i l at t i l f ø j e punkter t i l meshet<br />
∗/<br />
public void t i l f ø j P u n k t ( int id , Punkt3D punkt ) throws XMLParseError {<br />
// Tjek at e t punkt magen t i l i k k e er d e f i n e r e t<br />
I t e r a t o r i t = punkter . v a l u e s ( ) . i t e r a t o r ( ) ;<br />
Punkt3D p = null ;<br />
while ( i t . hasNext ( ) ) {<br />
p = ( Punkt3D ) i t . next ( ) ;<br />
i f ( p . erEns ( punkt ) )<br />
throw new XMLParseError ( i d + " ( punkt )\ n\ t \ tDer e r to ens punkter " ) ;<br />
}<br />
}<br />
punkter . put (new I n t e g e r ( i d ) , punkt ) ;<br />
/∗<br />
∗ Metode t i l at t i l f ø j e t r e k a n t e r t i l meshet .<br />
∗ Det f o r u d s æ t t e r at punkterne er i n d l æ s t<br />
∗ e l l e r s k a s t e s<br />
∗/<br />
public void t i l f ø j T r e k a n t ( int punkt1 , int punkt2 , int punkt3 ) throws XMLParseError {<br />
Punkt3D p1 = ( Punkt3D ) punkter . get (new I n t e g e r ( punkt1 ) ) ;<br />
Punkt3D p2 = ( Punkt3D ) punkter . get (new I n t e g e r ( punkt2 ) ) ;<br />
Punkt3D p3 = ( Punkt3D ) punkter . get (new I n t e g e r ( punkt3 ) ) ;<br />
// Sørg f o r v a l i d e punkter<br />
S t r i n g e r r o r = null ;<br />
int errorP = 0 ;<br />
i f ( p1 == null ) {<br />
e r r o r = "p1" ;<br />
errorP = punkt1 ;<br />
}<br />
i f ( p2 == null ) {<br />
e r r o r = "p2" ;<br />
errorP = punkt2 ;<br />
}<br />
61
}<br />
}<br />
i f ( p3 == null ) {<br />
e r r o r = "p3" ;<br />
errorP = punkt3 ;<br />
}<br />
i f ( e r r o r != null )<br />
throw new XMLParseError ( e r r o r+"\n\ t \ t U d e f i n e r e t punkt : "+errorP ) ;<br />
t r e k a n t e r . add (new Trekant ( p1 , p2 , p3 , hentFarve ( ) ) ) ;<br />
// Accessors og mutators<br />
protected Color hentFarve ( ) {<br />
return f a r v e ;<br />
}<br />
// P r i v a t e a t t r i b u t t e r<br />
private Color f a r v e = null ;<br />
private TreeMap punkter = new TreeMap (new Comparator ( ) {<br />
public int compare ( Object t a l 1 , Object t a l 2 ) {<br />
int t1 = ( ( I n t e g e r ) t a l 1 ) . intValue ( ) ;<br />
int t2 = ( ( I n t e g e r ) t a l 2 ) . intValue ( ) ;<br />
i f ( t1 < t2 )<br />
return −1;<br />
else i f ( t1 > t2 )<br />
return 1 ;<br />
else<br />
return 0 ;<br />
}<br />
} ) ;<br />
private Vector t r e k a n t e r = new Vector ( ) ;<br />
private Trekant sidstRamt = null ;<br />
E.7 Plan.java<br />
/∗<br />
∗ Repræsenterer en plan i form a f de f i r e k o e f f i c i e n t e r<br />
∗ (A, B, C og D) i den g e n e r e l l e l i g n i n g f o r en plan i R3<br />
∗<br />
∗ Ax+By+Cz+D = 0<br />
∗<br />
∗ O b j e k t e t s t å r f o r at beregne skæring med s t r å l e r<br />
∗ samt b e r e g n i n g a f normalvektorer i skæringer .<br />
∗<br />
∗/<br />
import java . awt . Color ;<br />
public class Plan extends Element {<br />
// Konstruktør<br />
//<br />
// Opretter en plan ud f r a e t stedpunkt ,<br />
// to r e t n i n g s v e k t o r e r og en f a r v e<br />
public Plan ( Punkt3D stedpunkt , Punkt3D vektor1 , Punkt3D vektor2 , Color f a r v e ) {<br />
this . f a r v e = f a r v e ;<br />
//Gem en normalvektor<br />
normal = vektor1 . findKrydsprodukt ( vektor2 ) ;<br />
//De f i r e k o e f f i c i e n t e r bestemmes<br />
// Først udregnes de t r e determinanter (A, B og C)<br />
A = vektor1 . hentY ( ) ∗ vektor2 . hentZ ( )<br />
− vektor1 . hentZ ( ) ∗ vektor2 . hentY ( ) ;<br />
62
}<br />
B = vektor1 . hentZ ( ) ∗ vektor2 . hentX ( )<br />
− vektor1 . hentX ( ) ∗ vektor2 . hentZ ( ) ;<br />
C = vektor1 . hentX ( ) ∗ vektor2 . hentY ( )<br />
− vektor1 . hentY ( ) ∗ vektor2 . hentX ( ) ;<br />
D = − A ∗ stedpunkt . hentX ( )<br />
− B ∗ stedpunkt . hentY ( )<br />
− C ∗ stedpunkt . hentZ ( )<br />
;<br />
/∗<br />
∗ Metode , der f i n d e r en e v t . skæring med<br />
∗ en g i v e n s t r å l e .<br />
∗<br />
∗ n u l l r e t u r n e r e s , h v i s der ingen skæring er<br />
∗/<br />
public Punkt3D findSkæring ( S t r å l e s t r å l e ) {<br />
// Hvis s t r å l e n i k k e er d e f i n e r e t , skærer den<br />
// i k k e planen<br />
i f ( s t r å l e == null )<br />
return null ;<br />
}<br />
Punkt3D s t r å l e R e t = s t r å l e . hentRetning ( ) ,<br />
s t r å l e S t a r t = s t r å l e . h e n t S t a r t ( ) ;<br />
//Udregn nævneren i l i g n i n g e n f o r t ( opgaven s . 9 )<br />
double nævner = hentA ( ) ∗ s t r å l e R e t . hentX ( )<br />
+ hentB ( ) ∗ s t r å l e R e t . hentY ( )<br />
+ hentC ( ) ∗ s t r å l e R e t . hentZ ( )<br />
;<br />
// Hvis nævneren er nul , så er planen<br />
// og s t r å l e n p a r a l l e l l e −> ingen skæring<br />
i f ( nævner == 0 . 0 )<br />
return null ;<br />
double t = − ( hentA ( ) ∗ s t r å l e S t a r t . hentX ( )<br />
+ hentB ( ) ∗ s t r å l e S t a r t . hentY ( )<br />
+ hentC ( ) ∗ s t r å l e S t a r t . hentZ ( ) + hentD ( )<br />
) / nævner<br />
;<br />
// t < 0 −> s t r å l e n skærer i k k e planen<br />
i f ( t < 0 . 0 )<br />
return null ;<br />
return s t r å l e S t a r t . findSum ( s t r å l e R e t . f i n d S k a l e r e t ( t ) ) ;<br />
/∗<br />
∗ Metode t i l at bestemme en normalvektoren<br />
∗ i e t skæringspunkt med en s t r å l e .<br />
∗<br />
∗ Hvis der i k k e er e t skæringspunkt , så er<br />
∗ der ingen normal −> n u l l<br />
∗<br />
∗/<br />
protected Punkt3D findNormal ( S t r å l e s o l s t r å l e ) {<br />
return normal ;<br />
}<br />
// Accessors og mutators<br />
protected Color hentFarve ( ) {<br />
return f a r v e ;<br />
}<br />
public double hentA ( ) {<br />
63
}<br />
return A;<br />
}<br />
public double hentB ( ) {<br />
return B;<br />
}<br />
public double hentC ( ) {<br />
return C;<br />
}<br />
public double hentD ( ) {<br />
return D;<br />
}<br />
// P r i v a t e a t t r i b u t t e r<br />
private Color f a r v e = null ;<br />
private Punkt3D normal = null ;<br />
private double A, B, C, D;<br />
E.8 Punkt3D.java<br />
/∗<br />
∗ Repræsenterer e t punkt (/ s t e d v e k t o r ) i t r e dimensioner<br />
∗<br />
∗ S t i l l e r d i v e r s e r e l a t e r e d e o p e r a t i o n e r t i l r å d i g h e d<br />
∗<br />
∗/<br />
public class Punkt3D {<br />
// Konstruktør<br />
public Punkt3D ( double x , double y , double z ) {<br />
saetX ( x ) ;<br />
saetY ( y ) ;<br />
saetZ ( z ) ;<br />
}<br />
//Metode der f o r t æ l l e r om de to punkter er ens<br />
public boolean erEns ( Punkt3D punkt ) {<br />
return f i n d D i f ( punkt ) . erNulVektor ( ) ;<br />
}<br />
//Metode der f o r t æ l l e r om d e t er n u l v e k t o r e n<br />
public boolean erNulVektor ( ) {<br />
return ( hentX ( ) == 0 && hentY ( ) == 0 && hentZ ( ) == 0 ) ;<br />
}<br />
//Metode t i l at beregne cos t i l v i n k l e n mellem<br />
// denne og en anden v e k t o r<br />
public double findCos ( Punkt3D punkt ) {<br />
return f i n d S k a l a r p r o d u k t ( punkt )<br />
/ ( findLængde ( ) ∗ punkt . findLængde ( ) ) ;<br />
}<br />
//Metode t i l at f i n d e d i f f e r e n s e n mellem<br />
// d e t t e punkt og en andet punkt<br />
public Punkt3D f i n d D i f ( Punkt3D punkt ) {<br />
return new Punkt3D ( hentX ( ) − punkt . hentX ( ) ,<br />
hentY ( ) − punkt . hentY ( ) ,<br />
hentZ ( ) − punkt . hentZ ( )<br />
) ;<br />
}<br />
//Metode t i l at f i n d e a f s t a n d e n mellem<br />
// d e t t e punkt og en andet punkt<br />
public double f i n d D i s t ( Punkt3D punkt ) {<br />
return this . f i n d V e k t o r T i l ( punkt ) . findLængde ( ) ;<br />
64
}<br />
//Metode t i l at beregne k r y d s p r o d u k t e t a f denne<br />
// og en anden v e k t o r<br />
public Punkt3D findKrydsprodukt ( Punkt3D punkt ) {<br />
return new Punkt3D ( hentY ( ) ∗ punkt . hentZ ( ) − hentZ ( ) ∗ punkt . hentY ( ) ,<br />
hentZ ( ) ∗ punkt . hentX ( ) − hentX ( ) ∗ punkt . hentZ ( ) ,<br />
hentX ( ) ∗ punkt . hentY ( ) − hentY ( ) ∗ punkt . hentX ( )<br />
) ;<br />
}<br />
//Metode t i l at beregne længden a f ( sted −) v e k t o r e n<br />
public double findLængde ( ) {<br />
return Math . s q r t (Math . pow( hentX ( ) , 2 . 0 )<br />
+ Math . pow( hentY ( ) , 2 . 0 )<br />
+ Math . pow( hentZ ( ) , 2 . 0 )<br />
) ;<br />
}<br />
//Metode t i l at beregne s k a l a r p r o d u k t e t a f denne<br />
// og en anden v e k t o r<br />
public double f i n d S k a l a r p r o d u k t ( Punkt3D punkt ) {<br />
return hentX ( ) ∗ punkt . hentX ( )<br />
+ hentY ( ) ∗ punkt . hentY ( )<br />
+ hentZ ( ) ∗ punkt . hentZ ( ) ;<br />
}<br />
//Metode der beregner p r o d u k t e t a f<br />
// denne v e k t o r og s k a l a r e n t<br />
public Punkt3D f i n d S k a l e r e t ( double t ) {<br />
return new Punkt3D ( t ∗hentX ( ) , t ∗hentY ( ) , t ∗ hentZ ( ) ) ;<br />
}<br />
//Metode t i l at f i n d e summen a f d e t t e punkt<br />
// ( v e k t o r ) og e t andet punkt ( v e k t o r )<br />
public Punkt3D findSum ( Punkt3D punkt ) {<br />
return new Punkt3D ( punkt . hentX ( ) + hentX ( ) ,<br />
punkt . hentY ( ) + hentY ( ) ,<br />
punkt . hentZ ( ) + hentZ ( )<br />
) ;<br />
}<br />
//Metode t i l at f i n d e v e k t o r e n f r a d e t t e punkt<br />
// t i l e t andet punkt<br />
public Punkt3D f i n d V e k t o r T i l ( Punkt3D punkt ) {<br />
return punkt . f i n d D i f ( this ) ;<br />
}<br />
public double hentX ( ) {<br />
return x ;<br />
}<br />
public double hentY ( ) {<br />
return y ;<br />
}<br />
public double hentZ ( ) {<br />
return z ;<br />
}<br />
// Accessors og mutators<br />
public void saetX ( double x ) {<br />
this . x = x ;<br />
}<br />
public void saetY ( double y ) {<br />
this . y = y ;<br />
}<br />
public void saetZ ( double z ) {<br />
65
}<br />
this . z = z ;<br />
}<br />
//De e g e n t l i g e k o o r d i n a t e r<br />
private double x , y , z ;<br />
E.9 Scene.java<br />
/∗<br />
∗ Repræsenterer en scene med elementer og l y s k i l d e r .<br />
∗<br />
∗ Scenen er a n s v a r l i g f o r at f o r e t a g e f a r v e b e s t e m m e l s e /<br />
∗ s t r å l e s p o r i n g .<br />
∗<br />
∗ Se grænsefladen SceneI<br />
∗/<br />
import java . awt . Color ;<br />
import java . u t i l . Vector ;<br />
import java . u t i l . Enumeration ;<br />
public class Scene implements SceneI {<br />
/∗<br />
∗ T i l f ø j element t i l scenen<br />
∗/<br />
public void t i l f ø j ( Element e ) {<br />
elementer . add ( e ) ;<br />
}<br />
/∗<br />
∗ Sæt s o l e n<br />
∗/<br />
public void t i l f ø j S o l ( Sol s ) throws XMLParseError {<br />
i f ( s o l != null ) //kun en s o l er t i l l a d t<br />
throw new XMLParseError ( "\n\ t \tKun én s o l e r t i l l a d t " ) ;<br />
s o l = s ;<br />
}<br />
/∗<br />
∗ Farvebestemmelsesfunktion<br />
∗/<br />
public void f i n d F a r v e ( S t r å l e s t r å l e ) {<br />
//en ikke −d e f i n e r e t s t r å l e har i k k e f a r v e<br />
i f ( s t r å l e == null )<br />
return ;<br />
// Ingen s o l −> ingen f a r v e ;−)<br />
i f ( hentSol ( ) == null ) {<br />
s t r å l e . saetFarve ( Color .BLACK) ;<br />
return ;<br />
}<br />
// Find nærmeste skæring og d e t t i l s v a r e n d e element<br />
Punkt3D skæring = new Punkt3D ( 0 . 0 , 0 . 0 , 0 . 0 ) ;<br />
Element element = s t r å l e s p o r i n g ( s t r å l e , skæring ) ;<br />
// Ingen skæring −> ingen f a r v e<br />
i f ( skæring == null ) {<br />
s t r å l e . saetFarve ( Color .BLACK) ;<br />
return ;<br />
}<br />
// Find ud a f om s o l e n s l y s rammer p u n k t e t<br />
66
}<br />
S t r å l e s o l s t r å l e = hentSol ( ) . b e l y s ( skæring ) ;<br />
Punkt3D solSkæring = new Punkt3D ( 0 . 0 , 0 . 0 , 0 . 0 ) ;<br />
i f ( s t r å l e s p o r i n g ( s o l s t r å l e , s o l S k æ r i n g ) == null ) {<br />
// s o l e n s t r å l e n ramte i k k e noget ( p r æ c i s i o n s f e j l )<br />
//−> ingen f a r v e<br />
s t r å l e . saetFarve ( Color .BLACK) ;<br />
return ;<br />
}<br />
i f ( ! sammenlign ( skæring , solSkæring ) ) {<br />
// s t r å l e n ramte noget andet<br />
s t r å l e . saetFarve ( Color .BLACK) ;<br />
return ;<br />
}<br />
// Find f a r v e n<br />
s t r å l e . saetFarve ( element . f i n d F a r v e ( s o l s t r å l e ) ) ;<br />
/∗<br />
∗ S t r å l e s p o r e r e n<br />
∗<br />
∗ Returnerer d e t ramte element og<br />
∗ s æ t t e r skæring t i l s k æ r i n g s p u n k t e t<br />
∗/<br />
private Element s t r å l e s p o r i n g ( S t r å l e s t r å l e , Punkt3D skæring ) {<br />
// Find nærmeste skæring og d e t t i l s v a r e n d e element<br />
Element element = null ;<br />
Punkt3D skær = null ;<br />
Element tmpEl = null ; // Arbejdsvar<br />
Punkt3D tmpSk = null ; // Arbejdsvar<br />
double s k D i s t = 0 ; // Afstand mellem s t r å l e og skæring<br />
Enumeration e = hentElementer ( ) . elements ( ) ;<br />
for ( ; e . hasMoreElements ( ) ; tmpSk = null ) {<br />
tmpEl = ( Element ) e . nextElement ( ) ;<br />
tmpSk = tmpEl . findSkæring ( s t r å l e ) ;<br />
}<br />
}<br />
// Find den skæring der s k a l gemmes<br />
i f ( ( tmpSk == null && skær == null ) | | tmpSk == null )<br />
continue ;<br />
else i f ( skær == null<br />
| | ( s k D i s t > s t r å l e . h e n t S t a r t ( ) . f i n d D i s t ( tmpSk ) )<br />
) {<br />
skær = tmpSk ;<br />
s k D i s t = s t r å l e . h e n t S t a r t ( ) . f i n d D i s t ( skær ) ;<br />
element = tmpEl ;<br />
}<br />
// Kopier e t e v t . skæringspunkt<br />
i f ( skær != null ) {<br />
skæring . saetX ( skær . hentX ( ) ) ;<br />
skæring . saetY ( skær . hentY ( ) ) ;<br />
skæring . saetZ ( skær . hentZ ( ) ) ;<br />
}<br />
return element ;<br />
/∗<br />
∗ Metode t i l at sammenligne om to<br />
∗ punkter er t i l s t r æ k k e l i g ens<br />
∗/<br />
private boolean sammenlign ( Punkt3D p1 , Punkt3D p2 ) {<br />
double OKDif = 1e −3; // Acceptabel a f s t a n d<br />
67
}<br />
}<br />
Punkt3D d i f = p2 . f i n d D i f ( p1 ) ;<br />
return ( d i f . findLængde ( ) < OKDif ) ? true : f a l s e ;<br />
// Accessors og mutators<br />
private Vector hentElementer ( ) {<br />
return elementer ;<br />
}<br />
private Sol hentSol ( ) {<br />
return s o l ;<br />
}<br />
// P r i v a t e a t t r i b u t t e r<br />
private Vector elementer = new Vector ( ) ;<br />
private Sol s o l = null ;<br />
E.10 SceneI.java<br />
/∗<br />
∗ I n t e r f a c e der d e f i n e r e r en scenes g r æ n s e f l a d e<br />
∗/<br />
public interface SceneI {<br />
//Metode t i l at t i l f ø j e elementer<br />
// t i l scenen<br />
public void t i l f ø j ( Element e ) ;<br />
}<br />
//Metode t i l at t i l f ø j e l y s k i l d e r<br />
//Kan k a s t e XMLParseError h v i s scenen har<br />
// begrænsninger på a n t a l l e t a f l y s k i l d e r<br />
public void t i l f ø j S o l ( Sol s ) throws XMLParseError ;<br />
// S t r å l e s p o r i n g s f u n k t i o n , der bestemmer<br />
// ( og s æ t t e r ) f a r v e n på den modtagne s t r å l e<br />
public void f i n d F a r v e ( S t r å l e s t r å l e ) ;<br />
E.11 Sceneopstiller.java<br />
/∗<br />
∗ S c e n e o p t i l l e r e n s opgave er at o v e r s æ t t e en<br />
∗ XML−b e s k r i v e l s e t i l den i n t e r n e r e p r æ s e n t a t i o n<br />
∗<br />
∗ Er l a v e t ud f r a XMLReadWrite a f Søren Sjørup ( zoren@diku . dk )<br />
∗<br />
∗ F e j l m e d d e l e l s e r b l i v e r o p b y g g e t h i e r a k i s k ,<br />
∗ dvs . de b l i v e r o p b y g g e t b a g f r a og f å r t i l f ø j e t<br />
∗ information ved b a c k t r a c k i n g .<br />
∗/<br />
import javax . xml . p a r s e r s . DocumentBuilder ;<br />
import javax . xml . p a r s e r s . DocumentBuilderFactory ;<br />
import org . xml . sax . SAXException ;<br />
import java . awt . Color ;<br />
import java . i o . F i l e ;<br />
import java . u t i l . Vector ;<br />
import org . w3c . dom . ∗ ;<br />
public class S c e n e o p s t i l l e r {<br />
68
∗<br />
∗ Metode t i l at o p s t i l l e en scene ud<br />
∗ f r a en XML− f i l .<br />
∗<br />
∗ Der r e t u r n e r e s en Vector med<br />
∗ KameraI−o b j e k t e r<br />
∗/<br />
public Vector o p s t i l S c e n e ( S t r i n g f i l n a v n ){<br />
// Vektor t i l kamera<br />
Vector kameraer = null ;<br />
// Scenen<br />
SceneI s c e n e = null ;<br />
}<br />
// Fortæl brugeren hvor l a n g t processen er<br />
System . out . p r i n t ( "\ nIndlæser "+f i l n a v n+" . . . " ) ;<br />
System . out . f l u s h ( ) ;<br />
// Indlæs f i l e n<br />
org . w3c . dom . Element r o o t=parseXML ( f i l n a v n ) ;<br />
// Tjek at dokumentet i n d e h o l d e r en rod og at den hedder scene<br />
i f ( r o o t==null ) {<br />
System . out . p r i n t l n ( "\n\nDer e r en f e j l i "+f i l n a v n+" : " ) ;<br />
System . out . p r i n t l n ( "\ t ( s c e n e )\ n\ t \ tDer s k a l være e t scene−tag " ) ;<br />
System . out . p r i n t l n ( "\nProgrammet a f s l u t t e s " ) ;<br />
System . e x i t ( 1 ) ;<br />
}<br />
i f ( ! r o o t . getNodeName ( ) . e q u a l s ( " s c e n e " ) ) {<br />
System . out . p r i n t l n ( "\n\nDer e r en f e j l i "+f i l n a v n+" : " ) ;<br />
System . out . p r i n t l n ( "\ t ( s c e n e )\ n\ t \tRoden s k a l være s c e n e ( i k k e "<br />
+r o o t . getNodeName()+" ) "<br />
) ;<br />
System . out . p r i n t l n ( "\nProgrammet a f s l u t t e s " ) ;<br />
System . e x i t ( 1 ) ;<br />
}<br />
try{<br />
//Lav i n t e r n e r e p r æ s e n t a t i o n a f scenen<br />
s c e n e = o v e r s æ t T i l S c e n e ( r o o t ) ;<br />
//Og gør kameraerne k l a r<br />
kameraer = klargørKameraer ( root , s c e n e ) ;<br />
}catch ( XMLParseError excep ){<br />
System . out . p r i n t l n ( "\n\nDer e r en f e j l i "+f i l n a v n+" : " ) ;<br />
System . out . p r i n t l n ( "\ t ( s c e n e)−>"+excep . getMessage ( ) ) ;<br />
System . out . p r i n t l n ( "\nProgrammet a f s l u t t e s " ) ;<br />
System . e x i t ( 1 ) ;<br />
}<br />
// Fortæl brugeren hvor l a n g t processen er<br />
System . out . p r i n t l n ( " f æ r d i g " ) ;<br />
System . out . f l u s h ( ) ;<br />
return kameraer ;<br />
private s t a t i c org . w3c . dom . Element parseXML ( S t r i n g f i l n a v n ){<br />
org . w3c . dom . Element r o o t=null ;<br />
Document document ;<br />
DocumentBuilderFactory f a c t o r y =DocumentBuilderFactory . newInstance ( ) ;<br />
try {<br />
DocumentBuilder b u i l d e r = f a c t o r y . newDocumentBuilder ( ) ;<br />
document = b u i l d e r . p a r s e ( new F i l e ( f i l n a v n ) ) ;<br />
r o o t=document . getDocumentElement ( ) ;<br />
} catch ( SAXException e ) { // s y n t a k t i s k f e j l<br />
System . out . p r i n t l n ( "\n\nDer e r en s y n t a k t i s k f e j l i "+f i l n a v n ) ;<br />
69
}<br />
System . out . p r i n t l n ( "\nProgrammet a f s l u t t e s " ) ;<br />
System . e x i t ( 1 ) ;<br />
} catch ( Throwable e ) {<br />
System . out . p r i n t l n ( "\n\nDer opstod en f e j l i f o r s ø g e t på at læse "+f i l n a v n ) ;<br />
System . out . p r i n t l n ( "\nProgrammet a f s l u t t e s " ) ;<br />
System . e x i t ( 1 ) ;<br />
}<br />
return r o o t ;<br />
// læs XML indeholdende scenedata<br />
// og l a v Kamera−o b j e k t e r<br />
private Vector klargørKameraer ( org . w3c . dom . Element root , SceneI s c e n e )<br />
throws XMLParseError<br />
{<br />
Vector kameraer = new Vector ( ) ;<br />
}<br />
NodeList n l ;<br />
n l=r o o t . getElementsByTagName ( " p i l o t s y n " ) ; // hent p i l o t s y n −t a g s<br />
for ( int i = 0 ; i
}<br />
S t r i n g i d = null ;<br />
try {<br />
i d = nnm . getNamedItem ( " i d " ) . getNodeValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( punkt )\ n\ t \ tEt i d s k a l a n g i v e s f o r punktet " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( punkt )\ n\ t \ t i d ’ e t e r a n g i v e t f o r k e r t " ) ;<br />
}<br />
try {<br />
double x=(new Double (nnm . getNamedItem ( "x" ) . getNodeValue ( ) ) ) . doubleValue ( ) ;<br />
punkt . saetX ( x ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( i d+" ( punkt)−>x"+<br />
"\n\ t \tEn x−værdi s k a l a n g i v e s f o r punktet " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( i d+" ( punkt)−>x"+<br />
"\n\ t \ tx−værdien e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( i d+" ( punkt)−>x"+<br />
"\n\ t \ tx−værdien s k a l være e t t a l " ) ;<br />
}<br />
try {<br />
double y=(new Double (nnm . getNamedItem ( "y" ) . getNodeValue ( ) ) ) . doubleValue ( ) ;<br />
punkt . saetY ( y ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( i d+" ( punkt)−>y"+<br />
"\n\ t \tEn y−værdi s k a l a n g i v e s f o r punktet " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( i d+" ( punkt)−>y"+<br />
"\n\ t \ ty−værdien e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( i d+" ( punkt)−>y"+<br />
"\n\ t \ ty−værdien s k a l være e t t a l " ) ;<br />
}<br />
try {<br />
double z=(new Double (nnm . getNamedItem ( " z " ) . getNodeValue ( ) ) ) . doubleValue ( ) ;<br />
punkt . saetZ ( z ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( i d+" ( punkt)−>z "+<br />
"\n\ t \tEn z−værdi s k a l a n g i v e s f o r punktet " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( i d+" ( punkt)−>z "+<br />
"\n\ t \ tz−værdien e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( i d+" ( punkt)−>z "+<br />
"\n\ t \ tz−værdien s k a l være e t t a l " ) ;<br />
}<br />
return i d ;<br />
// l æ s e r en t r e k a n t g i v e t e t map a f a t t r i b u t t e r<br />
// og i n d s æ t t e r i meshet<br />
private void oversætTrekantFraNNM (NamedNodeMap nnm, Mesh mesh ) throws XMLParseError {<br />
int p1 = 0 , p2 = 0 , p3 = 0 ;<br />
try {<br />
p1=(new I n t e g e r (nnm . getNamedItem ( "p1" ) . getNodeValue ( ) ) ) . intValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( t r e k a n t)−>p1\n\ t \ tPunktet s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( t r e k a n t)−>p1\n\ t \ tPunktet e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( " ( t r e k a n t)−>p1\n\ t \ tVærdien s k a l være e t t a l " ) ;<br />
}<br />
try {<br />
71
}<br />
p2=(new I n t e g e r (nnm . getNamedItem ( "p2" ) . getNodeValue ( ) ) ) . intValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( t r e k a n t)−>p2\n\ t \ tPunktet s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( t r e k a n t)−>p2\n\ t \ tPunktet e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( " ( t r e k a n t)−>p2\n\ t \ tVærdien s k a l være e t t a l " ) ;<br />
}<br />
try {<br />
p3=(new I n t e g e r (nnm . getNamedItem ( "p3" ) . getNodeValue ( ) ) ) . intValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( t r e k a n t)−>p3\n\ t \ tPunktet s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( t r e k a n t)−>p3\n\ t \ tPunktet e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( " ( t r e k a n t)−>p3\n\ t \ tVærdien s k a l være e t t a l " ) ;<br />
}<br />
// Punkterne må i k k e være ens<br />
i f ( p1 == p2 | | p2 == p3 | | p3 == p1 )<br />
throw new XMLParseError ( " ( t r e k a n t )\ n\ t \ tTrekanter må i k k e have to ens punkter " ) ;<br />
mesh . t i l f ø j T r e k a n t ( p1 , p2 , p3 ) ;<br />
//Metode t i l at i n dlæse en f a r v e g i v e t e t map a f a t t r i b u t t e r<br />
private Color oversætFarveFraNNM (NamedNodeMap nnm) throws XMLParseError {<br />
int r = 0 , g = 0 , b = 0 ;<br />
try {<br />
r=(new I n t e g e r (nnm . getNamedItem ( " r " ) . getNodeValue ( ) ) ) . intValue ( ) ;<br />
//kun værdier i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
i f ( r < 0 | | 255 < r )<br />
throw new XMLParseError ( " f a r v e −>r "+<br />
"\n\ t \ tr −værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ] " ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " f a r v e −>r \n\ t \tEn r−værdi s k a l a n g i v e s f o r f a r v e n " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " f a r v e −>r \n\ t \ tr −værdien e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( " f a r v e −>r \n\ t \ tr −værdien s k a l være e t h e l t a l " ) ;<br />
}<br />
try {<br />
g=(new I n t e g e r (nnm . getNamedItem ( "g" ) . getNodeValue ( ) ) ) . intValue ( ) ;<br />
//kun værdier i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
i f ( g < 0 | | 255 < g )<br />
throw new XMLParseError ( " f a r v e −>g"+<br />
"\n\ t \ tg−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ] " ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " f a r v e −>g\n\ t \tEn g−værdi s k a l a n g i v e s f o r f a r v e n " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " f a r v e −>g\n\ t \ tg−værdien e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( " f a r v e −>g\n\ t \ tg−værdien s k a l være e t h e l t a l " ) ;<br />
}<br />
try {<br />
b=(new I n t e g e r (nnm . getNamedItem ( "b" ) . getNodeValue ( ) ) ) . intValue ( ) ;<br />
//kun værdier i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
i f ( b < 0 | | 255 < b )<br />
throw new XMLParseError ( " f a r v e −>b"+<br />
"\n\ t \tb−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ] " ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " f a r v e −>b\n\ t \tEn b−værdi s k a l a n g i v e s f o r f a r v e n " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " f a r v e −>b\n\ t \tb−værdien e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( NumberFormatException e ) { // i k k e e t t a l<br />
throw new XMLParseError ( " f a r v e −>b\n\ t \tb−værdien s k a l være e t h e l t a l " ) ;<br />
}<br />
72
eturn new Color ( r , g , b ) ;<br />
}<br />
// l æ s e r en k u g l e g i v e t en xml−knude<br />
// og t i l f ø j e r t i l scenen<br />
private void oversætKugle ( Node nn , SceneI s c e n e ) throws XMLParseError{<br />
NamedNodeMap nnm=nn . g e t A t t r i b u t e s ( ) ;<br />
S t r i n g i d = null ;<br />
try {<br />
i d=nnm . getNamedItem ( " i d " ) . getNodeValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( kugle )\ n\ t \ tEt i d s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( kugle )\ n\ t \ t i d ’ e t e r a n g i v e t f o r k e r t " ) ;<br />
}<br />
NodeList n l = null ;<br />
Color f a r v e = null ;<br />
try {<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " f a r v e " ) ;<br />
f a r v e = oversætFarveFraNNM ( n l . item ( 0 ) . g e t A t t r i b u t e s ( ) ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( i d+" ( kugle)−>f a r v e \n\ t \ tFarve s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( i d+" ( kugle)−>f a r v e \n\ t \ tFarven e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( Throwable e ) { // F e j l i f a r v e<br />
throw new XMLParseError ( i d+" ( kugle)−>"+e . getMessage ( ) ) ;<br />
}<br />
double r = 0 ;<br />
try {<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " r a d i u s " ) ;<br />
r=new Double (<br />
n l . item ( 0 ) . g e t A t t r i b u t e s ( ) . getNamedItem ( " r " ) . getNodeValue ( )<br />
) . doubleValue ( ) ;<br />
//kun p o s i t i v e værdier<br />
i f ( r
}<br />
// Tjek at p u n k t e t hed p o s i t i o n<br />
i f ( ! pId . e q u a l s ( " centrum " ) )<br />
throw new XMLParseError ( i d+" ( kugle)−>(punkt )\ n\ t \ tUkendt punkt "+pId ) ;<br />
s c e n e . t i l f ø j (new Kugle ( p o s i t i o n , r , f a r v e ) ) ;<br />
// l æ s e r en plan g i v e t en xml−knude<br />
// og i n d s æ t t e r i scene<br />
private void oversætPlan ( Node nn , SceneI s c e n e ) throws XMLParseError{<br />
NamedNodeMap nnm=nn . g e t A t t r i b u t e s ( ) ;<br />
S t r i n g i d = null ;<br />
try {<br />
i d=nnm . getNamedItem ( " i d " ) . getNodeValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( plan )\ n\ t \ tEt i d s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( plan )\ n\ t \ t i d ’ e t e r a n g i v e t f o r k e r t " ) ;<br />
}<br />
NodeList n l = null ;<br />
Color f a r v e = null ;<br />
try {<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " f a r v e " ) ;<br />
f a r v e = oversætFarveFraNNM ( n l . item ( 0 ) . g e t A t t r i b u t e s ( ) ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( i d+" ( plan)−>f a r v e \n\ t \ tFarve s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( i d+" ( plan)−>f a r v e \n\ t \ tFarven e r a n g i v e t f o r k e r t " ) ;<br />
} catch ( Throwable e ) { // F e j l i f a r v e<br />
throw new XMLParseError ( i d+" ( plan)−>"+e . getMessage ( ) ) ;<br />
}<br />
Punkt3D stedpunkt = null ,<br />
r e t n i n g 1 = null ,<br />
r e t n i n g 2 = null<br />
;<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " punkt " ) ;<br />
for ( int i = 0 ; i
}<br />
}<br />
r e t n i n g 2 = new Punkt3D ( 0 . 0 , 0 . 0 , 0 . 0 ) ;<br />
oversætPunktFraNNM ( punktnnm , r e t n i n g 2 ) ;<br />
} catch ( XMLParseError e ) {<br />
throw new XMLParseError ( i d+" ( plan)−>"+e . getMessage ( ) ) ;<br />
}<br />
else<br />
throw new XMLParseError ( i d+" ( plan)−>"+navn+" ( punkt ) "+<br />
"\n\ t \ tUkendt punkt " ) ;<br />
// Tjek at de t r e punkter er a n g i v e t<br />
i f ( stedpunkt == null )<br />
throw new XMLParseError ( i d+" ( plan)−>stedpunkt ( punkt ) "+<br />
"\n\ t \ tStedpunkt s k a l a n g i v e s " ) ;<br />
i f ( r e t n i n g 1 == null )<br />
throw new XMLParseError ( i d+" ( plan)−>r e t n i n g s v e k t o r 1 ( punkt ) "+<br />
"\n\ t \ t R e t n i n g s v e k t o r 1 s k a l a n g i v e s " ) ;<br />
i f ( r e t n i n g 2 == null )<br />
throw new XMLParseError ( i d+" ( plan)−>r e t n i n g s v e k t o r 2 ( punkt ) "+<br />
"\n\ t \ t R e t n i n g s v e k t o r 2 s k a l a n g i v e s " ) ;<br />
// t j e k at de to v e k t o r e r i k k e er n u l v e k t o r e n<br />
i f ( r e t n i n g 1 . erNulVektor ( ) )<br />
throw new XMLParseError ( i d+" ( plan)−>r e t n i n g s v e k t o r 1 ( punkt ) "+<br />
"\n\ t \ t R e t n i n g s v e k t o r e r må i k k e være n u l v e k t o r e n " ) ;<br />
i f ( r e t n i n g 2 . erNulVektor ( ) )<br />
throw new XMLParseError ( i d+" ( plan)−>r e t n i n g s v e k t o r 2 ( punkt ) "+<br />
"\n\ t \ t R e t n i n g s v e k t o r e r må i k k e være n u l v e k t o r e n " ) ;<br />
// t j e k at de to v e k t o r e r i k k e er p a r a l l e l l e<br />
// | r2 | = | r e t n i n g 1 |<br />
Punkt3D r2 = r e t n i n g 2 . f i n d S k a l e r e t ( r e t n i n g 1 . findLængde ( ) / r e t n i n g 2 . findLængde ( ) ) ;<br />
i f ( r2 . f i n d D i f ( r e t n i n g 1 ) . findLængde ( ) == 0 . 0<br />
| | r2 . f i n d S k a l e r e t ( − 1 . 0 ) . f i n d D i f ( r e t n i n g 1 ) . findLængde ( ) == 0 . 0<br />
)<br />
throw new XMLParseError ( i d+" ( plan ) "+<br />
"\n\ t \ t R e t n i n g s v e k t o r e r n e må i k k e være p a r a l e l l e " ) ;<br />
s c e n e . t i l f ø j (new Plan ( stedpunkt , r e t n i n g 1 , r e t n i n g 2 , f a r v e ) ) ;<br />
// l æ s e r e t mesh g i v e t en xml−knude<br />
// og t i l f ø j e r t i l scenen<br />
private void oversætMesh ( Node nn , SceneI s c e n e ) throws XMLParseError{<br />
NamedNodeMap nnm=nn . g e t A t t r i b u t e s ( ) ;<br />
S t r i n g i d = null ;<br />
try {<br />
i d=nnm . getNamedItem ( " i d " ) . getNodeValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( mesh )\ n\ t \ tEt i d s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( mesh )\ n\ t \ t i d ’ e t e r a n g i v e t f o r k e r t " ) ;<br />
}<br />
try {<br />
NodeList n l = null ;<br />
Color f a r v e = null ;<br />
try {<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " f a r v e " ) ;<br />
f a r v e = oversætFarveFraNNM ( n l . item ( 0 ) . g e t A t t r i b u t e s ( ) ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " f a r v e \n\ t \ tFarve s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " f a r v e \n\ t \ tFarven e r a n g i v e t f o r k e r t " ) ;<br />
75
} // f e j l i f a r v e b l i v e r f a n g e t på næste niveau<br />
// Opret mesh<br />
Mesh mesh = new Mesh ( f a r v e ) ;<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " punkter " ) ;<br />
i f ( n l . getLength ( ) == 0)<br />
throw new XMLParseError ( " ( punkter )\ n\ t \ tPunkter s k a l a n g i v e s " ) ;<br />
for ( int i = 0 ; i
}<br />
i f ( n l . getLength ( ) == 0)<br />
throw new XMLParseError ( " ( t r e k a n t e r )\ n\ t \ tTrekanter s k a l a n g i v e s " ) ;<br />
for ( int i = 0 ; i
try {<br />
hoejde =(new I n t e g e r (nnm . getNamedItem ( " hoejde " ) . getNodeValue ( ) ) ) . intValue ( ) ;<br />
//kun p o s i t i v e værdier<br />
i f ( hoejde
}<br />
}<br />
vandret = new Punkt3D ( 0 . 0 , 0 . 0 , 0 . 0 ) ;<br />
oversætPunktFraNNM (nnm, vandret ) ;<br />
} catch ( XMLParseError e ) {<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−>"+e . getMessage ( ) ) ;<br />
}<br />
else<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−>"+navn+" ( punkt )\ n\ t \ tUkendt punkt " ) ;<br />
// t j e k at de f i r e punkter er a n g i v e t<br />
i f ( øjepunkt == null )<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−> p i l o t o e j e ( punkt ) "+<br />
"\n\ t \ t P i l o t e n s øjepunkt s k a l a n g i v e s " ) ;<br />
i f ( stedpunkt == null )<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−>cockpitvindue_stedpunkt ( punkt ) "<br />
+"\n\ t \ tStedpunkt s k a l a n g i v e s " ) ;<br />
i f ( vandret == null )<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−>cockpitvindue_vandret ( punkt ) "+<br />
"\n\ t \ tVandret s k a l a n g i v e s " ) ;<br />
i f ( l o d r e t == null )<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−>c o c k p i t v i n d u e _ l o d r e t ( punkt ) "<br />
+"\n\ t \ tLodret s k a l a n g i v e s " ) ;<br />
// t j e k at de to v e k t o r e r i k k e er n u l v e k t o r e n<br />
i f ( vandret . erNulVektor ( ) )<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−>cockpitvindue_vandret ( punkt ) "<br />
+"\n\ t \ tVandret må i k k e være n u l v e k t o r e n " ) ;<br />
i f ( l o d r e t . erNulVektor ( ) )<br />
throw new XMLParseError ( i d+" ( p i l o t s y n )−>c o c k p i t v i n d u e _ l o d r e t ( punkt ) "<br />
+"\n\ t \ tLodret må i k k e være n u l v e k t o r e n " ) ;<br />
kameraer . add (new Kamera ( øjepunkt , stedpunkt ,<br />
vandret , l o d r e t ,<br />
bredde , hoejde ,<br />
scene , i d<br />
) ) ;<br />
// l æ s e r en s o l g i v e t en xml−knude<br />
// og t i l f ø j e r t i l scene<br />
private void oversætSol ( Node nn , SceneI s c e n e ) throws XMLParseError{<br />
Color f a r v e = null ;<br />
Punkt3D p o s i t i o n = new Punkt3D ( 0 . 0 , 0 . 0 , 0 . 0 ) ;<br />
NamedNodeMap nnm=nn . g e t A t t r i b u t e s ( ) ;<br />
S t r i n g i d = null ;<br />
try {<br />
i d=nnm . getNamedItem ( " i d " ) . getNodeValue ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( " ( s o l )−>i d \n\ t \ tEt i d s k a l a n g i v e s " ) ;<br />
} catch ( DOMException e ) { // T y p e f e j l<br />
throw new XMLParseError ( " ( s o l )−>i d \n\ t \ t i d ’ e t e r a n g i v e t f o r k e r t " ) ;<br />
}<br />
NodeList n l = null ;<br />
try {<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " f a r v e " ) ;<br />
f a r v e = oversætFarveFraNNM ( n l . item ( 0 ) . g e t A t t r i b u t e s ( ) ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) { // i k k e a n g i v e t<br />
throw new XMLParseError ( i d+" ( s o l )−>f a r v e \n\ t \tEn f a r v e s k a l a n g i v e s " ) ;<br />
} catch ( XMLParseError e ) { // f e j l i f a r v e n<br />
throw new XMLParseError ( i d+" ( s o l )−>"+e . getMessage ( ) ) ;<br />
}<br />
79
}<br />
}<br />
NamedNodeMap punktnnm = null ;<br />
try {<br />
n l =(( org . w3c . dom . Element ) nn ) . getElementsByTagName ( " punkt " ) ;<br />
punktnnm=n l . item ( 0 ) . g e t A t t r i b u t e s ( ) ;<br />
} catch ( N u l l P o i n t e r E x c e p t i o n e ) {// i k k e a n g i v e t<br />
throw new XMLParseError ( i d+" ( s o l )−> p o s i t i o n ( punkt ) "<br />
+"\n\ t \ t P o s i t i o n e n s k a l a n g i v e s " ) ;<br />
}<br />
S t r i n g pId = null ;<br />
try {<br />
pId = oversætPunktFraNNM ( punktnnm , p o s i t i o n ) ;<br />
} catch ( XMLParseError e ) { // f e j l i p u n k t e t<br />
throw new XMLParseError ( i d+" ( s o l )−>"+e . getMessage ( ) ) ;<br />
}<br />
// Tjek at p u n k t e t hed p o s i t i o n<br />
i f ( ! pId . e q u a l s ( " p o s i t i o n " ) )<br />
throw new XMLParseError ( i d+" ( s o l )−>(punkt )\ n\ t \ tUkendt punkt "+pId ) ;<br />
// T i l f ø j s o l e n t i l scenen<br />
s c e n e . t i l f ø j S o l (new Sol ( p o s i t i o n , f a r v e ) ) ;<br />
E.12 Sol.java<br />
/∗<br />
∗ Repræsenterer s o l e n i form a f dens p l a c e r i n g og f a r v e .<br />
∗<br />
∗ Dens opgave er at l a v e l y s ;−)<br />
∗<br />
∗ Kaster N u l l P o i n t e r E x c e p t i o n h v i s den f å r n u l l som<br />
∗ argument t i l både k o n s t r u k t ø r e r og metoder , da de<br />
∗ i k k e er meningsfulde værdier<br />
∗<br />
∗/<br />
import java . awt . Color ;<br />
public class Sol {<br />
// Konstruktør<br />
public Sol ( Punkt3D p l a c e r i n g , Color f a r v e ) {<br />
this . p l a c e r i n g = p l a c e r i n g ;<br />
this . f a r v e = f a r v e ;<br />
}<br />
}<br />
//Metode t i l at b e s k r i v e h v i l k e n s o l s t r å l e ,<br />
// der l y s e r i r e t n i n g a f e t g i v e t punkt<br />
public S t r å l e b e l y s ( Punkt3D punkt ) {<br />
i f ( punkt == null ) // t j e k f o r u g y l d i g t argument<br />
throw new N u l l P o i n t e r E x c e p t i o n ( " Solen kan i k k e b e l y s e n u l l " ) ;<br />
}<br />
// Find r e t n i n g s v e k t o r<br />
Punkt3D r e t n i n g = p l a c e r i n g . f i n d V e k t o r T i l ( punkt ) ;<br />
// Returner s o l s t r å l e n<br />
return new S t r å l e ( p l a c e r i n g , r e t n i n g , f a r v e ) ;<br />
private Punkt3D p l a c e r i n g = null ;<br />
private Color f a r v e = null ;<br />
80
E.13 Stråle.java<br />
/∗<br />
∗ Repræsenterer en s t r å l e i t r e dimensioner .<br />
∗<br />
∗ D e f i n e r e s ved e t b e g y n d e l s e s p u n k t , en r e t n i n g s v e k t o r og en f a r v e .<br />
∗/<br />
import java . awt . Color ;<br />
public class S t r å l e {<br />
// Konstruktør<br />
public S t r å l e ( Punkt3D s t a r t , Punkt3D r e t n i n g , Color f a r v e ) {<br />
s a e t S t a r t ( s t a r t ) ;<br />
saetRetning ( r e t n i n g ) ;<br />
saetFarve ( f a r v e ) ;<br />
}<br />
}<br />
// Accessors og mutators<br />
public void s a e t S t a r t ( Punkt3D s t a r t ) {<br />
this . s t a r t = s t a r t ;<br />
}<br />
public Punkt3D h e n t S t a r t ( ) {<br />
return s t a r t ;<br />
}<br />
public void saetRetning ( Punkt3D r e t n i n g ) {<br />
this . r e t n i n g = r e t n i n g ;<br />
}<br />
public Punkt3D hentRetning ( ) {<br />
return r e t n i n g ;<br />
}<br />
public void saetFarve ( Color f a r v e ) {<br />
this . f a r v e = f a r v e ;<br />
}<br />
public Color hentFarve ( ) {<br />
return f a r v e ;<br />
}<br />
// Stedpunkt<br />
private Punkt3D s t a r t = null ;<br />
// R e t n i n g s v e k t o r<br />
private Punkt3D r e t n i n g = null ;<br />
// Farve<br />
private Color f a r v e = null ;<br />
E.14 Trekant.java<br />
/∗<br />
∗ Repræsenterer en t r e k a n t i form a f t r e punkter og en f a r v e<br />
∗/<br />
import java . awt . Color ;<br />
public class Trekant extends Element {<br />
// Konstruktør<br />
public Trekant ( Punkt3D punkt1 , Punkt3D punkt2 , Punkt3D punkt3 , Color f a r v e ) {<br />
this . punkt1 = punkt1 ;<br />
this . punkt2 = punkt2 ;<br />
this . punkt3 = punkt3 ;<br />
this . f a r v e = f a r v e ;<br />
//Lav den plan som t r e k a n t e n l i g g e r i<br />
plan = new Plan ( punkt1 ,<br />
81
}<br />
punkt1 . f i n d V e k t o r T i l ( punkt2 ) ,<br />
punkt1 . f i n d V e k t o r T i l ( punkt3 ) ,<br />
f a r v e<br />
) ;<br />
/∗<br />
∗ Metode , der f i n d e r en e v t . skæring med<br />
∗ en g i v e n s t r å l e .<br />
∗<br />
∗ n u l l r e t u r n e r e s , h v i s der ingen skæring er<br />
∗/<br />
public Punkt3D findSkæring ( S t r å l e s t r å l e ) {<br />
// Hvis s t r å l e n i k k e er d e f i n e r e t , skærer den<br />
// i k k e k u g l e n<br />
i f ( s t r å l e == null )<br />
return null ;<br />
// Find e v t . skæring mellem t r e k a n t e n s plan<br />
// og s t r å l e<br />
Punkt3D planSkæring = hentPlan ( ) . findSkæring ( s t r å l e ) ;<br />
i f ( planSkæring == null )<br />
return null ; // ingen skæring<br />
//Hent planens k o e f f i c i e n t e r<br />
double A = Math . abs ( plan . hentA ( ) ) ,<br />
B = Math . abs ( plan . hentB ( ) ) ,<br />
C = Math . abs ( plan . hentC ( ) )<br />
;<br />
// P r o j i c e r de t r e punkter og planskæringen<br />
// ind på den b e d s t e a f de t r e p l a n e r udspændt<br />
// a f akserne<br />
double [ ] p1 = new double [ 2 ] ,<br />
p2 = new double [ 2 ] ,<br />
p3 = new double [ 2 ] ,<br />
ps = new double [ 2 ]<br />
;<br />
i f (A > B && A > C) {<br />
p1 [ 0 ] = punkt1 . hentY ( ) ;<br />
p1 [ 1 ] = punkt1 . hentZ ( ) ;<br />
p2 [ 0 ] = punkt2 . hentY ( ) ;<br />
p2 [ 1 ] = punkt2 . hentZ ( ) ;<br />
p3 [ 0 ] = punkt3 . hentY ( ) ;<br />
p3 [ 1 ] = punkt3 . hentZ ( ) ;<br />
ps [ 0 ] = planSkæring . hentY ( ) ;<br />
ps [ 1 ] = planSkæring . hentZ ( ) ;<br />
} else i f (B > A && B > C) {<br />
p1 [ 0 ] = punkt1 . hentX ( ) ;<br />
p1 [ 1 ] = punkt1 . hentZ ( ) ;<br />
p2 [ 0 ] = punkt2 . hentX ( ) ;<br />
p2 [ 1 ] = punkt2 . hentZ ( ) ;<br />
p3 [ 0 ] = punkt3 . hentX ( ) ;<br />
p3 [ 1 ] = punkt3 . hentZ ( ) ;<br />
ps [ 0 ] = planSkæring . hentX ( ) ;<br />
ps [ 1 ] = planSkæring . hentZ ( ) ;<br />
} else {<br />
p1 [ 0 ] = punkt1 . hentX ( ) ;<br />
p1 [ 1 ] = punkt1 . hentY ( ) ;<br />
p2 [ 0 ] = punkt2 . hentX ( ) ;<br />
p2 [ 1 ] = punkt2 . hentY ( ) ;<br />
p3 [ 0 ] = punkt3 . hentX ( ) ;<br />
p3 [ 1 ] = punkt3 . hentY ( ) ;<br />
ps [ 0 ] = planSkæring . hentX ( ) ;<br />
ps [ 1 ] = planSkæring . hentY ( ) ;<br />
}<br />
82
}<br />
}<br />
//Udregn de t r e determinanter ( opgave s . 1 0 )<br />
double det1 = ( ps [0] − p1 [ 0 ] ) ∗ ( p2 [1] − p1 [ 1 ] ) − ( ps [1] − p1 [ 1 ] ) ∗ ( p2 [0] − p1 [ 0 ] ) ;<br />
double det2 = ( ps [0] − p2 [ 0 ] ) ∗ ( p3 [1] − p2 [ 1 ] ) − ( ps [1] − p2 [ 1 ] ) ∗ ( p3 [0] − p2 [ 0 ] ) ;<br />
double det3 = ( ps [0] − p3 [ 0 ] ) ∗ ( p1 [1] − p3 [ 1 ] ) − ( ps [1] − p3 [ 1 ] ) ∗ ( p1 [0] − p3 [ 0 ] ) ;<br />
i f ( ( det1 >= 0 . 0 && det2 >= 0 . 0 && det3 >= 0 . 0 )<br />
| | ( det1
F Afprøvningsdata<br />
Dette appendiks indeholder inddata, forventet uddata samt faktisk uddata fra afprøvningerne.<br />
F.1 Afprøvning 1<br />
Afprøvningen er kørsel af programmet med den obligatoriske lufthavn som inddata.<br />
Inddata<br />
Inddatafilen kan hentes på kursets hjemmeside:<br />
http://www.diku.dk/undervisning/<strong>2003</strong>f/dat0gb/lufthavn2.xml.<br />
Forventet uddata<br />
Vi forventer, at der løbende bliver rapporteret om, hvilken proces programmet er i gang<br />
med. For billedgenerering forventer vi endvidere en respons om hvor langt processen er.<br />
Programmet skal generere et billede for hvert af de tre pilotsyn (syn1.ppm, syn2.ppm og<br />
syn3.ppm) og billederne skal have en opløsning på 150×150. Billedet af pilotsyn „syn2“ skal<br />
ligne det der findes på adressen http://www.diku.dk/undervisning/<strong>2003</strong>f/dat0gb/syn2.tiff.<br />
Faktisk uddata<br />
Se figur 1 for de resulterende billeder.<br />
I n d l æ s e r l u f t h a v n 2 . xml . . . f æ r d i g<br />
Laver b i l l e d e " syn2 " : ∗∗∗∗∗∗∗∗∗∗ f æ r d i g<br />
" syn2 " e r gemt i syn2 . ppm<br />
Laver b i l l e d e " syn3 " : ∗∗∗∗∗∗∗∗∗∗ f æ r d i g<br />
" syn3 " e r gemt i syn3 . ppm<br />
Laver b i l l e d e " syn1 " : ∗∗∗∗∗∗∗∗∗∗ f æ r d i g<br />
" syn1 " e r gemt i syn1 . ppm<br />
F.2 Afprøvning 2<br />
Inddata<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at roden skal være scene.<br />
84
Faktisk uddata<br />
syn1.ppm syn2.ppm syn3.ppm<br />
I n d l æ s e r afproev_2 . xml . . .<br />
Der e r en f e j l i afproev_2 . xml:<br />
( s c e n e )<br />
Roden s k a l være s c e n e ( i k k e model )<br />
Programmet a f s l u t t e s<br />
F.3 Afprøvning 3<br />
Inddata<br />
<br />
Figur 1: Billeder fra afprøvning 1<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at id skal angives for pilotsyn.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_3 . xml . . .<br />
Der e r en f e j l i afproev_3 . xml:<br />
( s c e n e )−>( p i l o t s y n )−>i d<br />
85
Et i d s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
F.4 Afprøvning 4<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at hoejde skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_4 . xml . . .<br />
Der e r en f e j l i afproev_4 . xml:<br />
( s c e n e)−>syn1 ( p i l o t s y n )−>hoejde<br />
Højde s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.5 Afprøvning 5<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at bredde skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_5 . xml . . .<br />
86
Der e r en f e j l i afproev_5 . xml:<br />
( s c e n e)−>syn1 ( p i l o t s y n )−>bredde<br />
Bredde s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.6 Afprøvning 6<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at hoejde skal være et heltal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_6 . xml . . .<br />
Der e r en f e j l i afproev_6 . xml:<br />
( s c e n e)−>syn1 ( p i l o t s y n )−>hoejde<br />
Højde s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.7 Afprøvning 7<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at bredde skal være et heltal.<br />
Faktisk uddata<br />
87
I n d l æ s e r afproev_7 . xml . . .<br />
Der e r en f e j l i afproev_7 . xml:<br />
( s c e n e)−>syn1 ( p i l o t s y n )−>bredde<br />
Bredde s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.8 Afprøvning 8<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at hoejde skal være større end nul.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_8 . xml . . .<br />
Der e r en f e j l i afproev_8 . xml:<br />
( s c e n e)−>syn1 ( p i l o t s y n )−>hoejde<br />
Højde s k a l være s t ø r r e end nul<br />
Programmet a f s l u t t e s<br />
F.9 Afprøvning 9<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at bredde skal være større end nul.<br />
88
Faktisk uddata<br />
I n d l æ s e r afproev_9 . xml . . .<br />
Der e r en f e j l i afproev_9 . xml:<br />
( s c e n e)−>syn1 ( p i l o t s y n )−>bredde<br />
Bredde s k a l være s t ø r r e end nul<br />
Programmet a f s l u t t e s<br />
F.10 Afprøvning 10<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at sol skal have en farve.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_10 . xml . . .<br />
Der e r en f e j l i afproev_10 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e<br />
En f a r v e s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
F.11 Afprøvning 11<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at kugle skal have et centrum.<br />
89
Faktisk uddata<br />
I n d l æ s e r afproev_11 . xml . . .<br />
Der e r en f e j l i afproev_11 . xml:<br />
( s c e n e)−>kugle1 ( kugle)−>centrum ( punkt )<br />
Centrum s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
F.12 Afprøvning 12<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at radius skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_12 . xml . . .<br />
Der e r en f e j l i afproev_12 . xml:<br />
( s c e n e)−>kugle1 ( kugle)−>r a d i u s<br />
Radius s k a l være e t t a l<br />
Programmet a f s l u t t e s<br />
F.13 Afprøvning 13<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at radius skal være større end nul.<br />
90
Faktisk uddata<br />
I n d l æ s e r afproev_13 . xml . . .<br />
Der e r en f e j l i afproev_13 . xml:<br />
( s c e n e)−>kugle1 ( kugle)−>r a d i u s<br />
Radius s k a l være e t p o s i t i v<br />
Programmet a f s l u t t e s<br />
F.14 Afprøvning 14<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at plans to vektorer ikke må være parallelle.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_14 . xml . . .<br />
Der e r en f e j l i afproev_14 . xml:<br />
( s c e n e)−>plan1 ( plan )<br />
R e t n i n g s v e k t o r e r n e må i k k e være p a r a l e l l e<br />
Programmet a f s l u t t e s<br />
F.15 Afprøvning 15<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at planen mangler retningsvektor1.<br />
91
Faktisk uddata<br />
I n d l æ s e r afproev_15 . xml . . .<br />
Der e r en f e j l i afproev_15 . xml:<br />
( s c e n e)−>plan1 ( plan)−>r e t n i n g s v e k t o r 1 ( punkt )<br />
Retningsvektor 1 s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
F.16 Afprøvning 16<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at trekantens 3. punkt er ugyldigt.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_16 . xml . . .<br />
Der e r en f e j l i afproev_16 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r )−>1. ( t r e k a n t)−>p3<br />
U d e f i n e r e t punkt: 3<br />
Programmet a f s l u t t e s<br />
F.17 Afprøvning 17<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
92
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at mesh skal have en farve.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_17 . xml . . .<br />
Der e r en f e j l i afproev_17 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>f a r v e<br />
Farve s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
F.18 Afprøvning 18<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at punktets x-koordinat skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_18 . xml . . .<br />
Der e r en f e j l i afproev_18 . xml:<br />
( s c e n e)−> s o l ( s o l )−> p o s i t i o n ( punkt)−>x<br />
x−værdien s k a l være e t t a l<br />
Programmet a f s l u t t e s<br />
F.19 Afprøvning 19<br />
Inddata<br />
<br />
<br />
<br />
93
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at punktets y-koordinat skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_19 . xml . . .<br />
Der e r en f e j l i afproev_19 . xml:<br />
( s c e n e)−> s o l ( s o l )−> p o s i t i o n ( punkt)−>y<br />
y−værdien s k a l være e t t a l<br />
Programmet a f s l u t t e s<br />
F.20 Afprøvning 20<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at punktets z-koordinat ikke er et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_20 . xml . . .<br />
Der e r en f e j l i afproev_20 . xml:<br />
( s c e n e)−> s o l ( s o l )−> p o s i t i o n ( punkt)−>z<br />
z−værdien s k a l være e t t a l<br />
Programmet a f s l u t t e s<br />
F.21 Afprøvning 21<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
94
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at vektoren ikke må være nulvektoren.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_21 . xml . . .<br />
Der e r en f e j l i afproev_21 . xml:<br />
( s c e n e)−>syn1 ( p i l o t s y n )−>cockpitvindue_vandret ( punkt )<br />
Vandret må i k k e være n u l v e k t o r e n<br />
Programmet a f s l u t t e s<br />
F.22 Afprøvning 22<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at punktets id skal angives.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_22 . xml . . .<br />
Der e r en f e j l i afproev_22 . xml:<br />
( s c e n e)−> s o l ( s o l )−>(punkt )<br />
Et i d s k a l a n g i v e s f o r punktet<br />
Programmet a f s l u t t e s<br />
F.23 Afprøvning 23<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
95
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens r-værdi skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_23 . xml . . .<br />
Der e r en f e j l i afproev_23 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>r<br />
r−værdien s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.24 Afprøvning 24<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens g-værdi skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_24 . xml . . .<br />
Der e r en f e j l i afproev_24 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>g<br />
g−værdien s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.25 Afprøvning 25<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
96
Forventet uddata<br />
En fejlmeddelelse om at farvens b-værdi skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_25 . xml . . .<br />
Der e r en f e j l i afproev_25 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>b<br />
b−værdien s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.26 Afprøvning 26<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens r-værdi skal være et heltal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_26 . xml . . .<br />
Der e r en f e j l i afproev_26 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>r<br />
r−værdien s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.27 Afprøvning 27<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens g-værdi skal være et heltal.<br />
97
Faktisk uddata<br />
I n d l æ s e r afproev_27 . xml . . .<br />
Der e r en f e j l i afproev_27 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>g<br />
g−værdien s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.28 Afprøvning 28<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens b-værdi skal være et heltal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_28 . xml . . .<br />
Der e r en f e j l i afproev_28 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>b<br />
b−værdien s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.29 Afprøvning 29<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens r-værdi skal være større end eller lig nul.<br />
98
Faktisk uddata<br />
I n d l æ s e r afproev_29 . xml . . .<br />
Der e r en f e j l i afproev_29 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>r<br />
r−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
Programmet a f s l u t t e s<br />
F.30 Afprøvning 30<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens g-værdi skal være større end eller lig nul.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_30 . xml . . .<br />
Der e r en f e j l i afproev_30 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>g<br />
g−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
Programmet a f s l u t t e s<br />
F.31 Afprøvning 31<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens b-værdi skal være større end eller lig nul.<br />
99
Faktisk uddata<br />
I n d l æ s e r afproev_31 . xml . . .<br />
Der e r en f e j l i afproev_31 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>b<br />
b−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
Programmet a f s l u t t e s<br />
F.32 Afprøvning 32<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens r-værdi skal være mindre end 256.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_32 . xml . . .<br />
Der e r en f e j l i afproev_32 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>r<br />
r−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
Programmet a f s l u t t e s<br />
F.33 Afprøvning 33<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens g-værdi skal være mindre end 256.<br />
100
Faktisk uddata<br />
I n d l æ s e r afproev_33 . xml . . .<br />
Der e r en f e j l i afproev_33 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>g<br />
g−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
Programmet a f s l u t t e s<br />
F.34 Afprøvning 34<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens b-værdi skal være mindre end 256.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_34 . xml . . .<br />
Der e r en f e j l i afproev_34 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>b<br />
b−værdien s k a l være i i n t e r v a l l e t [ 0 ; 2 5 5 ]<br />
Programmet a f s l u t t e s<br />
F.35 Afprøvning 35<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at farvens g-værdi skal angives.<br />
101
Faktisk uddata<br />
I n d l æ s e r afproev_35 . xml . . .<br />
Der e r en f e j l i afproev_35 . xml:<br />
( s c e n e)−> s o l ( s o l )−>f a r v e −>g<br />
En g−værdi s k a l a n g i v e s f o r f a r v e n<br />
Programmet a f s l u t t e s<br />
F.36 Afprøvning 36<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_trekanter skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_36 . xml . . .<br />
Der e r en f e j l i afproev_36 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r)−>a n t a l _ t r e k a n t e r<br />
A n t a l l e t a f t r e k a n t e r s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.37 Afprøvning 37<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
102
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_trekanter skal være et heltal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_37 . xml . . .<br />
Der e r en f e j l i afproev_37 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r)−>a n t a l _ t r e k a n t e r<br />
A n t a l l e t a f t r e k a n t e r s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.38 Afprøvning 38<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_trekanter skal være større end eller lig nul.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_38 . xml . . .<br />
Der e r en f e j l i afproev_38 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r)−>a n t a l _ t r e k a n t e r<br />
A n t a l l e t a f t r e k a n t e r kan i k k e være n e g a t i v t<br />
Programmet a f s l u t t e s<br />
F.39 Afprøvning 39<br />
Inddata<br />
103
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_trekanter skal passe med antallet af trekant-tags.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_39 . xml . . .<br />
Der e r en f e j l i afproev_39 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r)−>a n t a l _ t r e k a n t e r<br />
A n t a l l e t a f t r e k a n t e r s k a l matche a n t a l _ t r e k a n t e r<br />
Programmet a f s l u t t e s<br />
F.40 Afprøvning 40<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_trekanter skal angives.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_40 . xml . . .<br />
104
Der e r en f e j l i afproev_40 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r)−>a n t a l _ t r e k a n t e r<br />
A n t a l l e t a f t r e k a n t e r s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
F.41 Afprøvning 41<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at trekantens punkter skal være forskellige.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_41 . xml . . .<br />
Der e r en f e j l i afproev_41 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r )−>1. ( t r e k a n t )−>( t r e k a n t )<br />
Trekanter må i k k e have to ens punkter<br />
Programmet a f s l u t t e s<br />
F.42 Afprøvning 42<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
105
Forventet uddata<br />
En fejlmeddelelse om at trekantens 3. punkt skal angives.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_42 . xml . . .<br />
Der e r en f e j l i afproev_42 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>( t r e k a n t e r )−>1. ( t r e k a n t )−>( t r e k a n t)−>p3<br />
Punktet s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
F.43 Afprøvning 43<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_punkter skal være et tal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_43 . xml . . .<br />
Der e r en f e j l i afproev_43 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>(punkter)−>antal_punkter<br />
A n t a l l e t a f punkter s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.44 Afprøvning 44<br />
Inddata<br />
106
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_punkter skal være et heltal.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_44 . xml . . .<br />
Der e r en f e j l i afproev_44 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>(punkter)−>antal_punkter<br />
A n t a l l e t a f punkter s k a l være e t h e l t a l<br />
Programmet a f s l u t t e s<br />
F.45 Afprøvning 45<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_punkter skal være større end eller lig nul.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_45 . xml . . .<br />
Der e r en f e j l i afproev_45 . xml:<br />
107
( s c e n e)−>mesh1 ( mesh)−>(punkter)−>antal_punkter<br />
A n t a l l e t a f punkter kan i k k e være n e g a t i v t<br />
Programmet a f s l u t t e s<br />
F.46 Afprøvning 46<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_punkter skal passe med antallet af punkt-tags.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_46 . xml . . .<br />
Der e r en f e j l i afproev_46 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>(punkter)−>antal_punkter<br />
A n t a l l e t a f punkter s k a l matche antal_punkter<br />
Programmet a f s l u t t e s<br />
F.47 Afprøvning 47<br />
Inddata<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
108
<br />
<br />
Forventet uddata<br />
En fejlmeddelelse om at antal_punkter skal angives.<br />
Faktisk uddata<br />
I n d l æ s e r afproev_47 . xml . . .<br />
Der e r en f e j l i afproev_47 . xml:<br />
( s c e n e)−>mesh1 ( mesh)−>(punkter)−>antal_punkter<br />
A n t a l l e t a f punkter s k a l a n g i v e s<br />
Programmet a f s l u t t e s<br />
109