28.07.2013 Views

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

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!