Dennis
De artificiële robot,in een
gesimuleerde wereld.
Project : Struktuur van
computerprogramma's II
Naam : Van Belle Werner
Rolnummer : 47091
2e Kandidatuur
Computerwetenschappen
e-mail : we47091@is1.vub.ac.be
Inhoudsopgave.............................................................................................................
1
Verslag....................................................................................................................................
3
Features.......................................................................................................................
4
Interface......................................................................................................................
4
Hoe een robot
creëren ?...................................................................................
4
Interface tot de
componenten............................................................................
6
Programma's....................................................................................................
6
Error-meldingen................................................................................................
7
De implementatie.......................................................................................................... 8
Basis adt's........................................................................................................ 8
Subworld.......................................................................................................... 9
World.............................................................................................................. 9
Untouchable world............................................................................................ 9
Componenten...................................................................................................
9
Hoe beweegt een
component/robot nu ?.............................................................
11
Mogelijke
verbeteringen................................................................................................
12
Tijdschema...................................................................................................................
13
Source.....................................................................................................................................
14
Inleiding.......................................................................................................................
15
Abstracte
definities wiskundige objecten, lijnen, punten, grafische set's............................. 16
Algemeen........................................................................................................
16
Hoeken............................................................................................................
17
Punten.............................................................................................................
18
Interval............................................................................................................
21
Lijnen..............................................................................................................
23
Cirkels.............................................................................................................
35
Nulpunten........................................................................................................
40
Open grafische
verzamelingen...........................................................................
41
Gesloten grafische
verzamelingen......................................................................
50
Intersecties......................................................................................................
54
De Werelden................................................................................................................
55
Set's................................................................................................................ 55
The untouchable world...................................................................................... 58
The global world............................................................................................... 59
The sub-worlds................................................................................................. 60
De robots en de
componenten.......................................................................................
64
Robot-drawings................................................................................................
64
Terminale
componenten (pen/boor/null)..............................................................
65
Arm-component...............................................................................................
69
Scharnier-component........................................................................................
75
De Robot-root..................................................................................................
80
User interface..............................................................................................................
84
Transcript-window/file......................................................................................
84
Grafisch scherm...............................................................................................
87
Error's............................................................................................................. 89
Programma's.................................................................................................... 89
Demos............................................................................................................. 93
Main................................................................................................................
95
Verloren
Werk/Voorwerpen..........................................................................................
97
Breuken...........................................................................................................
97
Oorspronkelijke
Grenzen...................................................................................
102
Oorspronkelijk
Interval......................................................................................
104
Het T-stuk.......................................................................................................
107
Uitgevoerde tests..........................................................................................................
110
Robot02.scm....................................................................................................
110
Robot03.scm.................................................................................................... 112
Robot04.scm.................................................................................................... 115
Robot06.scm.................................................................................................... 118
Robot07.scm.................................................................................................... 121
Robot08.scm.................................................................................................... 123
Robot10.scm.................................................................................................... 125
Robot12.scm.................................................................................................... 125
Robot13.scm.................................................................................................... 126
Robot16.scm.................................................................................................... 127
Robot19.scm.................................................................................................... 127
In onderstaande
opgave staan de doelstellingen die bereikt zijn in het vet aangegeven.
Dit project
bestaat uit het ontwerp en
implementatie van een algemeen robotbesturings-programma. Het programma
moet
een willekeurige robot kunnen besturen die opgebouwd is uit volgende
componenten :
Vaste arm van willekeurige lengte
Uitschuifbare arm met minimum- en
maximumlengte
Rotatie-scharnier dat tussen twee armen
wordt geplaatst, met minimum en maximum rotatie-hoek.
Verplaatsbaar voetstuk
Verscheidene armuiteinden: boor, grijparm, trekijzer, pen
Om redenen
van eenvoud beperken we ons tot
twee-dimensionale bewegingen. Als output wordt een grafische weergave
in een
vlak verwacht. Verschillende grijparmen kunnen andere output genereren. Een
boor bijvoorbeeld genereert een puntje op de plaats waar hij boort.
Bijkomende
aspecten:
Ontdekken dat de robot zichzelf snijdt
Met meer dan één robot tegelijkertijd
werken (met ontdekken van snijden onderling)
Enkele voorgedefiniëerde
constructies voorzien die bestaan uit een compositie van de bestaande
componenten. Bijvoorbeeld een "kootjes-arm" bestaande uit vele kleine
dezelfde armpjes en dezelfde scharnieren die een boog (of andere
ingewikkelde
bewegingen) benaderen.
Demonstreer
het robotbesturingsprogramma door
enkele robots te configureren en iets te laten uitvoeren (bijvoorbeeld
een
vierkant tekenen en in het midden een gat boren).
Een robot wordt
opgebouwd als een boom, waarbij elke knoop zelf zorgt dat hij zijn
opvolgers
kent. Het is dus geen boom die als structuur over componenten wordt
gemapt. Het
zijn de componenten die een boomstructuur krijgen. Robots worden
gecreëerd door
een scheme-expressie in te typen. Bijvoorbeeld de robot
wordt informeel
als volgt gecreëerd.
robot-root:=
(make-robot
(make-arm1 ...
(make-arm2 ...
(make-arm3 ...
(make-arm4 ...
null-component)))))
Wat er in de
plaats van de "..." komt hangt van component tot component af.
Meestal zit hier een voethoek tussen
die aanduidt welke hoek de volgende component (child)altijd
moet vormen met de huidige component. Zo is het
mogelijk twee armen direct aan mekaar te sluiten onder een willekeurige
vaste
hoek zonder een scharnier te moeten gebruiken.
Componenten |
|
How to make ? |
Visualization |
make-normal-arm lengte voethoek child |
|
make-arm minimum maximum lengte voethoek child |
|
make-scharnier minimum maximum rotation voethoek child |
|
make-robot position voethoek child |
|
Actions available |
|
name & parameters |
action |
boor boor-component |
Boort een gat op de
huidige plaats. Het gat wordt voorgesteld door een rondje op de plaats
waar geboord werd. |
pen-color pen-component |
Verandert de kleur
van de meegegeven pen. De volgende keer dat een lijn moet getekend
worden zal dit in de nieuwe kleur gebeuren. |
pen-down pen-component |
Zet de pen op
papier. De eerst volgende keer dat de pen wordt verplaatst.
Bijvoorbeeld door een armbeweging of door het verplaatsen van de robot
zal er een lijn in kleur color getekend worden. (color is gedefinieerd bij het creëeren van de pen) |
pen-up pen-component |
Heft de pen op van
het papier zodat, als de robot in het vervolg beweegt, geen lijnen meer
worden getekend. |
arm-length who angle |
Verandert de lengte
van de meegegeven arm. Who mag ofwel een vaste arm
zijn, ofwel een variabele arm. Bij het veranderen van de armlengte
wordt gecontroleerd of de robot zichzelf niet snijdt, nadien wordt
gecontroleerd of de globale wereld niet om zeep wordt geholpen. |
rotate who angle |
Verandert de hoek
van who, indien hiermee niet gezondigd wordt tegen de
minimum/maximum hoeken. Bij deze operatie worden geen[1] interne, noch externe snijdingen gecontroleerd. |
rel-move who speedx speedy |
Deze routine zorgt
dat de robot over (x,y) verplaatst. Hierbij worden
botsingen met andere robot's gecontroleerd. De meegegeven paramater who moet een robot-root zijn. Indien niet zal er een
error optreden. |
Het is normaal
dat een robot aangestuurd wordt door programma's. In deze implementatie
heb ik
gekozen voor scheme-programma's omdat die zeer expressief zijn,
recursie
aankunnen en voldoende abstractie toelaten. Een programma wordt
voorgesteld
door een lijst van commando's en instructies. Op het ogenblik dat een
error
ontstaat wordt het programma onderbroken om de error te laten zien,
nadien kan
verder gewerkt/gespeeld worden. Indien het programma de error
onderschept en
zelf oplost is hier natuurlijk geen enkel probleem en zal de loop van
het
programma niet onderbroken worden. Onderstaand voorbeeld is één van de
demo's.
(define
program2 '(
(define ralf-arm4 (make-arm 10 200 50
PI/2 null-component))
(define ralf-arm3 (make-arm 10 200 20
PI/2 ralf-arm4))
(define ralf-arm2 (make-arm 10 200 80
PI/2 ralf-arm3))
(define ralf-arm1 (make-arm 10 200 70
PI/2 ralf-arm2))
(define ralf-voet (make-robot
(make-point 150 30) PI/2 ralf-arm1))
(arm-length ralf-arm4 70)
(arm-length ralf-arm4 90)
(arm-length ralf-arm4 110)
(arm-length ralf-arm3 100)
(arm-length ralf-arm2 200)
(arm-length ralf-arm3 100)
(arm-length ralf-arm2 80)
(arm-length ralf-arm4 100)
(arm-length ralf-arm1 100)
))
(loop-program
program2)
Een error-melding
bestaat uit 2 delen, een numerieke representatie en een
string-representatie.
Dit is een beetje zoals de BGI waarbij je voor elke error een
bijpassende
string kan opvragen. Om te controleren of het resultaat een error is
kan je de
procedure error? gebruiken, om de
getal-waarde dan op te vragen gebruik je error-info
en om de textuele representatie te bemachtigen smeek je om error-text.
Mogelijke error-meldingen zijn :
Error-meldingen |
||
value |
textueel |
meaning |
'glue |
"robot-lussen" |
Je probeert één
component in 2 robot's te gebruiken. Of 1 component 2 vaders te geven. |
'sub |
"intersecting sub-world" |
De gevraagde actie
kan niet worden uitgevoerd omdat de robot's sub-world anders gestoord
wordt. M.a.w de robot zal zichzelf snijden. |
'glob |
"intersecting global world" |
De gevraagde actie
zal aanleiding geven tot snijdingen met andere robots. |
'arminit |
"impossible arm-value" |
Je wil een arm
initialiseren met akelig foute waarden. Bijvoorbeeld een
minimum-armlengte die groter is dan de maximumlengte. Of een
init-lengte die niet in [min,max] ligt |
'length |
"invalid length" |
Je hebt arm-length
opgeroepen en getracht een nieuwe waarde in te stellen die
groter is dan de maximumlengte (of keiner dan de minimumlengte) |
'rotinit |
"impossible rot-value" |
Het scharnier moet
een hoek meekrijgen tussen minangle en maxangle.
Ook moet minangle<maxangle. |
'rot |
"invalid angle" |
Rotate geeft deze error weer indien de gevraagde hoek
buiten het interval [minangle,maxangle]
valt. |
Het programma
maakt gebruik van een heel stel basis-adts. Meestal zijn dit abstracte
definities van grafische objecten met een verzameling operatoren op
gedefinieerd. Hieronder staan deze adt's snel bij elkaar geraapt.
Altijd weerkerend operaties |
|
name & parameters |
action |
x-int; y-int |
Geeft het
x/y-interval weer waarop het grafische object gedefinieerd is. |
type-number |
Elk grafisch object
heeft zijn eigen type-number zodat het berekenen van intersecties zeer
eenvoudig kan verlopen. |
display |
Deze functie vraagt
aan het object zichzelf af te printen in het trace venster door gebruik
te maken van de functie message. |
show-point color |
Vraagt het object
zichzelf zichtbaar te maken op een grafische wijze, waarbij gebruik
wordt gemaakt van de standaard PCS-BGI routines. Color bepaalt
de kleur waarin het object moet getekend worden. Als hier 'ownstyle
wordt meegegeven duidt dit aan dat er een zekere "standaardkleur"
gebruikt moet worden. |
translate vct |
Copieert self en verplaatst het resultaat over een afstand vct. |
translate-sleep vct |
Verplaatst self over een afstand vct. Hierbij wordt
een nieuw object gecreëerd, dat niet noodzakelijk van hetzelfde type
is. Een punt verslepen geeft bijvoorbeeld een lijn. |
rotate around angle |
Roteert self
over een hoek angle waarbij het centrum in around
gelegen is. Hierbij wordt een nieuw object gecreëerd. |
rotate-sleep around angle |
Roteert en sleept self. Hierbij wordt een nieuw object weergegeven dat niet
noodzakelijk van hetzelfde type is. Een punt rotate-sleep-en
bijvoorbeeld zal aanleiding geven tot een cirkelboog. |
punt-op? p |
Geeft weer of p op het grafische object ligt. Het is duidelijk
dat dit voor een open grafische verzameling anders is dan voor een
gesloten grafische verzameling. |
nulpunten@horizon horizon |
Geeft als resultaat
een gesorteerde lijst naar buiten van nulpunten. Deze operatie is nodig
om nadien te kunnen controleren of een punt in een gesloten kromme valt. |
Points
hebben niet veel speciaals voor de rest. Je kan hun x,y coordinaat
opvragen en
op het ogenblik dat ze aangemaakt worden, worden ze geconverteerd naar
een
grid.
Lines tussen twee verschillende punten. Operaties hierop zijn from-p; to-p, from-x; from-y; to-x; to-y; dx; dy; dx/dy; dy/dx; horizontal?; vertikal?; fast-poin-op?; point-in-range?; x@y; y@x.
Circles bestaande uit een middelpunt, straal, een from-angle en een to-angle. Operaties hierop zijn : radius; center; from-angle; to-angle; center-x; center-y; angle-of; point@angle; fast-point-op?
Een open grafische verzameling, graphset genaamd. Operaties zijn punt-in?; empty?; singleton; %replace; recalc-bounds; info; set-info!; foreach; copy; add!
Een
gesloten grafische verzameling is exactly een open grafische
verzameling met
het enige verschil dat de punt-op?
herschreven is.
De
subworld/subwereld is de omgeving waarin één robot leeft. Een subwereld
bestaat
uit een verzameling tekeningen geassocieerd met de bijhorende
componenten. De
subwereld kan zelf controleren of er ongewenste snijdingen optreden.
Dit is
enigzins normaal omdat men zo een mooi symmetrische oplossing
verkrijgt. Ik kon
evengoed de subwereld gewoon de verzameling van tekeningen/robots laten
zijn
zonder meer. Een soort dictionary without brains, maar de vraag is dan
:
"wie moet de snijdingen controleren ?". Moet de component die iets
wil doen zijn eigen snijdingen controleren. Nee want dit is net een
iets te
laag niveau. Met de oplossing die ik heb gekozen heb je een soort
supervisie
vanuit de subwereld over de robot. Al hetgeen nodig is om snijdingen te
controleren
is aanwezig. Terwijl je met een implementatie in de robots veel
rompslomp zou
krijgen van "dikmakende" data-members.
De world/wereld
is de verzameling van
robot-werelden, subworlds die in evenwicht zijn. Met in evenwicht zijn
bedoel
ik dat er geen interne snijdingen voorkomen. De wereld is in staat om
een
gegeven grafisch object te snijden met al de subwerelden (bijvoorbeeld
: een
sleeppad). Zo kan naderhand gecontroleerd worden of er geen globale
snijdingen
voorkomen.
The untouchable
world is de wereld waarbij
gewoon grafische objecten worden onthouden zonder dat deze enige
invloed hebben
op het gedrag van de robots. Hier worden lijnen/cirkels samen met hun
kleur
onthouden. Een robot kan dus "door" de tekeningen lopen zonder daar
enige
hinder van te ondervinden.
Een component kan
zijn : Vaste arm, Beweegbare arm, Robot-voet, Scharnier, Terminals
Waarbij de terminals de armuiteinde vormen, ttz : Pen, Boor, Null
Van een component
wordt verwacht dat hij in staat is te zeggen met wie hij altijd
verbonden is zodat de subworld kan opzoeken welke snijdingen relevant
zijn en
welke niet. Een arm bijvoorbeeld zal altijd snijden met zijn child-arm, daarom is deze snijding
verwaarloosbaar.
Componenten
moeten ook in staat zijn een sleeppad weer te geven van wat er gaat
gebeuren.
Op onderstaande tekening staat gedemonstreerd wat met een sleeppad
bedoelt
wordt.
Voor de rest
controleert de component nog of hetgeen hem gevraagd wordt wel een
uitvoerbare
eis is. Bijvoorbeeld een negatieve armlengte zal meestal niet goed
gekeurd
worden.
Berichten voor alle componenten |
|
name & parameters |
action |
set-sub-world! to |
Wordt opgeroepen
als de sub-world van de robot verandert. |
set-drawing! to |
Wordt opgeroepen
als de tekening van de component veranderd is. |
glue father |
Lijmt componenten
aaneen zodat ze een tree vormen. Indien father reeds gekend was wordt
#f weergegeven. (dit wil dus zeggen dat de component reeds in gebruik
was). De glue message wordt doorgegeven aan de
kinderen. |
unglue |
Zorgt dat de vader
niet meer gekend is. Deze routine dient opgeroepen te worden als de
creatie van de robot mislukt is, zodat de componenten in een nieuwe
robot gebruikt kunnen worden |
sign-in-world sw pos angle |
Na het aaneen glue-en van de componenten moet ook een subwereld
gecreëerd worden. Dit wordt met deze message gedaan. Sw
is de subworld waarin het resultaat moet komen, pos is
de positie van de component, angle is de hoek die de
component zal vormen. |
change-translate-world! result-in howmuch |
Vraagt de component
of hij zichzelf eens denkbeeldig wil verplaatsen over afstand howmuch. Hierbij wordt verwacht dat in result-in de oude tekening van de component wordt
vervangen door een nieuwe. |
add-translate-sleeppad! result-in howmuch |
Vraagt de component
of hij het sleeppad ten gevolge van een translate over howmuch
wil vervolledigen in result-in |
translate-action naar |
Vertelt de
component dat al de checks voor een translatie positief waren en dat de
translatie over naar uitgevoerd mag worden. Hierbij
wordt niet verwacht dat de tekeningen en de subworlds ge-update worden.
Deze zijn reeds veranderd. Deze routine zorgt gewoon dat een component
zijn nieuwe positie kan bijhouden |
change-rotate-world! result-in around howmuch |
Vraagt aan de
component of hij zichzelf eens denkbeeldig wil roteren rond around
bij een hoek van howmuch. Hierbij dient de oude
tekening van de component die aanwezig is in result-in
vervangen worden door een nieuwe tekening. |
rotate-action around angle |
Net zoals bij translate-action laat dit bericht toe dat de component
zijn posities en hoeken up to date blijven. |
Always-connected-to |
Dit bericht vraagt
de component of hij eens een lijst wil naar buiten geven met wie hij
altijd verbonden zal zijn. Dit is om vanzelfsprekende snijdingen op
voorhand weg te filteren en zelf niet meer te controleren. |
Waarom er voor
een translatie 3 berichten nodig zijn (change-translate-world!,
add-translate-sleeppad!, translate-action) zal duidelijk worden in
het
volgende kapittel :
De component weet
wat hij wil doen, maar vraagt aan een andere routine om deze taak tot
uitvoering te brengen. Deze routine heeft de, toch wel
vanzelfsprekende, naam want-to-act en zorgt voor een
zeer grote
leesbaarheid van de geïmplementeerde acties.
In : function get-sub-world,
function get-sleep-pad, function act
Out : error-melding/#t
Comments : Met de functie get-sub-world
mag de component een voorstel doen om een nieuwe subwereld te creëren
voor de
robot. Als de voorstel-subwereld intact is moet de caller een sleep-pad
opdissen zodat gecontroleerd kan worden of dit sleeppad tegen niets
onaangenaams knalt. Indien wel wordt een error naar buiten geworpen.
Indien ook
hier geen problemen waren mag de robot in actie treden door act
op te roepen.
Van act wordt niet verwacht
dat hij de oude componenten gaat verplaatsen in de nieuwe wereld. Deze
berekening is al eens gedaan en moet niet herdaan worden. Gewoon de
component-positions/angles moeten hierbij aangepast worden. Als act ten uitvoer wordt gebracht is de
nieuwe wereld reeds actief.
Ik heb het algoritme hieronder laten staan omdat het een zeer
representatief
stuk code is voor het gehele programma.
(define
(want-to-act get-sub-world get-sleep-pad act)
(let
((new-sub-world
(get-sub-world)))
(if
(new-sub-world 'disturbed?)
(begin
((new-sub-world 'redraw)
'red)
(make-error 'sub
"intersecting sub-world"))
(begin
(if sub-world ((world
'unregister) sub-world))
(let* ((sleeppad
(get-sleep-pad new-sub-world)))
(if ((world
'disturbs-with?) sleeppad (fast-set))
(begin
(if sub-world
((world 'register) sub-world))
((sleeppad
'show) 'red)
((new-sub-world
'redraw) 'light-red)
(make-error 'glob
"intersecting global world"))
(begin
(new-sub-world
'wring-er-tussen)
(act))))))))
Ik had de
intentie om de rotatie-operator in volle glorie te implementeren zodat
het
draaien van een scharnier tot geen onmogelijke situaties meer zou
leiden. Maar
bij gebrek aan PCS-cell-geheugen heb ik dit niet tot uitvoering kunnen
brengen.
Om mezelf toch een beetje te verdedigen en aan te tonen dat ik de
nodige
funderingen al had aangebracht beschrijf ik nu even wat er aan het
programma
zou moeten veranderen.
Voornamelijk
zorgen dat de Nulpunten@horizon
gedefinieerd wordt voor een cirkel. Dit is niet moeilijk maar nog niet
gedaan.
De
huidige rotatie-actie vervangen door de want-to-act
function (zonder aan want-to-act iets
te moeten aanpassen !)
Een ander
spaaklopend element van dit programma is ongetwijfeld zijn snelheid. Ik
heb
hier en daar al kleine optimisaties in gestoken omdat ik het anders
helemaal
niet meer kon testen, maar een paar
-altijd van gedroomd, maar nooit geïmplementeerde- optimisaties
staan
hieronder vermeld :
Om
grafische objecten te snijden wordt eerst rap uitgezocht of de
omvattende
vierhoeken niet snijden (xint/yint).
Als deze rechthoeken echt groot worden, wordt hier geen winst meer aan
gedaan
en zou ik beter op 6-hoeken gaan controleren. Dit zou zeker een
optimisatie
zijn daar waar een robot een grote move wil uitvoeren. (het sleeppad
zorgt dat
de rechthoek absurd groot word)
Ik
gebruik nog steeds list-dispatchers in plaats van vector-dispatchers.
Als ik
deze zou veranderen zou er een zeer grote snelheidswinst geboekt
worden. Maar
aangezien dit het werk van een compiler is heb ik me met deze
tijdverspilling
niet bezig gehouden.
En
dan natuurlijk nog de optimisaties afhankelijk van de omgeving waarin
ik werk :
Ik zou bijvoorbeeld al de variable-namen kunnen vervangen door 3
letters in
plaats van betekenisvolle woorden. Dit is natuurlijk één van de
lelijkste
(desalniettemin, wel performante) optimisaties die ik me kan inbeelden.
Vooral
het gebrek aan leesbaarheid zal nadien verschrikkelijk zijn.
Al
de verzamelingen die in het programma voorkomen zijn geïmplementeerd
met
lijsten. Dit zou veel sneller gaan als ik dubbelgelinkte lijsten zou
gebruiken.
Waarom ik het niet gedaan heb ? Natuurlijk omdat de code dan helemaal
niet meer
mooi/proper is. Als ik een dubbelgelinkte lijst gebruik moet elk object
dat ik
in de lijst bijhoud een fieldje bezitten dat vermeld in welke lijst hij
zit.
Dit fieldje zou dan de prev en next-pointer bevatten. Deze strategie
heb ik
vorig jaar in mijn project GMC toegepast (met veel succes) maar dit
jaar heb ik
geopteerd voor leesbare code waar geen extra -ik weet niet van waar-
fields in
voorkomen. Merk op dat de voorzieningen voor zo'n dubbel gelinkte lijst
al
aanwezig zijn. Graph-set's bevatten reeds een info-field. De
implementatie van
een dubbelgelinkte lijst verandert/verwijdert/voegt toe in O(1).
Het
hertekenen van het scherm op een slimme manier laten gebeuren. Als nu
een robot
verplaatst wordt, wordt het scherm volledig leeg gemaakt en dan alles
hertekend. Het is ook mogelijk de oude subwereld weg te tekenen en dan
de
nieuwe subwereld te tekenen.
Met nog iets meer verstand wordt eerst de oude subwereld verwijderd,
dan de
nieuwe getekend en uiteindelijk al de subwerelden die sneden met oude
ook nog
eens hertekend zodat 'domme zwarte' puntjes niet meer voorkomen.
Toegegeven :
deze laatste gaat veel code in beslag nemen en weinig zin hebben, des
te meer
omdat over de robot's gewaakt wordt zodat ze niet meer snijden.
De interface tot
de robot zou ik liever uitgebreider zien. Mogelijkheden hiertoe zijn
Als
een snijdings-error optreedt ook terug geven tegen wie gelopen wordt.
De
interface tot de wereld algemenere toegankelijker maken zodat
standaardobjecten
toegevoegd kunnen worden. (bijvoorbeeld een tafel die steeds aanwezig
is).
Hetgeen daarvoor nu gedaan moet worden is de init-world
aanroepen en nadien ((global-world
'register) my-table)
Een
meer layer-achtig scherm gebruiken waarbij je objecten op de voorgrond
hebt en
objecten op de achtergrond. Bijvoorbeeld een untouchable-world die voor
de
touchable world ligt en een untouchable world die achter de robots ligt.
Het
zou ook mogelijk zijn dit project om te vormen tot 3D. Het enige
dat
daarvoor aangepast moet worden is de definitie van de grafische
objecten en de
definitie van de snijdingen. Dit zal natuurlijk niet zo gemakkelijk
zijn.
Ook
een toffe mogelijkheid zou het toevoegen van eigen componenten zijn.
Dit is nu
mogelijk met goede kennis van zaken, maar anders ook niet. Je moet
weten op
welke berichten een component allemaal moet reageren. Maar aangezien
dit een
algoritmische bezigheid is kan het in een procedure create-component-maker
gestoken worden. Om een voorbeeld te hebben
wat ik bedoel kan je eens kijken naar de functie create-terminal.
17-03-95
Final
version afgeprint. (Met speciale dank aan Marc Van Limberghen die deze
tekst
grondig onderzocht heeft)
23-02-95
Afwerking
verslag en documenteren source.
17-02-95
Gauw
oude source door nieuwe source gemixt om verse source te krijgen die de
rotatie
kan uitvoeren. De opdracht nagelezen en de laatste hand gelegd aan het
programma.
10-02-95
De
pen samen met de untouchable world toegevoegd.
09-02-95
De
arm kan resizen met het testen van snijdingen
08-02-95
Een
optimisatie toevoegen zodat ik weer verder kan testen (x-int/y-int)
03-02-95
De
robot kan zichzelf volledig verplaatsen.
08-01-95
De
robot kan al gedefinieerd worden, alleen worden nog geen snijdingen
gecontroleerd.
Voor de rest werken de abstracte grafische objecten l volledig.
24-12-95
Gestart
met implementeren.
Onderstaande
source is grondig gedocumenteerd. Bij elke functie staat de invoer,
uitvoer en
eventuele comments vooraf vermeld. De source was oorspronkelijk
gedocumenteerd
in een soort 'project-farde' waarin gewoon alles
sequentieel bijgehouden werd. Door deze techniek toe te passen ben ik
in staat
geweest al de testen die ik uitgevoerd heb in de source aan te geven.
De documentatie
is als volgt
In : <type> parameter1, <type> parameter2
Out : <type>, <betekenis>
Comments : ...
(define (.... parameter1 parameter2)
...)
De gebruikte
types zijn
Angle
: een reëel getal dat een hoek voorstelt. Uitgedrukt in radialen.
(tussen 0 en )
Bool
: booleaanse waarde : #t of #f
Circle : een cirkel-segment, gecreëerd door make-circle
Color : kan black, blue, red, green, white, grey, dark-grey, 'light-grey, light-blue, light-green, cyan, magenta, yellow... zijn.
Cons-cel
: enkelvoudige cons-cel
Error
: een resultaat aangemaakt met make-error
Grens
: een reëel getal. Oorspronkelijk was het de bedoeling dat een grens
ook een
open/gesloten parameter meekreeg.
Interval
: een interval bestaande uit twee reële getallen.
Line
: het type line (zie line)
Nothing
: is een type dat steeds wordt weergegeven. dit wil zeggen dat het
resultaat
totaal geen belang heeft.
Open-graph-set : zie (open-graph-set)
Point :
het type point. (zie point)
Real
: een reëel getal van scheme
Something
: een parameter waarvan het type niet gekend is krijgt het type
something
toegewezn.
Terminal
: Een armuiteinde. Meestal worden deze gemaakt met create-terminal
Vaak wordt self
vermeld. Dit is de verwijzing naar
de huidige dispatcher waarmee gewerkt wordt. Soms wordt een functie
voorafgegaan door een %-teken. Bijvoorbeeld %makeb.
Dit %-teken toont aan dat de functie wel globaal gedefinieerd is maar
dat ze
best door een beperkt aantal functies aangeroepen wordt. Soms slaat het
%-teken
ook op een onverwacht gedrag van de functie.
Welke functies
heb ik buiten hun -closure gebracht ?
Functies
die symmetrisch werken op 2 objecten : =p,
intersect-p-p?, ...
Identificerende
functies :
point?, line?, ...
Al
de intersectie-functies omdat deze werken op twee objecten en dus als
het waren
evenveel data van het ene object als het andere nodig hebben. Een soort
symmetrie dus : intersect-l-p?,
intersect-l-l
In : point p1, point p2
Out : real, de afstand tussen p1 en p2 volgens de Euclidische Metriek.
Comments :
(define (euclid p1 p2)
(sqrt (+ (sqr (- (p1 'x) (p2 'x)))
(sqr (- (p1 'y) (p2 'y))))))
In : bool a, bool b
Out : real, a xor b
(define (xor a b)
;non-lazy
(or (and (not a) b)
(and a (not b))))
In : real a
Out : real,
(define (sqr a)
(* a a))
In : real a, real b, real c
Out : cons-cel, oplossing van de vierkantsvergelijking
Comments : indien de vkv geen oplossingen heeft wordt een
'(#f.#f) weergegeven,
indien ze slechts één oplossing heeft een '(x.#f) en als ze twee
oplossingen
heeft
(define (solve-vkv a b c)
(let ((D (- (sqr b) (* 4 a c))))
(cond ((< D 0) (cons #f
#f))
((=
D 0) (cons (/ (- b) (* 2
a)) #f))
(else
(cons (/ (- (- b) (sqrt
D)) (* 2 a))
(/ (- (sqrt
D) b) (* 2 a)))))))
Definitie van vaak
gebruikte constanten.
(define PI/2 (/ PI 2))
(define 3PI/2 (/ (* PI 3) 2))
(define 2PI (* PI 2))
Definitie van de
type-nummers. Deze nummers zijn nodig om nadien de snijding tussen twee
'onbekende' objecten te kunnen dirigeren.
(define point-id 1)
(define line-id 2)
(define circle-id 3)
(define graph-set-id 4)
(define closed-graph-set-id 5)
De grid is de resolutie
waarmee het programma werkt. Indien de resolutie te groot is zullen er
underflows en overflows optreden.
(define GRID 0.01)
De berekeningen
met hoeken worden hier behandeld. Deze zijn nodig om nadien rotaties te
kunnen
uitvoeren en ook in geringe mate om de verschillen in Bgcos/Bgsin van
de ene
scheme-implementatie naar de andere op te heffen.
In : point center, real radius, angle angle
Out : point result, dat op afstand radius van center ligt en waarbij de
halfrechte [center,result> een hoek angle
vormt met de horitzontale.
(define (realize-angle center radius
angle)
(make-point
(+ (center 'x) (* radius (cos
angle)))
(+ (center 'y) (* radius (sin
angle)))))
In : point center, point p
Out : point result, bepaalt de hoek
tussen de horizontale en de halfrechte [center,p>
(define (angle-of center p)
(let ((dx (- (p 'x) (center 'x)))
(dy
(- (p 'y) (center 'y))))
(cond ((> dx 0)
(cond ((> dy 0) (atan (/
dy dx)))
((= dy 0) 0)
(else (- 2PI (atan (/
(- dy) dx))))))
((=
dx 0)
(cond ((> dy 0) PI/2)
((= dy 0) (error
"Can't find angle..."))
(else 3PI/2)))
(else
(cond ((> dy 0) (- PI
(atan (/ dy (- dx)))))
((=
dy 0) PI)
(else (+ PI (atan (/
dy dx)))))))))
Points |
|
name & parameters |
action |
make-point x y |
Creëert een punt
met coordinaten x en y. Het punt wordt vanzelf geconverteerd naar een
grid. (met resolutie GRID) |
x; y |
Vraagt de
x-coordinaat/y-coordinaat van het punt op. |
(define (make-point x y)
In : nothing
Out : nothing
Comments : print self af onder de vorm
"(x,y)"
(define
(display-point)
(message "(" x
"," y ")"))
In : color color
Out : nothing
Comments : tekend self met kleur color, indien color 'ownstyle is wordt de std-point-color gebruikt.
(define
(show-point color)
(put-pixel point (if (eq?
color
'ownstyle) std-point-color color)))
In : point vct
Out : point r
Comments : r is het resultaat na self te verplaatsen over een afstand vct
(define
(translate vct)
(make-point (+ x (vct 'x)) (+
y (vct
'y))))
In : point around, angle angle
Out : point r
Comments : r is het beeld van self
door de rotatie-operatie met
fixpunt around en hoek angle
(define (rotate
around angle)
(if (and (= x (around 'x)) (=
y
(around 'y)))
(make-point
x y)
(let*
((dist (euclid around
point))
(angle-before (angle-of
around point)))
(realize-angle
around dist (+
angle-before angle)))))
In : point howmuch
Out : line r
Comments : r is het lijnstuk dat ontstaat
door self te verplaatsen over de
afstand howmuch.
(define
(translate-sleep howmuch)
(make-line point (translate
howmuch)))
In : point around, angle angle
Out : circle r
Comments : r is het cirkelsegment dat
ontstaat door self te roteren rond around
over een hoek angle
(define
(rotate-sleep around angle)
(if (and (= x (around 'x)) (=
y
(around 'y)))
(make-point
x y)
(let*
((dist (euclid around
point))
(angle-before (angle-of
around point)))
(make-circle
around dist
angle-before (+ angle-before angle)))))
Dispatcher point-self
(define
(point m)
(cond ((eq? m 'x) x)
((eq?
m 'y) y)
((eq?
m 'x-int) (make-interval
x x))
((eq?
m 'y-int) (make-interval
y y))
((eq?
m 'display)
(display-point))
((eq?
m 'type-number)
point-id)
((eq?
m 'show) show-point)
((eq?
m 'rotate) rotate)
((eq?
m 'translate) translate)
((eq?
m 'translate-sleep)
translate-sleep)
((eq?
m 'rotate-sleep)
rotate-sleep)
(else
(error "unkown
message - POINT" m))))
Initialisatie
Hier worden de
coordinaten omgezet naar de grid zodat er geen underflows/overflows
worden
gegenereerd.
Uiteindelijk wordt self weergegevn
(set! x (* GRID
(round (/ x GRID))))
(set! y (* GRID (round (/ y GRID))))
point)
In : something p
Out : bool
Comments : geeft #t weer indien p een
punt is, geeft #f weer indien p geen
punt is.[2]
(define (point? p)
(eq? (p 'type-number) point-id))
In : point p1, point p2
Out : bool
Comments : Geeft weer of
(define (=p p1 p2)
(and (= (p1 'x) (p2 'x))
(= (p1 'y)
(p2 'y))))
In : point p1, point p2
Out : open-graph-set r
Comments : Deze functie controleert of p1
en p2 samen vallen, dus snijden, en
geeft dan het resultaat van de snijding in de vorm van een
open-graph-set weer.
(define (Intersect-p-p p1 p2)
(if (=p p1 p2)
(graph-set p1)
(graph-set)))
Een interval
wordt gebruikt in alle eindige strukturen die zowel een beginpunt als
een
eindpunt hebben. Oorspronkelijk was deze gedefinieerd zodat het type
grens kon
meegegeven worden. (Open of gesloten). Ik heb deze mogelijkheid
verwijderd
zodat het programma sneller draait. De oorspronkelijke definitie van
een
interval volgt een beetje later.
In : grens from-grens, grens to-grens
Out : interval r
Comments : Het ADT Interval is gedefinieerd als een
struktuur met een verzameling
operaties. Door deze niet als een lambda te definieren maak ik een
forse
geheugenwinst en verbetering in berekenings-snelheid.
Zowel de from-grens als de to-grens behoren beiden tot het interval.
Dus
volledig gesloten.
(define (make-interval from-grens
to-grens)
(cons from-grens to-grens))
In : interval interval
Out : grens from-grens van interval interval
(define (from-grens interval)
(car interval))
In : interval interval
Out : grens to-grens van interval interval
(define (to-grens interval)
(cdr interval))
In : interval i
Out : bool b
Comments : Indien het meegegeven interval slechts uit één
punt bestaat wordt #t
weergegeven, in het andere geval wordt #f geretourneerd.
(define (punt-interval? i)
(= (from-grens i) (to-grens i)))
In : interval who
Out : nothing
Comments : print het interval af onder de vorm "[from,to]"
(define (display-interval who)
(message "[" (from-grens
who) "," (to-grens who) "]"))
In : interval interval
Out : interval r
Comments : r is het interval dat voldoet
aan de voorwaarde . Omdat dit
ADT enkel functioneel gebruikt kan worden moet er geen copie gemaakt
worden
indien het interval reeds geordend is.
(define
(orden-interval interval)
(if (> (from-grens interval)
(to-grens interval))
(make-interval
(to-grens interval)
(from-grens interval))
interval))
In : real p, interval CD
Out : bool r
Comments : indien p op het interval CD ligt zal #t worden weergegeven. #f in
het andere geval. Merk op dat CD als
gesloten interval beschouwd wordt.
(define (punt-op-interval?
p CD)
(set! CD
(orden-interval CD))
(and (>= p (from-grens CD))
(<= p
(to-grens CD))))
In : interval AB, interval CD
Out : interval result
Comments : deze functie maakt de snijding van twee
intervallen. Geen van beide moet
op voorand geordent zijn.
(define (intersect-interval AB CD)
(define (%intersect-interval A B C D)
(cond ((> A B)
(%intersect-interval B A C D))
((>
C D)
(%intersect-interval A B D C))
((<
C A)
(%intersect-interval C D A B))
((<=
D B) (make-interval C
D))
((<=
C B) (make-interval C
B))
((and
(= B C)) (make-interval
B B))
(else
#f)))
(%intersect-interval
(from-grens AB) (to-grens AB)
(from-grens CD) (to-grens
CD)))
Definitie van het
eenheidsinterval
(define I1 (make-interval 0 1))
Lines |
|
name & parameters |
action |
make-line from-p, to-p |
Maakt een lijn van from-p naar to-p. Hierbij zijn from-p en to-p punten die gemaakt zijn
met make-point. |
from-p; to-p |
Vraagt het van-punt
en het naar-punt van de lijn op. |
from-x; from-y; to-x; to-y |
Vraagt
respectievelijk : de x-coordinaat van from-p,
y-coordinaat van from-p, x-coordinaat van to-p,
y-coordinaat van to-p op. |
dx; dy |
Geeft het verschil
op de x/y-as. |
dx/dy; dy/dx |
Geeft de
richtingscoëfficient van de rechte en het omgekeerde van de rico weer. |
horizontal?;
vertikal? |
Zegt of een lijn
als horizontaal/vertikaal behandeld mag worden. |
fast-point-op? p |
Geeft #t weer als p.x in x-int valt en p.y in y-int valt. |
point-in-range? p |
Geeft #t weer als p op de rechte door from-p en to-p zou vallen. |
x@y; y@x |
x@y geeft de
x-coordinaat die hoort bij een bepaalde y-coordinaat. y@x doet
vanzelfsprekend het omgekeerde. |
Dit is de definitie
van een lijn. Normaal kon je hier bij geven of het begin/eindpunt tot
het
lijnstuk behoorde of niet.
(define (make-line from-p to-p)
In : Nothing
Out : x-coordinaat from-point
(define
(from-x)
(from-p 'x))
In : Nothing
Out : y-coordinaat from-point
(define
(from-y)
(from-p 'y))
In : Nothing
Out : x-coordinaat to-point
(define
(to-x)
(to-p 'x))
In : Nothing
Out : y-coordinaat to-point
(define
(to-y)
(to-p 'y))
In : Nothing
Out : real dx/dy
(define
(dx/dy)
(/ (dx) (dy)))
In : Nothing
Out : real dy/dx
(define
(dy/dx)
(/ (dy) (dx)))
In : Nothing
Out : real dx
(define
(dx)
(- (to-x) (from-x)))
In : Nothing
Out : real dy
(define
(dy)
(- (to-y) (from-y)))
In : Nothing
Out : bool r
Comments : geeft #t weer indien het een horizontale
rechte/lijnstuk is.
(define
(horizontaal?)
(= (to-y) (from-y)))
In : Nothing
Out : bool r
Comments : geeft #t weer indien het een vertikale
rechte/lijnstuk is.
(define (vertikaal?)
(= (to-x) (from-x)))
In : Nothing
Out : Nothing
Comments : print de lijn af onder de vorm "(from-p,to-p)"
(define (display-line)
(message "(")
(from-p 'display)
(message ",")
(to-p 'display)
(message ")"))
In : Nothing
Out : Nothing
Comments : tekent self op het scherm.
Indien color 'ownstyle is wordt een std-line-color
gebruikt
(define (show-line color)
(set-color (if (eq? color
'ownstyle)
std-line-color color))
(line from-p to-p))
In : point p
Out : bool r
Comments : geeft #t weer indien p op de rechte
ligt. Belangrijk is dat hierbij p
niet binnen de grenzen van self moet
vallen.
(define
(point-in-range? p)
;dy
dx acftie
;---------------------
; 0
/ y controleren
; /
0 x controleren
; /
/ gewoon de waarden invullen
(let ((x1 (from-x))
(x2
(to-x))
(y1
(from-y))
(y2
(to-y)))
(cond ((= x2 x1)
(= x1 (p 'x)))
((= y1 y2) (= y1 (p 'y)))
(else
(=
(* (- (p 'y) y1) (- x2
x1))
(* (- (p 'x) x1) (- y2
y1)))))))
In : point p
Out : bool r
Comments : geeft #t weer indien p in het vierkant
bepaalt door from-p en to-p ligt.
(define
(fast-point-op? p)
(and (punt-op-interval? (p
'x)
(make-interval (from-x) (to-x)))
(punt-op-interval?
(p 'y)
(make-interval (from-y) (to-y)))))
In : point p
Out : bool r
Comments : geeft #t weer indien p op self
ligt
(define
(punt-op? p)
(if (point-in-range? p)
(fast-point-op? p)))
In : real y
Out : real x
Comments : geeft de x-coordinaat weer die hoort bij een
bepaalde y-positie. Deze
operator werkt niet bij horizontale lijnen. Zoals de tekening aantoont
werkt
deze functie ook buiten het interval [from-p,to-p]
(define
(x@y y)
(+ (from-x) (* (- y (from-y))
(dx/dy))))
In : real x
Out : real y
Comments : geeft de y-coordinaat weer die hoort bij een
bepaalde x-positie. Deze
operator werkt niet bij vertikale lijnen. Deze functie ook buiten het
interval
[from-p,to-p]
(define (y@x x)
(+ (from-y) (* (- x (from-x))
(dy/dx))))
In : point p
Out : bool r
Comments : geeft #t weer indien p gelijk
is aan from-p. Dit wordt niet getest
door de pointers te vergelijken maar wel door de getalwaarden te
controleren.
(define
(from-eindpunt? p)
(=p p from-p))
In : point p
Out : bool r
Comments : geeft #t weer indien p gelijk
is aan to-p. Deze wordt weeral
vergeleken door de getalwaarden te checken.
(define
(to-eindpunt? p)
(=p p to-p))
In : Nothing
Out : 'up/'down
Comments : Deze functie is voor intern gebruik. Ze
wordt aangeroepen door nulpunten@horizon om te
controleren naar
waar de lijn vertrekt. Indien to-p
hoger ligt dan from-p (dus ) dan wordt
'down weergegeven. 'up in het andere
geval.
(define
(to-direction)
(if (> (to-p 'y) (from-p
'y))
'down
'up))
In : real horizon
Out : list of nulpunten
Comments : Geeft een verzameling van nulpunten weer. Bij
een lijn (hier dus) kan er
maar 1 nulpunt zijn. Het resultaat wordt als volgt bepaalt
self ligt boven/onder horizon : geen
nulpunt
self raakt aan de horizon en vertrekt
naar boven : (x 1 0)
self raakt horizon en vertrekt naar
beneden : (x 0 1)
self snijdt de horizon : (x 1 1)
(define
(nulpunten@horizon horizon)
(let ((ip (intersect-l-l
(make-horizon horizon) line-object)))
(cond ((ip
'empty?) '()) ;gewoon
geen snijpunt
((begin (set! ip (ip
'singleton)) #f)
(error "Unreachable
code"))
((line? ip) '())
;samenvallenden
((from-eindpunt? ip) ;van
from naar boven of beneden
(if (eq? (to-direction)
'up)
(list (make-nulpunt (ip
'x) 1 0))
(list (make-nulpunt (ip
'x) 0 1))))
((to-eindpunt? ip) ;van
to naar boven of beneden
(if (eq? (to-direction)
'down)
(list (make-nulpunt (ip
'x) 1 0))
(list
(make-nulpunt (ip 'x) 0 1))))
(else
;zowel naar boven als
beneden
(list (make-nulpunt (ip 'x)
1 1))))))
In : nothing
Out : interval r
Comments : het geretourneerde interval r
geeft de projectie van de lijn op de X-as weer.
(define (x-int)
(let ((x1 (from-p 'x))
(x2
(to-p 'x)))
(if (> x1 x2)
(make-interval
x2 x1)
(make-interval
x1 x2))))
In : nothing
Out : interval r
Comments : het geretourneerde interval r
geeft de projectie van de lijn op de Y-as weer.
(define (y-int)
(let ((y1 (from-p 'y))
(y2
(to-p 'y)))
(if (> y1 y2)
(make-interval
y2 y1)
(make-interval
y1 y2))))
In : point vct
Out : line
Comments : self wordt over afstand vct verschoven. Een nieuwe lijn wordt
gecreëerd.
(define (translate
vct)
(make-line
((from-p
'translate) vct)
((to-p
'translate) vct)))
In : point center, angle angle
Out : line
Comments : self wordt over een hoek angle gedraait waarbij het middelpunt center
is. Een nieuwe lijn wordt
gecreëerd.
(define (rotate
center angle)
(make-line
((from-p 'rotate)
center angle)
((to-p 'rotate)
center angle)))
In : point howmuch
Out : closed-graph-set
Comments : het resultaat is de gesloten-graph-set die
ontstaat door self te verschuiven over howmuch
(define
(translate-sleep howmuch)
(closed-graph-set
line-object
((to-p
'translate-sleep) howmuch)
(translate
howmuch)
((from-p
'translate-sleep)
howmuch)))
Dispatcher Line
(define
(line-object m)
(cond ((eq? m 'from-p) from-p)
((eq?
m 'to-p) to-p)
((eq?
m 'from-coef)
(from-coef))
((eq?
m 'to-coef) (to-coef))
((eq?
m 'from-x) (from-x))
((eq?
m 'from-y) (from-y))
((eq?
m 'to-x) (to-x))
((eq?
m 'to-y) (to-y))
((eq?
m 'dx) (dx))
((eq?
m 'dy) (dy))
((eq?
m 'dx/dy) (dx/dy))
((eq?
m 'dy/dx) (dy/dx))
((eq?
m 'display)
(display-line))
((eq? m 'horizontaal?) (horizontaal?))
((eq?
m 'vertikaal?)
(vertikaal?))
((eq?
m 'punt-op?) punt-op?)
((eq?
m 'fast-point-op?) fast-point-op?)
((eq?
m 'point-in-range?)
point-in-range?)
((eq?
m 'x@y) x@y)
((eq?
m 'y@x) y@x)
((eq?
m 'type-number) line-id)
((eq?
m 'show) show-line)
((eq?
m 'x-int) (x-int))
((eq?
m 'y-int) (y-int))
((eq?
m 'nulpunten@horizon)
nulpunten@horizon)
((eq?
m 'translate) translate)
((eq?
m 'rotate) rotate)
((eq?
m 'translate-sleep)
translate-sleep)
(else
(error "Unkown
message - line" m))))
Initialisatie van een lijn-object. Eerst wordt gecontroleerd of
from-p niet gelijk is aan to-p. Anders zouden er nadien wel eens rare
error's
kunnen optreden. Indien ze gelijk zijn wordt gewoon het punt
weergegeven.
(if (=p from-p to-p)
from-p
line-object))
In : Something l
Out : bool r
Comments : geeft weer of l een lijn is.
(define (line? l)
(eq? (l 'type-number) line-id))
In : real horizon
Out : line r
Comments : creëert een horizon op hoogte horizon.
(define (make-horizon horizon)
(make-line (make-point -1000000
horizon) (make-point +1000000 horizon)))
In : line l, interval new-interval
Out : line result
Comments : l zijn begin en eindpunt
worden verplaatst zodat de lengte van result
gelijk is aan de grootte van new-interval.
Deze functie wordt aangeroepen vanuit intersect-line.
(define (change-interval l
new-interval)
(let ((x1 (l 'from-x))
(y1
(l 'from-y))
(dx
(l 'dx))
(dy
(l 'dy)))
(define (give-point
factor)
(make-point
(+
(* factor dx) x1)
(+
(* factor dy) y1)))
(make-line
(give-point
(from-grens new-interval))
(give-point
(to-grens
new-interval)))))
In : line linevan, line normline
Out : interval r
Comments : Deze functie geeft een interval weer waarmee linevan en normline vergeleken kunnen
worden. Dit is nodig om bij het snijden
van samenvallende rechten het resultaat-interval te berekenen.
(uiteindelijk
zal het resultaatinterval weer op de normline
gemapt worden door de functie change-interval).
Als je de functie aanroept met linevan=normline
zal het eenheidsinterval weergegeven worden.
Belangrijk : deze bewerking is niet commutatief
(define (normeer-line linevan
normline)
(define (%normeer-line x1 x2 a1 a2)
(let ((c->d (- x2 x1))
(a->b
(- a2 a1))
(a->c
(- x1 a1)))
(make-interval (/
a->c a->b)
(/ (+ c->d a->c) a->b))))
(if (> (abs (normline 'dx)) (abs
(normline 'dy)))
(%normeer-line
(linevan 'from-x)
(linevan 'to-x)
(normline 'from-x)
(normline 'to-x))
(%normeer-line
(linevan 'from-y)
(linevan 'to-y)
(normline
'from-y)(normline 'to-y))))
In : line l, point p
Out : open-graph-set r
Comments : Controleert of p op l
valt en geeft (indien wel) een
graph-set weer met p in. Anders wordt
de lege verzameling weergegeven.
(define (intersect-l-p l p)
(if ((l 'punt-op?) p)
(graph-set p)
(graph-set)))
In : line l1, line l2
Out : open-graph-set gs
Comments : gs bevat ofwel
Niets
: de lijnen snijden niet
Een
punt : de lijnen snijden in dat specifieke punt
Een
lijn : de lijnen vallen samen
Het resultaat houdt
rekening met het bereik van elk lijnstuk. l1
en l2 worden dus niet als rechten
beschouwd. Hoe het resultaat wordt berekend staat vermeld in
onderstaande
tabel.
dx1 |
dy1 |
dx2 |
dy2 |
action |
0 |
/ |
0 |
/ |
// of samenvallende rechten |
0 |
/ |
/ |
0 |
Snijden @ (x lijn 1, y lijn 2) |
0 |
/ |
/ |
/ |
y@x L2 xlijn1 |
/ |
0 |
0 |
/ |
Snijden @ (x lijn 2, y lijn 1) |
/ |
0 |
/ |
0 |
// of samenvallende rechten |
/ |
0 |
/ |
/ |
x@y L1 ylijn2 |
/ |
/ |
0 |
/ |
[recurse] omdraaien en aanroepen |
/ |
/ |
/ |
0 |
[recurse] omdraaien en aanroepen |
|
Evenwijdige of samenvallende |
|||
|
Snijden |
(define (intersect-l-l
l1 l2)
In : Nothing
Out : open-graph-set
Comments : Onderstaande functie wordt aangeroepen als
geweten is dat l1 en l2 samenvallen.
Hiervoor moeten een paar intervallen gesneden
worden en het resultaat in een open-graph-set gestoken.
(define
(samenvallende)
(let ((new-interval
(intersect-interval I1 (normeer-line l2 l1))))
(if new-interval
(graph-set
(change-interval l1
new-interval))
(graph-set))))
In : Nothing
Out : open-graph-set
Comments : Deze interne werker geeft de lege verzameling
weer. Hij wordt opgeroepen
op het ogenblik dat geweten is dat de lijnen evenwijdig zijn.
(define
(evenwijdige)
(graph-set))
In : point s
Out : open-graph-set
Comments : Deze interne functie wordt wakker geschud als
het hypothetische snijpunt
berekend is. Hetgeen hier nog gebeurt is de controle dat s
zowel op l1 als op l2 ligt. Dit kan
gecontroleerd worden
met de fast-point-op? omdat het
snijpunt zodanig berekend is dat het zeker op de rechten l1 & l2 zal vallen. Dit zorgt voor
performantie-winst !
Het resultaat is een lege verzameling als s niet op één van beide
lijnen valt
en is de verzameling met s in als s
op beide lijnstukken valt.
(define (snijpunt s)
(if (and ((l1
'fast-point-op?) s)
((l2 'fast-point-op?) s))
(graph-set
s)
(graph-set)))
Hier begint dan de
echte hel voor de programmeur. Namelijk het implementeren van de
snijding...
dx1 |
dy1 |
dx2 |
dy2 |
action |
0 |
/ |
0 |
/ |
// of samenvallende rechten |
0 |
/ |
/ |
0 |
Snijden @ (x lijn 1, y lijn 2) |
0 |
/ |
/ |
/ |
y@x L2 xlijn1 |
(cond
((l1 'vertikaal?)
(cond
((l2 'vertikaal?)
(if
(= (l1 'from-x) (l2 'from-x))
(samenvallende)
(evenwijdige)))
((l2 'horizontaal?)
(snijpunt (make-point
(l1 'from-x) (l2 'from-y))))
(else
(snijpunt
(make-point (l1
'from-x) ((l2 'y@x) (l1 'from-x)))))))
dx1 |
dy1 |
dx2 |
dy2 |
action |
/ |
0 |
0 |
/ |
Snijden @ (x lijn2, y lijn1) |
/ |
0 |
/ |
0 |
// of samenvallende rechten |
/ |
0 |
/ |
/ |
x@y L1 ylijn2 |
((l1 'horizontaal?)
(cond
((l2 'vertikaal?)
(snijpunt
(make-point (l2 'from-x) (l1 'from-y))))
((l2 'horizontaal?)
(if (= (l1 'from-y) (l2
'from-y))
(samenvallende)
(evenwijdige)))
(else
(snijpunt
(make-point ((l2 'x@y) (l1 'from-y)) (l1
'from-y))))))
dx1 |
dy1 |
dx2 |
dy2 |
action |
/ |
/ |
0 |
/ |
y@x L1 L2x |
/ |
/ |
/ |
0 |
x@y L2 L1y |
|
Evenwijdige of samenvallende |
|||
|
Snijden |
(else
(cond
((l2 'vertikaal?)
(snijpunt
(make-point (l2
'from-x) ((l1 'y@x) (l2 'from-x)))))
((l2 'horizontaal?)
(snijpunt
(make-point ((l1 'x@y)
(l2 'from-y)) (l2 'from-y))))
(else
(let* ((x1 (l1 'from-x)) (y1 (l1 'from-y))
(x2 (l1 'to-x))
(y2 (l1 'to-y))
(a1 (l2 'from-x))
(b1 (l2 'from-y))
(a2 (l2 'to-x))
(b2 (l2 'to-y))
(dx1
(- x2 x1)) (dy1 (- y2
y1))
(dx2 (- a2
a1)) (dy2 (- b2 b1))
(m1 (/ dy1
dx1)) (m2 (/ dy2 dx2))
(B (* dy1
dx2)) (C (- (* dy2
dx1))))
(if (= (+ B C) 0) ;evenwijdig of samenvallende
(if ((l1
'point-in-range?) (l2 'from-p))
(samenvallende)
(evenwijdige))
(let* ((A (* dx1
dx2 (- b1 y1)))
(x (/ (+ A
(* x1 B) (* a1 C))
(+ B
C)))
(y (+ y1
(/ (* (- x x1) dy1) dx1))))
(snijpunt
(make-point x y))))))))))
In : line l1, line l2
Out : bool r
Comments : geeft #t weer indien l1 snijdt
met l2, #f in het andere geval.
(define (intersect?-l-l l1 l2)
(not ((intersect-l-l l1 l2) 'empty?)))
Circles |
|
name & parameters |
action |
make-cirlce center radius from-angle to-angle |
Maakt een circle
met middelpunt center en straal radius.
Enkel het stuk boog van from-angle tot en met to-angle wordt gebruikt. Indien to-angle=2PI
en from-angle=0 dan wordt de volledige
cirkel beslagen. |
radius; center; from-angle; to-angle |
Vragen
respectievelijk straal, middelpunt, van-hoek en naar-hoek op. |
center-x; center-y |
Vraagt de
x/y-coordinaat op van het middelpunt. |
angle-of p |
Vraagt van een
meegegeven punt de hoek op die gevormd wordt met het centrum en de
horizontale. Het antwoord is een georienteerde hoek. |
point@angle angle |
Vraagt het punt van
de cirkel op hoek angle op |
fast-point-op? p |
Geeft weer of een
punt in de sector bepaalt door from-angle tot to-angle ligt. |
(define (make-circle center radius from-angle to-angle)
In : nothing
Out : real x
Comments : geeft de x-coordinaat van het centrum weer.
(define (center-x)
(center 'x))
In : nothing
Out : real y
Comments : geeft de y-coordinaat van het centrum weer.
(define (center-y)
(center 'y))
In : angle a
Out : angle n
Comments : geeft een nieuwe hoek naar buiten waarbij n in ligt. Let op het feit
dat ook tot het interval
behoort. Dit maakt het
mogelijk een volledige cirkel te definiëren.
(define
(normalize-angle a)
(if (> a 2PI)
;duidelijk een strikte ongelijkheid...
(normalize-angle
(- a 2PI))
a))
In : angle a
Out : point r
Comments : Vraagt het punt van de cirkel op hoek a
op
(define (point@angle
a)
(realize-angle center radius
a))
In : angle a
Out : bool r
Comments : Vraagt van een bepaalde hoek of hij op de
cirkelboog ligt, of niet.
(define (angle-op?
a)
(and (>= a from-angle)
(<= a
to-angle)))
In : angle a
Out : angle r
Comments : Vraagt van een meegegeven punt de hoek op die
gevormd wordt met het centrum en de horizontale. Het antwoord is een
georienteerde hoek
(define (%angle-of
p)
(angle-of center p))
In : point p
Out : bool r
Comments : Geeft weer of een punt in de sector bepaalt door
from-angle tot to-angle ligt.
(define
(fast-point-op? p)
(angle-op? (%angle-of p)))
In : nothing
Out : nothing
Comments : print de circle af onder de vorm "(center,fromangle,toangle)"
(define
(display-circle)
(message "(")
(center 'display)
(message ",")
(message from-angle)
(message ",")
(message to-angle)
(message radius))
In : color color
Out : nothing
Comments : Tekent de cirkel door gebruik te maken van ellipse. Door deze functie te gebruiken
zorg ik dat veranderde scaling geen probleem meer oplevert.
(define (show-circle
color)
(let ((fa (round (/ (*
from-angle
360) 2PI)))
(ta
(round (/ (* to-angle 360)
2PI))))
(set-color (if
(eq? color
'ownstyle) std-circle-color color))
(ellipse center
fa ta (make-point
radius radius))
))
Dispatcher circle
(define
(circle-object m)
(cond ((eq? m 'radius) radius)
((eq?
m 'center) center)
((eq?
m 'center-x) (center-x))
((eq?
m 'center-y) (center-y))
((eq?
m 'from-angle)
from-angle)
((eq?
m 'to-angle) to-angle)
((eq? m 'fast-point-op?) fast-point-op?)
((eq?
m 'angle-of) %angle-of)
((eq?
m 'display)
(display-circle))
((eq?
m 'point@angle)
point@angle)
((eq?
m 'type-number)
circle-id)
((eq?
m 'show) show-circle)
(else
(error "Zapping
against zhe walls..." m))))
Initialisatie van een cirkel-object. Hierbij worden de hoeken
genormalizeerd en georiënteerd.
(set! from-angle
(normalize-angle from-angle))
(set! to-angle (normalize-angle
to-angle))
(if (> from-angle to-angle)
(let ((temp from-angle))
(set! from-angle
to-angle)
(set! to-angle
temp)))
circle-object)
In : something o
Out : bool b
Comments : geeft weer of o een cirkelboog
is of niet.
(define (circle? o)
(eq? (o 'type-number) circle-id))
In : point p, circle c
Out : graph-set s
Comments : Geeft een verzameling weer van de snijpunten die
ontstaan bij het snijden van p met c.
Dit is een gemakkelijke...
(define (intersect-p-c p c)
(if ((c 'punt-op?) p)
(graph-set p)
(graph-set)))
In : line l, circle c
Out : graph-set s
Comments : Geeft een verzameling weer van de snijpunten die
ontstaan door l met c te snijden. Er
worden 3 gevallen
beschouwd : l is horizontaal, l is
vertikaal en l loopt schuin.
(define (intersect-l-c l c)
(let ((answer (graph-set))
(b (c
'center-y))
(a (c
'center-x))
(r (c
'radius)))
(define (snijpunt s)
(if (and ((c
'fast-point-op?) s)
((l 'fast-point-op?) s))
((answer
'add!) s)))
(cond ((l 'vertikaal?)
(let*
((x (l 'from-x))
(bigc (+ (- (sqr r))
(sqr (- x a))
(sqr b)))
(bigb (* -2 b))
(result (solve-vkv 1
bigb bigc)))
(define (snijpunt@y y)
(if y (snijpunt
(make-point x y))))
(snijpunt@y (car result))
(snijpunt@y (cdr result))))
((l 'horizontaal?)
(let* ((y (l 'from-y))
(bigc (+ (- (sqr r))
(sqr (- y b))
(sqr a)))
(bigb (* -2 a))
(result (solve-vkv 1
bigb bigc)))
(define (snijpunt@x x)
(if x (snijpunt
(make-point x y))))
(snijpunt@x (car result))
(snijpunt@x (cdr result))))
(else
(let* ((x1 (l 'from-x))
(y1 (l 'from-y))
(m (l 'dx/dy))
(x1-a (- x1 a))
(m2 (sqr m))
(BigA (+ 1 m2))
(BigB (+ (* -2 y1 m2)
(* 2 m x1-a)
(* -2 b)))
(BigC (+ (sqr (- (*
y1 m) x1-a))
(sqr b)
(- (sqr
r))))
(result (solve-vkv
BigA BigB BigC)))
(define (snijpunt@y y)
(if y (snijpunt
(make-point ((l 'x@y) y) y))))
(snijpunt@y (car result))
(snijpunt@y (cdr
result)))))
answer))
In : circle c1, circle c2
Out : graph-set s
Comments : Er wordt een graph-set naar buiten gegeven die
al de snijpunten bevat tussen c1 en c2.
Er worden drie gevallen in
beschouwing genomen : samenvallende cirkels, concentrische cirkels en
gewoon
snijdende cirkels.
(define (intersect-c-c C1 C2)
(if (=p (C1 'center) (C2 'center))
;samenvallen of concentrisch
(if (= (C1
'radius) (C2 'radius))
;samenvallen,
nu nog de
angle-ntervallen snijden
(let
((f1 (C1 'from-angle))
(t1 (C1 'to-angle))
(f2 (C2 'from-angle))
(t2 (C2 'to-angle))
(i1 #f)
(i2 #f))
(if (< t1 f1) (set! t1 (+
t1 2PI)))
(if (< t2 f2) (set! t2 (+
t2 2PI)))
(set! i1 (make-interval f1
t1))
(set! i2 (make-interval f2
t2))
(set! i1 (intersect-interval
i1 i2))
(if i1
(graph-set (make-circle
(C1 'center)
(C1 'radius)
(from-grens
i1) (to-grens i1)))
(graph-set)))
(graph-set))
(let* ((a (C1 'center-x))
(b (C1 'center-y))
(c (C2 'center-x))
(d (C2 'center-y))
(BigB2 (+ (sqr (- c a))
(sqr (- d b))))
(Big-A2 (- (sqr (C2
'radius))))
(BigC (C1 'radius))
(BigB (sqrt BigB2))
(BigC2 (sqr BigC))
(toacos (/ (+ Big-A2 BigB2
BigC2) (* 2 BigB BigC))))
(if
(> (abs toacos) 1)
(graph-set) ;te ver van een
(let ((angle (acos toacos))
(answer (graph-set))
(stdhoek ((C1
'angle-of) (C2 'center))))
(define (snijpunt p)
(if (and ((C1
'fast-point-op?) p) ((C2 'fast-point-op?) p))
((answer 'add!) p)))
(snijpunt ((C1
'point@angle) (+ stdhoek angle)))
(snijpunt ((C1
'point@angle) (- stdhoek angle)))
answer)))))
Nulpunten zijn
nodig om de graph-set toe te laten te controleren of een bepaald punt
begrensd
wordt door de objecten die het bevat. Daarom staat hier een mini-ADT.
In : real nulpuntpos, int pos-count, int neg-count
Out : nulpunt nlpnt
Comments : De nulpunten worden gewoon opgeslagen in
lijst-vorm. Opvragen van de fields gebeurt met nulpunt-pos,
positiviteit
en negativiteit.
(define nulpunt-pos car)
(define positiviteit cadr)
(define negativiteit cddr)
(define (make-nulpunt nulpuntpos
pos-count
neg-count)
(cons nulpuntpos (cons pos-count
neg-count)))
In : nulpunt a, nulpunt b
Out : nulpunt c
Comments : geeft een nieuw nulpunt naar buiten waarbij de pos-counts van beide en de neg-counts
van beide zijn opgeteld. Deze
operatie heeft enkel zin als de nulpunt-posities
van beide gelijk zijn.
(define (merge-nulpunten a b)
(make-nulpunt
(nulpunt-pos a)
(+ (positiviteit a)
(positiviteit
b))
(+ (negativiteit a)
(negativiteit
b))))
Open grafische verzameling : Graph-set |
|
name & parameters |
action |
make-graph-set object-list |
Maakt een
verzameling van grafische objecten. Object-list is een
scheme-lijst die de gewenste data bevat. Deze
objecten worden onafhankelijk van elkaar beschouwd, zodat er 'open'
vlakken ontstaan en geen 'gesloten' |
punt-in? p |
Geeft weer of punt p in de grafische verzameling valt, of niet. Dit is
nuttig als er een gesloten vlak wordt gecreëerd met lijnen. |
empty? |
Geeft #t weer
indien de set leeg is. |
singleton |
Geeft het enige
aanwezige element dat in de verzameling zit naar buiten. Indien er
meerdere elementen zijn wordt een runtime-error gecreëerd. |
%replace old new |
Deze operatie
verandert het object old naar new
waarbij de grenzen niet worden aangepast. Vandaar het %-teken. |
recalc-bounds |
Na een reeks %replace-operaties dient deze functie eens aangeroepen te
worden zodat de x/y-intervallen weer goed staan. |
info |
Vraagt de info van
de graph-set op. |
set-info! |
Verandert de info
van de graph-set. Het info-field speelt totaal geen rol bij het gedrag
van de verzameling. |
foreach func |
Past, indien
gevraagd, op elk element func toe. Er wordt #f
weergegeven als de functie voortijdig gestopt werd. #t in het andere
geval. Func moet voldoen aan volgende voorwaarden :
hij moet 1 parameter (een grafisch object) verwachten en moet altijd
als resultaat een 'stop of een 'gadoor
naar buiten werpen. Tijdens het verloop van een foreach kan de
verzameling door de gebruiker van het ADT gerust gewijzigd worden
(elementen toevoegen, weglaten) |
copy |
Copieert het
volledige adt. Hierbij worden de deel-objecten niet gecopieerd. (dit is
ook niet nodig omdat de enig mogelijke objecten volledig functioneel
worden aangesproken) |
add! |
Voegt een element
toe aan de verzameling. De bounds staan nadien vanzelf weer goed. |
In : grafische objecten pi
Out : graph-set r
Comments : r
bevat al de meegegeven objecten. Een voorbeeld van een aanroep :
(graph-set
(make-point 0 0) (make-point 10 20))
(define graph-set
(lambda object-list
(make-graph-set object-list)))
In : list object-list
Out : graph-set r
Comments : Deze procedure maakt een open grafische
verzameling waarbij al de objecten onafhankelijk van mekaar worden in
acht
genomen. (behalve de operatie punt-in?)
(define (make-graph-set object-list)
(let ((info #f)
(xmin
#f)
(ymin
#f)
(xmax
#f)
(ymax
#f))
In : something w
Out : something info
Comments : Verandert de info van de
graph-set. Het info-field speelt totaal geen rol bij het gedrag van de
verzameling. Als resultaat wordt de nieuwe info
naar buiten gesmeten.
(define (set-info!
w)
(set! info w))
In : go wat
Out : nothing
Comments : Voegt een element toe aan de verzameling. De
bounds staan nadien vanzelf
weer goed. Als wat=#f dan wordt er
niets toegevoegd.
(define (add! wat)
(if wat
(begin
(set!
object-list (cons wat
object-list))
(add-grensum
wat))))
In : function action
Out : bool result
Comments : Past, indien gevraagd, op elk element func toe. Er wordt #f weergegeven als de functie
voortijdig gestopt
werd. #t in het andere geval. Func moet
voldoen aan volgende voorwaarden : hij moet 1 parameter (een grafisch
object)
verwachten en moet altijd als resultaat een 'stop
of een 'gadoor naar buiten werpen.
Tijdens het verloop van een foreach kan de verzameling door de
gebruiker van
het ADT gerust gewijzigd worden (elementen toevoegen, weglaten)
(define (foreach
action)
(define (loop l)
(if
(null? l)
#t ;ze zijn allemaal gedaan
(let ((return (action (car
l))))
(cond ((eq? return
'gadoor) (loop (cdr l)))
((eq? return 'stop)
#f) ;voortijdig gestopt
(else (error
"graph-set-foreach : " return))))))
(loop
object-list))
In : nothing
Out : bool b
Comments : Geeft #t weer indien self leeg
is.
(define (empty?)
(null?
object-list))
In : nothing
Out : go result
Comments : Geeft het enig aanwezige element dat in de
verzameling zit naar buiten.
Indien er meerdere elementen zijn wordt een runtime-error gecreëerd.
(define
(singleton)
(if (null?
object-list)
(error
"Graph-set empty,
singleton")
(if
(pair? (cdr object-list))
(error "More than 1
element, singleton")
(car object-list))))
In : nothing
Out : nothing
Comments : print self af onder de vorm
"{go1,go2,...gon}"
(define
(display-graph-set)
(define (iter l)
(if
(null? l) #t
(begin
((car l) 'display)
(if (pair? (cdr l))
(message " , "))
(iter (cdr l)))))
(message "{")
(iter object-list)
(message "}"))
In : Nothing
Out : Nothing
Comments : tekent self op het scherm.
Indien color 'ownstyle is wordt elk
object apart getekend met zijn eigen standaardkleur.
(define
(show-graph-set color)
(foreach (lambda
(o) ((o 'show)
color) 'gadoor)))
In : real horizon
Out : list nlpntn
Comments : Geeft als resultaat een gesorteerde lijst naar
buiten van nulpunten.
Deze operatie is nodig om nadien te kunnen controleren of een punt in
een
gesloten kromme valt.
(define
(nulpunten@horizon horizon)
;geeft als
resultaat een
gesorteerde lijst weer van punten die
;op de horizon
liggen
(let ((result
(list 'prefix)))
(define
(add-nulpunt nlpnt)
(let
((np1 (nulpunt-pos nlpnt)))
(define (iter prev cur)
(cond ((null? cur)
(set-cdr! prev (list nlpnt)))
((< (nulpunt-pos
(car cur)) np1)
(iter cur (cdr
cur)))
((= (nulpunt-pos
(car cur)) np1)
(set-car! cur
(merge-nulpunten (car cur) nlpnt)))
(else
(set-cdr! prev
(cons nlpnt cur)))))
(iter result (cdr result))
#f))
(define
(add-nulpunten
nlpnt-lst)
(for-each
(lambda (nlpnt)
(add-nulpunt nlpnt)) nlpnt-lst))
(foreach
(lambda
(go)
(add-nulpunten ((go
'nulpunten@horizon) horizon))
'gadoor))
(cdr
result)))
In : real waar, bool gebied-nu,
int pos-count, int neg-count,
list nlpntn
Out : bool result
Comments : result geeft weer of de
positie waar, positief/negatief is
door rekening te houden met de nlpntn-list.
Normaal gebruik van deze functie is als volgt : (%positief-gebied waar #f
0 0 nulpunten). Voor de rest is dit een interne functie die niet
toegankelijk is van buiten uit. (%)
(define (%positief-gebied?
waar
gebied-nu
pos-count neg-count
next-nulpunt)
(if (null?
next-nulpunt)
gebied-nu
(let ((nulpunt (car
next-nulpunt)))
(if (> (nulpunt-pos
nulpunt) waar)
gebied-nu
(begin
(set! pos-count (+
(positiviteit nulpunt) pos-count))
(set! neg-count (+
(negativiteit nulpunt) neg-count))
(set! pos-count (if
(= (remainder pos-count 2) 1) 1 0))
(set! neg-count (if
(= (remainder neg-count 2) 1) 1 0))
(if (and (= pos-count
1) (= neg-count 1))
(%positief-gebied?
waar (not gebied-nu) 0 0 (cdr
next-nulpunt))
(%positief-gebied?
waar gebied-nu pos-count neg-count
(cdr
next-nulpunt))))))))
In : point p
Out : bool r
Comments : geeft #t weer indien p op self
ligt
(define (punt-op?
p)
(not (foreach
(lambda (go)
(if ((go 'punt-op?)
p)
'stop
'gadoor)))))
In : point p
Out : bool r
Comments : Geeft weer of punt p in de
grafische verzameling valt, of niet. Dit is nuttig als er een gesloten
vlak
wordt gecreëerd met lijnen.
(define (punt-in? p)
(if (punt-op? p)
#t
(let*
((nulpunten
(nulpunten@horizon (p 'y))))
(%positief-gebied? (p 'x) #f
0 0 nulpunten))))
In : nothing
Out : interval r
Comments : het geretourneerde interval r
geeft de projectie van de lijn op de X-as weer.
(define (x-int)
(make-interval
xmin xmax))
In : nothing
Out : interval r
Comments : het geretourneerde interval r
geeft de projectie van de lijn op de Y-as weer.
(define (y-int)
(make-interval
ymin ymax))
In : go obj
Out : Nothing
Comments : Past de huidige grenzen aan aan de grenzen van obj. Zodat het x-int
& y-int van self valid blijft.
(define
(add-grensum obj)
(let ((xint (obj
'x-int))
(yint (obj 'y-int)))
(if
(not xmin)
(begin
(set! xmin (from-grens
xint))
(set! xmax (to-grens
xint))
(set! ymin (from-grens
yint))
(set! ymax (to-grens
yint)))
(begin
(if (> xmin (from-grens
xint)) (set! xmin (from-grens xint)))
(if (> ymin (from-grens
yint)) (set! ymin (from-grens yint)))
(if (< xmax (to-grens
xint)) (set! xmax (to-grens xint)))
(if (< ymax (to-grens
yint)) (set! ymax (to-grens yint)))))))
In : point vct
Out : list r
Comments : r is het resultaat na self te verplaatsen over een afstand vct. Er
wordt gewoon een lijst van
verplaatste objecten naar buiten gegeven. Vandaar het %-teken.
(define
(%translate vct)
(let
((result-list '()))
(foreach
(lambda
(go)
(set! result-list (cons ((go
'translate) vct) result-list))
'gadoor))
result-list))
In : point around, angle angle
Out : list r
Comments : r is het beeld van self
door de rotatie-operatie met
fixpunt around en hoek angle. Er
wordt een lijst van gedraaide
objecten naar buiten gegeven.
(define (%rotate
center angle)
(let
((result-list '()))
(foreach
(lambda
(go)
(set! result-list (cons
((go 'rotate) center
angle) result-list))
'gadoor))
result-list))
In : point around, angle angle
Out : graph-set r
Comments : r is het beeld van self
door de rotatie-operatie met
fixpunt around en hoek angle. Er
wordt een nieuwe graph-set
gemaakt.
(define (rotate
center angle)
(make-graph-set
(%rotate center angle)))
In : point vct
Out : graph-set r
Comments : r is het resultaat na self te verplaatsen over een afstand vct. Er
wordt een nieuwe graph-set
gemaakt.
(define (translate
vct)
(make-graph-set
(%translate vct)))
In : point howmuch
Out : list r
Comments : r is het lijnstuk dat ontstaat
door self te verplaatsen over de
afstand howmuch. Er wordt een lijst
van gesleepte objecten naar buiten gegeven.
(define
(%translate-sleep howmuch)
(let
((result-list '()))
(foreach
(lambda
(go)
(set! result-list (cons
((go 'translate-sleep)
howmuch) result-list))
'gadoor))
result-list))
In : point howmuch
Out : graph-set r
Comments : r is het lijnstuk dat ontstaat
door self te verplaatsen over de
afstand howmuch. Er wordt een nieuwe
grafische verzameling naar buiten gegeven.
(define
(translate-sleep howmuch)
(make-graph-set
(%translate-sleep
howmuch)))
In : Nothing
Out : Nothing
Comments : Na een reeks %replace-operaties
dient deze functie eens aangeroepen te worden zodat de x/y-intervallen
weer
goed staan.
(define
(recalc-bounds)
(set! xmin #f)
(set! xmax #f)
(set! ymin #f)
(set! ymax #f)
(foreach (lambda
(obj) (add-grensum
obj) 'gadoor)))
In : go old, go new
Out : Nothing
Comments : Deze operatie verandert het object old
naar new waarbij de grenzen niet
worden aangepast. Vandaar het %-teken.
(define (%replace!
old new)
(define (loop cur)
(cond
((null? cur) (error
"10 m/s2"))
((eq? (car cur) old)
(set-car! cur new))
(else (loop (cdr cur)))))
(loop object-list)
#t)
In : nothing
Out : graph-set result
Comments : Copieert het volledige adt. Hierbij worden de
deel-objecten niet
gecopieerd. (dit is ook niet nodig omdat de enig mogelijke objecten
volledig
functioneel worden aangesproken)
(define (xcopy)
(make-graph-set
(copy
object-list)))
Dispatcher graph-set
(define (graph-set-self m)
(cond ((eq? m 'display)
(display-graph-set))
((eq? m 'punt-in?) punt-in?)
((eq? m 'punt-op?) punt-op?)
((eq?
m 'empty?) (empty?))
((eq? m 'singleton)
(singleton))
((eq? m 'nulpunten@horizon)
nulpunten@horizon)
((eq?
m 'add!) add!)
((eq? m '%replace!)
%replace!)
;het %-teken duid aan dat na
deze operatie de x-int en y-int
;mogelijk fout staan
((eq? m 'type-number)
graph-set-id)
((eq? m 'recalc-bounds)
(recalc-bounds))
((eq? m 'show)
show-graph-set)
((eq? m 'info) info)
((eq? m 'foreach) foreach)
((eq? m 'x-int) (x-int))
((eq? m 'y-int) (y-int))
((eq? m 'set-info!)
set-info!)
((eq? m 'translate)
translate)
((eq? m 'rotate) rotate)
((eq? m '%translate)
%translate)
((eq? m '%rotate) %rotate)
((eq? m 'translate-sleep)
translate-sleep)
((eq? m 'copy) (xcopy))
((eq? m 'type) 'graph-set)
(else (error "unkown
message - graph-set" m))))
Initialisatie van de graph-set. De bounds worden natuurlijk
eerst berekend.
(recalc-bounds)
graph-set-self))
In : something o
Out : bool b
Comments : identificeert o. Geeft #t weer
indien het een graph-set is.
(define (graph-set? o)
(eq? (o 'type-number) graph-set-id))
In : graph-set graphset, go something
Out : bool result
Comments : Geeft #t weer indien graphset
ergens snijdt met something.
(define (%intersect?-gs-something
graphset
something)
(not
((graphset 'foreach)
(lambda (graphset-deel)
(if
(intersect? something
graphset-deel)
'stop
'gadoor)))))
In : graph-set gs, line l
Out : bool result
Comments : Geeft weer of gs snijdt met l.
(define (intersect?-gs-l gs l)
(%intersect?-gs-something gs l))
In : graph-set gs1, graph-set gs2
Out : bool result
Comments : Geeft weer of gs1 snijdt met gs2. Hierbij is mutuele recursie
mogelijk.
(define (intersect?-gs-gs gs1 gs2)
(%intersect?-gs-something gs1 gs2))
In : grafische objecten pi
Out : closed-graph-set r
Comments : r
bevat al de meegegeven objecten. Een
voorbeeld van een
aanroep :
(closed-graph-set
(make-line (make-point 0 0)
(make-point 0 20))
(make-line (make-point 0 20) (make-point 10
0))
(make-line (make-point 10 0) (make-point 0 20)))
(define closed-graph-set
(lambda object-list
(make-closed-graph-set
object-list)))
In : list object-list
Out : closed-graph-set r
Comments : Deze procedure maakt een gesloten grafische
verzameling. In feite is dit een open grafische verzameling waarbij de
punt-op?
geherdefiniëerd is.
(define (make-closed-graph-set
object-list)
(define under-gs (make-graph-set
object-list))
In : point around, angle angle
Out : closed-graph-set r
Comments : r is het beeld van self
door de rotatie-operatie met
fixpunt around en hoek angle. Een
nieuwe gesloten grafische
verzameling wordt aangemaakt.
(define (rotate
center angle)
(make-closed-graph-set
((under-gs '%rotate)
center angle)))
In : point vct
Out : point r
Comments : r is het resultaat na self te verplaatsen over een afstand vct. Hierbij
wordt een nieuwe gesloten
graph-set geprepareerd.
(define (translate
vct)
(make-closed-graph-set
((under-gs
'%translate) vct)))
In : point howmuch
Out : closed-graph-set r
Comments : r is het lijnstuk dat ontstaat
door self te verplaatsen over de
afstand howmuch. Er wordt een nieuwe closed-graph-set
naar buiten gegeven.
(define
(translate-sleep howmuch)
(closed-graph-set
closed-graph-set-self
(translate
howmuch)
((under-gs
'translate-sleep)
howmuch)))
Dispatcher closed-graph-set-self.
Initialisatie door het naar buiten geven van self.
(define
(closed-graph-set-self m)
(cond ((eq? m 'type-number)
closed-graph-set-id)
((eq?
m 'punt-op?) (under-gs
'punt-in?))
((eq?
m 'translate) translate)
((eq?
m 'rotate) rotate)
((eq?
m 'translate-sleep)
translate-sleep)
(else
(under-gs m))))
closed-graph-set-self)
Out : bool b
Comments : identificeert o. Geeft #t weer
indien het een closed-graph-set is.
(define (closed-graph-set? o)
(eq? (o 'type-number)
closed-graph-set-id))
In : list points
Out : closed-graph-set result
Comments : Geeft een gesloten verzameling naar buiten die
bestaan uit de
verbindingslijnen tussen de meegegeven punten points.
Bijvoorbeeld
(%make-L-vlak
(list
(make-point 0 0)
(make-point 0 20)
(make-point 10 0)))
is equivalent met
(closed-graph-set
(make-line (make-point 0 0)
(make-point 0 20))
(make-line (make-point 0 20) (make-point 10
0))
(make-line (make-point 10 0) (make-point 0 20)))
(define (%make-L-vlak punten-lijst)
(let ((result (closed-graph-set)))
(define (iter prev cur)
(cond ((null? cur)
((result 'add!) (make-line
(car punten-lijst) prev))
result)
(else
((result 'add!) (make-line
prev (car cur)))
(iter (car cur) (cdr
cur)))))
(iter (car punten-lijst) (cdr
punten-lijst))))
In : point p1, point p2,point p3
Out : closed-graph-set result
Comments : Deze is een eenvoudige definitie om gesloten
vlakken te maken. Voorbeeld :
(%make-L-vlak
(list
(make-point 0 0)
(make-point 0 20)
(make-point 10 0)))
wordt :
(make-L-vlak
(make-point 0 0)
(make-point 0 20)
(make-point 10 0))
(define make-L-vlak
(lambda punten-lijst
(%make-L-vlak punten-lijst)))
In : closed-graph-set cgs, go other
Out : bool result
Comments : Geeft #t weer indien other
snijdt met cgs
(define (%intersect-cgs-other cgs
other)
(not
((cgs 'foreach)
(lambda
(splitsing)
(if
(intersect? other splitsing)
'stop
'gadoor)))))
In : closed-graph-set cgs, line l
Out : bool result
Comments : Geeft #t weer als l ergen op cgs valt.
(define (intersect?-cgs-l cgs l)
(or (%intersect-cgs-other cgs l)
((cgs 'punt-op?) (l 'from-p))
((cgs 'punt-op?) (l 'to-p))))
In : closed-graph-set a, closed-graph-set b
Out : bool result
Comments : Geeft weer of a snijdt met b. Dit is een vreemd stukje code omdat de bewerkging %intersect-cgs-other niet commutatief is als other ook een closed-graph-set is. Neem bijvoorbeeld
Het resultaat van
(%intersect-cgs-other a b) is hier #t, maar
het resultaat van (%intersect-cgs-other b a) is #f.
(define (intersect?-cgs-cgs a b)
(or (%intersect-cgs-other a b)
(%intersect-cgs-other b a)))
In : closed-graph-set cgs, graph-set gs
Out : bool result
Comments : Result
is #f als cgs niet snijdt met gs.
(define (intersect?-cgs-gs cgs gs)
(%intersect-cgs-other cgs gs))
In : go a, go b
Out : bool result
Comments : Geeft weer of a op één of
andere manier snijdt met b. Eerst
worden a en b gesorteerd volgens
type-number. Nadien wordt gecontroleerd of het
kanshebbers zijn om te snijden en uiteindelijk wordt de werkelijke
snijd-routine aangeroepen.
(define (intersect? a b)
(cond ((> (b 'type-number) (a
'type-number)) (intersect? b a))
((not
(intersect-interval (a
'x-int) (b 'x-int))) #f)
((not
(intersect-interval (a
'y-int) (b 'y-int))) #f)
((point?
a) (intersect?-p-p a
b))
((line?
a)
(cond
((point? b)
(intersect?-l-p a b))
((line? b)
(intersect?-l-l a b))
(else (error
"intersect line-?"))))
((circle?
a)
(cond
((point? b)
(intersect?-c-p a b))
((line? b)
(intersect?-c-l a b))
((circle? b)
(intersect?-c-c a b))
(else (error
"intersect circle-?"))))
((graph-set?
a)
(cond
((point? b)
(intersect?-gs-p a b))
((line? b)
(intersect?-gs-l a b))
((circle? b)
(intersect?-gs-c a b))
((graph-set? b)
(intersect?-gs-gs a b))
(else (error "intersect
graph-set-?"))))
((closed-graph-set?
a)
(cond
((point? b)
(intersect?-cgs-p a b))
((line? b)
(intersect?-cgs-l a b))
((circle? b)
(intersect?-cgs-c a b))
((graph-set? b)
(intersect?-cgs-gs a b))
((closed-graph-set? b)
(intersect?-cgs-cgs a b))
(else (error
"intersect closed-graph-set-?"))))))
Set |
|
name & parameters |
action |
add who |
Voegt who
toe aan de verzameling. Indien men in een foreach
zit zal het nieuwe element niet meer bekeken worden. |
add-set! other-set |
Voegt een nieuwe
verzameling toe aan self. Indien
men met een foreach bezig is zal func
ook nog eens worden aangeroepen voor de nieuwe elementen. |
delete! who |
Verwijdert een
element uit de verzameling. Dit levert geen problemen in de foreach. |
empty? |
Geeft weer of de
verzameling leeg is. |
replace! old new |
Vervangt old door new. Het nieuwe element wordt
niet meer behandeld in een foreach. |
list |
Geeft een
lijst-representatie van de verzameling naar buiten. |
present? who |
Controleert of who aanwezig is in de verzameling. |
foreach |
Past, indien
gevraagd, op elk element func toe. Er wordt #f
weergegeven als de functie voortijdig gestopt werd. #t in het andere
geval. Func moet voldoen aan volgende voorwaarden :
hij moet 1 parameter (een element van de verzameling) verwachten en
moet altijd als resultaat een 'stop of een 'gadoor
naar buiten werpen. Tijdens het verloop van een foreach
kan de verzameling door de gebruiker van het ADT gerust gewijzigd
worden (elementen toevoegen, weglaten...). |
In : list contents
Out : set result
Comments : contents
is de lijst van objecten die initiëel aanwezig zijn.
(define (make-set contents)
In : something who
Out : bool result
Comments : Verwijdert who uit de lijst.
Merk op dat hiervoor speciaal een prefix wordt gemaakt.
(define (delete who)
(define (loop prev cur)
(cond ((null?
cur) #t)
((eq? (car cur) who)
(set-cdr! prev (cdr cur))
(loop prev (cdr cur)))
(else
(loop cur (cdr cur)))))
(let ((prefix (cons 'prefix
contents)))
(loop prefix
contents)
(set! contents
(cdr prefix))
#t))
In : something who
Out : bool result
Comments : Voegt who toe aan het begin
van de verzameling (voor zover een verzameling geordent is natuurlijk)
(define (add who)
(set! contents (cons who
contents))
#t)
In : function action
Out : bool result
Comments : Past, indien gevraagd, op elk element func toe. Er wordt #f weergegeven als de functie
voortijdig gestopt
werd. #t in het andere geval. Func moet
voldoen aan volgende voorwaarden : hij moet 1 parameter (een element
van de
verzameling) verwachten en moet altijd als resultaat een 'stop
of een 'gadoor naar
buiten werpen. Tijdens het verloop van een foreach kan de verzameling
door de
gebruiker van het ADT gerust gewijzigd worden (elementen toevoegen,
weglaten...).
(define
(foreach action)
(define (loop l)
(if (null? l)
#t
;ze zijn allemaal gedaan
(let
((return (action (car
l))))
(cond ((eq? return 'gadoor)
(loop (cdr l)))
((eq? return 'stop)
#f) ;voortijdig gestopt
(else
(error
"foreach-action geeft geeft weer : " return))))))
(loop contents))
In : something old, something new
Out : bool result
Comments : Verandert het oude object door het nieuwe.
(define (replace!
old new)
(define (loop prev cur)
(cond ((null?
cur) (error
"Nothing to replace"))
((eq? (car cur) old)
(set-cdr! prev (cons new (cdr
cur))))
(else (loop cur (cdr
cur)))))
(let ((prefix (cons 'prefix
contents)))
(loop prefix
contents)
(set! contents
(cdr prefix))
#t))
In : something who
Out : bool result
Comments : Zoekt op of who aanwezig is.
(define (present?
who)
(not
(foreach
(lambda
(item)
(if
(eq? item who)
'stop
'gadoor)))))
In : set from
Out : bool result
Comments : Transformeert self naar de
unie van self en from.
(define (add-set!
from)
(set! contents (append
contents
(from 'list))))
Dispatcher adt-set
(define
(adt-set m)
(cond ((eq? m 'add!) add)
((eq?
m 'add-set!) add-set!)
((eq?
m 'delete!) delete)
((eq?
m 'foreach) foreach)
((eq?
m 'empty?) (null?
contents))
((eq?
m 'replace!) replace!)
((eq?
m 'list) contents)
((eq?
m 'present?) present?)
(else
(error "unkown
message - ADT-SET" m))))
adt-set)
In : something obj1, something obj2, something obj3 ...
Out : set result
Comments : Deze procedure is een handigheidje voor de
programmeur. Nu kan ik
(fast-set 1 2 3) schrijven in plaats van (make-set (list 1 2 3))
(fast-set) maakt een
lege verzameling.
(define fast-set
(lambda obj-lst
(make-set obj-lst)))
Zoals u
waarschijnlijk al is opgevallen kunnen er van dit object niet meer dan
één
instance voorkomen.
(define untouchable-world
(let ((contents (make-set '())))
In : Nothing
Out : Nothing
Comments : Ledigt de volledige wereld.
(define
(init-world)
(set! contents
(make-set '())))
In : Nothing
Out : Nothing
Comments : Hertekent elk object in zijn eigen specifieke
kleur. (deze kleur werd
meegegeven bij add!)
(define (redraw)
((contents
'foreach)
(lambda
(draw-color)
(((car
draw-color) 'show) (cdr
draw-color))
'gadoor)))
In : go drawing, color color
Out : Nothing
Comments : Zorgt dat het meegegeven object toegevoegd wordt
aan de onschendbare
wereld. Het nieuwe object zal steeds in kleur color
getekend worden.
(define (add!
drawing color)
((contents 'add!)
(cons drawing
color)))
Dispatcher
(lambda (m)
(cond ((eq? m
'redraw) (redraw))
((eq? m 'add!) add!)
((eq? m 'init) (init-world))
(else (error
"Untouchable world -- " m))))))
Net zoals bij
"the untouchable world" kan ook hier maar één instance van de wereld
bestaan. Als geheugenopfrissertje : een wereld is een verzameling
subwerelden.
(define world
(let ((contents (make-set '())))
In : Nothing
Out : Nothing
Comments : Herinitializeert de wereld door al de
subwerelden de vernielen.
(define
(init-world)
(set! contents
(make-set '())))
In : subworld with, set of components exclude
of : graph-set with, set of components exclude
Out : bool result
Comments : Geeft #t weer indien with
ergens met de globale wereld snijdt.
(define
(disturbs-with? with exclude)
(if (eq? (with
'type) 'sub-world)
(set!
with (subworld->graphset
with)))
(not
((contents
'foreach)
(lambda
(subworld)
(if ((subworld
'disturbs-with?) with exclude)
'stop
'gadoor)))))
In : color color
Out : Nothing
Comments : Hertekent de volledige wereld. Alles in kleur color. (Color mag 'ownstyle
zijn)
(define (redraw
color)
((contents
'foreach)
(lambda
(subworld)
((subworld
'redraw) color)
'gadoor)))
In : subworld which-sub-world
Out : Nothing
Comments : Voegt de meegegeven subwereld toe aan de globale
wereld. Hierbij wordt
geen controle uitgeoefend op het al dan niet snijden met andere
subworlds.
(define (register
which-sub-world)
((contents 'add!)
which-sub-world))
In : subworld which-sub-world
Out : Nothing
Comments : Verwijdert de subwereld uit de globale wereld.
(define
(unregister which-sub-world)
((contents
'delete!)
which-sub-world))
Dispatcher
(lambda (m)
(cond ((eq? m
'disturbs-with?)
disturbs-with?)
((eq? m 'redraw) redraw)
((eq? m 'register) register)
((eq? m 'unregister)
unregister)
((eq? m 'init) (init-world))
(else (error "World --
" m))))))
In : Nothing
of : set optionalinit
Out : subworld result
Comments : Creëert een subwereld die geïnitialiseerd is met
optionalinit. Bij de creatie wordt
niet gecontroleerd of het wel een geldige wereld is.
(define (make-subworld .
optionalinit)
(let ((contents #f))
In : graph-set with, set of components kill-set
Out : bool result
Comments
: Controleert of with
snijd met self. De
tekeningen die behoren tot een
component aanwezig in kill-set worden
zelf niet bekeken.
(define (disturbs-with? with kill-set)
;kill-list is een
set van
componenten (en dus niet van drawings)
;een drawing die
hoort bij een
component in de verzameling wordt
;overgeslagen
(not
((contents
'foreach)
(lambda
(robot-drawing)
(if ((kill-set 'present?) (robot-drawing
'info))
'gadoor
(if (intersect?
robot-drawing with)
'stop
'gadoor))))))
In : Nothing
Out : bool result
Comments : Geeft #t weer als de wereld gestoord is.
Hiervoor moet elke component een geldige always-connected-to
weergeven.
(define
(disturbed?)
(not
((contents
'foreach)
(lambda
(robot-drawing)
(let ((robot (robot-drawing
'info)))
(if (disturbs-with?
robot-drawing
(robot
'always-connected-to))
'stop
'gadoor))))))
In : component who, go drawing
Out : Nothing
Comments : Registreert de nieuwe component in de subwereld
waarbij het info-field van de drawing op who
wordt gezet, zodat nadien van elke drawing onmiddelijk gezegd kan
worden tot
welke component hij hoort.
(define (sign-in
who drawing)
((drawing
'set-info!) who)
((contents 'add!)
drawing))
In : color color
Out : Nothing
Comments : Hertekent de subwereld in kleur color.
Color mag opnieuw 'ownstyle
zijn.
(define (redraw
color)
((contents 'show)
color))
In : go old, go new
Out : Nothing
Comments : Vervangt de oude tekening door de nieuwe. De nieuwe tekening krijgt dezelfde info als de oude. Na het veranderen van deze tekening zijn de grenzen (x-int, y-int) niet aangepast. (%)
(define (%replace-drawing! old new)
((contents
'%replace!) old new)
((new 'set-info!)
(old 'info)))
In : Nothing
Out : Nothing
Comments : Deze routine verplicht al de componenten die hij
kent zichzelf te aanvaarden als DE subwereld. Dit is in feite het
actief maken
van een denkbeeldige subwereld.
(define
(wring-er-tussen)
((contents
'foreach)
(lambda
(robot-drawing)
(let
((robot (robot-drawing
'info)))
(if (not robot)
(begin
((robot-drawing 'show)
'white)
(error "AAAAARG,
i'm trying 9.81")))
((robot 'set-sub-world!)
subworld-self)
((robot 'set-drawing!) robot-drawing)
'gadoor)))
((world
'register) subworld-self))
In : point vct
Out : subworld r
Comments : r is het resultaat na self te verplaatsen over een afstand vct.
Hierbij worden de info-fields van
de oude subworld gecopiëerd naar de nieuwe.
(define (translate
speed)
(let
((result-graph-set
(graph-set)))
((contents
'foreach)
(lambda
(before)
(let ((after ((before
'translate) speed)))
((after 'set-info!) (before
'info))
((result-graph-set 'add!)
after))
'gadoor))
(make-subworld
result-graph-set)))
In : point howmuch
Out : graph-set r
Comments : r is het lijnstuk dat ontstaat
door self te verplaatsen over de
afstand howmuch. Er wordt hier geen
subwereld naar buiten gegeven maar wel een grafische (open) verzameling.
(define
(translate-sleep speed)
((contents
'translate-sleep)
speed))
In : noting
Out : subworld other
Comments : other is
een nieuwe subwereld waarbij al de tekeningen overgenomen zijn. De
tekeningen
zelf zijn niet gedupliceerd.
(define (copy)
(make-subworld
(contents 'copy)))
Dispatcher subworld-self
(define (subworld-self m)
(cond ((eq? m
'sign-in) sign-in)
((eq? m 'disturbs-with?)
disturbs-with?)
((eq? m 'redraw) redraw)
((eq? m 'type) 'sub-world)
((eq? m 'wring-er-tussen)
(wring-er-tussen))
((eq? m 'full-drawing)
contents)
((eq? m 'recalc-bounds)
(contents 'recalc-bounds))
((eq? m '%replace-drawing!)
%replace-drawing!)
((eq? m 'translate)
translate)
((eq? m 'disturbed?)
(disturbed?))
((eq? m 'translate-sleep)
translate-sleep)
((eq? m 'copy) (copy))
(else (error "Subworld
" m))))
Initialisatie waarbij een eventueel zelf gekozen graph-set
wordt aanvaard als contents.
(if optionalinit
(begin
(set!
contents (car
optionalinit))
(set!
optionalinit #f))
(set!
contents (graph-set)))
subworld-self))
In : subworld who
Out : graph-set result
Comments : Converteert een subwereld naar zijn bijhorende
graph-set.
(define (subworld->graphset who)
(who 'full-drawing))
Ik heb al de
tekeningen van de robots bijeen gebracht zodat ze gemakkelijk aan te
passen
zijn. Als ik bijvoorbeeld in een snellere omgeving met meer geheugen
werk kan
ik zorgen dat de armen en de scharnierer fijner worden getekend.
Ik heb de
tekeningen bewust buiten de ADT's gebracht omdat zo een scheiding
ontstaat
tussen code en data. De tekeningen zouden nu kunnen aangepast worden
vanuit de
programma's.
Wat als de
gebruiker wil dat elke component een eigen tekening heeft ?
Verander
al de drawing@'s zodat ze een request
om een tekening naar de databank sturen.
Verander
deze robot-drawings door een databank van tekeningen/procedures.
of de meer voor de hand liggende oplossing :
Mix
bovenstaande databank tussen de component-adt's. Zodat drawing@
direct weet wat weergegeven moet worden. (persoonlijk vind
ik dat hier de abstractie een beetje verloren loopt)
In : nothing
Out : closed-graph-set result
Comments :
result=
(define (robot-drawing)
(make-L-vlak
(make-point 20 0)
(make-point -20 0)
(make-point -14 -10)
(make-point 14 -10)))
In : real lengte
Out : graph-set result
Comments : Vraagt een arm van lengte l op. result=
(define (arm-drawing lengte)
(make-L-vlak
(make-point 0 -5)
(make-point 0 5)
(make-point lengte 5)
(make-point lengte -5)))
In : angle angle
Out : graph-set result
Comments : Vraagt een tekening van een scharnier op. Result=
(define (scharnier-drawing angle)
(let ((mid-point (make-point 10 0)))
(make-l-vlak
(make-point 0 -5)
(make-point 0 5)
(make-point (- 10
(* 5 (sin
angle))) 5)
(realize-angle
mid-point
11.18033989 (+ angle 0.463647609))
(realize-angle
mid-point
11.18033989 (- angle 0.463647609))
(make-point (+ 10
(* 5 (sin
angle))) -5))))
In : function trans-func, function rot-func, function own-dispatcher
Out : terminal result
Comments : Result is een voorgedefinieerd
armuiteinde waarbij trans-func, rot-func en
own-dispatcher op het juiste moment
worden aangeroepen. M.a.w. het gedrag van het uiteinde t.o.v. de
onschendbare
wereld kan zelf gekozen worden. Trans-func
wordt opgeroepen wanneer het uiteinde verplaatst wordt. Trans-func
verwacht 2 parameters. De
oude positie en de verplaatsingsvector.
Rot-func verwacht 3 parameters : de
oude positie, het centrum van de draaiing en de hoek waarover gedraaid
wordt.
Own-dispatcher wordt aangeroepen als
er een bericht binnenkomt dat door de terminal niet verstaan wordt.
(define (create-terminal trans-func
rot-func
own-dispatcher)
(let ((old-pos #f)
(last-angle
#f)
(drawing
(graph-set)))
In : color color
Out : nothing
Comments : Dit is één van de dummy-achtigen. Het bericht
show kan opgestuurd worden
naar een terminal, maar aangezien die geen tekening heeft moet er ook
niets
getekend worden.
(define
(show-terminal color)
#t)
In : component father
Out : bool result
Comments : Lijmt componenten aaneen zodat ze een tree
vormen. Indien father reeds
gekend was wordt #f weergegeven. (dit wil dus zeggen dat de component
reeds in
gebruik was). De glue message wordt
doorgegeven aan de kinderen. In dit geval komt dit neer op weergeven
dat al de
kinderen gelijmt zijn.
(define (glue
father)
#t)
In : sub-world sw, point pos, angle angle
Out : nothing
Comments : Na het aaneen glue-en van de
componenten moet ook een subwereld gecreëerd worden. Dit wordt met deze
routine
gedaan. Sw is de subworld waarin het
resultaat moet komen, pos is de
positie van de component, angle is de
hoek die de component zal vormen. Hier wordt de old-pos en de hoek
gewoon
onthouden.
(define
(sign-in-world sub-world pos angle)
(set! old-pos pos)
(set! last-angle
angle)
#t)
In : graph-set result-in, point howmuch
Out : nothing
Comments : Vraagt de component of hij het sleeppad ten
gevolge van een translate
over howmuch wil vervolledigen in result-in.
(define
(add-translate-sleeppad result-in howmuch)
result-in)
In : point naar
Out : nothing
Comments : Vertelt de component dat al de checks voor een
translatie positief waren
en dat de translatie over naar
uitgevoerd mag worden. Hierbij wordt niet verwacht dat de tekeningen en
de
subworlds ge-update worden. Deze zijn reeds veranderd. Deze routine
zorgt
gewoon dat een component zijn nieuwe positie kan bijhouden. Hier moet
daarvoor
de trans-func aangeroepen worden.
(define
(translate-action naar)
(trans-func
old-pos naar)
(set! old-pos
((old-pos
'translate) naar))
#t)
In : point around, angle angle
Out : nothing
Comments : Net zoals bij translate-action
laat dit bericht toe dat de component zijn posities en hoeken up to
date blijven.
De rot-func wordt hierbij
aangeroepen.
(define
(rotate-action rond angle)
(rot-func old-pos
rond angle)
(set! old-pos
((old-pos 'rotate)
rond angle))
(set! last-angle
(+ last-angle
angle))
#t)
In : nothing
Out : set of components result
Comments : Dit bericht vraagt de component of hij eens een
lijst wil naar buiten
geven met wie hij altijd verbonden zal zijn. Dit is om vanzelfsprekende
snijdingen op voorhand weg te filteren en zelf niet meer te
controleren. Omdat
er geen tekening bestaat van een armuiteinde wordt de lege verzameling
naar
buiten gemikt.
(define
(always-connected-to)
(fast-set))
In : subworld result-in, point howmuch
Out : nothing
Comments : Vraagt de component of hij zichzelf eens
denkbeeldig wil verplaatsen
over afstand howmuch. Hierbij wordt
verwacht dat in result-in de oude
tekening van de component wordt vervangen door een nieuwe. Hier komt
dit neer
op : niets veranderen en result-in
weergeven.
(define
(change-translate-world! result-in translation)
result-in)
In : subworld result-in, point around, angle howmuch
Out : nothing
Comments : Vraagt aan de component of hij zichzelf eens
denkbeeldig wil roteren
rond around bij een hoek van howmuch.
Hierbij dient de oude tekening
van de component die aanwezig is in result-in
vervangen worden door een nieuwe tekening. Ook hier komt dit neer op :
niets
veranderen en result-in weergeven.
(define
(change-rotate-world! result-in around rot)
result-in)
In : graph-set result-in, point howmuch
Out : nothing
Comments : Vraagt de component of hij het sleeppad ten
gevolge van een translate
over howmuch wil vervolledigen in result-in.
Een tekening die niet bestaat
heeft geen sleeppad dus result-in
wordt gewoon naar buiten gegooid.
(define (add-translate-sleeppad!
result-in translation)
result-in)
Dispatcher terminal-self
(define (terminal-self m)
(cond ((eq? m
'glue) glue)
((eq? m 'unglue) #t)
((eq? m
'always-connected-to) (always-connected-to))
((eq? m 'sign-in-world)
sign-in-world)
((eq? m 'show)
show-terminal)
((eq? m 'drawing) drawing)
((eq? m 'translate-action)
translate-action)
((eq? m 'rotate-action)
rotate-action)
((eq? m 'child-list) '())
((eq? m
'change-translate-world!) change-translate-world!)
((eq? m
'change-rotate-world!) change-rotate-world!)
((eq? m
'add-translate-sleeppad!) add-translate-sleeppad!)
(else (own-dispatcher m
old-pos))))
terminal-self))
De null-component.
Deze reageert niet op translaties, rotaties en heeft geen eigen
berichten. (er
is slechts 1 null-component)
(define null-component
(create-terminal
(lambda (oldpos vect)
#t)
(lambda (oldpos around angle)
#t)
(lambda (m oldpos)
(error "unkown
message
null-component" m))))
In : color color
Out : pen-component result
Comments : Er wordt een pen gemaakt die reageert op
translaties/rotaties en een
paar eigen berichten heeft.
(define (make-pen color)
(let ((pen-down #f))
(create-terminal
(lambda (oldpos
vect)
(if
pen-down
((untouchable-world 'add!)
((oldpos 'translate-sleep)
vect)
color)))
(lambda (old-pos
rond angle)
(if
pen-down
((untouchable-world 'add!)
((old-pos 'rotate-sleep)
rond angle)
color)))
(lambda (m
old-pos)
(cond
((eq? m 'pen-up) (set!
pen-down #f))
((eq? m 'pen-down) (set!
pen-down #t))
((eq? m 'color!)
(lambda (new-color) (set!
color new-color)))
(else (error "Unkown
message pen -- " m)))))))
In : nothing
Out : boor-component result
Comments : Maakt een boor die enkel reageert op het bericht
'boor. De gaten die
geboort worden zijn altijd in magenta.
(define (make-boor)
(create-terminal
(lambda (oldpos vect)
#t)
(lambda (old-pos rond angle)
#t)
(lambda (m old-pos)
(cond ((eq? m
'boor)
((untouchable-world 'add!)
old-pos
'magenta)
((untouchable-world 'add!)
(make-circle old-pos 2 0
2PI)
'magenta)
(redraw)
)
(else (error "Unkown
message boor -- " m))))))
In : real min, real max, real lengte, angle voethoek, component child
Out : arm result
Comments :
Bij de creatie van
de arm wordt nog niet gecontroleerd of er snijdingen zullen optreden.
Wel wordt
al gecontroleerd of de meegegeven parameters aan een paar minimumeisen
voldoen.
Namelijk : "Minimum<maximum, Lengte tussen minimum en maximum,
Minimum>10"
(define (make-arm minimum maximum
lengte
voethoek child)
(let ((parent #f)
(drawing
#f)
(last-pos
#f)
(last-angle
#f)
(sub-world
#f))
In : sub-world to
Out : nothing
Comments : Wordt opgeroepen als de sub-world van de robot
verandert. Hierbij wordt
de subworld van de component gezet op to.
(define
(set-sub-world! to)
(set! sub-world
to))
In : graph-set to
Out : nothing
Comments : Wordt opgeroepen als de sub-world van de robot
verandert. Hierbij wordt
de drawing van de component gezet op to.
(define
(set-drawing! to)
(set! drawing to))
In : component father
Out : bool result
Comments : Lijmt componenten aaneen zodat ze een tree
vormen. Indien father reeds
gekend was wordt #f weergegeven. (dit wil dus zeggen dat de component
reeds in
gebruik was). De glue message wordt
doorgegeven aan de kinderen.
(define (glue
father)
(if parent
#f
(begin
(set! parent father)
((child 'glue) arm-self))))
In : nothing
Out : nothing
Comments : Zorgt dat de vader niet meer gekend is. Deze
routine dient opgeroepen te
worden als de creatie van de robot mislukt is, zodat de componenten in
een
nieuwe robot gebruikt kunnen worden
(define (unglue)
(set! parent #f)
(child 'unglue))
In : point pos, angle angle, real l
Out : go
Comments : De tekening van een arm wordt opgevraagd,
geroteerd en verplaatst naar
de juiste positie.
(define (drawing@
pos angle l)
(((((arm-drawing
l)
'rotate)
(make-point 0 0)
angle)
'translate)
pos))
In : real l
Out : bool result
Comments : Geeft weer of l een
aanvaardbare
lengte is voor de arm.
(define
(valid-length? l)
(and (>=
minimum 10)
(>= l minimum)
(<= l maximum)))
In : nothing
Out : bool/error result
Comments : controleert of de initiële armlengte
aanvaardbaar is. Indien niet wordt
een error naar buiten gegeven en geen boolean.
(define
(valid-init?)
(if
(valid-length? lengte)
#t
(make-error
'value
"Impossible arm-value")))
In : point pos, angle angle
Out : point end-point
Comments : Berekent het eindpunt van de arm. Dus het
beginpunt van de child-component.
(define
(calc-end-point pos angle)
(realize-angle
pos lengte angle))
In : sub-world sw, point pos, angle angle
Out : nothing
Comments : Na het aaneen glue-en van de
componenten moet ook een subwereld gecreëerd worden. Dit wordt met deze
routine
gedaan. Sw is de subworld waarin het
resultaat moet komen, pos is de
positie van de component, angle is de
hoek die de component zal vormen.
(define
(sign-in-world sw pos angle)
(set! last-angle
angle)
(set! last-pos
pos)
(set! drawing
(drawing@ pos angle
lengte))
((sw 'sign-in)
arm-self drawing)
((child
'sign-in-world) sw
(calc-end-point pos angle)
(+ angle
voethoek)))
In : nothing
Out : set of components result
Comments : Dit bericht vraagt de component of hij eens een
lijst wil naar buiten
geven met wie hij altijd verbonden zal zijn. Dit is om vanzelfsprekende
snijdingen op voorhand weg te filteren en zelf niet meer te controleren.
(define (always-connected-to)
(fast-set parent
arm-self child))
In : graph-set result-in, point howmuch
Out : nothing
Comments : Vraagt de component of hij het sleeppad ten
gevolge van een translate
over howmuch wil vervolledigen in result-in.
(define
(add-translate-sleeppad! result-in howmuch)
((result-in
'add!) ((drawing
'translate-sleep) howmuch))
((child
'add-translate-sleeppad!)
result-in howmuch))
In : point naar
Out : nothing
Comments : Vertelt de component dat al de checks voor een
translatie positief waren
en dat de translatie over naar
uitgevoerd mag worden. Hierbij wordt niet verwacht dat de tekeningen en
de
subworlds ge-update worden. Deze zijn reeds veranderd. Deze routine
zorgt
gewoon dat een component zijn nieuwe positie kan bijhouden
(define
(translate-action naar)
(set! last-pos
((last-pos
'translate) naar))
((child
'translate-action) naar))
In : subworld result-in, point howmuch
Out : nothing
Comments : Vraagt de component of hij zichzelf eens
denkbeeldig wil verplaatsen
over afstand howmuch. Hierbij wordt
verwacht dat in result-in de oude
tekening van de component wordt vervangen door een nieuwe.
(define
(change-translate-world! result-in howmuch)
((result-in
'%replace-drawing!)
drawing
((drawing
'translate) howmuch))
((child
'change-translate-world!)
result-in howmuch))
In : point around, angle angle
Out : nothing
Comments : Net zoals bij translate-action
laat dit bericht toe dat de component zijn posities en hoeken up to
date
blijven.
(define
(rotate-action around angle)
(set! last-angle
(+ last-angle
angle))
(set! last-pos
((last-pos 'rotate)
around angle))
((child
'rotate-action) around
angle))
In : subworld result-in, point around, angle howmuch
Out : nothing
Comments : Vraagt aan de component of hij zichzelf eens
denkbeeldig wil roteren
rond around bij een hoek van howmuch.
Hierbij dient de oude tekening
van de component die aanwezig is in result-in
vervangen worden door een nieuwe tekening.
(define (change-rotate-world!
result-in around howmuch)
((result-in
'%replace-drawing!)
drawing
((drawing
'rotate) around
howmuch))
((child
'change-rotate-world!)
result-in around howmuch))
In : function get-sub-world, function get-sleep-pad, function get-kill-set, function act
Out : error-melding/#t
Comments :
Met de functie get-sub-world
mag de component een
voorstel doen om een nieuwe subwereld te creëren voor de robot.
Als de voorstel-subwereld intact is moet de caller een sleep-pad
opdissen zodat
gecontroleerd kan worden of dit sleeppad tegen niets onaangenaams
knalt. Indien
wel wordt een error naar buiten geworpen. Indien ook hier geen
problemen waren
mag de robot in actie treden door act
op te roepen.
Get-kill-set is hier nodig om te
weten welke componenten eigenlijk in beweging zijn. Al de
vader-componenten
bijvoorbeeld mogen niet zomaar weggegooid worden.
Van act wordt niet verwacht
dat hij ook nog de oude componenten gaat verplaatsen in de nieuwe
wereld. Deze
berekening is al eens gedaan en moet niet herdaan worden. Gewoon de
component-positions/angles moeten hierbij aangepast worden. Als act te uitvoer wordt gebracht is de
nieuwe wereld reeds actief.
Ik heb het algoritme hieronder laten staan omdat het een zeer
representatief
stuk code is voor het gehele programma.
(define (want-to-act get-sub-world
get-sleep-pad get-kill-set act)
;deze wanttoact
is verschilend van
degene die in de robot
;steekt. Hier is
een bepaalde
optimizatie verandert zodat
;hij nog steeds
juist blijft
werken...
(let
((new-sub-world (get-sub-world)))
(if
(new-sub-world 'disturbed?)
(begin
((new-sub-world 'redraw)
'red)
(make-error 'sub
"intersecting sub-world"))
(let ((sleeppad (get-sleep-pad
new-sub-world)))
(if ((world
'disturbs-with?) sleeppad (get-kill-set))
(begin
((sleeppad 'show)
'red)
((new-sub-world
'redraw) 'light-red)
(make-error 'glob
"intersecting global world"))
(begin
(if sub-world
((world 'unregister) sub-world))
(new-sub-world
'wring-er-tussen)
(act)))))))
In : real new-length
Out : error/bool result
Comments : Probeert de armlengte te wijzigen naar new-length. Indien new-length
geen geldige grootte is wordt een error weergegeven. Indien de
lengteverandering een ongewenste snijding zou veroorzaken wordt ook een
error
weergegeven.
(define
(arm-length new-length)
(if (not
(valid-length?
new-length))
(make-error
'length
"invalid length")
(let
((new-drawing (drawing@
last-pos last-angle new-length))
(translation
(realize-angle
(make-point 0 0)
(- new-length lengte)
last-angle)))
(want-to-act
(lambda
() ;get-new-sub-world
(let ((answer-world
(sub-world 'copy)))
((answer-world
'%replace-drawing!) drawing new-drawing)
((child
'change-translate-world!) answer-world translation)
(answer-world
'recalc-bounds)
answer-world))
(lambda
(new-sub)
;get-sleep-pad
(let ((answer-sleep
(graph-set new-drawing)))
((child
'add-translate-sleeppad!) answer-sleep translation)
answer-sleep))
(lambda
() ;get-kill-set
(make-set (cons parent (cons
arm-self (child 'child-list)))))
(lambda
() ;action!
(set! lengte new-length)
((child 'translate-action)
translation)
(redraw))))))
Dispatcher arm-self
(define (arm-self m)
(cond ((eq? m
'glue) glue)
((eq? m 'unglue) (unglue))
((eq? m 'set-sub-world!)
set-sub-world!)
((eq? m 'set-drawing!)
set-drawing!)
((eq? m
'always-connected-to) (always-connected-to))
((eq? m 'sign-in-world)
sign-in-world)
((eq? m 'translate-action)
translate-action)
((eq? m 'change-translate-world!)
change-translate-world!)
((eq? m 'child-list) (cons
arm-self (child 'child-list)))
((eq? m
'add-translate-sleeppad!) add-translate-sleeppad!)
((eq? m 'rotate-action)
rotate-action)
((eq? m 'change-rotate-world!)
change-rotate-world!)
((eq? m 'arm-length)
arm-length)
(else (error "arm"
m))))
Initialisatie van de arm. Er wordt enkel gecontroleerd of de
lengtes wel aanvaardbare waarden hebben.
(let
((error-result (valid-init?)))
(if (error?
error-result)
error-result
arm-self))))
In : angle min, angle max, angle rotation, angle voethoek, component child
Out : scharnier result
Comments :
Bij de creatie wordt
zoals gewoonlijk weer niet gecontroleerd of er mogelijke snijdingen
zijn, er
wordt enkel gecheckt of de meegegeven parameters wel geldig zijn.
(define (make-scharnier minimum
maximum rotation
voethoek child)
(let ((parent #f)
(drawing
#f)
(last-pos
#f)
(last-angle
#f)
(sub-world
#f))
In : sub-world to
Out : nothing
Comments : Wordt opgeroepen als de sub-world van de robot
verandert. Hierbij wordt
de subworld van de component gezet op to.
(define (set-sub-world!
to)
(set! sub-world
to))
In : graph-set to
Out : nothing
Comments : Wordt opgeroepen als de sub-world van de robot
verandert. Hierbij wordt
de drawing van de component gezet op to.
(define
(set-drawing! to)
(set! drawing to))
In : component father
Out : bool result
Comments : Lijmt componenten aaneen zodat ze een tree
vormen. Indien father reeds
gekend was wordt #f weergegeven. (dit wil dus zeggen dat de component
reeds in
gebruik was). De glue message wordt
doorgegeven aan de kinderen.
(define (glue
father)
(if parent
#f
(begin
(set! parent father)
((child 'glue)
scharnier-self))))
In : nothing
Out : nothing
Comments : Zorgt dat de vader niet meer gekend is. Deze
routine dient opgeroepen te
worden als de creatie van de robot mislukt is, zodat de componenten in
een
nieuwe robot gebruikt kunnen worden
(define (unglue)
(set! parent #f)
(child 'unglue))
In : point pos, angle angle, angle rot
Out : go result
Comments : Er wordt een scharnier getekend op positie pos waarbij de interne hoek van het scharnier gelijk is
aan rot en de draaiingshoek in het vlak
gelijk aan angle.
(define (drawing@
pos angle rot)
(((((scharnier-drawing
rot)
'rotate)
(make-point 0 0)
angle)
'translate)
pos))
In : angle r
Out : bool res
Comments : Controleert of r wel een
geldige rotatie-hoek is voor het scharnier. Indien niet wordt
natuurlijk #f
weergegeven.
(define
(valid-rotation? r)
(and (>= r
minimum)
(<=
r maximum)))
In : nothing
Out : bool/error result
Comments : Controleert of de initiële parameters wel geldig
zijn. Er wordt een
error naar buiten geslingerd indien dit niet het geval is. Anders een
waardevolle #t.
(define
(valid-init?)
(if
(valid-rotation? rotation)
#t
(make-error
'value
"Impossible arm-value")))
In : point pos, angle angle, angle rot
Out : point end-point
Comments : Het resultaat is het beginpunt van de volgende
component. (of het
eindpunt van deze component)
(define
(calc-end-point pos angle rot)
(realize-angle
(realize-angle
pos 10 angle)
10 (+
rot angle)))
In : sub-world sw, point pos, angle angle
Out : nothing
Comments : Na het aaneen glue-en van de
componenten moet ook een subwereld gecreëerd worden. Dit wordt met deze
routine
gedaan. Sw is de subworld waarin het
resultaat moet komen, pos is de
positie van de component, angle is de
hoek die de component zal vormen.
(define
(sign-in-world sw pos angle)
(set! last-angle
angle)
(set! last-pos
pos)
(set! drawing
(drawing@ pos angle
rotation))
((sw 'sign-in)
scharnier-self
drawing)
((child
'sign-in-world) sw
(calc-end-point
pos angle
rotation) (+ angle voethoek rotation)))
In : nothing
Out : set of components result
Comments : Dit bericht vraagt de component of hij eens een
lijst wil naar buiten
geven met wie hij altijd verbonden zal zijn. Dit is om vanzelfsprekende
snijdingen op voorhand weg te filteren en zelf niet meer te controleren.
(define
(always-connected-to)
(fast-set parent
scharnier-self
child))
In : graph-set result-in, point howmuch
Out : nothing
Comments : Vraagt de component of hij het sleeppad ten
gevolge van een translate
over howmuch wil vervolledigen in result-in.
(define
(add-translate-sleeppad! result-in howmuch)
((result-in
'add!) ((drawing
'translate-sleep) howmuch))
((child
'add-translate-sleeppad!)
result-in howmuch))
In : point naar
Out : nothing
Comments : Vertelt de component dat al de checks voor een
translatie positief waren
en dat de translatie over naar
uitgevoerd mag worden. Hierbij wordt niet verwacht dat de tekeningen en
de
subworlds ge-updated worden. Deze zijn reeds veranderd. Deze routine
zorgt
gewoon dat een component zijn nieuwe positie kan bijhouden
(define
(translate-action naar)
(set! last-pos
((last-pos
'translate) naar))
((child
'translate-action) naar))
In : subworld result-in, point howmuch
Out : nothing
Comments : Vraagt de component of hij zichzelf eens
denkbeeldig wil verplaatsen
over afstand howmuch. Hierbij wordt
verwacht dat in result-in de oude
tekening van de component wordt vervangen door een nieuwe.
(define
(change-translate-world! result-in howmuch)
((result-in
'%replace-drawing!)
drawing
((drawing
'translate) howmuch))
((child
'change-translate-world!)
result-in howmuch))
In : point around, angle angle
Out : nothing
Comments : Net zoals bij translate-action
laat dit bericht toe dat de component zijn posities en hoeken up to
date
blijven.
(define
(rotate-action around angle)
(set! last-angle
(+ last-angle
angle))
(set! last-pos
((last-pos 'rotate)
around angle))
((child
'rotate-action) around
angle))
In : subworld result-in, point around, angle howmuch
Out : nothing
Comments : Vraagt aan de component of hij zichzelf eens
denkbeeldig wil roteren
rond around bij een hoek van howmuch.
Hierbij dient de oude tekening
van de component die aanwezig is in result-in
vervangen worden door een nieuwe tekening.
(define
(change-rotate-world! result-in around howmuch)
((result-in
'%replace-drawing!)
drawing
((drawing
'rotate) around
howmuch))
((child
'change-rotate-world!)
result-in around howmuch))
In : angle new-rot
Out : Error/bool result
Comments : Beweegt het scharnier naar de nieuwe
rotatiehoek. Hierbij wordt enkel
gecontroleerd dat het wel een geldige rotatiehoek is. Er is geen
controle op de
snijdingen.
(define
(scharnier-angle new-rot)
(if (not
(valid-rotation?
new-rot))
(make-error
'ROT "invalid
angle")
(let
((new-drawing (drawing@
last-pos last-angle new-rot))
(torotate (- new-rot
rotation))
(midpoint (realize-angle
last-pos 10 last-angle)))
(define
(get-new-sub-world)
(let
((answer-world (sub-world
'copy)))
((answer-world
'%replace-drawing!) drawing new-drawing)
((child
'change-rotate-world!) answer-world midpoint torotate)
(answer-world
'recalc-bounds)
answer-world))
(define
(act)
(set!
rotation new-rot)
((child
'rotate-action)
midpoint torotate)
(redraw))
(if
sub-world ((world
'unregister) sub-world))
((get-new-sub-world)
'wring-er-tussen)
(act))))
Dispatcher scharnier-self
(define (scharnier-self m)
(cond ((eq? m
'glue) glue)
((eq? m 'unglue) (unglue))
((eq? m 'set-sub-world!)
set-sub-world!)
((eq? m 'set-drawing!)
set-drawing!)
((eq? m
'always-connected-to) (always-connected-to))
((eq? m 'sign-in-world)
sign-in-world)
((eq? m 'translate-action)
translate-action)
((eq? m
'change-translate-world!) change-translate-world!)
((eq? m 'rotate-action)
rotate-action)
((eq? m
'change-rotate-world!) change-rotate-world!)
((eq? m 'child-list) (cons
scharnier-self (child 'child-list)))
((eq? m
'add-translate-sleeppad!) add-translate-sleeppad!)
((eq? m 'scharnier-angle)
scharnier-angle)
(else (error
"scharnier" m))))
Initialisatie van het scharnier. Enkel controle op de initiële
parameters.
(let
((error-result (valid-init?)))
(if (error?
error-result)
error-result
scharnier-self))))
Dit is een stuk
rare code omdat hier bijna bij elke operatie een uitzondering gevormd
moet
worden. Deze uitzonderingen ontstaan door het feit dat dit het
beginpunt van de
robot is. Op het ogenblik dat deze gemaakt wordt moet ik een robot op
het
scherm zetten (wat bij de componenten niet gebeurt)
Een andere uitzondering geeft aanleiding tot een optimisatie : het
verplaatsen
van de robot wil gewoon zeggen dat de volledige subwereld wil
verplaatsen. Dan
moet ik niet aan elke component gaan vragen of hij mij het sleeppad
eens wil
geven.
(define (make-robot pos voethoek
comp)
(let ((drawing #f)
(sub-world
#f)
)
In : sub-world to
Out : nothing
Comments : Wordt opgeroepen als de sub-world van de robot
verandert. Hierbij wordt
de subworld van de component gezet op to.
(define
(set-sub-world! to)
(set! sub-world
to))
In : graph-set to
Out : nothing
Comments : Wordt opgeroepen als de sub-world van de robot
verandert. Hierbij wordt
de drawing van de component gezet op to.
(define
(set-drawing! to)
(set! drawing to))
In : color color
Out : nothing
Comments : Tekent de robot door gewoon de volledige
subwereld te hertekenen. Hier
wordt dus niet aan elke component gevraagd of hij zichzelf eens wil
tekenen. Color mag 'ownstyle zijn.
(define
(show-robot color)
((sub-world
'redraw) color))
In : point p
Out : graph-set result
Comments : de functie drawing@ geeft de
tekening weer die hoort bij de robot. Dit is een soort van 'private'
member.
(define (drawing@
p)
(((robot-drawing)
'translate) p))
In : nothing
Out : bool result
Comments : Lijmt componenten aaneen zodat ze een tree
vormen. Indien er ergens
lussen voorkomen wordt #f weergegeven. (dit wil dus zeggen dat de
component
reeds in gebruik was). De glue
message wordt doorgegeven aan de kinderen. Merk op dat deze glue
verschilt van de andere in het feit
dat deze geen parameter verwacht. Father
is namelijk toch #f
(define (glue)
((comp 'glue)
robot-self))
In : nothing
Out : nothing
Comments : Zorgt dat de vader niet meer gekend is. Deze
routine dient opgeroepen te
worden als de creatie van de robot mislukt is, zodat de componenten in
een
nieuwe robot gebruikt kunnen worden
(define (unglue)
(comp 'unglue))
In : nothing
Out : subworld result
Comments : deze functie vervolledigt de subwereld door er
al de tekeningen van de
componenten in te steken.
(define
(init-sub-world)
(let ((result-sub
(make-subworld)))
((comp
'sign-in-world)
result-sub pos voethoek)
(set!
drawing (drawing@ pos))
((result-sub
'sign-in)
robot-self drawing)
result-sub))
In : nothing
Out : set of components result
Comments : Dit bericht vraagt de component of hij eens een
lijst wil naar buiten
geven met wie hij altijd verbonden zal zijn. Dit is om vanzelfsprekende
snijdingen op voorhand weg te filteren en zelf niet meer te controleren.
(define
(always-connected-to)
(fast-set
robot-self comp))
In : nothing
Out : error/bool result
Comments : als deze true weergeeft, is de robot gesigned-in en
zijn al de
kinderen reeds aaneen gelijmd...
Anders wordt een passende error geprepareerd.
(define (valid-init?)
(define
(try-something)
(if
(not (glue))
(make-error 'glue
"robot-lussen")
(want-to-act
init-sub-world
(lambda (new-sub-world)
(new-sub-world 'full-drawing))
(lambda () #f))))
(let ((try-result
(try-something)))
(if
(error? try-result)
(unglue))
try-result))
In : function get-sub-world, function get-sleep-pad, function act
Out : error-melding/#t
Comments :
Met de functie get-sub-world
mag de component een voorstel doen om een nieuwe
subwereld te creëren voor de robot.
Als de voorstel-subwereld intact is moet de caller een sleep-pad
opdissen zodat
gecontroleerd kan worden of dit sleeppad tegen niets onaangenaams
knalt. Indien
wel wordt een error naar buiten geworpen. Indien ook hier geen
problemen waren
mag de robot in actie treden door act
op te roepen.
Van act wordt niet verwacht
dat hij ook nog de oude componenten gaat verplaatsen in de nieuwe
wereld. Deze
berekening is al eens gedaan en moet niet herdaan worden. Gewoon de
component-positions/angles moeten hierbij aangepast worden. Als act te uitvoer wordt gebracht is de
nieuwe wereld reeds actief.
Ik heb het algoritme hieronder laten staan omdat het een zeer
representatief
stuk code is voor het gehele programma.
(define (want-to-act get-sub-world get-sleep-pad act)
(let
((new-sub-world (get-sub-world)))
(if
(new-sub-world 'disturbed?)
(begin
((new-sub-world 'redraw)
'red)
(make-error 'sub
"intersecting sub-world"))
(begin
(if sub-world ((world
'unregister) sub-world))
(let*
((sleeppad (get-sleep-pad new-sub-world)))
(if ((world
'disturbs-with?) sleeppad (fast-set))
(begin
(if sub-world
((world 'register) sub-world))
((sleeppad 'show)
'red)
((new-sub-world
'redraw) 'light-red)
(make-error 'glob
"intersecting global world"))
(begin
(new-sub-world
'wring-er-tussen)
(act))))))))
In : point naar
Out : nothing
Comments : Vertelt de component dat al de checks voor een translatie positief waren en dat de translatie over naar uitgevoerd mag worden. Hierbij wordt niet verwacht dat de tekeningen en de subworlds ge-update worden. Deze zijn reeds veranderd. Deze routine zorgt gewoon dat een component zijn nieuwe positie kan bijhouden
(define (translate-action naar)
(set! pos ((pos
'translate) naar))
((comp
'translate-action) naar)
(redraw))
In : point speed
Out : error/bool result
Comments : Dit is de vraag die gesteld wordt als de robot zich moet verplaatsen. Merk op dat hier een optimisatie plaatsgrijpt doordat ik de volledige subwereld versleep en niet aan elke component vraag of hij zichzelf eens wil veranderen in een denkbeeldige wereld.
(define (translation-move speed)
(want-to-act
(lambda
() ((sub-world
'translate) speed))
(lambda
(new-sub-world)
((sub-world 'translate-sleep) speed))
(lambda
() (translate-action
speed))))
Dispatcher robot-self
(define (robot-self m)
(cond ((eq? m
'show) show-robot)
((eq? m 'drawing) drawing)
((eq? m 'right)
translation-move)
((eq? m 'set-sub-world!)
set-sub-world!)
((eq? m 'always-connected-to)
(always-connected-to))
((eq? m 'set-drawing!)
set-drawing!)
(else (error
"robot" m))))
Initialisatie.
Hier wordt gecontroleerd of er door het
maken van
de robot geen disturbed worlds optreden. Verder wordt onderzocht of er
geen componenten
zijn die 2 keer gebruikt worden. Indien alles perfect verlopen is wordt
de
robot-self weergegeven. In het andere geval een passende error.
(let
((error-result (valid-init?)))
(if (error?
error-result)
error-result
(begin
(show-robot 14)
robot-self)))))
Vanaf hier begint zo meer het omgeving-afhankelijke. Het aansturen van het scherm bijvoorbeeld.
PCS-window : dit is het trace-window onderaan het scherm.
(define trace-window #f)
Initialisatie van het trace-window. Dit wordt gedaan door de statusline over den hoop te smijten, en de console op maat te brengen.
(define (init-trace-window
trace-window-size)
(full-screen)
(let* ((ysize-normaltext (+ 1 (car
(window-get-position
'console))
(car (window-get-size
'console))))
(lettergrootte
(/ (1+ maxy)
ysize-normaltext)))
(window-set-position!
trace-window
(-
ysize-normaltext
trace-window-size) 0)
(set! maxy (- maxy (* lettergrootte trace-window-size) 1))
(set-viewport '(0 . 0) (cons
maxx
maxy) #t) ;#t = clipping
(window-set-attribute!
trace-window
'text-attributes 78)
(window-clear trace-window)
(window-set-cursor!
trace-window
(-1+ trace-window-size) 0)))
Dit is de file naar waar al de messages en vragen worden uitgevoerd. De grafische uitvoer wordt hierin niet opgeslagen
(define transcript-file #f)
Verandert de transcriptfile
(define (set-transcript-file
filename)
(if transcript-file (close-output-port
transcript-file))
(set! transcript-file #f)
(set! transcript-file
(open-output-file filename)))
Initialiseert de transcriptfile. Normaal is het de file trans.txt die wordt geopend.
(define (init-transcript-file)
(set-transcript-file
"trans.txt"))
Sluit de transcript-file.
(define (close-transcript-file)
(if transcript-file (close-output-port
transcript-file)))
De constanten gebruikt in message en message-list.
(define nl 'newline)
(define wt 'wait)
Print een lijst van berichten af. Indien het element van de lijst
nl is : voeg een enter tussen
wt : wacht tot de gebruiker een toets drukt
procedure is, m.a.w : een object. Dan wordt de display-member aangeroepen
anders : gewoon display'n
(define (message-list l)
(cond ((null? l) #t)
((procedure?
(car l))
((car
l) 'display)
(message-list
(cdr l)))
((eq?
(car l) wt)
(press-any-key)
(message-list
(cdr l)))
((eq?
(car l) nl)
(if
transcript-file (newline
transcript-file))
(newline)
(message-list
(cdr l)))
(else
(if
transcript-file (display
(car l) transcript-file))
(display
(car l))
(message-list
(cdr l)))))
Deze routine print een boodschap
af op het
scherm en naar de transcript-file indien deze laatste bestaat. Het
gebruik ziet
er als volgt uit :
(message "test") print
test
op het scherm (zonder enter)
(message "test" nl) print
test
op het scherm (met enter)
(message "dit" nl "is" nl" een test") geeft dan
dit
is
een test
(define message
(lambda string-list
(message-list string-list)))
Vraagt de gebruiker een yes/no vraag. Het resultaat en de vraag zelf worden ook naar de transcriptfile geschreven.
(define (Ask-Yes-No Phrase)
(flush-input)
(message Phrase " ? ")
(let ((char (read-char)))
(cond ((or (eq? char '#\Y)
(eq? char
'#\y))
(message "YES" nl)
#t)
((or
(eq? char '#\N) (eq? char
'#\n))
(message "NO" nl)
#f)
(else
(message nl)
(Ask-Yes-No Phrase)))))
Wacht tot de gebruiker een toets indrukt. Van deze actie wordt niets naar de transcriptfile geschreven.
(define (press-any-key)
(flush-input)
(if (eq? (char->integer
(read-char)) 0) (read-char))
#t)
Vraagt een filename aan de gebruiker. Alles wordt weeral naar de transcriptfile gedumpt.
(define (ask-filename)
(define answer)
(message "Filename : ")
(flush-input)
(set! answer (read-line))
(if transcript-file
(begin
(display answer
transcript-file)
(newline
transcript-file)))
answer)
Vraagt een expressie aan de gebruiker. Weeral een dump naar de transcriptfile en naar het scherm.
(define (ask-user)
(define answer)
(set! answer (read))
(if transcript-file
(begin
(display
answer transcript-file)
(newline
transcript-file)))
answer)
Deze functie maakt het trace-window-pje leeg.
(define (clw)
(window-delete trace-window))
Constanten voor de definitie van standaardkleuren en maximumcoordinaten.
(define maxx #f)
(define maxy #f)
(define background-color 'BLACK)
(define std-line-color 'GREEN)
(define std-point-color 'LIGHT-RED)
(define std-circle-color 'YELLOW)
De scaling constanten zodat het scherm 400 bij 400 gemapt wordt naar het bestaande raster-scherm.
(define xfact #f)
(define xterm #f)
(define yfact #f)
(define yterm #f)
Dit berekent de coordinaten eens in functie van de meegegeven gevraagde bounds.
(define (set-xworld left top right
bottom)
(set! xterm (- left))
(set! yterm (- top))
(set! xfact (/ maxx (- right left)))
(set! yfact (/ maxy (- bottom top))))
Voort een nieuw coordinatenstelsel in. Hierbij steun ik nogal sterk op hetgeen PCS me aanreikt. (de functies set-coordinates! en set-point?-! heb ik niet geschreven.)
(define (init-points)
(set-xworld -200 200 200 -200)
(set-point?-!
(lambda (p)
(and
(procedure?
p)
(point?
p))))
(set-coordinates!
(lambda (p)
(round (* (+ (p
'x) xterm)
xfact)))
(lambda (p)
(round (* (+ (p
'y) yterm)
yfact)))
(lambda (xy)
(make-point (car
xy) (cdr xy)))))
Initialiseert een nieuwe definitie van afstand zodat cirkels ook juist worden getekend. De functie set-distances! is er weerom één van PCS.
(define (init-circles)
(set-fill-style 'EMPTY 'BLACK)
(set-distances!
(lambda (p k)
(round (* (k 'x)
xfact)))
(lambda (p k)
(round (* (k 'y)
yfact)))
(lambda (p k)
(error
"unary-dist,
circles"))))
Initialiseert de grafische objecten door de punten te registreren en de circles.
(define (init-graphical-objects)
(init-points)
(init-circles)
)
Maakt het grafische scherm leeg.
(define (cls)
(clear-viewport))
Hertekent het volledige scherm. De untouchable world wordt achter de global world getekend.
(define (redraw)
(cls)
(untouchable-world 'redraw)
((world 'redraw) 14))
Herinitializeert de werelden en hertekent het scherm
(define (reset-world)
(init-world)
(redraw))
Herinitialiseert de werelden zonder het scherm te hertekenen.
(define (init-world)
(world 'init)
(untouchable-world 'init))
Initialiseert een nieuwe aspect-ratio zodat circles getekend worden zoals ik ze vraag (en niet zoals de gebruiker een cirkel wil zien)
(define (init-graphics)
(init-graph)
(set-aspect-ratio '(1 . 1))
(set! maxx (car (get-max-xy)))
(set! maxy (cdr (get-max-xy)))
(%reify-port! pcs-status-window 11
(bitwise-and (%reify-port
pcs-status-window
11) -11))
(clear-device))
Hier is de definitie van de error's voorhanden. Deze is zo simpel dat er weinig uitleg bij moet.
(define (make-error info . text)
(list 'error info text))
(define (error? e)
(and (pair? e) (eq? (car e) 'error)))
(define (error-text e)
(caddr e))
(define (error-info e)
(cadr e))
In : real lengte, angle voethoek, component child
Out : arm result
Comments :
(define (make-normal-arm lengte
voethoek child)
(make-arm lengte lengte lengte
voethoek child))
In : angle rotation, angle voethoek, component child
Out : scharnier result
Comments :
Dit scharnier wordt abnormaal genoemd omdat het geen minimum/maximum rotatiehoek heeft, hij kan volledig 360° ronddraaien zonder morren.
(define (make-abnormal-scharnier
rotation
voethoek child)
(make-scharnier 0 2PI rotation
voethoek child))
In : robot who, int x, int y
Out : #t/error
Comments
: Deze routine zorgt dat de robot over (x,y) verplaatst. Hierbij worden
botsingen met andere robot's gecontroleerd. De meegegeven parameter who moet een robot-root zijn. Indien
niet zal er een error optreden.
(define (rel-move who speedx speedy)
((who 'right) (make-point speedx
speedy)))
In : arm who, real length
Out : #t/error
Comments : Verandert de lengte van de meegegeven arm. who mag ofwel een vaste-arm zijn, ofwel een variabele arm. Bij het veranderen van de armlengte wordt gecontroleerd of de robot zichzelf niet snijdt, nadien wordt gecontroleerd of de globale wereld niet om zeep wordt geholpen.
(define (arm-length who new-length)
((who 'arm-length) new-length))
In : pen-component who
Out : #t
Comments : Heft de pen op van het papier zodat, als de robot in het vervolg beweegt, geen lijnen meer worden getekend.
(define (pen-up who)
(who 'pen-up))
In : pen-component who
Out : #t
Comments : Zet de pen op papier. De eerst volgende keer dat de pen wordt verplaatst. Bijvoorbeeld door een armbeweging of door het verplaatsen van de robot zal er een lijn in kleur color getekend worden. (color is gedefinieerd bij het creëeren van de pen)
(define (pen-down who)
(who 'pen-down))
In : pen-component who, color nieuwekleur
Out : #t
Comments : Verandert de kleur van de meegegeven pen. De volgende keer dat een lijn moet getekend worden zal dit in de nieuwe kleur gebeuren.
(define (pen-color who nieuwekleur)
((who 'color!) nieuwekleur))
In : scharnier-component who, angle angle
Out : #t/error
Comments : Verandert de hoek van who, indien mogelijk natuurlijk. Bij deze operatie worden geen interne, noch externe snijdingen gecontroleerd.
(define (rotate who angle)
((who 'scharnier-angle) angle))
In : boor-component wie
Out : #t
Comments : Boort een gat op de huidige plaats van de boor. Deze wordt voorgesteld door een rondje op de plaats waar geboord werd.
(define (boor wie)
(wie 'boor))
In : list lst
Out : 'done
Comments : Deze routine creëert een nieuwe scheme-omgeving en laat de lijst van commando's erin runnen. Voor het uitvoeren van de eerste instructie worden al de voorgaande gegevens gewist. Na het uitvoeren van lst worden nog eens al de werelden leeg gemaakt.
Caution : Er gebeurt geen controle op het recursief aanroepen van programma's. Dit zou dus tot erg onaangename verrassingen kunnen leiden.
(define (loop-program lst)
(let ((env (make-environment)))
(define (action wat)
(let ((result #f))
(message
wat nl wt)
(set!
result (eval wat env))
(if
(and (pair? wat) (eq? (car
wat) 'define))
(set! result (eval result
env)))
result))
(define (loop lst)
(if (null? lst)
#t
(let
((result (action (car
lst))))
(if (error? result)
(begin
(message " =>
" result nl wt)
(redraw)))
(loop (cdr lst)))))
(init-world)
(redraw)
(loop lst)
(init-world)
(redraw)
'done))
(define (demo)
(message "Programma 1" nl
wt)
(loop-program program1)
(message "Programma 2" nl
wt)
(loop-program program2)
(message "Programma 3" nl
wt)
(loop-program program3)
(message "Programma 4" nl
wt)
(loop-program program4)
(message "Programma 5" nl
wt)
(loop-program program5)
(message "Programma 6" nl
wt)
(loop-program program6)
(message "That's all folks
!" nl wt)
(init-world)
(redraw)
*the-non-printing-object*)
(define program1 '(
(define dennis-pen (make-pen 'WHITE))
(define dennis-arm2 (make-arm 0 100 50
0 dennis-pen))
(define dennis-arm2 (make-arm 10 49 50
0 dennis-pen))
(define dennis-arm2 (make-arm 10 100
50 0 dennis-pen))
(define dennis-arm1 (make-arm 10 100
50 (/ PI 6) dennis-arm2))
(define dennis (make-robot (make-point
0 0) PI/2 dennis-arm1))
(rel-move dennis 100 0)
(rel-move dennis 50 -100)
(pen-down dennis-pen)
(rel-move dennis -50 10)
(pen-color dennis-pen 'LIGHT-BLUE)
(rel-move dennis 10 100)
(pen-color dennis-pen 'LIGHT-GREEN)
(arm-length dennis-arm1 100)
(arm-length dennis-arm2 110)
(arm-length dennis-arm2 100)
(arm-length dennis-arm1 10)
(arm-length dennis-arm2 10)
))
(define program2 '(
(define ralf-arm4 (make-arm 10 200 50
PI/2 null-component))
(define ralf-arm3 (make-arm 10 200 20
PI/2 ralf-arm4))
(define ralf-arm2 (make-arm 10 200 80
PI/2 ralf-arm3))
(define ralf-arm1 (make-arm 10 200 70
PI/2 ralf-arm2))
(define ralf-voet (make-robot
(make-point 150 30) PI/2 ralf-arm1))
(arm-length ralf-arm4 70)
(arm-length ralf-arm4 90)
(arm-length ralf-arm4 110)
(arm-length ralf-arm3 100)
(arm-length ralf-arm2 200)
(arm-length ralf-arm3 100)
(arm-length ralf-arm2 80)
(arm-length ralf-arm4 100)
(arm-length ralf-arm1 100)
))
(define program3 '(
(define ralf-arm (make-normal-arm 200
0 null-component))
(define ralf
(make-robot (make-point -150
-30) (-
PI/2 (/ PI 8)) ralf-arm))
(define dennis-pen (make-pen 'BLUE))
(define dennis-arm2 (make-arm 10 200
30 0 dennis-pen))
(define dennis-arm1 (make-arm 10 200
30 (/ PI 4) dennis-arm2))
(define dennis (make-robot (make-point
150 30) (/ PI 4) dennis-arm1))
(arm-length ralf-arm 100)
(arm-length ralf-arm 250)
(pen-down dennis-pen)
(rel-move dennis -280 0)
(rel-move dennis -150 0)
(rel-move ralf 300 0)
(rel-move ralf 300 -20)
(rel-move dennis -100 -2.5)
(arm-length dennis-arm2 100)
(arm-length dennis-arm1 100)
))
(define program4 '(
(define circler-pen (make-pen 'BLUE))
(define circler-arm2 (make-normal-arm
100 0 circler-pen))
(define circler-rot2 (make-scharnier
(/ PI 4) PI/2 PI/2 0 circler-arm2))
(define circler-arm1 (make-normal-arm
100 0 circler-rot2))
(define circler-rot1
(make-abnormal-scharnier PI/2 0 circler-arm1))
(define circler (make-robot
(make-point 30 0) PI/2 circler-rot1))
(pen-down circler-pen)
(rotate circler-rot2 0)
(rotate circler-rot2 (/ PI 4))
(rotate circler-rot1 (/ PI 4))
(rotate circler-rot2 (/ PI 2))
(rotate circler-rot1 (/ PI 2))
))
(define program5 '(
(define circler-pen (make-pen 'GREEN))
(define circler-arm2 (make-normal-arm
100 0 circler-pen))
(define circler-rot2
(make-abnormal-scharnier
PI/2 (/ PI
8) circler-arm2))
(define circler-arm1 (make-normal-arm
100 (/ PI 8) circler-rot2))
(define circler-rot1
(make-abnormal-scharnier
PI/2 (/ PI
8) circler-arm1))
(define circler (make-robot
(make-point 30 0) (/ PI 4) circler-rot1))
(pen-down circler-pen)
(rotate circler-rot2 (/ PI 4))
(rotate circler-rot1 (/ PI 4))
(rotate circler-rot2 (/ PI 2))
(rotate circler-rot1 (/ PI 2))
))
(define program6 '(
(define boor-end (make-boor))
(define boormachien (make-robot
(make-point
0 0) 0 boor-end))
(boor boor-end)
(rel-move boormachien 0 -100)
(boor boor-end)
(rel-move boormachien 0 200)
(boor boor-end)
(rel-move boormachien -100 -100)
(boor boor-end)
(rel-move boormachien 200 0)
(boor boor-end)
))
De my-random is een gewone randomfunctie. Het enige dat ik heb veranderd is dat de 0 nog steeds werkt. (De random van PCS loopt vast bij een 0)
(define (my-random x)
;deze heb ik moeten definieren omdat
die
;van PCS niet goed gaat
(if (= x 0)
0
(random
x)))
Een beetje show om aan te tonen wie dit programma gemaakt heeft : ikke, me, mezelf, and I.
(define (about)
(let* ((midx (/ maxx 2))
(midy
(/ maxy 2))
(mid-point
(cons midx midy))
(maxcolor
(get-max-color)))
(define
(iter count)
(set-color (1+
(my-random (-1+
maxcolor))))
(set-text-style
'DEFAULT 'horiz 5)
(set-text-justify
'CENTER 'BOTTOM)
(out-text-xy
mid-point
"Dennis")
(set-text-justify
'CENTER 'TOP)
(set-text-style
'DEFAULT 'horiz 1)
(out-text-xy
mid-point
"De
artificieel levende
robot in een gesimuleerde wereld")
(set-text-justify
'CENTER 'BOTTOM)
(out-text-xy
(cons midx (- maxy
45)) "Made by Werner Van Belle 1995")
(set-text-justify
'LEFT 'TOP)
(if (> count
0) (iter (-1+
count))))
(iter 30)
(iter 1)
(clear-device)
))
Initialiseert de application
(define (init-app)
(init-graphics)
(about)
(set! about #f) ;voor de gc
(init-trace-window 8)
(init-graphical-objects)
(init-transcript-file)
(init-world))
Sluit de application
(define (close-app)
(close-transcript-file)
(close-graph)
*the-non-printing-object*)
Het hoofdprogramma !
(init-app)
(demo)
In deze paragraaf worden de ADT's besproken die ik gedefinieerd en geïmplementeerd heb, maar die ik omwille van het plaatsgebrek en de snelheid van PCS nooit heb kunnen gebruiken. (zonde!). De werkelijk gebruikte ADT's zijn gewoon afgeslankte versies van onderstaande.
Dit ADT vormt de definitie van de breuken. Dit ADT is niet gebruikt in het project omdat het te veel geheugen vraagt en te traag werkt. Met behulp van de breuken kon ik met oneindig werken als ware het niets. Het geestige was natuurlijk wel dat er hier en daar toch nog altijd moest gecontroleerd worden of we niet met oneindig te maken hadden. Dit zou opgelost kunnen worden (denk ik) door bij elk rationaal getal een soort historiek bij te houden, zodat de operaties dan kunnen bedenken wat het meest wenselijke resultaat zou zijn. Maar aangezien dit geen project is om wiskundige structuren te definiëren heb ik ze er gewoon maar uit gelaten.
In : integer teller, integer noemer
Out : breuk r
Comments : deze is als macro gedefiniëerd omwill van performantie-redenen.
(macro %makeb (lambda (p)
`(cons ,(cadr p) ,(caddr p))))
In : breuk b
Out : real teller
(macro teller (lambda (p)
`(car ,(cadr p))))
In : breuk b
Out : real noemer
(macro noemer (lambda (p)
`(cdr ,(cadr p))))
In : integer teller, integer
noemer
Out : breuk r
Comments : creëert een breuk en zet ze onmiddelijk om naar een intern gewenst formaat. Normaal moet makeb altijd worden aangeroepen en niet %makeb
(define (makeb t n)
(vereenvoudig (%makeb t n)))
In : something b
Out : bool r
Comments : geeft #t weer als b een breuk is.
(define (breuk? b)
(pair? b))
In : breuk b
Out : bool r
Comments : deze functie geeft weer of de breuk +inf voorstelt.
(define (+inf? b)
(and (> (teller b) 0) (= (noemer b)
0)))
In : breuk b
Out : bool r
Comments : deze functie geeft weer of de breuk -inf voorstelt.
(define (-inf? b)
(and (< (teller b) 0) (= (noemer b)
0)))
In : breuk b
Out : bool r
Comments : deze functie geeft weer of de breuk -inf of +inf voorstelt.
(define (inf? b)
(and (<> (teller b) 0) (=
(noemer b) 0)))
In : breuk b
Out : bool r
Comments : deze functie geeft weer of de breuk +0 voorstelt.
(define (+zero? b)
(and (> (noemer b) 0) (= (teller b)
0)))
In : breuk b
Out : bool r
Comments : deze functie geeft weer of de breuk -0 voorstelt.
(define (-zero? b)
(and (< (noemer b) 0) (= (teller b)
0)))
In : breuk b
Out : bool r
Comments : deze functie geeft weer of de breuk 0 voorstelt.
(define (bzero? b)
(and (<> (noemer b) 0) (=
(teller b) 0)))
In : breuk b
Out : bool r
Comments : kijkt of b voorgesteld kan worden als een reëel getal.
(define (is-real? b)
(<> (noemer b) 0))
In : breuk b
Out : bool r
Comments : kijkt of b geen reëel getal is. Deze functie verschilt van inf? omdat 0/0 geen reëel getal is maar ook niet oneindig.
(define (is-no-real? b)
(= (noemer b) 0))
In : breuk b
Out : bool r
Comments : geeft #f weer als de breuk negatief is.
(define (bpositive? b)
(>b b 0b))
In : breuk b
Out : nothing
Comments : print de breuk af. Mogelijk uitvoer is
+inf
-inf
+0
-0
teller/noemer
(define (display-breuk b)
(cond ((+inf? b) (message
"+inf"))
((-inf?
b) (message "-inf"))
((+zero?
b) (message
"+0"))
((-zero?
b) (message
"-0"))
((=
(noemer b) 1) (message
(teller b)))
(else
(message
(teller b))
(message
"/")
(message
(noemer b)))))
In : breuk b
Out : breuk r
Comments : de breuk wordt vereenvoudigd en naar buiten gegeven. Normaal moet deze functie niet aangeroepen worden. Elke operatie zal deze vanzelf aanroepen.
(define (vereenvoudig b)
(cond ((and (= (teller b) 0) (=
(noemer b) 0))
(error
"Creating
nan"))
((inf?
b)
(if
(+inf? b) (%makeb 1 0)
(%makeb -1 0)))
((bzero?
b)
(if
(+zero? b) (%makeb 0 1)
(%makeb 0 -1)))
(else
(if
(< (noemer b) 0)
(set! b (%makeb (- (teller
b)) (- (noemer b)))))
(let
((deeldoor (gcd (teller
b) (noemer b))))
(%makeb (quotient (teller b)
deeldoor)
(quotient (noemer b)
deeldoor))))))
In : breuk b
Out : breuk r
Comments : maakt het inverse van b. Indien b + oneindig was, zal b nadien +0 zijn. Evenzo voor -oneindig
(define (inverse b)
(makeb (noemer b) (teller b)))
In : breuk b, integer g
Out : breuk r
Comments : Vermenigvuldigt g met b en geeft het resultaat weer. Hier wordt niet gecontroleerd of g wel een integer is. Desalwelteplus zal dit zeker niet tot errors leiden.
(define (b*g b g)
(*b b (makeb g 1)))
In : breuk q
Out : integer z
Comments : geeft het gehele deel van de breuk weer, indien mogelijk. Er wordt geen error-checking gedaan.
(define (q->z q)
(quotient (teller q) (noemer q)))
In : breuk b1, breuk b2
Out : breuk r
Comments : vermenigvuldigt b1 met b2. Hier wordt error-checking gedaan voor operaties zoals 0 vermenigvuldigt met oneindig.
(define (*b b1 b2)
(makeb (* (teller b1) (teller b2))
(*
(noemer b1) (noemer b2))))
In : breuk b1, breuk b2
Out : breuk r
Comments : deelt b1 met b2. Hier wordt error-checking gedaan voor operaties zoals 0 vermenigvuldigt met oneindig.
(define (/b b1 b2)
(*b b1 (inverse b2)))
In : breuk b1, breuk b2
Out : breuk r
Comments : telt b1 bij b2 en geeft het resultaat weer. Geen error-checking op oneindig.
(define (+b b1 b2)
(makeb (+ (* (teller b1) (noemer b2))
(* (teller b2) (noemer b1)))
(*
(noemer b1) (noemer b2))))
In : breuk b1, breuk b2
Out : breuk r
Comments : trekt b2 af van b1 en geeft het resultaat weer. Geen error-checking op oneindig.
(define (-b b1 b2)
(makeb (- (* (teller b1) (noemer b2))
(* (teller b2) (noemer b1)))
(*
(noemer b1) (noemer b2))))
In : breuk b1, breuk b2
Out : bool r
Comments : controleert of b1 gelijk is aan b2. Geen problemen met oneindig en dergelijke.
(define (=b b1 b2)
(and (= (teller b1) (teller b2))
(= (noemer
b1) (noemer b2))))
In : breuk b1, breuk b2
Out : bool r
Comments : geeft weer of b1>b2. Bij definitie (mijn definitie althans) is +oneindig niet groter dan +oneindig en -oneindig niet kleiner dan -oneindig.
(define (>b b1 b2)
(cond ((or (and (+inf? b1) (+inf? b2))
(and (-inf? b1) (-inf?
b2))) #f)
((and
(-inf? b1) (+inf? b2)) #f)
((and
(+inf? b1) (-inf? b2)) #t)
(else
(if
(-zero? b1) (set! b1 0B))
(if
(-zero? b2) (set! b2 0B))
(>
(* (teller b1) (noemer
b2))
(* (noemer b1) (teller
b2)))))))
In : breuk b1, breuk b2
Out : bool r
Comments : geeft weer of Deze functie steunt
volledig op de definitie
van >b en =b.
(define (>=b b1 b2)
(or (=b b1 b2) (>b b1 b2)))
In : breuk b1, breuk b2
Out : bool r
Comments : geeft weer of Deze functie steunt volledig op de definitie van >b en =b.
(define (<b b1 b2)
(not (>=b b1 b2)))
In : breuk b1, breuk b2
Out : bool r
Comments : geeft weer of Deze functie steunt volledig op de definitie van >b.
(define (<=b b1 b2)
(not (>b b1 b2)))
In : breuk b
Out : real r
Comments : Converteert b naar een
bijhorend reëel getal. Hier wordt geen error-checking gedaan voor het
geval
oneindig.
(define (b->r b)
(/ (teller b) (noemer b)))
In : integer g
Out : breuk r
Comments : converteert het meegegeven getal naar een breuk. Dit had eigelijk een macro kunnen zijn.
(define (g->b g)
(makeb g 1))
In : breuk a
Out : breuk b
Comments : Het absolute deel van a wordt weergegeven. Geen probleem voor +inf, -inf, nan, +0 & -0.
(define (babs a)
(makeb (abs (teller a))
(abs
(noemer a))))
Definities van vaak gebruikte rationale getallen.
(define 0B (makeb 0 1))
(define 1B (makeb 1 1))
(define +inf (makeb 1 0))
(define -inf (makeb -1 0))
In : real coefficient, open/gesloten
Out : grens
Comments : deze grenzen waren nodig om nadien de half-open/open/gesloten intervallen te definieren.
(define (make-grens coefficient
open-of-gesloten)
(if (inf? coefficient) (set!
open-of-gesloten open))
(cons coefficient open-of-gesloten))
Definitie van
open/gesloten
(define open 'open)
(define gesloten 'gesloten)
In : grens grens
Out : bool r
Comments : Geeft #t weer als dit een open grens is.
(define (open?
grens)
(eq? open (cdr grens)))
In : grens grens
Out : bool r
Comments : Geeft #t weer als dit een gesloten grens is.
(define (gesloten? grens)
(eq? gesloten (cdr grens)))
In : grens grens
Out : open/gesloten r
Comments : geeft weer of r open of gesloten is. Deze kan nadien gecontroleerd worden met eq?
(define (open-gesloten? grens)
(cdr grens))
In : grens grens
Out : real r
Comments : Geeft de grens-waarde naar buiten
(define (coef grens)
(car grens))
In : grens grens, real new-coef
Out : grens r
Comments : Maakt een nieuwe grens waarbij de open/gesloten
gecopieerd wordt van grens, en de coefficiënt van new-coef
(define (change-coef grens naar)
(make-grens naar (open-gesloten?
grens)))
In : grens from-grens, grens to-grens
Out : interval r
Comments : Het ADT Interval is gedefinieerd als een
struktuur met een verzameling
operaties. Error-gevallen zijn de volgende intervallen :
[a;a[ of ]a;a]
]-inf;-inf[
]+inf;+inf[
(define (make-interval
from-grens to-grens)
(if (or
(and
(=b
(coef from-grens) (coef
to-grens))
(not
(eq? (open-gesloten?
from-grens)
(open-gesloten?
to-grens))))
(and
(-inf? (coef from-grens))
(-inf? (coef to-grens)))
(and
(+inf? (coef from-grens))
(+inf? (coef to-grens))))
(error "creating
some stupid
interval")
(cons from-grens
to-grens)))
Definitie van het eenheidsinterval en van de reële rechte. In het draaiende programma is deze rechte vervangen door de functie make-horizon
(define I1
(make-interval
(make-grens 0b 'gesloten)
(make-grens 1b 'gesloten)))
(define IR (make-interval (make-grens -inf 'open) (make-grens +inf
open)))
In : interval interval
Out : grens from-grens van interval interval
(define (from-grens interval)
(car interval))
In : interval interval
Out : grens to-grens van interval interval
(define (to-grens interval)
(cdr interval))
In : interval i
Out : bool b
Comments : Indien de sluiting van i slechts uit één punt bestaat wordt #t weergegeven, in het andere geval wordt #f geretourneerd.
(define (punt-interval? i)
(=b (coef (from-grens i)) (coef
(to-grens i))))
In : interval who
Out : nothing
Comments : print het interval af onder de vorm "[from,to[". De haakjes staan naar gelang de grenzen open of gesloten zijn.
(define (display-interval who)
(message (if (open? (from-grens who))
"]" "["))
(display-breuk (coef (from-grens
who)))
(message ",")
(display-breuk (coef (to-grens who)))
(message (if (open? (to-grens who))
"[" "]")))
In : interval interval
Out : interval r
Comments : r is het interval dat voldoet aan de voorwaarde . Omdat dit ADT enkel functioneel gebruikt kan worden moet er geen copie gemaakt worden indien het interval reeds geordend is.
(define (orden-interval interval)
(if (>b (coef (from-grens
interval)) (coef (to-grens interval)))
(make-interval
(to-grens interval)
(from-grens interval))
interval))
In : real p, interval CD
Out : bool r
Comments : indien p op het interval CD ligt zal #t worden weergegeven. #f in het andere geval. Merk op dat CD als gesloten interval beschouwd wordt.
(define (punt-op-interval? p CD)
(set! CD (orden-interval CD))
(let ((Cg (from-grens CD))
(Dg
(to-grens CD)))
(if (punt-interval? CD)
(=b p
(coef Cg))
(and
((if (open? Cg) >b
>=b) p (coef Cg))
((if (open? Dg) <b
<=b) p (coef Dg))))))
In : interval AB, interval CD
Out : interval result
Comments : deze functie maakt de snijding van twee intervallen. Geen van beide moet op voorhand geordend zijn.
(define (intersect-interval AB
CD)
(define (leftgrens most-left other)
(if (and (=b (coef most-left)
(coef
other)) (open? most-left))
(make-grens
(coef other) open)
other))
(define (rightgrens most-left other)
(if (and (=b (coef most-left)
(coef
other)) (open? other))
(make-grens
(coef most-left)
open)
most-left))
(let ((Ag (from-grens AB))
(Bg
(to-grens AB))
(Cg
(from-grens CD))
(Dg
(to-grens CD)))
(cond ((punt-interval? AB)
(if
(punt-op-interval? (coef Ag) CD) AB))
((punt-interval?
CD) (if
(punt-op-interval? (coef CD) AB) CD))
((begin
(set! AB (orden-interval
AB))
(set! CD (orden-interval
CD))
#f) (error "Dit is een
actie geen predicaat"))
((<b
(coef Cg) (coef Ag))
(intersect-interval CD AB))
((<=b
(coef Dg) (coef Bg))
(make-interval (leftgrens Ag
Cg) (rightgrens Dg Bg)))
((<=b
(coef Cg) (coef Bg))
(make-interval (leftgrens Ag
Cg) (rightgrens Bg Dg)))
((and
(=b (coef Bg) (coef Cg))
(gesloten? Bg) (gesloten? Cg))
(make-interval Bg Bg))
(else
#f))))
In het programma had ik ook een T-stuk gedefinieerd, maar deze was helemaal onhandelbaar geworden. Zonder dat er fouten in de code staken was een robot waar een T-stuk in voorkwam amper in staat zich te verplaatsen bij gebrek aan stack-space.
De code is niet gedocumenteerd omdat het een typische component is.
(define (T-drawing aantal)
(let ((point-list (list (make-point 0
0)))
(x 0))
(define (loop nr)
(if (= nr 0)
point-list
(begin
(set! point-list
(append point-list
(list
(make-point x 10)
(make-point x 20)
(make-point (+ x 5)
20)
(make-point (+ x 5)
10)
)))
(set! x (+ x 20))
(loop (- nr 1)))))
(loop aantal)
(%make-L-vlak (append
point-list
(list (make-point x 0))))))
(define make-T
(lambda childs
(let ((aantal (length childs))
(parent
#f)
(drawing
#f)
(last-pos
#f)
(last-angle
#f)
(sub-world
#f))
(define (set-sub-world! to)
(set! sub-world
to))
(define (set-drawing! to)
(set! drawing to))
(define (glue father)
(if parent
#f
(begin
(set! parent father)
(for-each
(lambda (child)
((child 'glue) T-self))
childs)
#t)))
(define (unglue)
(set! parent #f)
(for-each
(lambda
(child) (child 'unglue))
childs))
(define (drawing@ pos angle)
(((((T-drawing
aantal)
'rotate)
(make-point 0 0)
angle)
'translate)
pos))
(define (valid-init?)
#t)
(define (calc-end-point pos angle nr)
(((((make-point
(* 20 nr) 20)
'rotate)
(make-point 0 0)
angle)
'translate)
pos))
(define (sign-in-world sw pos angle)
(let ((nr 0))
(set!
last-angle angle)
(set!
last-pos pos)
(set!
drawing (drawing@ pos
angle))
((sw
'sign-in) T-self drawing)
(for-each
(lambda
(child)
((child 'sign-in-world)
sw
(calc-end-point pos angle
nr)
(+ angle PI/2))
(set! nr (+ nr 1)))
childs)))
(define (kill-set)
(define result
(make-set childs))
((result 'add!)
parent)
((result 'add!)
T-self)
result)
(define (translate-action naar)
(set! last-pos
((last-pos
'translate) naar))
(for-each
(lambda
(child)
((child
'translate-action)
naar))
childs))
(define (add-translate-sleeppad! result-in howmuch)
((result-in
'add!) ((drawing
'translate-sleep) howmuch))
(for-each
(lambda
(child)
((child
'add-translate-sleeppad!) result-in howmuch))
childs))
(define (change-translate-world! result-in howmuch)
((result-in
'%replace-drawing!)
drawing
((drawing
'translate) howmuch))
(for-each
(lambda
(child)
((child
'change-translate-world!) result-in howmuch))
childs))
(define (child-list)
(let ((result
(list T-self)))
(for-each
(lambda
(child)
(append (child 'child-list)
result))
childs)
result))
(define (T-self m)
(cond ((eq? m
'glue) glue)
((eq? m 'unglue) (unglue))
((eq? m 'set-sub-world!)
set-sub-world!)
((eq? m 'set-drawing!)
set-drawing!)
((eq? m 'kill-set)
(kill-set))
((eq? m 'sign-in-world)
sign-in-world)
((eq? m 'translate-action)
translate-action)
((eq? m
'change-translate-world!) change-translate-world!)
((eq? m 'child-list)
(child-list))
((eq? m
'add-translate-sleeppad!) add-translate-sleeppad!)
(else (error "T-stuk"
m))))
(let
((error-result (valid-init?)))
(if (error?
error-result)
error-result
T-self)))))
Hieronder staat een groot deel van de tests die ik uitgevoerd heb. Dat de nummering niet doorloopt is omdat de ontbrekende stukken, programma's waren in een debug-toestand. M.a.w. De tests van de voorgaande nummers waren gecopierd maar de code is verandert.
;Test1
Test open & gesloten met verschillende coefs
;-----
(define a (makep (g->b 1) (g->b 2)))
(define b (makep (g->b 5) (g->b 3)))
(define c)
(define d)
(define a->)
(define <-a)
(define l (make-line a b (create-interval (create-grens 0b gesloten)
create-grens 1b open))))
(display "Test1 ")
(view (and (%p-op-l a l) (not (%p-op-l b l))))
;Test2 Test
gesloten met dezelfde coefs
;-----
(set! l (make-line a b (create-interval (create-grens 1b gesloten)
(create-grens 1b gesloten))))
(display "Test2 ")
(view (and (not (%p-op-l a l)) (%p-op-l b l)))
;Test3
Test open met dezelfde coefs
;-----
(set! l (make-line a b (create-interval (create-grens 0b open)
(create-grens 0b
open))))
(display "Test3 ")
(view (and (not (%p-op-l a l)) (not (%p-op-l b l))))
;Test4
test een punt dat er totaal naast ligt
;-----
(set! l (make-line a b (create-interval (create-grens 0b gesloten)
(create-grens 1b open))))
(set! a (makep (g->b 5) (g->b 5)))
(display "Test4 ")
(view (not (%p-op-l a l)))
;Test5
oneindig testen op vertikale lijnen
;-----
(set! a (makep (g->b 5) (g->b 5)))
(set! c (makep (g->b 5) (g->b 100000)))
(set! d (makep (g->b 5) (g->b -10000)))
(set! <-a (make-line a b (create-interval (create-grens -inf open)
(create-grens 0b open))))
(set! a-> (make-line a b (create-interval (create-grens 0b open)
(create-grens +inf open))))
(display "Test5 ")
(view (not (%p-op-l a <-a)) ) ;a mag
niet op <-a liggen
(view (not (%p-op-l a a->)) ) ;a mag
ook niet op a-> liggen
(view (%p-op-l c <-a)
) ;c ligt op <-a
(view (not (%p-op-l c a->)) ) ;c
ligt niet op a->
(view (not (%p-op-l d <-a)) ) ;d
ligt niet op <-a
(view (%p-op-l d a->)
) ;d ligt op ->a
;Test6
oneindig testen op horizontale lijnen
;-----
(set! a (makep (g->b 8) (g->b 3)))
(set! c (makep (g->b 100002) (g->b 3)))
(set! d (makep (g->b -256) (g->b 3)))
(set! <-a (make-line a b (create-interval (create-grens -inf open)
(create-grens 0b open))))
(set! a-> (make-line a b (create-interval (create-grens 0b open)
(create-grens +inf open))))
(display "Test6 ")
(view (not (%p-op-l a <-a)) ) ;a mag
niet op <-a liggen
(view (not (%p-op-l a a->)) ) ;a mag
ook niet op a-> liggen
(view (%p-op-l c <-a)
) ;c ligt op <-a
(view (not (%p-op-l c a->)) ) ;c
ligt niet op a->
(view (not (%p-op-l d <-a)) ) ;d
ligt niet op <-a
(view (%p-op-l d a->)
) ;d ligt op ->a
;Test7
oneindig testen op horizontale lijnen
;-----
(set! a (makep (g->b 7) (g->b 4)))
(set! c (makep (g->b 9) (g->b 5)))
(set! d (makep (g->b 3) (g->b 2)))
(set! <-a (make-line a b (create-interval (create-grens -inf open)
(create-grens 0b open))))
(set! a-> (make-line a b (create-interval (create-grens 0b open)
(create-grens +inf open))))
(display "Test7 ")
(view (not (%p-op-l a <-a)) ) ;a mag
niet op <-a liggen
(view (not (%p-op-l a a->)) ) ;a mag
ook niet op a-> liggen
(view (%p-op-l c <-a)
) ;c ligt op <-a
(view (not (%p-op-l c a->)) ) ;c
ligt niet op a->
(view (not (%p-op-l d <-a)) ) ;d
ligt niet op <-a
(view (%p-op-l d a->)
) ;d ligt op ->a
;---------------------------------------------------------
;test1 : testen van vertikaal samenvallende rechten
;---------------------------------------------------------
(define x (makeb 50 1))
(define (fast-line fromx fromy tox toy fromcoef from-og tocoef to-og)
(define (mb watte)
(if (breuk? watte)
watte
(makeb
watte 1)))
(make-line
(make-point (mb fromx) (mb
fromy))
(make-point (mb tox) (mb toy))
(make-interval
(make-grens (mb
fromcoef) from-og)
(make-grens (mb
tocoef) to-og))))
(define A (fast-line x 0 x -2 -3
gesloten -inf
open))
(define B (fast-line x 0 x -2 (makeb 3 2) open (makeb -3 2) gesloten))
(define C (fast-line x 12 x 6 1 gesloten +inf open))
(define D (fast-line x 0 x 1 0 gesloten +inf open))
(define E (fast-line x 0 x 1 -inf gesloten +inf open))
(message "A -> ") (A 'display)
(crlf)
(message "B -> ") (B 'display) (crlf)
(message "C -> ") (C 'display) (crlf)
(message "D -> ") (D 'display) (crlf)
(message "E -> ") (E 'display) (crlf)
(message "A i A -> ") (view
(intersect-l-l A A))
(message "A i b -> ") (view (intersect-l-l A b))
(message "A i c -> ") (view (intersect-l-l A c))
(message "A i d -> ") (view (intersect-l-l A d))
(message "b i A -> ") (view (intersect-l-l b A))
(message "b i b -> ") (view (intersect-l-l b b))
(message "b i c -> ") (view (intersect-l-l b c))
(message "b i d -> ") (view (intersect-l-l b d))
(message "c i A -> ") (view (intersect-l-l c A))
(message "c i b -> ") (view (intersect-l-l c b))
(message "c i c -> ") (view (intersect-l-l c c))
(message "c i d -> ") (view (intersect-l-l c d))
(message "d i A -> ") (view (intersect-l-l d A))
(message "d i b -> ") (view (intersect-l-l d b))
(message "d i c -> ") (view (intersect-l-l d c))
(message "d i d -> ") (view (intersect-l-l d d))
(message "E i E -> ") (view (intersect-l-l E e))
;---------------------------------------------------------
;test2 : testen van vertikaal samenvallende rechten
;---------------------------------------------------------
(set! A (fast-line 0 x -2 x -3 gesloten -inf
open))
(set! B (fast-line 0 x -2 x (makeb 3 2) open (makeb -3 2) gesloten))
(set! C (fast-line 12 x 6 x 1 gesloten +inf open))
(set! D (fast-line 0 x 1 x 0 gesloten +inf open))
(set! E (fast-line 0 x 1 x -inf gesloten +inf open))
(message "A -> ") (A 'display)
(crlf)
(message "B -> ") (B 'display) (crlf)
(message "C -> ") (C 'display) (crlf)
(message "D -> ") (D 'display) (crlf)
(message "E -> ") (E 'display) (crlf)
(message "A i A -> ") (view
(intersect-l-l A A))
(message "A i b -> ") (view (intersect-l-l A b))
(message "A i c -> ") (view (intersect-l-l A c))
(message "A i d -> ") (view (intersect-l-l A d))
(message "b i A -> ") (view (intersect-l-l b A))
(message "b i b -> ") (view (intersect-l-l b b))
(message "b i c -> ") (view (intersect-l-l b c))
(message "b i d -> ") (view (intersect-l-l b d))
(message "c i A -> ") (view (intersect-l-l c A))
(message "c i b -> ") (view (intersect-l-l c b))
(message "c i c -> ") (view (intersect-l-l c c))
(message "c i d -> ") (view (intersect-l-l c d))
(message "d i A -> ") (view (intersect-l-l d A))
(message "d i b -> ") (view (intersect-l-l d b))
(message "d i c -> ") (view (intersect-l-l d c))
(message "d i d -> ") (view (intersect-l-l d d))
(message "E i E -> ") (view (intersect-l-l E e))
;------------------------------------------
;test3 : kruisingen horizontaal & vertikaal
;------------------------------------------
(set! A (fast-line 0 0 1 0 -inf gesloten
+inf open))
(set! B (fast-line 0 0 0 1 -inf gesloten +inf open))
(set! C (fast-line 123 -1 123 5 0 gesloten 1 gesloten))
(set! D (fast-line 124 -1 124 5 1 open 2 gesloten))
(set! E (fast-line 120 11 119 11 0 open -30 gesloten))
(define F (fast-line 120 12 119 12 150 open 0 open))
(message "A -> ") (A 'display)
(crlf)
(message "B -> ") (B 'display) (crlf)
(message "C -> ") (C 'display) (crlf)
(message "D -> ") (D 'display) (crlf)
(message "E -> ") (E 'display) (crlf)
(message "F -> ") (F 'display) (crlf)
(message "A i A -> ") (view
(intersect-l-l A A))
(message "A i b -> ") (view (intersect-l-l A b))
(message "A i c -> ") (view (intersect-l-l A c))
(message "A i d -> ") (view (intersect-l-l A d))
(message "A i e -> ") (view (intersect-l-l A e))
(message "A i f -> ") (view (intersect-l-l A f))
(message "b i A -> ") (view (intersect-l-l b A))
(message "b i b -> ") (view (intersect-l-l b b))
(message "b i c -> ") (view (intersect-l-l b c))
(message "b i d -> ") (view (intersect-l-l b d))
(message "b i e -> ") (view (intersect-l-l b e))
(message "b i f -> ") (view (intersect-l-l b f))
(message "c i A -> ") (view (intersect-l-l c A))
(message "c i b -> ") (view (intersect-l-l c b))
(message "c i c -> ") (view (intersect-l-l c c))
(message "c i d -> ") (view (intersect-l-l c d))
(message "c i e -> ") (view (intersect-l-l c e))
(message "c i f -> ") (view (intersect-l-l c f))
(message "d i A -> ") (view (intersect-l-l d A))
(message "d i b -> ") (view (intersect-l-l d b))
(message "d i c -> ") (view (intersect-l-l d c))
(message "d i d -> ") (view (intersect-l-l d d))
(message "d i e -> ") (view (intersect-l-l d e))
(message "d i f -> ") (view (intersect-l-l d f))
(message "e i A -> ") (view (intersect-l-l e A))
(message "e i b -> ") (view (intersect-l-l e b))
(message "e i c -> ") (view (intersect-l-l e c))
(message "e i d -> ") (view (intersect-l-l e d))
(message "e i e -> ") (view (intersect-l-l e e))
(message "e i f -> ") (view (intersect-l-l e f))
(message "f i A -> ") (view (intersect-l-l f A))
(message "f i b -> ") (view (intersect-l-l f b))
(message "f i c -> ") (view (intersect-l-l f c))
(message "f i d -> ") (view (intersect-l-l f d))
(message "f i e -> ") (view (intersect-l-l f e))
(message "f i f -> ") (view (intersect-l-l f f))
Test1 tot en met 3
werden gecopierd van Robot03.scm
;-------------------------------------------------
;test4 : horizontale lijnen snijden met schuine
;-------------------------------------------------
(message "Test 4")
(crlf)
(set! A (fast-line -10 5 20 5 0
gesloten 1 gesloten))
(set! B (fast-line -10 -5 20 -5 -inf
gesloten +inf gesloten))
(set! C (fast-line 18 12 15 6 0
gesloten 1 gesloten))
(set! D (fast-line 20 12 17 6 0 open
+inf open))
(set! E (fast-line 20 3 19 -3 0 open
-inf open))
(message "A -> ") (A 'display)
(crlf)
(message "B -> ") (B 'display) (crlf)
(message "C -> ") (C 'display) (crlf)
(message "D -> ") (D 'display) (crlf)
(message "E -> ") (E 'display) (crlf)
(message "A i A -> ") (view
(intersect-l-l A A))
(message "A i b -> ") (view (intersect-l-l A b))
(message "A i c -> ") (view (intersect-l-l A c))
(message "A i d -> ") (view (intersect-l-l A d))
(message "A i e -> ") (view (intersect-l-l A e))
(message "b i A -> ") (view (intersect-l-l b A))
(message "b i b -> ") (view (intersect-l-l b b))
(message "b i c -> ") (view (intersect-l-l b c))
(message "b i d -> ") (view (intersect-l-l b d))
(message "b i e -> ") (view (intersect-l-l b e))
(message "c i A -> ") (view (intersect-l-l c A))
(message "c i b -> ") (view (intersect-l-l c b))
(message "d i A -> ") (view (intersect-l-l d A))
(message "d i b -> ") (view (intersect-l-l d b))
(message "e i A -> ") (view (intersect-l-l e A))
(message "e i b -> ") (view (intersect-l-l e b))
;-------------------------------------------------
;test5 : vertikale lijnen snijden met schuine
;-------------------------------------------------
(message "Test 5")
(crlf)
(set! A (fast-line 5 -10 5 20 0 gesloten 1
gesloten))
(set! B (fast-line -5 -10 -5 20 -inf gesloten +inf gesloten))
(set! C (fast-line 12 18 6 15 0 gesloten 1
gesloten))
(set! D (fast-line 12 20 6 17 0 open
+inf open))
(set! E (fast-line 3 20 -3 19 0 open
-inf open))
(message "A -> ") (A 'display)
(crlf)
(message "B -> ") (B 'display) (crlf)
(message "C -> ") (C 'display) (crlf)
(message "D -> ") (D 'display) (crlf)
(message "E -> ") (E 'display) (crlf)
(message "A i A -> ") (view
(intersect-l-l A A))
(message "A i b -> ") (view (intersect-l-l A b))
(message "A i c -> ") (view (intersect-l-l A c))
(message "A i d -> ") (view (intersect-l-l A d))
(message "A i e -> ") (view (intersect-l-l A e))
(message "b i A -> ") (view (intersect-l-l b A))
(message "b i b -> ") (view (intersect-l-l b b))
(message "b i c -> ") (view (intersect-l-l b c))
(message "b i d -> ") (view (intersect-l-l b d))
(message "b i e -> ") (view (intersect-l-l b e))
(message "c i A -> ") (view (intersect-l-l c A))
(message "c i b -> ") (view (intersect-l-l c b))
(message "d i A -> ") (view (intersect-l-l d A))
(message "d i b -> ") (view (intersect-l-l d b))
(message "e i A -> ") (view (intersect-l-l e A))
(message "e i b -> ") (view (intersect-l-l e b))
;---------------------------------------------------------
;test6 : testen van schuin samenvallende rechten
;---------------------------------------------------------
(message "Test 6")
(crlf)
(set! A (fast-line 200 0 198 -2
-3 gesloten -inf open))
(set! B (fast-line 200 0 198 -2 (makeb
3 2) open (makeb -3 2) gesloten))
(set! C (fast-line 212 12 206 6 1
gesloten +inf open))
(set! D (fast-line 200 0 201 1 0
gesloten +inf open))
(set! E (fast-line 200 0 201 1 -inf
gesloten +inf open))
(message "A -> ") (A 'display)
(crlf)
(message "B -> ") (B 'display) (crlf)
(message "C -> ") (C 'display) (crlf)
(message "D -> ") (D 'display) (crlf)
(message "E -> ") (E 'display) (crlf)
(message "A i A -> ") (view
(intersect-l-l A A))
(message "A i b -> ") (view (intersect-l-l A b))
(message "A i c -> ") (view (intersect-l-l A c))
(message "A i d -> ") (view (intersect-l-l A d))
(message "b i A -> ") (view (intersect-l-l b A))
(message "b i b -> ") (view (intersect-l-l b b))
(message "b i c -> ") (view (intersect-l-l b c))
(message "b i d -> ") (view (intersect-l-l b d))
(message "c i A -> ") (view (intersect-l-l c A))
(message "c i b -> ") (view (intersect-l-l c b))
(message "c i c -> ") (view (intersect-l-l c c))
(message "c i d -> ") (view (intersect-l-l c d))
(message "d i A -> ") (view (intersect-l-l d A))
(message "d i b -> ") (view (intersect-l-l d b))
(message "d i c -> ") (view (intersect-l-l d c))
(message "d i d -> ") (view (intersect-l-l d d))
(message "E i E -> ") (view (intersect-l-l E e))
;---------------------------------------------------------
;test7 : testen van snijdende rechten
;---------------------------------------------------------
(message "Test 7")
(crlf)
(set! A (fast-line (makeb 1 2) (makeb 3 2) -1 1 -1 gesloten 1 open))
(set! B (fast-line (makeb 1 2) (makeb 3 2) -1 1 -1 gesloten 1 gesloten))
(set! C (fast-line (makeb -3 2) 3 -2 5 -1 gesloten 1 gesloten))
(set! D (fast-line 2 2 0 (makeb 35 10) 0 gesloten 2 gesloten))
(message "A -> ") (A 'display)
(crlf)
(message "B -> ") (B 'display) (crlf)
(message "C -> ") (C 'display) (crlf)
(message "D -> ") (D 'display) (crlf)
(message "A i A -> ") (view
(intersect-l-l A A))
(message "A i b -> ") (view (intersect-l-l A b))
(message "A i c -> ") (view (intersect-l-l A c))
(message "A i d -> ") (view (intersect-l-l A d))
(message "b i A -> ") (view (intersect-l-l b A))
(message "b i b -> ") (view (intersect-l-l b b))
(message "b i c -> ") (view (intersect-l-l b c))
(message "b i d -> ") (view (intersect-l-l b d))
(message "c i A -> ") (view (intersect-l-l c A))
(message "c i b -> ") (view (intersect-l-l c b))
(message "c i c -> ") (view (intersect-l-l c c))
(message "c i d -> ") (view (intersect-l-l c d))
(message "d i A -> ") (view (intersect-l-l d A))
(message "d i b -> ") (view (intersect-l-l d b))
(message "d i c -> ") (view (intersect-l-l d c))
(message "d i d -> ") (view (intersect-l-l d d))
Dit waren de test voor het controleren van de punt-in? operatie
;------------------
;test1 : rechthoek
;------------------
(define (fast-line fromx fromy tox toy)
(define (mb watte)
(if (breuk? watte)
watte
(makeb
watte 1)))
(make-line
(make-point (mb fromx) (mb
fromy))
(make-point (mb tox) (mb toy))
I1))
(define (fast-point x y)
(define (mb watte)
(if (breuk? watte)
watte
(makeb
watte 1)))
(make-point (mb x) (mb y)))
(define V1
(make-graph-set
(fast-line -10 -10 -10 10)
(fast-line
-10 10 10 10)
(fast-line 10 10 10 -10)
(fast-line 10 -10 -10 -10)))
(define p1
(fast-point -20 -20))
(define p2 (fast-point -10 -20))
(define p3 (fast-point
0 -20))
(define p4 (fast-point
10 -20))
(define p5 (fast-point
20 -20))
(define p6
(fast-point -20 -10))
(define p7 (fast-point -10 -10))
(define p8 (fast-point
0 -10))
(define p9 (fast-point
10 -10))
(define p10 (fast-point 20 -10))
(define p11 (fast-point -20 0))
(define p12 (fast-point -10 0))
(define p13 (fast-point 0 0))
(define p14 (fast-point 10 0))
(define p15 (fast-point 20 0))
(define p16 (fast-point -20 10))
(define p17 (fast-point -10 10))
(define p18 (fast-point 0 10))
(define p19 (fast-point 10
10))
(define p20 (fast-point 20
10))
(define p21 (fast-point -20 20))
(define p22 (fast-point -10 20))
(define p23 (fast-point 0 20))
(define p24 (fast-point 10
20))
(define p25 (fast-point 20
20))
(message "Test1 :")
(message "p1 in V1 ? ") (view ((V1 'punt-in?) p1))
(message "p2 in V1 ? ") (view ((V1 'punt-in?) p2))
(message "p3 in V1 ? ") (view ((V1 'punt-in?) p3))
(message "p4 in V1 ? ") (view ((V1 'punt-in?) p4))
(message "p5 in V1 ? ") (view ((V1 'punt-in?) p5))
(message "p6 in V1 ? ") (view ((V1
'punt-in?) p6))
(message "p7 in V1 ? ") (view ((V1 'punt-in?) p7))
(message "p8 in V1 ? ") (view ((V1 'punt-in?) p8))
(message "p9 in V1 ? ") (view ((V1 'punt-in?) p9))
(message "p10 in V1 ? ") (view ((V1 'punt-in?) p10))
(message "p11 in V1 ? ") (view ((V1
'punt-in?) p11))
(message "p12 in V1 ? ") (view ((V1 'punt-in?) p12))
(message "p13 in V1 ? ") (view ((V1 'punt-in?) p13))
(message "p14 in V1 ? ") (view ((V1 'punt-in?) p14))
(message "p15 in V1 ? ") (view ((V1 'punt-in?) p15))
(message "p16 in V1 ? ") (view ((V1
'punt-in?) p16))
(message "p17 in V1 ? ") (view ((V1 'punt-in?) p17))
(message "p18 in V1 ? ") (view ((V1 'punt-in?) p18))
(message "p19 in V1 ? ") (view ((V1 'punt-in?) p19))
(message "p20 in V1 ? ") (view ((V1 'punt-in?) p20))
(message "p21 in V1 ? ") (view ((V1
'punt-in?) p21))
(message "p22 in V1 ? ") (view ((V1 'punt-in?) p22))
(message "p23 in V1 ? ") (view ((V1 'punt-in?) p23))
(message "p24 in V1 ? ") (view ((V1 'punt-in?) p24))
(message "p25 in V1 ? ") (view ((V1 'punt-in?) p25))
;----------------------------
;test2 : gedraaide rechthoek
;-----------------------------
(message "Test 2")
(define V1
(make-graph-set
(fast-line -15 -10 -10 15)
(fast-line -10 15 15 10)
(fast-line 15 10 10 -15)
(fast-line 10 -15 -15 -10)))
(message "p1 in V1 ? ") (view ((V1
'punt-in?) p1))
(message "p2 in V1 ? ") (view ((V1 'punt-in?) p2))
(message "p3 in V1 ? ") (view ((V1 'punt-in?) p3))
(message "p4 in V1 ? ") (view ((V1 'punt-in?) p4))
(message "p5 in V1 ? ") (view ((V1 'punt-in?) p5))
(message "p6 in V1 ? ") (view ((V1
'punt-in?) p6))
(message "p7 in V1 ? ") (view ((V1 'punt-in?) p7))
(message "p8 in V1 ? ") (view ((V1 'punt-in?) p8))
(message "p9 in V1 ? ") (view ((V1 'punt-in?) p9))
(message "p10 in V1 ? ") (view ((V1 'punt-in?) p10))
(message "p11 in V1 ? ") (view ((V1
'punt-in?) p11))
(message "p12 in V1 ? ") (view ((V1 'punt-in?) p12))
(message "p13 in V1 ? ") (view ((V1 'punt-in?) p13))
(message "p14 in V1 ? ") (view ((V1 'punt-in?) p14))
(message "p15 in V1 ? ") (view ((V1 'punt-in?) p15))
(message "p16 in V1 ? ") (view ((V1
'punt-in?) p16))
(message "p17 in V1 ? ") (view ((V1 'punt-in?) p17))
(message "p18 in V1 ? ") (view ((V1 'punt-in?) p18))
(message "p19 in V1 ? ") (view ((V1 'punt-in?) p19))
(message "p20 in V1 ? ") (view ((V1 'punt-in?) p20))
(message "p21 in V1 ? ") (view ((V1
'punt-in?) p21))
(message "p22 in V1 ? ") (view ((V1 'punt-in?) p22))
(message "p23 in V1 ? ") (view ((V1 'punt-in?) p23))
(message "p24 in V1 ? ") (view ((V1 'punt-in?) p24))
(message "p25 in V1 ? ") (view ((V1 'punt-in?) p25))
Dit waren de test op het snijden van cirkels met lijnen en cirkels met cirkels. De test nummeren voort vanaf 7.
;-----------------------------------------------------
;test8 : testen van het snijden lijnen met een circle
;-----------------------------------------------------
(define (fast-circle x y r fa ta)
(make-circle (make-point x y) r fa
ta))
(define C1 (fast-circle 0 0
5 0 (/ PI 2)))
(define C2 (fast-circle 10 10 3 0 (* 2
PI)))
(define C3 (fast-circle 7 2
6 (/
PI 4) 3PI/2))
(define L1 (fast-line 5 17 5 0))
(define L2 (fast-line 9 12 9 -20))
(define L3 (fast-line 0 0 14 12))
(define L4 (fast-line 3 5 16 10))
(define L5 (fast-line 9.2426409 8.24640686 13.2426409 4.24640686))
(define L6 (fast-line 12 9 1 9))
(define L7 (fast-line 3 13 15 13))
(message "Test 8")
(crlf)
(message "L1 i C1") (view (intersect-l-c l1 C1))
(message "L2 i C1") (view (intersect-l-c l2 C1))
(message "L3 i C1") (view (intersect-l-c l3 C1))
(message "L4 i C1") (view (intersect-l-c l4 C1))
(message "L5 i C1") (view (intersect-l-c l5 C1))
(message "L6 i C1") (view (intersect-l-c l6 C1))
(message "L7 i C1") (view (intersect-l-c l7 C1))
(message "L1 i C2") (view
(intersect-l-c l1 C2))
(message "L2 i C2") (view (intersect-l-c l2 C2))
(message "L3 i C2") (view (intersect-l-c l3 C2))
(message "L4 i C2") (view (intersect-l-c l4 C2))
(message "L5 i C2") (view (intersect-l-c l5 C2))
(message "L6 i C2") (view (intersect-l-c l6 C2))
(message "L7 i C2") (view (intersect-l-c l7 C2))
(message "L1 i C3") (view
(intersect-l-c l1 C3))
(message "L2 i C3") (view (intersect-l-c l2 C3))
(message "L3 i C3") (view (intersect-l-c l3 C3))
(message "L4 i C3") (view (intersect-l-c l4 C3))
(message "L5 i C3") (view (intersect-l-c l5 C3))
(message "L6 i C3") (view (intersect-l-c l6 C3))
(message "L7 i C3") (view (intersect-l-c l7 C3))
;--------------------------------------------
;test9 : het snijden van circles met circles
;--------------------------------------------
(define C4 (fast-circle 0 0
5 0
2PI))
(define C5 (fast-circle 10 10 3 0 2PI))
(define C6 (fast-circle 7 2
6 0
2PI))
(message "Test 9")
(crlf)
(message "C1 i C1") (view (intersect-c-c C1 C1))
(message "C1 i C2") (view (intersect-c-c C1 C2))
(message "C1 i C3") (view (intersect-c-c C1 C3))
(message "C1 i C4") (view (intersect-c-c C1 C4))
(message "C1 i C5") (view (intersect-c-c C1 C5))
(message "C1 i C6") (view (intersect-c-c C1 C6))
(message "C2 i C1") (view
(intersect-c-c C2 C1))
(message "C2 i C2") (view (intersect-c-c C2 C2))
(message "C2 i C3") (view (intersect-c-c C2 C3))
(message "C2 i C4") (view (intersect-c-c C2 C4))
(message "C2 i C5") (view (intersect-c-c C2 C5))
(message "C2 i C6") (view (intersect-c-c C2 C6))
(message "C4 i C1") (view
(intersect-c-c C4 C1))
(message "C4 i C2") (view (intersect-c-c C4 C2))
(message "C4 i C3") (view (intersect-c-c C4 C3))
(message "C4 i C4") (view (intersect-c-c C4 C4))
(message "C4 i C5") (view (intersect-c-c C4 C5))
(message "C4 i C6") (view (intersect-c-c C4 C6))
(message "C5 i C1") (view
(intersect-c-c C5 C1))
(message "C5 i C2") (view (intersect-c-c C5 C2))
(message "C5 i C3") (view (intersect-c-c C5 C3))
(message "C5 i C4") (view (intersect-c-c C5 C4))
(message "C5 i C5") (view (intersect-c-c C5 C5))
(message "C5 i C6") (view (intersect-c-c C5 C6))
(message "C6 i C1") (view
(intersect-c-c C6 C1))
(message "C6 i C2") (view (intersect-c-c C6 C2))
(message "C6 i C3") (view (intersect-c-c C6 C3))
(message "C6 i C4") (view (intersect-c-c C6 C4))
(message "C6 i C5") (view (intersect-c-c C6 C5))
(message "C6 i C6") (view (intersect-c-c C6 C6))
Dit is nog eens het testen van de punt-in?, maar nu op een ingewikkeldere figuur.
;-------------------
;test3 : kasteeltje
;-------------------
(define (l-line lst)
(let ((s (make-graph-set)))
(define (loop prev cur)
(if (null? cur) s
(begin
((s 'add)
(make-line
(make-point (car prev)
(cdr prev))
(make-point (car (car
cur)) (cdr (car cur)))))
(loop (car cur) (cdr
cur)))))
(loop (car lst) (cdr lst))
s))
(define K (l-line
'(
(0 . 0)
(1 . 1)
(2 . 1)
(3 . 2)
(4 . 1)
(5 . 1)
(6 . 0)
(7 . 1)
(8 . 1)
(8 . 0)
(4 . 0)
(3 . 1)
(2 . 0)
(0 . 0)
)))
(define test-list
'(
(0 . 1)
(1 . 1)
(1.5 . 1)
(2 . 1)
(2.5 . 1)
(3 . 1)
(3.5 . 1)
(4 . 1 )
(4.5 . 1)
(5 . 1)
(6 . 1)
(7 . 1)
(7.5 . 1)
(8 . 1)
(9 . 1)
(1.5 . 0.5)
(3 . 0.5)
(4.5 . 0.5)
(6 . 0.5)
(7.5 . 0.5)
(9 . 0.5)
(0 . 0.5)
(3 . 0)
(9 . 0)
(1.5 . 1.5)
(3 . 1.5)
(6 . 1.5)
(5 . 2)
(1 . 2)
))
(define (test-program)
(define (loop lst)
(if (pair? lst)
(begin
(message
(car lst))
(message
" in K ? ")
(view
((K 'punt-in?)
(make-point (caar lst)
(cdar lst))))
(loop (cdr lst)))))
(loop test-list))
(test-program)
Hier zat een bug in bij 100 10 10 10 23 10 10 10
(define (testje l1 l2 l3 l4 l5 l6 l7
l8)
(make-robot
(make-point 0 0)
(make-arm
l1
(make-arm
l1
(make-arm
l2
(make-arm
l2
(make-arm
l3
(make-arm
l3
(make-arm
l4
(make-arm
l4
(make-arm
l5
(make-arm
l5
(make-arm
l6
(make-arm
l6
(make-arm
l7
(make-arm
l7
(make-arm
l8
(make-arm
l8
null-component))))))))))))))))))
(define ralf-arm4 (make-arm 30
null-component))
(define ralf-arm3 (make-arm 20 ralf-arm4))
(define ralf-arm2 (make-arm 40 ralf-arm3))
(define ralf-arm1 (make-arm 80 ralf-arm2))
(define ralf
(make-robot
(make-point -150 30)
ralf-arm1))
(define dennis-arm (make-arm 50 null-component))
(define dennis
(make-robot
(make-point 0 0)
dennis-arm))
(define (move-to who speedx speedy)
((who 'right) (make-point speedx
speedy)))
(define (arm-length who new-length)
((who 'arm-length) new-length))
Dit is een test op
een T-stuk dat ik had gedefinieerd. Wat blijkt : PCS had te weinig
geheugen om
ermee overweg te kunnen.
(define ralf-pen1 (make-pen
'light-blue))
(define ralf-pen2 (make-pen 'light-blue))
(define ralf-pen3 (make-pen 'light-blue))
(define ralf-pen4 (make-pen 'light-blue))
(define ralf-arm4 (make-arm 10 0 ralf-pen4))
(define ralf-arm3 (make-arm 50 0 ralf-pen3))
(define ralf-arm2 (make-arm 100 0 ralf-pen2))
(define ralf-arm1 (make-arm 100 0 ralf-pen1))
(define ralf-T (make-T ralf-arm1 ralf-arm2 ralf-arm3 ralf-arm4))
(define ralf
(make-robot
(make-point -150 30)
0
ralf-T))
Het testen van de rotatie's.
(define circler-pen (make-pen 'BLUE))
(define circler-arm2 (make-arm 100 0 circler-pen))
(define circler-rot2 (make-scharnier PI/2 0 circler-arm2))
(define circler-arm1 (make-arm 100 0 circler-rot2))
(define circler-rot1 (make-scharnier PI/2 0 circler-arm1))
(define circler (make-robot (make-point 30 0) PI/2 circler-rot1))
(pen-down circler-pen)
Testen op de
boormachines.
(define boor-end (make-boor))
(define boormachien (make-robot (make-point 0 0) 0 boor-end))
(boor boor-end)
(rel-move boormachien 0 -100)
(boor boor-end)
(rel-move boormachien 0 200)
(boor boor-end)
(rel-move boormachien -100 -100)
(boor boor-end)
(rel-move boormachien 200 0)
(boor boor-end)
Special thanks to
George Lucas
Marc Van Limberghen
[1]Dit is te wijten aan het feit dat PCS 4.02PL1 veel te weinig geheugen heeft om dit te kunnen runnen en testen. Alles is voorhanden om de rotatie te implementeren. Op te weten hoe dit moet gebeuren verwijs ik naar het paragraafje "Mogelijke verbeteringen"
[2]Dit slag operaties staat niet in het ADT omdat ik anders een goeie 25 messages kan gaan toevoegen. Voor elk grafisch object moet ik dan een point?, line?, go?, cgo?, circle? toevoegen. Op het ogenblik herken ik de verschillende soorten aan de hand van hun type-number, dat voor elk object een zeer gerestricteert uniek nummer is.