Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Simonstrator
PeerfactSim.KOM
Commits
a34faa8d
Commit
a34faa8d
authored
Feb 20, 2018
by
Tobias Meuser
Browse files
First working version of monitoring
parent
d134fb97
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/de/tud/kom/p2psim/impl/simengine/Scheduler.java
View file @
a34faa8d
...
@@ -2,17 +2,17 @@
...
@@ -2,17 +2,17 @@
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
*
* This file is part of PeerfactSim.KOM.
* This file is part of PeerfactSim.KOM.
*
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or
* any later version.
* any later version.
*
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*
...
@@ -40,11 +40,11 @@ import de.tudarmstadt.maki.simonstrator.api.component.core.TimeComponent;
...
@@ -40,11 +40,11 @@ import de.tudarmstadt.maki.simonstrator.api.component.core.TimeComponent;
* generated events in order to provide valid experiments. The duration of each
* generated events in order to provide valid experiments. The duration of each
* experiment is controlled by the scheduler and the parameters defined by the
* experiment is controlled by the scheduler and the parameters defined by the
* Application.
* Application.
*
*
* @author Sebastian Kaune
* @author Sebastian Kaune
*/
*/
public
class
Scheduler
implements
EventHandler
,
public
class
Scheduler
implements
EventHandler
,
SchedulerComponent
,
TimeComponent
{
SchedulerComponent
,
TimeComponent
{
// Flag to allow the compiler to remove the unneeded debug code
// Flag to allow the compiler to remove the unneeded debug code
private
static
final
boolean
DEBUG_CODE
=
false
;
private
static
final
boolean
DEBUG_CODE
=
false
;
...
@@ -96,7 +96,7 @@ public class Scheduler implements EventHandler,
...
@@ -96,7 +96,7 @@ public class Scheduler implements EventHandler,
/**
/**
* Constructs a new scheduler instance using a calendar queue. If desired,
* Constructs a new scheduler instance using a calendar queue. If desired,
* status events about the progress of the simulation will be plotted.
* status events about the progress of the simulation will be plotted.
*
*
* @param statusEvent
* @param statusEvent
* the flag which speficies if status events will be plotted
* the flag which speficies if status events will be plotted
*/
*/
...
@@ -158,7 +158,7 @@ public class Scheduler implements EventHandler,
...
@@ -158,7 +158,7 @@ public class Scheduler implements EventHandler,
/**
/**
* Wake up thread safe and insert event immediately.
* Wake up thread safe and insert event immediately.
*
*
* @param content
* @param content
* the content
* the content
* @param handler
* @param handler
...
@@ -198,17 +198,17 @@ public class Scheduler implements EventHandler,
...
@@ -198,17 +198,17 @@ public class Scheduler implements EventHandler,
}
}
Monitor
.
log
(
Scheduler
.
class
,
Level
.
INFO
,
Monitor
.
log
(
Scheduler
.
class
,
Level
.
INFO
,
"Simulated realtime: "
+
Time
.
getFormattedTime
()
"Simulated realtime: "
+
Time
.
getFormattedTime
()
+
" - End of simulation.\n Scheduler processed in total "
+
" - End of simulation.\n Scheduler processed in total "
+
this
.
processedEventCounter
+
" events with "
+
this
.
processedEventCounter
+
" events with "
+
this
.
eventQueue
.
size
()
+
this
.
eventQueue
.
size
()
+
" unprocessed events still in queue"
);
+
" unprocessed events still in queue"
);
}
}
/**
/**
* Sets the end time at which the simulation framework will finish at the
* Sets the end time at which the simulation framework will finish at the
* latest the simulation , irrespective if there are still unprocessed
* latest the simulation , irrespective if there are still unprocessed
* events in the event queue.
* events in the event queue.
*
*
* @param endTime
* @param endTime
* point in time at which the simulator will finish at the latest
* point in time at which the simulator will finish at the latest
*/
*/
...
@@ -223,7 +223,7 @@ public class Scheduler implements EventHandler,
...
@@ -223,7 +223,7 @@ public class Scheduler implements EventHandler,
/**
/**
* Process the next event from the event queue.
* Process the next event from the event queue.
*
*
* @return whether an event was processed
* @return whether an event was processed
*/
*/
synchronized
private
boolean
processNextEvent
()
{
synchronized
private
boolean
processNextEvent
()
{
...
@@ -252,9 +252,9 @@ public class Scheduler implements EventHandler,
...
@@ -252,9 +252,9 @@ public class Scheduler implements EventHandler,
}
}
assert
(
nextEvent
.
getSimulationTime
()
>=
currentTime
)
:
"Next event: "
assert
(
nextEvent
.
getSimulationTime
()
>=
currentTime
)
:
"Next event: "
+
nextEvent
.
getSimulationTime
()
+
nextEvent
.
getSimulationTime
()
+
", but current "
+
", but current "
+
currentTime
+
"."
;
+
currentTime
+
"."
;
if
(
nextEvent
.
getSimulationTime
()
<=
newRoundsCurrentTime
)
{
if
(
nextEvent
.
getSimulationTime
()
<=
newRoundsCurrentTime
)
{
...
@@ -273,7 +273,7 @@ public class Scheduler implements EventHandler,
...
@@ -273,7 +273,7 @@ public class Scheduler implements EventHandler,
if
(
realEvent
.
schedulerType
==
TYPE_END
)
if
(
realEvent
.
schedulerType
==
TYPE_END
)
return
false
;
return
false
;
synchronized
(
this
.
eventQueue
)
{
synchronized
(
this
.
eventQueue
)
{
if
(
this
.
eventQueue
.
peek
().
getSimulationTime
()
<
newRoundsCurrentTime
)
{
if
(
this
.
eventQueue
.
peek
().
getSimulationTime
()
<
newRoundsCurrentTime
)
{
unhandledRegularEventsInPast
=
true
;
unhandledRegularEventsInPast
=
true
;
...
@@ -310,9 +310,9 @@ public class Scheduler implements EventHandler,
...
@@ -310,9 +310,9 @@ public class Scheduler implements EventHandler,
}
}
assert
(
peekedEvent
.
getSimulationTime
()
>=
currentTime
)
:
"Next event: "
assert
(
peekedEvent
.
getSimulationTime
()
>=
currentTime
)
:
"Next event: "
+
peekedEvent
.
getSimulationTime
()
+
peekedEvent
.
getSimulationTime
()
+
", but current "
+
", but current "
+
currentTime
+
"."
;
+
currentTime
+
"."
;
if
(
peekedEvent
.
getSimulationTime
()
>
currentTime
)
{
if
(
peekedEvent
.
getSimulationTime
()
>
currentTime
)
{
...
@@ -326,12 +326,12 @@ public class Scheduler implements EventHandler,
...
@@ -326,12 +326,12 @@ public class Scheduler implements EventHandler,
/*
/*
* ATTENTION: Magic happening here!
* ATTENTION: Magic happening here!
*
*
* Correct for uncertainties of going to real sleep.
* Correct for uncertainties of going to real sleep.
*/
*/
final
long
SLEEP_CORRECTION_FACTOR
=
400
;
final
long
SLEEP_CORRECTION_FACTOR
=
400
;
final
long
realTime_errorMs
=
System
.
currentTimeMillis
()
final
long
realTime_errorMs
=
System
.
currentTimeMillis
()
-
0
/* Starttime */
-
0
/* Starttime */
-
(
currentTime
/
Time
.
MILLISECOND
);
-
(
currentTime
/
Time
.
MILLISECOND
);
final
long
realTime_correctedTimeToWaitMs
=
realTime_timeToWaitMs
final
long
realTime_correctedTimeToWaitMs
=
realTime_timeToWaitMs
-
(
realTime_errorMs
/
SLEEP_CORRECTION_FACTOR
);
-
(
realTime_errorMs
/
SLEEP_CORRECTION_FACTOR
);
...
@@ -379,8 +379,8 @@ public class Scheduler implements EventHandler,
...
@@ -379,8 +379,8 @@ public class Scheduler implements EventHandler,
final
SchedulerEvent
realEvent
=
this
.
eventQueue
.
remove
();
final
SchedulerEvent
realEvent
=
this
.
eventQueue
.
remove
();
assert
(
realEvent
.
getSimulationTime
()
>=
currentTime
)
:
"Next event: "
assert
(
realEvent
.
getSimulationTime
()
>=
currentTime
)
:
"Next event: "
+
realEvent
.
getSimulationTime
()
+
", but current "
+
realEvent
.
getSimulationTime
()
+
", but current "
+
currentTime
+
"."
;
+
currentTime
+
"."
;
if
(
timeSkew
>
0
)
{
if
(
timeSkew
>
0
)
{
/*
/*
...
@@ -392,7 +392,7 @@ public class Scheduler implements EventHandler,
...
@@ -392,7 +392,7 @@ public class Scheduler implements EventHandler,
if
(
timeToWait
>
0
)
{
if
(
timeToWait
>
0
)
{
Monitor
.
log
(
Scheduler
.
class
,
Level
.
DEBUG
,
Monitor
.
log
(
Scheduler
.
class
,
Level
.
DEBUG
,
"Scheduler sleeping: "
+
timeToWait
/
1000
"Scheduler sleeping: "
+
timeToWait
/
1000
+
" milliseconds"
);
+
" milliseconds"
);
try
{
try
{
Thread
.
sleep
((
long
)
((
timeToWait
/
1000
)
/
timeSkew
));
Thread
.
sleep
((
long
)
((
timeToWait
/
1000
)
/
timeSkew
));
...
@@ -437,7 +437,7 @@ public class Scheduler implements EventHandler,
...
@@ -437,7 +437,7 @@ public class Scheduler implements EventHandler,
/**
/**
* Return whether event queue is empty.
* Return whether event queue is empty.
*
*
* @return whether event queue is empty.
* @return whether event queue is empty.
*/
*/
public
boolean
isEmpty
()
{
public
boolean
isEmpty
()
{
...
@@ -446,16 +446,17 @@ public class Scheduler implements EventHandler,
...
@@ -446,16 +446,17 @@ public class Scheduler implements EventHandler,
/**
/**
* Returns the current time of the scheduler
* Returns the current time of the scheduler
*
*
* @return current scheduler time
* @return current scheduler time
*/
*/
@Override
public
long
getCurrentTime
()
{
public
long
getCurrentTime
()
{
return
currentTime
;
return
currentTime
;
}
}
/**
/**
* Returns the end time of the scheduler
* Returns the end time of the scheduler
*
*
* @return
* @return
*/
*/
public
long
getEndTime
()
{
public
long
getEndTime
()
{
...
@@ -475,7 +476,7 @@ public class Scheduler implements EventHandler,
...
@@ -475,7 +476,7 @@ public class Scheduler implements EventHandler,
/**
/**
* Method for JUnit tests in order to verify the correctness
* Method for JUnit tests in order to verify the correctness
*
*
* @return number of events in event queue.
* @return number of events in event queue.
*/
*/
public
int
getEventQueueSize
()
{
public
int
getEventQueueSize
()
{
...
@@ -483,7 +484,7 @@ public class Scheduler implements EventHandler,
...
@@ -483,7 +484,7 @@ public class Scheduler implements EventHandler,
}
}
protected
static
final
class
SchedulerEvent
implements
protected
static
final
class
SchedulerEvent
implements
Comparable
<
SchedulerEvent
>
{
Comparable
<
SchedulerEvent
>
{
protected
final
int
schedulerType
;
protected
final
int
schedulerType
;
...
@@ -494,9 +495,9 @@ public class Scheduler implements EventHandler,
...
@@ -494,9 +495,9 @@ public class Scheduler implements EventHandler,
protected
final
Object
data
;
protected
final
Object
data
;
protected
long
simTime
;
protected
long
simTime
;
protected
long
globalOrderIdx
;
protected
long
globalOrderIdx
;
protected
static
long
globalOrderCounter
=
0
;
protected
static
long
globalOrderCounter
=
0
;
protected
SchedulerEvent
(
Object
data
,
long
simTime
,
protected
SchedulerEvent
(
Object
data
,
long
simTime
,
...
@@ -518,6 +519,7 @@ public class Scheduler implements EventHandler,
...
@@ -518,6 +519,7 @@ public class Scheduler implements EventHandler,
return
simTime
;
return
simTime
;
}
}
@Override
public
int
compareTo
(
SchedulerEvent
o
)
{
public
int
compareTo
(
SchedulerEvent
o
)
{
int
comp
=
Double
.
compare
(
this
.
simTime
,
o
.
simTime
);
int
comp
=
Double
.
compare
(
this
.
simTime
,
o
.
simTime
);
return
comp
==
0
?
Double
.
compare
(
this
.
globalOrderIdx
,
o
.
globalOrderIdx
)
:
comp
;
return
comp
==
0
?
Double
.
compare
(
this
.
globalOrderIdx
,
o
.
globalOrderIdx
)
:
comp
;
...
@@ -530,7 +532,7 @@ public class Scheduler implements EventHandler,
...
@@ -530,7 +532,7 @@ public class Scheduler implements EventHandler,
/**
/**
* Returns wheather the scheduler is running in realTime mode or not.
* Returns wheather the scheduler is running in realTime mode or not.
*
*
* @return the real time
* @return the real time
*/
*/
public
boolean
getRealTime
()
{
public
boolean
getRealTime
()
{
...
@@ -540,7 +542,7 @@ public class Scheduler implements EventHandler,
...
@@ -540,7 +542,7 @@ public class Scheduler implements EventHandler,
/**
/**
* a flag for slowing down the simulation down to real time. This flag only
* a flag for slowing down the simulation down to real time. This flag only
* makes sense for simulations which run faster than real time
* makes sense for simulations which run faster than real time
*
*
* @param realTime
* @param realTime
* flag for switching the scheduler to real time mode
* flag for switching the scheduler to real time mode
*/
*/
...
@@ -556,7 +558,7 @@ public class Scheduler implements EventHandler,
...
@@ -556,7 +558,7 @@ public class Scheduler implements EventHandler,
/**
/**
* method for setting the time skew. A time skew of 100 means, that the
* method for setting the time skew. A time skew of 100 means, that the
* simulation runs 100 times faster than real time
* simulation runs 100 times faster than real time
*
*
* @param timeSkew
* @param timeSkew
* the time skew
* the time skew
*/
*/
...
@@ -567,10 +569,14 @@ public class Scheduler implements EventHandler,
...
@@ -567,10 +569,14 @@ public class Scheduler implements EventHandler,
}
}
}
}
public
double
getTimeSkew
()
{
return
timeSkew
;
}
/**
/**
* Sets the simulation speed lock, changes in setRealTime or setTimeSkew
* Sets the simulation speed lock, changes in setRealTime or setTimeSkew
* will not apply while the lock is set.
* will not apply while the lock is set.
*
*
* @param locked
* @param locked
* the new simulation speed locked
* the new simulation speed locked
*/
*/
...
@@ -593,7 +599,7 @@ public class Scheduler implements EventHandler,
...
@@ -593,7 +599,7 @@ public class Scheduler implements EventHandler,
/**
/**
* The comparator
* The comparator
*
*
* @author Bjoern Richerzhagen
* @author Bjoern Richerzhagen
* @version 1.0, 05.03.2012
* @version 1.0, 05.03.2012
*/
*/
...
...
src/de/tud/kom/p2psim/impl/simengine/Simulator.java
View file @
a34faa8d
...
@@ -2,17 +2,17 @@
...
@@ -2,17 +2,17 @@
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
* Copyright (c) 2005-2011 KOM - Multimedia Communications Lab
*
*
* This file is part of PeerfactSim.KOM.
* This file is part of PeerfactSim.KOM.
*
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* the Free Software Foundation, either version 3 of the License, or
* any later version.
* any later version.
*
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*
...
@@ -56,11 +56,11 @@ import de.tudarmstadt.maki.simonstrator.api.component.core.RandomGeneratorCompon
...
@@ -56,11 +56,11 @@ import de.tudarmstadt.maki.simonstrator.api.component.core.RandomGeneratorCompon
/**
/**
* Concrete implementation of a simulator which can be used to run a simulation
* Concrete implementation of a simulator which can be used to run a simulation
* by calling the main method in the SimulatorRunner class.
* by calling the main method in the SimulatorRunner class.
*
*
* @author Sebastian Kaune
* @author Sebastian Kaune
* @author Konstantin Pussep
* @author Konstantin Pussep
* @version 3.0, 11/29/2007
* @version 3.0, 11/29/2007
*
*
*/
*/
public
class
Simulator
implements
RandomGeneratorComponent
,
GlobalComponent
{
public
class
Simulator
implements
RandomGeneratorComponent
,
GlobalComponent
{
...
@@ -68,7 +68,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -68,7 +68,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
* These constant should be ALWAYS used for virtual time calculations.
* These constant should be ALWAYS used for virtual time calculations.
*/
*/
public
final
static
double
NANOSECOND_UNIT
=
1
E
-
3
d
;
public
final
static
double
NANOSECOND_UNIT
=
1
E
-
3
d
;
/**
/**
* These constant should be ALWAYS used for virtual time calculations.
* These constant should be ALWAYS used for virtual time calculations.
*/
*/
...
@@ -130,7 +130,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -130,7 +130,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* This class is singleton, so use getInstance() method to obtain a
* This class is singleton, so use getInstance() method to obtain a
* reference to it.
* reference to it.
*
*
*/
*/
private
Simulator
()
{
private
Simulator
()
{
singleton
=
this
;
singleton
=
this
;
...
@@ -145,7 +145,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -145,7 +145,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* Returns the single instance of the SimulationFramework
* Returns the single instance of the SimulationFramework
*
*
* @return the SimulationFramework
* @return the SimulationFramework
*/
*/
public
static
Simulator
getInstance
()
{
public
static
Simulator
getInstance
()
{
...
@@ -158,10 +158,10 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -158,10 +158,10 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
scheduler
.
reset
();
scheduler
.
reset
();
}
}
/**
/**
* Set the scenario (protocol stack, network topology etc.) which will be
* Set the scenario (protocol stack, network topology etc.) which will be
* used to run the simulation.
* used to run the simulation.
*
*
* @param scenario
* @param scenario
* simulation scenario to be used
* simulation scenario to be used
*/
*/
...
@@ -172,7 +172,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -172,7 +172,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* Returns the scenario used to run the simulation.
* Returns the scenario used to run the simulation.
*
*
* @return
* @return
*/
*/
public
Scenario
getScenario
()
{
public
Scenario
getScenario
()
{
...
@@ -181,7 +181,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -181,7 +181,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* Only for internal use
* Only for internal use
*
*
* @return
* @return
*/
*/
public
static
Scheduler
getScheduler
()
{
public
static
Scheduler
getScheduler
()
{
...
@@ -195,35 +195,35 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -195,35 +195,35 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* This method will run the simulation using the previously set scenario
* This method will run the simulation using the previously set scenario
* data.
* data.
*
*
*/
*/
public
void
start
(
boolean
throwExceptions
)
{
public
void
start
(
boolean
throwExceptions
)
{
checkRunning
();
checkRunning
();
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
"Prepare Scenario ..."
);
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
"Prepare Scenario ..."
);
this
.
scenario
.
prepare
();
this
.
scenario
.
prepare
();
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
"Prepare Scenario ..."
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
"Prepare Scenario ..."
+
getSeed
());
+
getSeed
());
/* Real World Starting Time:
/* Real World Starting Time:
* Block till we're allowed to start.
* Block till we're allowed to start.
*/
*/
if
(
realWorldStartTime
!=
null
)
{
if
(
realWorldStartTime
!=
null
)
{
try
{
try
{
//final Date now = new Date();
//final Date now = new Date();
final
Date
now
=
NTPClient
.
getDate
();
final
Date
now
=
NTPClient
.
getDate
();
final
long
waitFor
=
realWorldStartTime
.
getTime
()
-
now
.
getTime
();
final
long
waitFor
=
realWorldStartTime
.
getTime
()
-
now
.
getTime
();
Thread
.
sleep
(
waitFor
);
Thread
.
sleep
(
waitFor
);
}
catch
(
InterruptedException
e
)
{
}
catch
(
InterruptedException
e
)
{
//
//
}
}
}
}
startTime
=
System
.
currentTimeMillis
();
startTime
=
System
.
currentTimeMillis
();
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
"Simulation started..."
);
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
"Simulation started..."
);
this
.
running
=
true
;
this
.
running
=
true
;
...
@@ -282,53 +282,53 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -282,53 +282,53 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* Configure simulation from an XML file.
* Configure simulation from an XML file.
*
*
* @param configFile
* @param configFile
* XML file with the configuration data.
* XML file with the configuration data.
* @param variables
* @param variables
* the variables which are specified in the XML file with the
* the variables which are specified in the XML file with the
* configuarion data.
* configuarion data.
*/
*/
public
void
configure
(
String
configFile
,
Map
<
String
,
String
>
variables
,
Map
<
String
,
String
>
modifiedVariables
,
List
<
String
>
variations
)
{
public
void
configure
(
String
configFile
,
Map
<
String
,
String
>
variables
,
Map
<
String
,
String
>
modifiedVariables
,
List
<
String
>
variations
)
{
// TODO create a class, that contains general informations of the
// TODO create a class, that contains general informations of the
// simulation, which can be accessed from every component during a
// simulation, which can be accessed from every component during a
// simulation. This can be seen as an alternative to implementing the
// simulation. This can be seen as an alternative to implementing the
// Composable interface
// Composable interface
if
(
configFile
.
endsWith
(
".xml"
))
{
if
(
configFile
.
endsWith
(
".xml"
))
{
this
.
defaultConfigurator
=
new
DefaultConfigurator
(
configFile
);
this
.
defaultConfigurator
=
new
DefaultConfigurator
(
configFile
);
defaultConfigurator
.
setVariables
(
variables
);
defaultConfigurator
.
setVariables
(
variables
);
}
else
{
}
else
{
SimCfgConfigurator
simCfgConfigurator
=
new
SimCfgConfigurator
(
configFile
);
SimCfgConfigurator
simCfgConfigurator
=
new
SimCfgConfigurator
(
configFile
);
simCfgConfigurator
.
applyVariations
(
variations
);
simCfgConfigurator
.
applyVariations
(
variations
);
simCfgConfigurator
.
setVariables
(
modifiedVariables
);
simCfgConfigurator
.
setVariables
(
modifiedVariables
);
this
.
defaultConfigurator
=
simCfgConfigurator
;
this
.
defaultConfigurator
=
simCfgConfigurator
;
}
}
this
.
defaultConfigurator
.
register
(
Configurator
.
CORE
,
this
);
this
.
defaultConfigurator
.
register
(
Configurator
.
CORE
,
this
);
this
.
defaultConfigurator
.
configureAll
();
this
.
defaultConfigurator
.
configureAll
();
// The next steps are only required for the xml version.
// The next steps are only required for the xml version.
// SimCfg will execute them in the configurator
// SimCfg will execute them in the configurator
if
(
configFile
.
endsWith
(
".xml"
))
{
if
(
configFile
.
endsWith
(
".xml"
))
{
ScenarioFactory
scenarioBuilder
=
(
ScenarioFactory
)
this
.
defaultConfigurator
.
getConfigurable
(
Configurator
.
SCENARIO_TAG
);
ScenarioFactory
scenarioBuilder
=
(
ScenarioFactory
)
this
.
defaultConfigurator
.
getConfigurable
(
Configurator
.
SCENARIO_TAG
);
if
(
scenarioBuilder
==
null
)
if
(
scenarioBuilder
==
null
)
throw
new
ConfigurationException
(
throw
new
ConfigurationException
(
"No scenario builder specified in the configuration file. Nothing to do."
);
"No scenario builder specified in the configuration file. Nothing to do."
);
Scenario
scenario
=
scenarioBuilder
.
createScenario
();
Scenario
scenario
=
scenarioBuilder
.
createScenario
();
setScenario
(
scenario
);
setScenario
(
scenario
);
}
}
}
}
/**
/**
* Returns the seed used within a simulation run.
* Returns the seed used within a simulation run.
*
*
* @return the predefined seed
* @return the predefined seed
*
*
*/
*/
public
static
long
getSeed
()
{
public
static
long
getSeed
()
{
return
seed
;
return
seed
;
...
@@ -337,7 +337,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -337,7 +337,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* This method sets the seed of the global random generator which can be
* This method sets the seed of the global random generator which can be
* obtained using the static getRandom()-method.
* obtained using the static getRandom()-method.
*
*
* @param seed
* @param seed
* the seed to configure the global random generator
* the seed to configure the global random generator
*/
*/
...
@@ -356,53 +356,53 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -356,53 +356,53 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
throw
new
IllegalStateException
(
"Simulator is already running."
);
throw
new
IllegalStateException
(
"Simulator is already running."
);
}
}
/**
/**
* This method provides a newly created random generator, configured
* This method provides a newly created random generator, configured
* with the specified seed of the simulator. This method should be preferred
* with the specified seed of the simulator. This method should be preferred
* over the deprecated @{link getRandom}.
* over the deprecated @{link getRandom}.
*
*
* <b>Notes:</b>
* <b>Notes:</b>
* Doing so will prevent components from influencing each other, thus creating
* Doing so will prevent components from influencing each other, thus creating
* reproducible results while allowing different compositions of components.
* reproducible results while allowing different compositions of components.
*
*
* The method allows the use of an object as source. This is to allow the use in
* The method allows the use of an object as source. This is to allow the use in
* different situations:
* different situations:
* 1. Random generators belonging to a single component should pass the class
* 1. Random generators belonging to a single component should pass the class
* object of that component to this method.
* object of that component to this method.
* 2. Components that are always loaded during a simulation can use the
* 2. Components that are always loaded during a simulation can use the
* Simulator.class object for a system wide random generator like {@link #getRandom()}
* Simulator.class object for a system wide random generator like {@link #getRandom()}
* provided.
* provided.
* 3. Utility classes that are loaded by many different components should use
* 3. Utility classes that are loaded by many different components should use
* a reference to themselves to avoid transitive dependencies on the same random
* a reference to themselves to avoid transitive dependencies on the same random
* generator throughout different components.
* generator throughout different components.
* This approach will provide way to to configure different seeds for specific class
* This approach will provide way to to configure different seeds for specific class
* objects. This will allow component specific seeds and, e.g., the transfer of movement
* objects. This will allow component specific seeds and, e.g., the transfer of movement
* behavior from one configured scenario to another.
* behavior from one configured scenario to another.
*
*
* @param source The source that requires the random generator (component class object is preferred)
* @param source The source that requires the random generator (component class object is preferred)
* @param salt Added to the default seed, should be bound
* @param salt Added to the default seed, should be bound
* @return The random generator for the given source
* @return The random generator for the given source
*/
*/
@Override
@Override
public
Random
getRandom
(
Object
source
)
{
public
Random
getRandom
(
Object
source
)
{
if
(
randomGenerators
.
containsKey
(
source
))
{
if
(
randomGenerators
.
containsKey
(
source
))
{
return
randomGenerators
.
get
(
source
);
return
randomGenerators
.
get
(
source
);
}
else
{
}
else
{
long
thisSeed
=
source
.
toString
().
hashCode
()
+
31
long
thisSeed
=
source
.
toString
().
hashCode
()
+
31
*
seed
;
*
seed
;
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
Monitor
.
log
(
Simulator
.
class
,
Level
.
INFO
,
"Created a new Random Source for %s with seed %d"
,
source
,
"Created a new Random Source for %s with seed %d"
,
source
,
thisSeed
);
thisSeed
);
Random
randomGenerator
=
new
Random
(
thisSeed
);
Random
randomGenerator
=
new
Random
(
thisSeed
);
randomGenerators
.
put
(
source
,
randomGenerator
);
randomGenerators
.
put
(
source
,
randomGenerator
);
return
randomGenerator
;
return
randomGenerator
;
}
}
}
}
/**
/**
* Returns the current simulation unit value.
* Returns the current simulation unit value.
*
*
* @return the current simulation unit value
* @return the current simulation unit value
*/
*/
public
static
long
getCurrentTime
()
{
public
static
long
getCurrentTime
()
{
...
@@ -411,17 +411,17 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -411,17 +411,17 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* Returns the start time of the simulation.
* Returns the start time of the simulation.
*
*
* @return
* @return
*/
*/
public
static
long
getStartTime
()
{
public
static
long
getStartTime
()
{
return
singleton
.
startTime
;
return
singleton
.
startTime
;
}
}
/**
/**
* Returns the end time of the simulation.
* Returns the end time of the simulation.
*
*
* @return
* @return
*/
*/
public
static
long
getEndTime
()
{
public
static
long
getEndTime
()
{
...
@@ -432,7 +432,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -432,7 +432,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
* Sets the end time at which the simulation framework will finish at the
* Sets the end time at which the simulation framework will finish at the
* latest the simulation , irrespective if there are still unprocessed
* latest the simulation , irrespective if there are still unprocessed
* events in the event queue.
* events in the event queue.
*
*
* @param endTime
* @param endTime
* point in time at which the simular will finish at the latest
* point in time at which the simular will finish at the latest
*/
*/
...
@@ -450,7 +450,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -450,7 +450,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
* in turn will save the state in a static variable. Is this flag set
* in turn will save the state in a static variable. Is this flag set
* to true the MeasurementDAO will return from every method before
* to true the MeasurementDAO will return from every method before
* doing any work.
* doing any work.
*
*
* @param inactive
* @param inactive
*/
*/
public
void
setDatabaseInactive
(
boolean
inactive
)
{
public
void
setDatabaseInactive
(
boolean
inactive
)
{
...
@@ -463,25 +463,25 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -463,25 +463,25 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
}
}
}
}
/**
/**
* Overrides the database name provided in the persistence.xml.
* Overrides the database name provided in the persistence.xml.
*
*
* As the DAO class only provides static methods and is not a singleton it
* As the DAO class only provides static methods and is not a singleton it
* cannot be accessed through the config file otherwise.
* cannot be accessed through the config file otherwise.
*
*
* @param database
* @param database
* @deprecated use the MetricOutputDAO instead to do all relevant
* @deprecated use the MetricOutputDAO instead to do all relevant
* configuration!
* configuration!
*/
*/
@Deprecated
@Deprecated
public
void
setDatabase
(
String
database
)
{
public
void
setDatabase
(
String
database
)
{
DAO
.
database
=
database
;
DAO
.
database
=
database
;
}
}
/**
/**
* Can be used to format the absolute simulation time (current, past or
* Can be used to format the absolute simulation time (current, past or
* future) into human-readable format: (h:m:s:ms).
* future) into human-readable format: (h:m:s:ms).
*
*
* @param time
* @param time
* - absolute simulation time like the one obtained via
* - absolute simulation time like the one obtained via
* getCurrentTime();
* getCurrentTime();
...
@@ -494,7 +494,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -494,7 +494,7 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
/**
/**
* Specifies how often the scheduler will printout the current simulation
* Specifies how often the scheduler will printout the current simulation
* time.
* time.
*
*
* @param time
* @param time
*/
*/
public
void
setStatusInterval
(
long
time
)
{
public
void
setStatusInterval
(
long
time
)
{
...
@@ -512,38 +512,38 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
...
@@ -512,38 +512,38 @@ public class Simulator implements RandomGeneratorComponent, GlobalComponent {
public
void
setSimulationSpeedLocked
(
boolean
locked
)
{
public
void
setSimulationSpeedLocked
(
boolean
locked
)
{
scheduler
.
setSimulationSpeedLocked
(
locked
);
scheduler
.
setSimulationSpeedLocked
(
locked
);
}
}
public
static
Configurator
getConfigurator
()
{
public
static
Configurator
getConfigurator
()
{
return
defaultConfigurator
;
return
defaultConfigurator
;
}
}
/**
/**
* Sets the real world start time.
* Sets the real world start time.
*
*
* @param realWorldStartTime the new real world start time
* @param realWorldStartTime the new real world start time
*/
*/
public
void
setRealWorldStartTime
(
String
realWorldStartTime
)
{
public
void
setRealWorldStartTime
(
String
realWorldStartTime
)
{
final
Date
now
=
new
Date
();
final
Date
now
=
new
Date
();
SimpleDateFormat
formatter
=
new
SimpleDateFormat
(
"HH:mm:ss z dd.MM.yyyy"
,
Locale
.
GERMANY
);
SimpleDateFormat
formatter
=
new
SimpleDateFormat
(
"HH:mm:ss z dd.MM.yyyy"
,
Locale
.
GERMANY
);
try
{
try
{
final
Date
startTime
=
formatter
.
parse
(
realWorldStartTime
);
final
Date
startTime
=
formatter
.
parse
(
realWorldStartTime
);
if
(
now
.
after
(
startTime
)
)
{
if
(
now
.
after
(
startTime
)
)
{
throw
new
AssertionError
(
throw
new
AssertionError
(
"Simulator was supposed to run in the past. Check config for realWorldStartTime."
);
"Simulator was supposed to run in the past. Check config for realWorldStartTime."
);
}
}
this
.
realWorldStartTime
=
startTime
;
this
.
realWorldStartTime
=
startTime
;
}
catch
(
ParseException
e
)
{
}
catch
(
ParseException
e
)
{
Monitor
.
log
(
Monitor
.
log
(
Simulator
.
class
,
Simulator
.
class
,
Level
.
WARN
,
Level
.
WARN
,
"Could not parse realWorldStartTime. Please check configuration file. Starting *NOW*"
);
"Could not parse realWorldStartTime. Please check configuration file. Starting *NOW*"
);
}
}
}
}
public
void
addObserver
(
SimulatorObserver
observer
)
{
public
void
addObserver
(
SimulatorObserver
observer
)
{
...
...
src/de/tud/kom/p2psim/impl/topology/movement/vehicular/sumo/simulation/controller/traci/TraciSimulationController.java
View file @
a34faa8d
...
@@ -826,10 +826,8 @@ public class TraciSimulationController implements VehicleController, SimulationS
...
@@ -826,10 +826,8 @@ public class TraciSimulationController implements VehicleController, SimulationS
List
<
RoadNetworkLane
>
lanes
=
_roadNetwork
.
getEdge
(
pEdgeID
).
getLanes
();
List
<
RoadNetworkLane
>
lanes
=
_roadNetwork
.
getEdge
(
pEdgeID
).
getLanes
();
if
(
lanes
.
size
()
>
0
)
{
if
(
lanes
.
size
()
>
0
)
{
List
<
Location
>
laneShape
=
getLaneShape
(
lanes
.
get
(
0
).
getLaneID
());
List
<
Location
>
laneShape
=
getLaneShape
(
lanes
.
get
(
0
).
getLaneID
());
for
(
Location
location
:
laneShape
)
{
if
(
laneShape
.
size
()
>
1
)
{
if
(
0
<=
location
.
getLongitude
()
&&
location
.
getLongitude
()
<=
_endX
-
_startX
&&
0
<=
location
.
getLatitude
()
&&
location
.
getLatitude
()
<=
_endY
-
_startY
)
{
return
true
;
return
true
;
}
}
}
}
}
return
false
;
return
false
;
...
...
src/de/tud/kom/p2psim/impl/topology/views/visualization/ui/SimControlPanel.java
View file @
a34faa8d
...
@@ -20,6 +20,7 @@
...
@@ -20,6 +20,7 @@
package
de.tud.kom.p2psim.impl.topology.views.visualization.ui
;
package
de.tud.kom.p2psim.impl.topology.views.visualization.ui
;
import
java.awt.Color
;
import
java.awt.Dimension
;
import
java.awt.Dimension
;
import
java.awt.event.ActionEvent
;
import
java.awt.event.ActionEvent
;
import
java.awt.event.ActionListener
;
import
java.awt.event.ActionListener
;
...
@@ -28,12 +29,16 @@ import javax.swing.AbstractAction;
...
@@ -28,12 +29,16 @@ import javax.swing.AbstractAction;
import
javax.swing.Action
;
import
javax.swing.Action
;
import
javax.swing.Box
;
import
javax.swing.Box
;
import
javax.swing.BoxLayout
;
import
javax.swing.BoxLayout
;
import
javax.swing.JButton
;
import
javax.swing.JCheckBoxMenuItem
;
import
javax.swing.JCheckBoxMenuItem
;
import
javax.swing.JLabel
;
import
javax.swing.JLabel
;
import
javax.swing.JMenu
;
import
javax.swing.JMenu
;
import
javax.swing.JMenuBar
;
import
javax.swing.JMenuBar
;
import
javax.swing.JPanel
;
import
javax.swing.JSlider
;
import
javax.swing.JSlider
;
import
javax.swing.JSpinner
;
import
javax.swing.JToggleButton
;
import
javax.swing.JToggleButton
;
import
javax.swing.SpinnerNumberModel
;
import
javax.swing.SwingConstants
;
import
javax.swing.SwingConstants
;
import
javax.swing.event.ChangeEvent
;
import
javax.swing.event.ChangeEvent
;
import
javax.swing.event.ChangeListener
;
import
javax.swing.event.ChangeListener
;
...
@@ -44,6 +49,9 @@ import de.tud.kom.p2psim.impl.topology.views.visualization.ComponentVisManager;
...
@@ -44,6 +49,9 @@ import de.tud.kom.p2psim.impl.topology.views.visualization.ComponentVisManager;
import
de.tud.kom.p2psim.impl.topology.views.visualization.ComponentVisManager.VisInfo
;
import
de.tud.kom.p2psim.impl.topology.views.visualization.ComponentVisManager.VisInfo
;
import
de.tud.kom.p2psim.impl.topology.views.visualization.ComponentVisManager.VisualizationListener
;
import
de.tud.kom.p2psim.impl.topology.views.visualization.ComponentVisManager.VisualizationListener
;
import
de.tud.kom.p2psim.impl.util.guirunner.Config
;
import
de.tud.kom.p2psim.impl.util.guirunner.Config
;
import
de.tudarmstadt.maki.simonstrator.api.Event
;
import
de.tudarmstadt.maki.simonstrator.api.EventHandler
;
import
de.tudarmstadt.maki.simonstrator.api.Time
;
/**
/**
* Menu-Bar containing means to alter the simulation speed, pause and un-pause
* Menu-Bar containing means to alter the simulation speed, pause and un-pause
...
@@ -70,6 +78,8 @@ public class SimControlPanel extends JMenuBar implements ActionListener, ChangeL
...
@@ -70,6 +78,8 @@ public class SimControlPanel extends JMenuBar implements ActionListener, ChangeL
private
ComponentVisManager
visManager
;
private
ComponentVisManager
visManager
;
private
JPanel
runUntil
;
public
SimControlPanel
(
ComponentVisManager
visManager
)
{
public
SimControlPanel
(
ComponentVisManager
visManager
)
{
// super("Control");
// super("Control");
this
.
visManager
=
visManager
;
this
.
visManager
=
visManager
;
...
@@ -86,6 +96,8 @@ public class SimControlPanel extends JMenuBar implements ActionListener, ChangeL
...
@@ -86,6 +96,8 @@ public class SimControlPanel extends JMenuBar implements ActionListener, ChangeL
this
.
add
(
getSpeedLabel
());
this
.
add
(
getSpeedLabel
());
this
.
add
(
Box
.
createHorizontalStrut
(
10
));
this
.
add
(
Box
.
createHorizontalStrut
(
10
));
this
.
add
(
getPlayPauseButton
());
this
.
add
(
getPlayPauseButton
());
this
.
add
(
Box
.
createHorizontalStrut
(
10
));
this
.
add
(
getRunUntil
());
this
.
add
(
Box
.
createHorizontalGlue
());
this
.
add
(
Box
.
createHorizontalGlue
());
}
}
...
@@ -162,6 +174,53 @@ public class SimControlPanel extends JMenuBar implements ActionListener, ChangeL
...
@@ -162,6 +174,53 @@ public class SimControlPanel extends JMenuBar implements ActionListener, ChangeL
return
speedslider
;
return
speedslider
;
}
}
protected
JPanel
getRunUntil
()
{
if
(
runUntil
==
null
)
{
runUntil
=
new
JPanel
();
runUntil
.
setBackground
(
new
Color
(
0
,
0
,
0
,
0
));
JButton
button
=
new
JButton
(
"Run until"
);
runUntil
.
add
(
button
);
JSpinner
spinner
=
new
JSpinner
(
new
SpinnerNumberModel
(
0
,
0
,
Simulator
.
getEndTime
()
/
Time
.
MINUTE
,
1
));
runUntil
.
add
(
spinner
);
runUntil
.
add
(
new
JLabel
(
"min"
));
button
.
addActionListener
(
new
ActionListener
()
{
@Override
public
void
actionPerformed
(
ActionEvent
pE
)
{
int
value
=
(
int
)((
double
)
spinner
.
getValue
());
boolean
wasPaused
=
isSimulatorPaused
;
if
(
Time
.
getCurrentTime
()
<
value
*
Time
.
MINUTE
)
{
if
(
wasPaused
)
{
unpauseSimulation
();
}
double
timeSkew
=
Simulator
.
getScheduler
().
getTimeSkew
();
Simulator
.
getScheduler
().
setTimeSkew
(
0
);
Event
.
scheduleWithDelay
(
value
*
Time
.
MINUTE
-
Time
.
getCurrentTime
(),
new
EventHandler
()
{
@Override
public
void
eventOccurred
(
Object
pContent
,
int
pType
)
{
if
(
Simulator
.
getScheduler
().
getTimeSkew
()
==
0
)
{
Simulator
.
getScheduler
().
setTimeSkew
(
timeSkew
);
}
if
(
wasPaused
)
{
pauseSimulation
();
}
}
},
null
,
0
);
}
}
});
}
return
runUntil
;
}
protected
JLabel
getSpeedLabel
()
{
protected
JLabel
getSpeedLabel
()
{
if
(
speedlabel
==
null
)
{
if
(
speedlabel
==
null
)
{
speedlabel
=
new
JLabel
(
"max"
);
speedlabel
=
new
JLabel
(
"max"
);
...
...
src/de/tud/kom/p2psim/impl/topology/views/visualization/world/NodeInfoComponentVis.java
View file @
a34faa8d
...
@@ -27,6 +27,7 @@ import java.awt.Graphics;
...
@@ -27,6 +27,7 @@ import java.awt.Graphics;
import
java.awt.Graphics2D
;
import
java.awt.Graphics2D
;
import
java.awt.Point
;
import
java.awt.Point
;
import
java.awt.RenderingHints
;
import
java.awt.RenderingHints
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.LinkedList
;
import
java.util.LinkedList
;
...
@@ -112,7 +113,7 @@ implements VisualizationComponent {
...
@@ -112,7 +113,7 @@ implements VisualizationComponent {
g2
.
setRenderingHint
(
RenderingHints
.
KEY_ANTIALIASING
,
g2
.
setRenderingHint
(
RenderingHints
.
KEY_ANTIALIASING
,
RenderingHints
.
VALUE_ANTIALIAS_ON
);
RenderingHints
.
VALUE_ANTIALIAS_ON
);
boolean
first
=
true
;
boolean
first
=
true
;
for
(
NodeVis
vis
:
nodes
)
{
for
(
NodeVis
vis
:
new
ArrayList
<>(
nodes
)
)
{
vis
.
draw
(
g2
);
vis
.
draw
(
g2
);
if
(
first
)
{
if
(
first
)
{
first
=
false
;
first
=
false
;
...
@@ -238,7 +239,7 @@ implements VisualizationComponent {
...
@@ -238,7 +239,7 @@ implements VisualizationComponent {
g2
.
setStroke
(
new
BasicStroke
(
3
));
g2
.
setStroke
(
new
BasicStroke
(
3
));
for
(
int
color
=
0
;
color
<
segments
;
color
++)
{
for
(
int
color
=
0
;
color
<
segments
;
color
++)
{
if
(!
activeLayers
[
color
])
{
if
(
activeLayers
.
length
<=
color
||
!
activeLayers
[
color
])
{
continue
;
continue
;
}
}
g2
.
setColor
(
Color
.
DARK_GRAY
);
g2
.
setColor
(
Color
.
DARK_GRAY
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment