load a world asynchronously or without blocking the main thread - java

I'm working on a minigames plugin. After an arena finishes it should be regenerated - I use the unload and load trick. It has an obvious disadvantage - it freezes the server for a while to prepare spawn areas. I decided to put the arena reset code into an runnable asynchronous task runTaskAsynchronously(). However, when the server tries to run the code inside the thread, it throws an exception:
Caused by: java.lang.IllegalStateException: Asynchronous entity world add!
Here's a part of my code:
getServer().getScheduler().runTaskAsynchronously(this, new Runnable()
{
#Override
public void run()
{
String w_name = world.getName();
getServer().unloadWorld(world.getName(), false);
world = getServer().createWorld(new WorldCreator(w_name));
}
});
Any suggestions how to deal with this problem?

Bukkit doesn't like it when you try to edit anything through the API in an async task. Reading and processing is fine but bukkit enforces nothing when it comes to thread safety and thus affecting the world with more than 1 thread can cause issues.
Try splitting up your arena reset into smaller chunks and spreading out the operation over several ticks with a series of synchronous tasks, might help with the performance.
This isn't my code but it does a decent job of demonstrating the idea https://gist.github.com/aadnk/5443172

-- You can load worlds async using this: http://pastebin.com/K9CuVMS5 --
No you cannot, and if you tried it would have a high chance of world corruption. But if you don't care about it this is what you can do:
Bukkit loads worlds via Bukkit.createWorld(WorldCreator) which activates Server.createWorld(WorldCreator) which activates:
Validate.notNull(creator, "Creator may not be null");
String name = creator.name();
ChunkGenerator generator = creator.generator();
File folder = new File(this.getWorldContainer(), name);
World world = this.getWorld(name);
WorldType type = WorldType.getType(creator.type().getName());
boolean generateStructures = creator.generateStructures();
if(world != null) {
return world;
} else if(folder.exists() && !folder.isDirectory()) {
throw new IllegalArgumentException("File exists with the name \'" + name + "\' and isn\'t a folder");
} else {
if(generator == null) {
generator = this.getGenerator(name);
}
WorldLoaderServer converter = new WorldLoaderServer(this.getWorldContainer());
if(converter.isConvertable(name)) {
this.getLogger().info("Converting world \'" + name + "\'");
converter.convert(name, new ConvertProgressUpdater(this.console));
}
int dimension = 10 + this.console.worlds.size();
boolean used = false;
do {
Iterator sdm = this.console.worlds.iterator();
while(sdm.hasNext()) {
WorldServer hardcore = (WorldServer)sdm.next();
used = hardcore.dimension == dimension;
if(used) {
++dimension;
break;
}
}
} while(used);
boolean var25 = false;
ServerNBTManager var24 = new ServerNBTManager(this.getWorldContainer(), name, true);
WorldData worlddata = var24.getWorldData();
if(worlddata == null) {
WorldSettings internal = new WorldSettings(creator.seed(), EnumGamemode.getById(this.getDefaultGameMode().getValue()), generateStructures, var25, type);
internal.setGeneratorSettings(creator.generatorSettings());
worlddata = new WorldData(internal, name);
}
worlddata.checkName(name);
WorldServer var26 = (WorldServer)(new WorldServer(this.console, var24, worlddata, dimension, this.console.methodProfiler, creator.environment(), generator)).b();
if(!this.worlds.containsKey(name.toLowerCase())) {
return null;
} else {
var26.scoreboard = this.getScoreboardManager().getMainScoreboard().getHandle();
var26.tracker = new EntityTracker(var26);
var26.addIWorldAccess(new WorldManager(this.console, var26));
var26.worldData.setDifficulty(EnumDifficulty.EASY);
var26.setSpawnFlags(true, true);
this.console.worlds.add(var26);
if(generator != null) {
var26.getWorld().getPopulators().addAll(generator.getDefaultPopulators(var26.getWorld()));
}
this.pluginManager.callEvent(new WorldInitEvent(var26.getWorld()));
System.out.print("Preparing start region for level " + (this.console.worlds.size() - 1) + " (Seed: " + var26.getSeed() + ")");
if(var26.getWorld().getKeepSpawnInMemory()) {
short short1 = 196;
long i = System.currentTimeMillis();
for(int j = -short1; j <= short1; j += 16) {
for(int k = -short1; k <= short1; k += 16) {
long l = System.currentTimeMillis();
if(l < i) {
i = l;
}
if(l > i + 1000L) {
int chunkcoordinates = (short1 * 2 + 1) * (short1 * 2 + 1);
int j1 = (j + short1) * (short1 * 2 + 1) + k + 1;
System.out.println("Preparing spawn area for " + name + ", " + j1 * 100 / chunkcoordinates + "%");
i = l;
}
BlockPosition var27 = var26.getSpawn();
var26.chunkProviderServer.getChunkAt(var27.getX() + j >> 4, var27.getZ() + k >> 4);
}
}
}
this.pluginManager.callEvent(new WorldLoadEvent(var26.getWorld()));
return var26.getWorld();
}
}
Now by creating you own world loader, you can make it so it only generates a chunk every tick or so.

Related

Handler method is slow on new devices

I have a simple method running inside a handler. I am populating numbers using an array adapter. My code take more time to run on newer devices with Android 6 or higher, as oppose to old ones.
Here is part of my code, CCA is derived from ArrayAdapter:
numbersToRun = amount;
myHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (numbersToRun > 0) {
boolean isInt2 = IsIntegerOnly.isChecked();
if (isInt2) {
int n = Rnd.nextInt(max - min + 1) + min;
String Str = n + "";
RandomData.add(Str);
CCA.notifyDataSetChanged();
RandomsList.setSelection(CCA.getCount() - 1);
} else {
double d = min + (max - min) * Rnd.nextDouble();
String Str = String.format("%.4f", d) + "";
RandomData.add(Str);
CCA.notifyDataSetChanged();
RandomsList.setSelection(CCA.getCount() - 1);
}
numbersToRun--;
myHandler.postDelayed(this, new Double(interval*1000).longValue());
} else {
myHandler.removeCallbacksAndMessages(null);
}
}
}, 0);
Do I need to run garbage collection here?
What can I do in order to get good performance on stronger and newer devices?

Go to Page in epub reader (PageTurner)

I have to implement Go To Page feature in epub reader. I have try to implement this feature in source code of Page-Turner, but its not working successfully because of multiple xhtml in .epub file, as we know that each chapter have single xhtml file and its divide as per screen size in this app. So whenever screen size is big then total number of pages are less and more number of pages when screen is small, So there is no fix page number where to jump. I have edit and try to implement like giver below.
ReadingFragment.java
public void performSearch(String query) {
int index = Integer.parseInt(query);
if (index > bookView.getTotalNumberOfPages()) {
Toast.makeText(context, "Please enter number between 0 to " + bookView.getTotalNumberOfPages(), Toast.LENGTH_SHORT).show();
} else {
bookView.gotoPageNumber(index);
}
}
BookView.java
public void gotoPageNumber(int pageNum) {
strategy.gotoPage(pageNum);
progressUpdate();
}
PageChangeStrategy.java
public void gotoPage(int pageNumber);
FixedPagesStrategy.java
#Override
public void gotoPage(int pageNumber) {
PageTurnerSpine spinePos = bookView.getSpine();
this.storedPosition = -1;
int currentPage = getCurrentPage() + spinePos.getUptoPage(spinePos.getPosition());
Log.e(TAG, "Adding >> Upto Page : " + spinePos.getUptoPage(spinePos.getPosition())
+ ", currentPage : " + getCurrentPage());
Log.e(TAG, "pagenum : " + pageNum);
if (pageNumber > currentPage) { //pageNumber is greater then current page
int jumpSpine = spinePos.getIndexFromPage(pageNumber);
int currentSpine = spinePos.getPosition();
Log.e(TAG, "jumpSpine : " + jumpSpine + ", currentSpine : " + currentSpine);
if (jumpSpine == currentSpine) {
int diffrence = pageNumber - currentPage;
Log.e(TAG, "diffrence < : " + diffrence);
Log.e(TAG, "Minimum >> PageOffSets - 1 : " + (spinePos.getPageOffSets(currentSpine) - 1)
+ ", pageNum + diffrence : " + (pageNum + diffrence));
this.pageNum = Math.min(pageNum + diffrence, spinePos.getPageOffSets(currentSpine) - 1);
updatePosition();
} else {
PageTurnerSpine spine = bookView.getSpine();
if (spine == null || !spine.navigateFrontSpine(spine.getIndexFromPage(pageNumber))) {
return;
}
this.pageNum = 0;
gotoPage(pageNumber);
}
} else { //pageNumber is less then current page
int jumpSpine = spinePos.getIndexFromPage(pageNumber);
int currentSpine = spinePos.getPosition();
Log.e(TAG, "jumpSpine : " + jumpSpine + ", currentSpine : " + currentSpine);
if (jumpSpine == currentSpine) {
int diffrence = currentPage - pageNumber;
Log.e(TAG, "diffrence > : " + diffrence);
Log.e(TAG, "pagenum - diffrence : " + (pageNum - diffrence));
this.pageNum = Math.max(pageNum - diffrence, 0);
updatePosition();
} else {
PageTurnerSpine spine = bookView.getSpine();
if (spine == null || !spine.navigateBackSpine(spine.getIndexFromPage(pageNumber))) {
return;
}
this.pageNum = 0;
gotoPage(pageNumber);
}
}
Log.e(TAG, "In last pageNum : " + pageNum);
}
PageTurnerSpine.java
public int getIndexFromPage(int pageNumber) {
int total = 0;
int totalIndex = 0;
for (List<Integer> pagesPerSection : pageOffsets) {
total += pagesPerSection.size();
totalIndex = totalIndex + 1;
if (total - 1 >= pageNumber) {
return totalIndex - 1;
}
}
return 0;
}
public int getUptoPage(int position) {
int total = 0, max = 0;
for (List<Integer> pagesPerSection : pageOffsets) {
max = max + 1;
if (position == max - 1) {
return total;
}
total += pagesPerSection.size();
}
return 0;
}
public int getPageOffSets(int position) {
int max = 0;
for (List<Integer> pagesPerSection : pageOffsets) {
max = max + 1;
if (position == max - 1) {
return pagesPerSection.size();
}
}
return 0;
}
public boolean navigateFrontSpine(int indexSpine) {
if (this.position == size() - 1) {
return false;
}
this.position = indexSpine;
return true;
}
public boolean navigateBackSpine(int indexSpine) {
if (this.position == 0) {
return false;
}
this.position = indexSpine;
return true;
}
When i apply this code and run some time it work correctly. but some time it jump on other page number, like if i enter 110 then it will jump on 109. and when i am trying to jump on chapter starting page then contain dose not changes. Please help me.
https://github.com/NightWhistler/PageTurner
In this source code i have edited some file given above. they already exists in this project.
Mostly i see that most of epub reader like Kindle, FBReader, etc... does not implement Go To Page feature. So, i want to also know that is it possible to implement this feature or not?
Thanks for Help :)
You really need to consult the IDPF Epub standards at IDPF.org/epub .
One approach, that I think is optional within the standard (but am not sure about) is to mark the content with the physical page numbers from the paper book (if there is one), or decide on your own numbering system along with your Table of Contents, and use a corresponding virtual page as the start of it.
This enables going to the start of the same page, but the number of virtual pages per physical page will vary, depending on font sizes etc. currently in use.
It's a data issue as much as a programming one.

Setting band level in Equalizer not working

I am writing an app that plays 4 mp3 files simultaneously using 4 MediaPlayer objects. I have added 3 custom knobs to control bass, mid, and treble using 4 equalizers, each attached to its specific MediaPlayer. I have verified that I am passing the correct values (in Millibels) to setBandLevel for each as specified, but I don't hear any difference in sound when spinning the controls. I have added the relevant code below.
One thing I noticed that seems really odd is that the Equalizer method I am calling expects a short, but the frequency range upper limits come back as high as 6,000,000 millibels. I may be missing something here, but a short in android is 2^16 which should mean an upper limit of 64k.
public void setBandLevel(short band, short level)
The code runs without hitting exceptions and I have traces all values to verify each frequency is within its band's range, but I get no variance in sound when I spin the control knobs. I have tested this on K, L and M with the same results.
I appreciate any insight into this.
public void onResume() {
super.onResume();
// Load an ad into the AdMob banner view.
AdView adView = (AdView) getView().findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder()
.setRequestAgent("android_studio:ad_template").build();
adView.loadAd(adRequest);
//initialize views
initializeViews();
setInstrumentNames();
mediaPlayer1.start();
mediaPlayer2.start();
mediaPlayer3.start();
mediaPlayer4.start();
// Start the songtime thread and remember its object so it can be stopped legally
play();
setEqualizer();
setupKnobButtons();
}
public void setEqualizer() {
eq1 = new Equalizer(0, mediaPlayer1.getAudioSessionId());
eq2 = new Equalizer(0, mediaPlayer2.getAudioSessionId());
eq3 = new Equalizer(0, mediaPlayer3.getAudioSessionId());
eq4 = new Equalizer(0, mediaPlayer4.getAudioSessionId());
if (eq1 != null && eq2 != null && eq3 != null && eq4 != null) {
int z = eq1.setEnabled(true);
int c = eq2.setEnabled(true);
int d = eq3.setEnabled(true);
int e = eq4.setEnabled(true);
// The number of bands is usually 5 but could be up to 13
num_bands = eq1.getNumberOfBands();
// The band range will always return the min and max
// Gets the level range for use by setBandLevel(short,short)}. The level is expressed in
// milliBel. Return the band level range in an array of short integers. The first element is the lower
// limit of the range, the second element the upper limit.
// --- THIS IS FOR THE FULL RANGE OF ALL BANDS ---///
range = eq1.getBandLevelRange();
min_level = range[0];
max_level = range[1];
Log.d(TAG_BANDLEVELS, "min level = " + min_level + " max level = " + max_level);
// Loop through all the bands ( usually 5 ) and create 2 arrays
// ( one for lower limit of each band and one for the upper )
for (int i = 0; i < num_bands; i++) {
freq_range = eq1.getBandFreqRange((short) i);
freqRangeLowerLimit.add(freq_range[0]);
freqRangeUpperLimit.add(freq_range[1]);
Log.d(TAG_BANDLEVELS, "freqRangeLowerLimit = " + freq_range[0] +
" freqRangeUpperLimit = " + freq_range[1] + " band = " + i);
}
}
}
private void setBandLevels(int percentage, int new_level1, int new_level2, int nBand) {
if (eq1.hasControl()) {
eq1.setBandLevel((short) nBand, (short) new_level1);
}
else
Log.d(TAG_BANDLEVELS, "EQ 1 DOES NOT HAVE CONTROL");
if (eq2.hasControl()) {
eq2.setBandLevel((short) nBand, (short) new_level1);
}
else
Log.d(TAG_BANDLEVELS, "EQ 2 DOES NOT HAVE CONTROL");
if (eq3.hasControl()) {
eq3.setBandLevel((short) nBand, (short) new_level1);
}
else
Log.d(TAG_BANDLEVELS, "EQ 3 DOES NOT HAVE CONTROL");
if (eq4.hasControl()) {
eq4.setBandLevel((short) nBand, (short) new_level1);
}
else
Log.d(TAG_BANDLEVELS, "EQ 4 DOES NOT HAVE CONTROL");
// Mid and Treble use 2 bands (Mid = 2nd and 3rd Treble = 4th and 5th
if (nBand == PlayFragment.BAND_BASS || nBand == PlayFragment.BAND_TREBLE) {
try {
eq1.setBandLevel((short) (nBand+1), (short) new_level2);
eq2.setBandLevel((short) (nBand+1), (short) new_level2);
eq3.setBandLevel((short) (nBand+1), (short) new_level2);
eq4.setBandLevel((short) (nBand+1), (short) new_level2);
} catch (Throwable ex2) {
ex2.printStackTrace();
}
}
}
public void setupKnobButtons() {
RoundKnobButton rnbBass = (RoundKnobButton) getView().findViewById(R.id.btRoundBass);
rnbBass.SetListener(new RoundKnobButtonListener() {
TextView tvEQBass = (TextView) getView().findViewById(R.id.tvEQBass);
public void onStateChange(boolean newstate) {
Toast.makeText(getActivity(), "New state:" + newstate, Toast.LENGTH_SHORT).show();
}
public void onRotate(final int percentage) {
tvEQBass.post(new Runnable() {
public void run() {
tvEQBass.setText("\n" + percentage + "%\n");
// Bass only uses the first band
int lower1 = freqRangeLowerLimit.get(0);
int upper1 = freqRangeUpperLimit.get(0);
int new_level1 = lower1 + ((upper1 - lower1) * percentage/100);
// new_level1 /= 1000;
// int new_level1 = calc1/100;
int lower2 = freqRangeLowerLimit.get(1);
int upper2 = freqRangeUpperLimit.get(1);
int new_level2 = lower1 + ((upper2 - lower2) * percentage/100);
// new_level2 /= 1000;
// int new_level2 = calc2/100;
setBandLevels(percentage, new_level1, new_level2, BAND_BASS);
Log.d(TAG_BANDLEVELS, "Band = Bass " + "New Level1 = " + new_level1 + "New Level2 = " + new_level2 + " Percentage = " + percentage);
}
});
}
});

Multithreading in java - 4 threads that do the same automatically

I've written a program to scan for amicable numbers (a pair of 2 numbers that the sum of all devisors of one equals to the other) It works ok and I'll include the entire code below.
I tried to get it to run with several threads so I moved the code to a class called Breaker and my main looks as follows:
Breaker line1 = new Breaker("thread1");
Breaker line2 = new Breaker("thread2");
Breaker line3 = new Breaker("thread3");
Breaker line4 = new Breaker("thread4");
line1.scanRange(1L, 650000L);
line2.scanRange(650001L, 850000L);
line3.scanRange(850001L, 1000000L);
line4.scanRange(1000001L, 1200001L);
Now this does shorten the time noticably, but this is not a smart solution and the threads end each on very different times.
What I'm trying to do, is to automate the process so that a master thread that has the entire range, will fire up sections of short ranges (10000) from the master range, and when a thread ends, to fire up the next section in a new thread, until the entire master range is done.
I've tried understanding how to use synchronized, notify() and wait() but after several tries all ended with different errors and unwanted behaviour.
Here is Breaker.java:
import java.util.ArrayList;
public class Breaker implements Runnable{
Long from, to = null;
String name = null;
Thread t = new Thread(this);
public Breaker(String name){
this.name = name;
}
public void scanRange(Long from, Long to){
this.from = from;
this.to = to;
t.start();
}
#Override
public void run() {
this.scan();
}
private void scan() {
ArrayList<ArrayList<Long>> results = new ArrayList<ArrayList<Long>>();
Long startingTime = new Long(System.currentTimeMillis() / 1000L);
Long lastReport = new Long(startingTime);
System.out.println(startingTime + ": Starting number is: " + this.from);
for (Long i = this.from; i <= this.to; i++) {
if (((System.currentTimeMillis() / 1000L) - startingTime ) % 60 == 0 && (System.currentTimeMillis() / 1000L) != lastReport) {
System.out.println((System.currentTimeMillis() / 1000L) + ": " + this.name + " DOING NOW " + i.toString() + ".");
lastReport = (System.currentTimeMillis() / 1000L);
}
ArrayList<Long> a = new ArrayList<Long>();
a = getFriendPair(i);
if(a != null) {
results.add(a);
System.out.println(this.name + ": FOUND PAIR! " + a.toString());
}
}
System.out.println((System.currentTimeMillis() / 1000L) + ": " + this.name + " Done. Total pairs found: " + results.size() +
". Total working time: " + ((System.currentTimeMillis() / 1000L) - startingTime) + " seconds.");
}
/**
* Receives integer and returns an array of the integer and the number who is it's
* pair in case it has any. Else returns null.
* #param i
* #return
*/
private static ArrayList<Long> getFriendPair(Long i) {
Long possibleFriend = getAndSumAllDevisors(i);
if (possibleFriend.compareTo(i) <= 0) return null;
Long sumOfPossibleFriend = getAndSumAllDevisors(possibleFriend);
if(sumOfPossibleFriend.equals(i)) {
ArrayList<Long> pair = new ArrayList<Long>();
pair.add(i);
pair.add(possibleFriend);
return pair;
}
return null;
}
private static Long getAndSumAllDevisors(Long victim) {
Long sum = new Long(1);
Long i = 2L;
Long k = new Long(0);
while ((k = i * i) <= victim) {
if ((victim % i) == 0) {
sum += i;
if (k == victim) return sum;
sum += (victim / i);
}
i++;
}
return sum;
}
}
Consider ExecutorService, which is backed by a thread pool. You feed it tasks and they get shuffled off to worker threads as they become available:
http://www.vogella.com/articles/JavaConcurrency/article.html#threadpools
What you need is a "Fixed Thread Pool". See http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool%28int%29
I would go for a ExecutorService with a fixed thread pool size. Your master thread can either feed directly to the executor service or you can disconnect them via a BlockingQueue. The Java Doc of the blocking queue describes the producer-consumer pattern quite nicely.
I ended up taking none of the answers but rather Marko's comment and implemented my solution using a Fork/Join framework. It works and runs almost at twice the speed of the none optimized version.
My code looks now like so:
main file (runner)
public class runner {
private static Long START_NUM = 1L;
private static Long END_NUM = 10000000L;
public static void main(String[] args) {
Long preciseStartingTime = new Long(System.currentTimeMillis());
ForkJoinPool pool = new ForkJoinPool();
WorkManager worker = new WorkManager(START_NUM, END_NUM);
pool.invoke(worker);
System.out.println("precise time: " + (System.currentTimeMillis() - preciseStartingTime));
}
WorkManager
I've defined here 3 class variables. from and to are set from a constructor which is called from the main file. And threshold which is the maximum amount of numbers the program will assign a single thread to compute serially.
As you can see in the code, it will recursively make the range smaller until it is small enough to to compute directly, then it calls Breaker to start breaking.
import java.util.concurrent.RecursiveAction;
public class WorkManager extends RecursiveAction{
Long from, to;
Long threshold = 10000L;
public WorkManager(Long from, Long to) {
this.from = from;
this.to = to;
}
protected void computeDirectly(){
Breaker b = new Breaker(from, to);
b.scan();
}
#Override
protected void compute() {
if ((to - from) <= threshold){
System.out.println("New thread from " + from + " to " + to);
computeDirectly();
}
else{
Long split = (to - from) /2;
invokeAll(new WorkManager(from, from + split),
new WorkManager(from + split + 1L, to));
}
}
}
Breaker (is no longer an implementation of of Runnable)
public class Breaker{
Long from, to = null;
public Breaker(Long lFrom, Long lTo) {
this.from = lFrom;
this.to = lTo;
}
public void scan() {
ArrayList<ArrayList<Long>> results = new ArrayList<ArrayList<Long>>();
Long startingTime = new Long(System.currentTimeMillis() / 1000L);
for (Long i = this.from; i <= this.to; i++) {
ArrayList<Long> a = new ArrayList<Long>();
a = getFriendPair(i);
if(a != null) {
results.add(a);
System.out.println((System.currentTimeMillis() / 1000L) + ": FOUND PAIR! " + a.toString());
}
}
}
/**
* Receives integer and returns an array of the integer and the number who is it's
* pair in case it has any. Else returns null.
* #param i
* #return
*/
private static ArrayList<Long> getFriendPair(Long i) {
Long possibleFriend = getAndSumAllDevisors(i);
if (possibleFriend.compareTo(i) <= 0) return null;
Long sumOfPossibleFriend = getAndSumAllDevisors(possibleFriend);
if(sumOfPossibleFriend.equals(i)) {
ArrayList<Long> pair = new ArrayList<Long>();
pair.add(i);
pair.add(possibleFriend);
return pair;
}
return null;
}
private static Long getAndSumAllDevisors(Long victim) {
Long sum = new Long(1);
Long i = 2L;
Long k = new Long(0);
while ((k = i * i) <= victim) {
if ((victim % i) == 0) {
sum += i;
if (k == victim) return sum;
sum += (victim / i);
}
i++;
}
return sum;
}
}

Parallelize preorder tree

I want to modify or clone/transform items in a preorder sorted List of tree items in parallel. That is the list traversal starts at a random item in the list and denotes a subtree-traversal (depth, parent-pointer, descendantSize and angleStart/angleEnd is available for a radial view).
My code currently looks like:
items = ((AbsModel<SunburstContainer, SunburstItem>)model).listIterator(pHitItemIndex);
items.next();
for (int i = pHitItemIndex + 1; i < endIndex && items.hasNext(); i++) {
final SunburstItem oldChild = items.next();
final SunburstItem newChild = new SunburstItem(oldChild);
final float newStartAngle =
(oldChild.getAngleStart() - oldRoot.getAngleStart()) * angleFactor;
LOGWRAPPER.debug("angleStart: " + newStartAngle);
newChild.setAngleStart(newStartAngle);
float newEndAngle =
(oldChild.getAngleEnd() - oldChild.getAngleStart()) * angleFactor
+ newChild.getAngleStart();
LOGWRAPPER.debug("angleEnd: " + newEndAngle);
if (newEndAngle > PConstants.TWO_PI) {
newEndAngle = PConstants.TWO_PI;
}
newChild.setAngleEnd(newEndAngle);
newChild.setAngleCenter(newChild.getAngleStart()
+ ((newChild.getAngleEnd() - newChild.getAngleStart()) / 2f));
newChild.setIndexToParent(oldChild.getIndexToParent() - pHitItemIndex);
int newDepth = 0;
LOGWRAPPER.debug("child depth: " + oldChild.getDepth());
LOGWRAPPER
.debug("parent depth: " + model.getItem(oldChild.getIndexToParent()).getDepth());
final int parentDepth = model.getItem(oldChild.getIndexToParent()).getDepth();
if ((parentDepth + 1) != oldChild.getDepth()) {
newDepth = oldDepthMax + 2;
} else {
newDepth = newItems.get(newChild.getIndexToParent()).getDepth() + 1;
}
if (newDepth > depthMax) {
depthMax = newDepth;
}
LOGWRAPPER.debug("newDepth: " + newDepth);
newChild.setDepth(newDepth);
newChild.update(mMappingMode, mBuffer);
newItems.add(newChild);
}
I think about simply partitioning the (sub)list, that is [pHitItemIndex + 1, endIndex] into different parts and submit Callables to an ExecutorService. Currently the whole algorithm is executed in a Callable submitted to an ExecutorService, but I assume I can also simply submit partitions/Callables to the same ExecutorService. I wonder if I would gain any advantage of using actors for instance using Akka, or using the ForkJoin framework.
Sounds like a problem where Parallel Collections in Scala could help out.

Categories

Resources