-
-
Notifications
You must be signed in to change notification settings - Fork 237
/
World.java
1437 lines (1203 loc) · 40.7 KB
/
World.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// (C) Uri Wilensky. https://github.com/NetLogo/NetLogo
package org.nlogo.agent;
import org.nlogo.api.AgentException;
import org.nlogo.api.Color;
import org.nlogo.api.CompilerServices;
import org.nlogo.api.ImporterUser;
import org.nlogo.api.LogoException;
import org.nlogo.api.Nobody$;
import org.nlogo.api.Program;
import org.nlogo.api.Shape;
import org.nlogo.api.ShapeList;
import org.nlogo.api.TrailDrawerInterface;
import org.nlogo.api.ValueConstraint;
import org.nlogo.api.WorldDimensionException;
import org.nlogo.api.WorldDimensions;
import org.nlogo.util.MersenneTwisterFast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
// A note on wrapping: normally whether x and y coordinates wrap is a
// product of the topology. But we also have the old "-nowrap" primitives
// that don't wrap regardless of what the topology is. So that's why many
// methods like distance() and towards() take a boolean argument "wrap";
// it's true for the normal prims, false for the nowrap prims. - ST 5/24/06
public strictfp class World
implements org.nlogo.api.World {
public static final Double ZERO = Double.valueOf(0.0);
public static final Double ONE = Double.valueOf(1.0);
public final TickCounter tickCounter = new TickCounter();
public double ticks() {
return tickCounter.ticks();
}
public final Timer timer = new Timer();
private final ShapeList _turtleShapeList;
public ShapeList turtleShapeList() {
return _turtleShapeList;
}
private final ShapeList _linkShapeList;
public ShapeList linkShapeList() {
return _linkShapeList;
}
private double patchSize = 12.0; // keep the unzoomed patchSize here
TrailDrawerInterface trailDrawer;
private final Map<Agent, Double> lineThicknesses = new HashMap<Agent, Double>();
Topology topology;
RootsTable rootsTable;
protected Protractor _protractor;
public Protractor protractor() {
return _protractor;
}
public LinkManager linkManager;
public TieManager tieManager;
public InRadiusOrCone inRadiusOrCone;
// This is a flag that the engine checks in its tightest innermost loops
// to see if maybe it should stop running NetLogo code for a moment
// and do something like halt or update the display. It doesn't
// particularly make sense to keep it in World, but since the check
// occurs in inner loops, we want to put in a place where the engine
// can get to it very quickly. And since every Instruction has a
// World object in it, the engine can always get to World quickly.
// - ST 1/10/07
public volatile boolean comeUpForAir = false; // NOPMD pmd doesn't like 'volatile'
public World() {
_turtleShapeList = new ShapeList();
_linkShapeList = new ShapeList();
_observer = createObserver();
_observers = new ArrayAgentSet(Observer.class, 1, "observers", false, this);
linkManager = new LinkManager(this);
tieManager = new TieManager(this, linkManager);
inRadiusOrCone = new InRadiusOrCone(this);
_protractor = new Protractor(this);
_observers.add(_observer);
changeTopology(true, true);
// create patches in the constructor, it's necessary in case
// the first model we load is 1x1 since when we do create patches
// in the model loader we only do the reallocation if the dimensions
// are different than the stored dimensions. This doesn't come up
// often because almost always load the default model first, and there
// aren't many 1x1 models. ev 2/5/07
createPatches(_minPxcor, _maxPxcor, _minPycor, _maxPycor);
}
Observer createObserver() {
return new Observer(this);
}
/// empty agentsets
private final AgentSet _noTurtles = new ArrayAgentSet(Turtle.class, 0, false, this);
private final AgentSet _noPatches = new ArrayAgentSet(Patch.class, 0, false, this);
private final AgentSet _noLinks = new ArrayAgentSet(Link.class, 0, false, this);
public AgentSet noTurtles() {
return _noTurtles;
}
public AgentSet noPatches() {
return _noPatches;
}
public AgentSet noLinks() {
return _noLinks;
}
///
public void trailDrawer(TrailDrawerInterface trailDrawer) {
this.trailDrawer = trailDrawer;
}
/// get/set methods for World Topology
Topology getTopology() {
return topology;
}
public void changeTopology(boolean xWrapping, boolean yWrapping) {
topology = Topology.getTopology(this, xWrapping, yWrapping);
if (_patches != null) // is null during initialization
{
for (AgentSet.Iterator it = _patches.iterator(); it.hasNext();) {
((Patch) it.next()).topologyChanged();
}
}
}
public double wrappedObserverX(double x) {
try {
x = topology.wrapX(x - topology.followOffsetX());
} catch (AgentException e) {
org.nlogo.util.Exceptions.ignore(e);
}
return x;
}
public double wrappedObserverY(double y) {
try {
y = topology.wrapY(y - topology.followOffsetY());
} catch (AgentException e) {
org.nlogo.util.Exceptions.ignore(e);
}
return y;
}
public double followOffsetX() {
return _observer.followOffsetX();
}
public double followOffsetY() {
return _observer.followOffsetY();
}
// These are just being used for setting the checkboxes in the ViewWidget config dialog
// with default values. These should no be used within World to control any behavior.
// All wrapping related behavior specific to a topology is/should-be hardcoded in the methods
// for each specific topological implementation.
public boolean wrappingAllowedInX() {
return (topology instanceof Torus || topology instanceof VertCylinder);
}
public boolean wrappingAllowedInY() {
return (topology instanceof Torus || topology instanceof HorizCylinder);
}
/// export world
public void exportWorld(java.io.PrintWriter writer, boolean full) {
new Exporter(this, writer).exportWorld(full);
}
public void importWorld(org.nlogo.agent.Importer.ErrorHandler errorHandler, ImporterUser importerUser,
org.nlogo.agent.Importer.StringReader stringReader, java.io.BufferedReader reader)
throws java.io.IOException {
new Importer(errorHandler, this,
importerUser, stringReader).importWorld(reader);
}
// anything that affects the outcome of the model should happen on the
// main RNG
public final MersenneTwisterFast mainRNG = new MersenneTwisterFast();
// anything that doesn't and can happen non-deterministically (for example monitor updates)
// should happen on the auxillary rng. JobOwners should know which RNG they use.
public final MersenneTwisterFast auxRNG = new MersenneTwisterFast();
/// random seed generator
public double generateSeed() {
return org.nlogo.api.RandomSeedGenerator$.MODULE$.generateSeed();
}
/// line thickness
public void setLineThickness(Agent agent, double size) {
lineThicknesses.put(agent, Double.valueOf(size));
}
public double lineThickness(Agent agent) {
Double size = lineThicknesses.get(agent);
if (size != null) {
return size.doubleValue();
}
return 0.0;
}
public void removeLineThickness(Agent agent) {
lineThicknesses.remove(agent);
}
/// equality
void drawLine(double x0, double y0, double x1, double y1,
Object color, double size, String mode) {
trailDrawer.drawLine(x0, y0, x1, y1, color, size, mode);
}
// boxed versions of geometry/size methods, for efficiency
Double _worldWidthBoxed;
public Double worldWidthBoxed() {
return _worldWidthBoxed;
}
Double _worldHeightBoxed;
public Double worldHeightBoxed() {
return _worldHeightBoxed;
}
Double _minPxcorBoxed;
public Double minPxcorBoxed() {
return _minPxcorBoxed;
}
Double _minPycorBoxed;
public Double minPycorBoxed() {
return _minPycorBoxed;
}
Double _maxPxcorBoxed;
public Double maxPxcorBoxed() {
return _maxPxcorBoxed;
}
Double _maxPycorBoxed;
public Double maxPycorBoxed() {
return _maxPycorBoxed;
}
/// world geometry
int _worldWidth;
public int worldWidth() {
return _worldWidth;
}
int _worldHeight;
public int worldHeight() {
return _worldHeight;
}
// arbitrary sizes
int _minPxcor;
public int minPxcor() {
return _minPxcor;
}
int _minPycor;
public int minPycor() {
return _minPycor;
}
int _maxPxcor;
public int maxPxcor() {
return _maxPxcor;
}
int _maxPycor;
public int maxPycor() {
return _maxPycor;
}
public double wrapX(double x)
throws AgentException {
return topology.wrapX(x);
}
public double wrapY(double y)
throws AgentException {
return topology.wrapY(y);
}
public double wrap(double pos, double min, double max) {
return Topology.wrap(pos, min, max);
}
public void diffuse(double param, int vn)
throws AgentException, PatchException {
topology.diffuse(param, vn);
}
public void diffuse4(double param, int vn)
throws AgentException, PatchException {
topology.diffuse4(param, vn);
}
public int roundX(double x)
throws AgentException {
// floor() is slow so we don't use it
try {
x = topology.wrapX(x);
} catch (AgentException ex) {
throw new AgentException("Cannot access patches beyond the limits of current world.");
}
if (x > 0) {
return (int) (x + 0.5);
} else {
int intPart = (int) x;
double fractPart = intPart - x;
return (fractPart > 0.5) ? intPart - 1 : intPart;
}
}
public int roundY(double y)
throws AgentException {
// floor() is slow so we don't use it
try {
y = topology.wrapY(y);
} catch (AgentException ex) {
throw new AgentException("Cannot access patches beyond the limits of current world.");
}
if (y > 0) {
return (int) (y + 0.5);
} else {
int intPart = (int) y;
double fractPart = intPart - y;
return (fractPart > 0.5) ? intPart - 1 : intPart;
}
}
public Turtle createTurtle(AgentSet breed) {
return new Turtle(this, breed, ZERO, ZERO);
}
// c must be in 0-13 range
// h can be out of range
public Turtle createTurtle(AgentSet breed, int c, int h) {
Turtle baby = new Turtle(this, breed, ZERO, ZERO);
baby.colorDoubleUnchecked(Double.valueOf(5 + 10 * c));
baby.heading(h);
return baby;
}
/// observer/turtles/patches
final AgentSet _observers;
public AgentSet observers() {
return _observers;
}
final Observer _observer;
public Observer observer() {
return _observer;
}
AgentSet _patches = null;
public AgentSet patches() {
return _patches;
}
AgentSet _turtles = null;
public AgentSet turtles() {
return _turtles;
}
AgentSet _links = null;
public AgentSet links() {
return _links;
}
public AgentSet agentClassToAgentSet(Class<? extends Agent> agentClass) {
if (agentClass == Turtle.class) {
return _turtles;
} else if (agentClass == Patch.class) {
return _patches;
} else if (agentClass == Observer.class) {
return _observers;
} else if (agentClass == Link.class) {
return _links;
}
throw new IllegalArgumentException
("agentClass = " + agentClass);
}
public WorldDimensions getDimensions() {
return new WorldDimensions(_minPxcor, _maxPxcor, _minPycor, _maxPycor);
}
public boolean isDimensionVariable(String variableName) {
return
variableName.equalsIgnoreCase("MIN-PXCOR") ||
variableName.equalsIgnoreCase("MAX-PXCOR") ||
variableName.equalsIgnoreCase("MIN-PYCOR") ||
variableName.equalsIgnoreCase("MAX-PYCOR") ||
variableName.equalsIgnoreCase("WORLD-WIDTH") ||
variableName.equalsIgnoreCase("WORLD-HEIGHT");
}
public WorldDimensions setDimensionVariable(String variableName, int value, WorldDimensions d)
throws WorldDimensionException {
if (variableName.equalsIgnoreCase("MIN-PXCOR")) {
d.minPxcor_$eq(value);
} else if (variableName.equalsIgnoreCase("MAX-PXCOR")) {
d.maxPxcor_$eq(value);
} else if (variableName.equalsIgnoreCase("MIN-PYCOR")) {
d.minPycor_$eq(value);
} else if (variableName.equalsIgnoreCase("MAX-PYCOR")) {
d.maxPycor_$eq(value);
} else if (variableName.equalsIgnoreCase("WORLD-WIDTH")) {
d.minPxcor_$eq(growMin(_minPxcor, _maxPxcor, value, d.minPxcor()));
d.maxPxcor_$eq(growMax(_minPxcor, _maxPxcor, value, d.maxPxcor()));
} else if (variableName.equalsIgnoreCase("WORLD-HEIGHT")) {
d.minPycor_$eq(growMin(_minPycor, _maxPycor, value, d.minPycor()));
d.maxPycor_$eq(growMax(_minPycor, _maxPycor, value, d.maxPycor()));
}
return d;
}
public int growMin(int min, int max, int value, int d)
throws WorldDimensionException {
if (value < 1) {
throw new WorldDimensionException();
}
if (max == -min) {
if (value % 2 != 1) {
throw new WorldDimensionException();
}
return -(value - 1) / 2;
} else if (max == 0) {
return -(value - 1);
}
return d;
}
public int growMax(int min, int max, int value, int d)
throws WorldDimensionException {
if (value < 1) {
throw new WorldDimensionException();
}
if (max == -min) {
if (value % 2 != 1) {
throw new WorldDimensionException();
}
return (value - 1) / 2;
} else if (min == 0) {
return (value - 1);
}
return d;
}
public boolean equalDimensions(WorldDimensions d) {
return d.minPxcor() == _minPxcor &&
d.maxPxcor() == _maxPxcor &&
d.minPycor() == _minPycor &&
d.maxPycor() == _maxPycor;
}
public Patch getPatch(int id) {
return (Patch) _patches.toArray()[id];
}
public Patch getPatchAt(double x, double y)
throws AgentException {
int xc = roundX(x);
int yc = roundY(y);
int id = ((_worldWidth * (_maxPycor - yc))
+ xc - _minPxcor);
return (Patch) _patches.toArray()[id];
}
// this procedure is the same as calling getPatchAt when the topology is a torus
// meaning it will override the Topology's wrapping rules and
public Patch getPatchAtWrap(double x, double y) {
int xc, yc, intPart;
double fractPart;
x = Topology.wrap(x, _minPxcor - 0.5, _maxPxcor + 0.5);
y = Topology.wrap(y, _minPycor - 0.5, _maxPycor + 0.5);
if (x > 0) {
xc = (int) (x + 0.5);
} else {
intPart = (int) x;
fractPart = intPart - x;
xc = (fractPart > 0.5) ? intPart - 1 : intPart;
}
if (y > 0) {
yc = (int) (y + 0.5);
} else {
intPart = (int) y;
fractPart = intPart - y;
yc = (fractPart > 0.5) ? intPart - 1 : intPart;
}
int patchid = ((_worldWidth * (_maxPycor - yc)) + xc - _minPxcor);
return (Patch) _patches.toArray()[patchid];
}
public boolean validPatchCoordinates(int xc, int yc) {
return
xc >= _minPxcor &&
xc <= _maxPxcor &&
yc >= _minPycor &&
yc <= _maxPycor;
}
public Patch fastGetPatchAt(int xc, int yc) {
return (Patch) _patches.toArray()[(_worldWidth * (_maxPycor - yc))
+ xc - _minPxcor];
}
public Turtle getTurtle(long id) {
return (Turtle) _turtles.getAgent(Double.valueOf(id));
}
public Link getLink(Object end1, Object end2, AgentSet breed) {
return linkManager.findLink((Turtle) _turtles.getAgent(end1),
(Turtle) _turtles.getAgent(end2),
breed, false);
}
private long nextTurtleIndex = 0;
void nextTurtleIndex(long nextTurtleIndex) {
this.nextTurtleIndex = nextTurtleIndex;
}
long nextTurtleIndex() {
return nextTurtleIndex;
}
long newTurtleId() {
return nextTurtleIndex++;
}
// we assign an unique ID to links, like turtles, except that
// it's not visible to anyone and it can't affect the outcome of
// the model. I added it because it greatly complicates hubnet
// view mirroring to have the only unique identifier be a
// 3 element list. ev 5/1/08
private long nextLinkIndex = 0;
long newLinkId() {
return nextLinkIndex++;
}
// used by Importer and Parser
public Turtle getOrCreateTurtle(long id) {
Turtle turtle = getTurtle(id);
if (turtle == null) {
turtle = new Turtle(this, id);
nextTurtleIndex = StrictMath.max(nextTurtleIndex, id + 1);
}
return turtle;
}
public Link getOrCreateLink(Double end1, Double end2, AgentSet breed) {
return getOrCreateLink(getOrCreateTurtle(end1.longValue()),
getOrCreateTurtle(end2.longValue()), breed);
}
public Link getOrCreateLink(Turtle end1, Turtle end2, AgentSet breed) {
Link link = getLink(end1.agentKey(), end2.agentKey(), breed);
if (link == null) {
link = linkManager.createLink(end1, end2, breed);
}
return link;
}
public Link getOrCreateDummyLink(Object end1, Object end2, AgentSet breed) {
Link link = (end1 == Nobody$.MODULE$ || end2 == Nobody$.MODULE$) ? null
: getLink(((Turtle) end1).agentKey(), ((Turtle) end2).agentKey(), breed);
if (link == null) {
link = new DummyLink(this, end1, end2, breed);
}
return link;
}
// possibly need another array for 3D colors
// since it seems messy to collapse 3D array into 2D
int[] patchColors;
// GLView
// this is used by the OpenGL texture code to decide whether
// it needs to make a new texture or not - ST 2/9/05
boolean patchColorsDirty = true;
public boolean patchColorsDirty() {
return patchColorsDirty;
}
public void markPatchColorsDirty() {
patchColorsDirty = true;
}
public void markPatchColorsClean() {
patchColorsDirty = false;
}
// performance optimization -- avoid drawing an all-black bitmap if we
// could just paint one big black rectangle
boolean patchesAllBlack = true;
public boolean patchesAllBlack() {
return patchesAllBlack;
}
// performance optimization for 3D renderer -- avoid sorting by distance
// from observer unless we need to. once this flag becomes true, we don't
// work as hard as we could to return it back to false, because doing so
// would be expensive. we just reset it at clear-all time.
boolean mayHavePartiallyTransparentObjects = false;
public boolean mayHavePartiallyTransparentObjects() {
return mayHavePartiallyTransparentObjects;
}
public int[] patchColors() {
return patchColors;
}
int patchesWithLabels = 0; // for efficiency in Renderer
public int patchesWithLabels() {
return patchesWithLabels;
}
/// creating & clearing
public void createPatches(WorldDimensions dim) {
createPatches(dim.minPxcor(), dim.maxPxcor(), dim.minPycor(), dim.maxPycor());
}
public void createPatches(int minPxcor, int maxPxcor,
int minPycor, int maxPycor) {
patchScratch = null;
_minPxcor = minPxcor;
_maxPxcor = maxPxcor;
_minPycor = minPycor;
_maxPycor = maxPycor;
_worldWidth = maxPxcor - minPxcor + 1;
_worldHeight = maxPycor - minPycor + 1;
rootsTable = new RootsTable(_worldWidth, _worldHeight);
_worldWidthBoxed = Double.valueOf(_worldWidth);
_worldHeightBoxed = Double.valueOf(_worldHeight);
_minPxcorBoxed = Double.valueOf(_minPxcor);
_minPycorBoxed = Double.valueOf(_minPycor);
_maxPxcorBoxed = Double.valueOf(_maxPxcor);
_maxPycorBoxed = Double.valueOf(_maxPycor);
if (_program.breeds() != null) {
for (Iterator<Object> iter = _program.breeds().values().iterator();
iter.hasNext();) {
((AgentSet) iter.next()).clear();
}
}
if (_program.linkBreeds() != null) {
for (Iterator<Object> iter = _program.linkBreeds().values().iterator();
iter.hasNext();) {
((AgentSet) iter.next()).clear();
}
}
if (_turtles != null) _turtles.clear(); // so a SimpleChangeEvent is published
_turtles = new TreeAgentSet(Turtle.class, "TURTLES", this);
if (_links != null) _links.clear(); // so a SimpleChangeEvent is published
_links = new TreeAgentSet(Link.class, "LINKS", this);
int x = minPxcor;
int y = maxPycor;
Agent[] patchArray = new Agent[_worldWidth * _worldHeight];
patchColors = new int[_worldWidth * _worldHeight];
Arrays.fill(patchColors, Color.getARGBbyPremodulatedColorNumber(0.0));
patchColorsDirty = true;
int numVariables = _program.patchesOwn().size();
_observer.resetPerspective();
for (int i = 0; _worldWidth * _worldHeight != i; i++) {
Patch patch = new Patch(this, i, x, y, numVariables);
x++;
if (x == (maxPxcor + 1)) {
x = minPxcor;
y--;
}
patchArray[i] = patch;
}
_patches = new ArrayAgentSet(Patch.class, patchArray, "patches", this);
patchesWithLabels = 0;
patchesAllBlack = true;
mayHavePartiallyTransparentObjects = false;
}
public void clearAll() {
tickCounter.clear();
clearTurtles();
clearPatches();
clearGlobals();
clearLinks();
_observer.resetPerspective();
mayHavePartiallyTransparentObjects = false;
}
// in a 2D world the drawing lives in the
// renderer so the workspace takes care of it.
public void clearDrawing() {
}
public void stamp(Agent agent, boolean erase) {
trailDrawer.stamp(agent, erase);
}
public double patchSize() {
return patchSize;
}
public boolean patchSize(double patchSize) {
if (this.patchSize != patchSize) {
this.patchSize = patchSize;
return true;
}
return false;
}
public Object getDrawing() {
return trailDrawer.getDrawing();
}
public boolean sendPixels() {
return trailDrawer.sendPixels();
}
public void markDrawingClean() {
trailDrawer.sendPixels(false);
}
public void clearPatches() {
for (AgentSet.Iterator iter = _patches.iterator(); iter.hasNext();) {
Patch patch = (Patch) iter.next();
patch.pcolorDoubleUnchecked(Color.BoxedBlack());
patch.label("");
patch.labelColor(Color.BoxedWhite());
try {
for (int j = patch.NUMBER_PREDEFINED_VARS;
j < patch.variables.length;
j++) {
patch.setPatchVariable(j, ZERO);
}
} catch (AgentException ex) {
throw new IllegalStateException(ex);
}
}
patchesAllBlack = true;
}
public void clearTurtles() {
if (_program.breeds() != null) {
for (Iterator<Object> iter = _program.breeds().values().iterator();
iter.hasNext();) {
((AgentSet) iter.next()).clear();
}
}
for (AgentSet.Iterator iter = _turtles.iterator(); iter.hasNext();) {
Turtle turtle = (Turtle) iter.next();
lineThicknesses.remove(turtle);
linkManager.cleanup(turtle);
turtle.id(-1);
}
_turtles.clear();
for (AgentSet.Iterator iter = _patches.iterator(); iter.hasNext();) {
((Patch) iter.next()).clearTurtles();
}
nextTurtleIndex = 0;
_observer.updatePosition();
}
public void clearLinks() {
if (_program.linkBreeds() != null) {
for (Iterator<Object> iter = _program.linkBreeds().values().iterator();
iter.hasNext();) {
AgentSet set = ((AgentSet) iter.next());
set.clear();
}
}
for (AgentSet.Iterator iter = _links.iterator(); iter.hasNext();) {
Link link = (Link) iter.next();
link.id = -1;
}
_links.clear();
nextLinkIndex = 0;
linkManager.reset();
}
public void clearGlobals() {
for (int j = _program.interfaceGlobals().size();
j < _observer.variables.length;
j++) {
try {
ValueConstraint con = _observer.variableConstraint(j);
if (con != null) {
_observer.setObserverVariable(j, con.defaultValue());
} else {
_observer.setObserverVariable(j, ZERO);
}
} catch (AgentException ex) {
throw new IllegalStateException(ex);
} catch (LogoException ex) {
throw new IllegalStateException(ex);
}
}
}
// this exists to support recompiling a model without causing
// agent state information to be lost. it is called after a
// successful recompilation.
public void realloc() {
// copy the breed agentsets from the old Program object from
// the previous compile to the new Program object that was
// created when we recompiled. any new breeds that were created,
// we create new agentsets for. (if this is a first compile, all
// the breeds will be created.) any breeds that no longer exist
// are dropped.
for (String breedName : _program.breeds().keySet()) {
AgentSet breed = (AgentSet) oldBreeds.get(breedName);
if (breed == null) {
_program.breeds().put
(breedName,
new TreeAgentSet(Turtle.class, breedName.toUpperCase(), this));
} else {
_program.breeds().put(breedName, breed);
}
}
for (Iterator<String> breedNames = _program.linkBreeds().keySet().iterator();
breedNames.hasNext();) {
String breedName = breedNames.next();
boolean directed = _program.linkBreeds().get(breedName).equals("DIRECTED-LINK-BREED");
AgentSet breed = (AgentSet) oldLinkBreeds.get(breedName);
if (breed == null) {
breed = new TreeAgentSet(Link.class, breedName.toUpperCase(), this);
} else {
// clear the lists first
breed.clearDirected();
}
_program.linkBreeds().put(breedName, breed);
breed.setDirected(directed);
}
List<Agent> doomedAgents = new ArrayList<Agent>();
// call Agent.realloc() on all the turtles
try {
if (_turtles != null) {
for (AgentSet.Iterator iter = _turtles.iterator(); iter.hasNext();) {
Agent agt = iter.next().realloc(true);
if (agt != null) {
doomedAgents.add(agt);
}
}
for (Iterator<Agent> i = doomedAgents.iterator(); i.hasNext();) {
((Turtle) i.next()).die();
}
doomedAgents.clear();
}
} catch (AgentException ex) {
throw new IllegalStateException(ex);
}
// call Agent.realloc() on all links
try {
if (_links != null) {
for (AgentSet.Iterator iter = _links.iterator(); iter.hasNext();) {
Agent agt = iter.next().realloc(true);
if (agt != null) {
doomedAgents.add(agt);
}
}
for (Iterator<Agent> i = doomedAgents.iterator(); i.hasNext();) {
((Link) i.next()).die();
}
doomedAgents.clear();
}
} catch (AgentException ex) {
throw new IllegalStateException(ex);
}
// call Agent.realloc() on all the patches
try {
// Note: we only need to realloc() if the patch variables have changed.
// ~Forrest ( 5/2/2007)
if (_patches != null && !_program.patchesOwn().equals(oldPatchesOwn)) {
for (AgentSet.Iterator iter = _patches.iterator(); iter.hasNext();) {
iter.next().realloc(true);
}
}
} catch (AgentException ex) {
throw new IllegalStateException(ex);
}
// call Agent.realloc() on the observer
_observer.realloc(true);
// and finally...
turtleBreedShapes.setUpBreedShapes(false, _program.breeds());
linkBreedShapes.setUpBreedShapes(false, _program.linkBreeds());
}
/// patch scratch
// a scratch area that can be used by commands such as _diffuse
double[][] patchScratch;
public double[][] getPatchScratch() {
if (patchScratch == null) {
patchScratch = new double[_worldWidth][_worldHeight];
}
return patchScratch;
}
/// agent-owns
public int indexOfVariable(Class<? extends Agent> agentClass, String name) {
if (agentClass == Observer.class) {
return observerOwnsIndexOf(name);
} else if (agentClass == Turtle.class) {
return turtlesOwnIndexOf(name);
} else if (agentClass == Link.class) {
return linksOwnIndexOf(name);
} else // patch
{
return patchesOwnIndexOf(name);
}
}
public int indexOfVariable(Agent agent, String name) {
if (agent instanceof Observer) {
return observerOwnsIndexOf(name);
} else if (agent instanceof Turtle) {
AgentSet breed = ((Turtle) agent).getBreed();
if (breed != _turtles) {
int result = breedsOwnIndexOf(breed, name);
if (result != -1) {
return result;
}
}
return turtlesOwnIndexOf(name);
} else if (agent instanceof Link) {
AgentSet breed = ((Link) agent).getBreed();
if (breed != _links) {
int result = linkBreedsOwnIndexOf(breed, name);
if (result != -1) {
return result;