Detecting closest element in array - java

I'm having issues detecting the closest element in an array of blocks to the player (using circles).
What I have so far is:
public static int closestBarrier(GameObject object, GameObject[] barriers) {
int closest = -1;
float minDistSq = Float.MAX_VALUE;// ridiculously large value to start
for (int i = 0; i < barriers.length; i++) {
float barrierRadius = barriers[i].getWidth() / 2;
float objectRadius = object.getWidth() / 2;
GameObject curr = barriers[i];// current
float dx = (object.getX()) - ((curr.getX()));
float dy = (object.getY()) - ((curr.getY()));
float distSq = (((dx * dx + dy * dy) - objectRadius) - barrierRadius) ;// use the squared distance
if (distSq < minDistSq) {// find the smallest and remember the id
minDistSq = distSq;
closest = i;
}
}
return closest;
}
It passes most of the tests but on the final one the returned index of the closest one is 2 instead of the expected 3. Here are the tests (it is failing 'closest to fourth' :
public final void testClosestBarrier() {
// Closest to first
GameObject player = new GameObject(0,1);
player.setWidth(2);
GameObject[] barriers = new GameObject[4];
barriers[0] = new GameObject(8,9);
barriers[0].setWidth(3);
barriers[1] = new GameObject(10,15);
barriers[1].setWidth(2);
barriers[2] = new GameObject(15,20);
barriers[2].setWidth(5);
barriers[3] = new GameObject(100,210);
barriers[3].setWidth(10);
assertEquals("Player closest to first barrier",0,
Submission.closestBarrier(player,barriers));
// Closest to second
player.setX(12);
player.setY(12);
assertEquals("Player closest to second barrier",1,
Submission.closestBarrier(player,barriers));
// Closest to third
player.setX(12);
player.setY(20);
assertEquals("Player closest to third barrier",2,
Submission.closestBarrier(player,barriers));
// Closest to fourth
player.setX(90);
player.setY(100);
assertEquals("Player closest to fourth barrier",3,
Submission.closestBarrier(player,barriers));
}

Your code is correct and the test you have written is wrong - barrier 2 is closer to 90,100 than barrier 3.
barrier 2:
(90-15)^2 + (100-20)^2
12025
barrier 3:
(100-90)^2 + (210-100)^2
12200
12025 < 12200 -> barrier 2 is closer
EDIT: In your edited answer, you forgot to square objectRadius and barrierRadius. e.g.
float distSq = (((dx * dx + dy * dy) - objectRadius) - barrierRadius)
In this line, you have dx^2, dy^2 but only non-squared objectRadius and barrierRadius.

Related

Detect collision with lines and limit movement

I'm making a game with libGDX in Java. I'm trying to make a collision detection. As you can see in the image, I have a line which is a wall and a player with specified radius. The desired position is the next location which the player is trying to be in. But because there is a wall, he's placed in the Actual Position which is on the Velocity vector, but more closer to the prev location. I'm trying to figure out how can I detect that closer position?
My attempt:
private void move(float deltaTime) {
float step;
beginMovementAltitude();
if (playerComponent.isWalking())
step = handleAcceleration(playerComponent.getSpeed() + playerComponent.getAcceleration());
else step = handleDeacceleration(playerComponent.getSpeed(), playerComponent.getAcceleration());
playerComponent.setSpeed(step);
if (step == 0) return;
takeStep(deltaTime, step, 0);
}
private void takeStep(float deltaTime, float step, int rotate) {
Vector3 position = playerComponent.getCamera().position;
float x = position.x;
float y = position.y;
int radius = playerComponent.getRadius();
auxEnvelope.init(x, x + radius, y, y + radius);
List<Line> nearbyLines = lines.query(auxEnvelope);
float theta;
int numberOfIntersections = 0;
float angleToMove = 0;
Gdx.app.log(step + "", "");
for (Line line : nearbyLines) {
VertexElement src = line.getSrc();
VertexElement dst = line.getDst();
auxVector3.set(playerComponent.getCamera().direction);
auxVector3.rotate(Vector3.Z, rotate);
float nextX = x + (step * deltaTime) * (auxVector3.x);
float nextY = y + (step * deltaTime) * playerComponent.getCamera().direction.y;
float dis = Intersector.distanceLinePoint(src.getX(), src.getY(), dst.getX(), dst.getY(), nextX, nextY);
boolean bodyIntersection = dis <= 0.5f;
auxVector21.set(src.getX(), src.getY());
auxVector22.set(dst.getX(), dst.getY());
auxVector23.set(nextX, nextY);
if (bodyIntersection) {
numberOfIntersections++;
if (numberOfIntersections > 1) {
return;
}
theta = auxVector22.sub(auxVector21).nor().angle();
float angle = (float) (180.0 / MathUtils.PI * MathUtils.atan2(auxVector23.y - position.y, auxVector23.x - position.x));
if (angle < 0) angle += 360;
float diff = (theta > angle) ? theta - angle : angle - theta;
if (step < 0) step *=-1;
angleToMove = (diff > 90) ? theta + 180 : theta;
}
}
if (numberOfIntersections == 0) {
moveCameraByWalking(deltaTime, step, rotate);
} else {
moveCameraInDirection(deltaTime, step, angleToMove);
}
}
The idea is to find intersection of path of object center and the line moved by radius of the circle, see that picture.
At first, you need to find a normal to the line. How to do it, depends on how the line is defined, if it's defined by two points, the formula is
nx = ay - by
ny = bx - ax
If the line is defined by canonical equation, then coefficients at x and y define normal, if I remembered correctly.
When normal is found, we need to normalize it - set length to 1 by dividing coordinates by vector length. Let it be n.
Then, we will project starting point, desired point and randomly chosen point on line to n, treating them as radius vectors.
Projection of vector a to vector b is
project (a, b) = scalar_product (a, b) / length (b)**2 * b
but since b is n which length equals 1, we will not apply division, and also we want to only find length of the result, we do not multiply by b. So we only compute scalar product with n for each of three aforementioned points, getting three numbers, let s be the result for starting point, d for desired point, l for chosen point on the line.
Then we should modify l by radius of the circle:
if (s < d) l -= r;
else if (s > d) l += r;
If s = d, your object moves in parallel along the line, so line can't obstruct its movement. It's highly improbable case but should be dealt with.
Also, that's important, if l was initially between s and d but after modifying is no longer between then, it's a special case you may want to handle (restrict object movement for example)
Ather that, you should compute (d - s) / (l - s).
If the result is greater or equals 1, the object will not reach the line.
If the result is between 0 and 1, the line obstructs movement and the result indicates part of the path the object will complete. 0.5 means that object will stop halfway.
If the result is negative, it means the line is behind the object and will not obstruct movement.
Note that when using floating point numbers the result will not be perfectly precise, that's why we handle that special case. If you want to prevent this from happening at all, organize loop and try approximations until needed precision is reached.

Diamond Square improper implementation

Hello Stack Community,
I thought long and hard about posting this seeing as I did not want to attract yet another "duplicate" thread. However I have run out of ideas and do not know of any forums or other stacks where I could post this to get some help.
I wrote this application as a fun project in an attempt to generate some height-maps. However whenever I try to generate more than one height-map at a time all my duplicates appear as either black voids or if the MAP_SIZE variable is low enough white voids. (Example, 16 && 33 create white voids, 1025 creates black)
My output folder appears as follows: low value vrs higher value
Why is this? Is it simply a mathematical fluke that I am missing at 3:15 am?
I wrote the printMap specifically for the function of checking the values of the map data and while they are within ranges that would designate them to be black/white. I see no reason for this to exist continuously after the first iteration.
Just for fun I printed 44 more maps, and after the first one they all were black, MAP_SIZE was set at 1025. Feel free to check this out yourselves.
I created my diamond square algorithm based off my readings from here: http://www.gameprogrammer.com/fractal.html#heightmaps
And my greyWriteImage from a older stack overflow thread about simplex noise maps.
EDIT
Thanks to I was able to solve my problem, turns out it was just a simple fact that for each new map you attempted to create using the populateMap function I forgot to reset avgOffset to 1. Essentially the problem was you were dividing the avgOffset continuously by 2 getting smaller and smaller results, which always which would always be cast a certain way.
Below I have included my completed source code for anyone who would like to work with my algorithm and output. Have fun.
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import java.util.concurrent.ThreadLocalRandom;
public class generateHeightMap {
// https://stackoverflow.com/questions/43179809/diamond-square-improper-implementation
private static final Random RAND = new Random();
// Size of map to generate, must be a value of (2^n+1), ie. 33, 65, 129
// 257,1025 are fun values
private static final int MAP_SIZE = 1025;
// initial seed for corners of map
private static final double SEED = ThreadLocalRandom.current().nextInt(0, 1 + 1);
// average offset of data between points
private static double avgOffSetInit = 1;
private static final String PATH = "C:\\Users\\bcm27\\Desktop\\grayScale_export";
private static String fileName = "\\grayscale_map00.PNG";
public generateHeightMap(int howManyMaps) {
System.out.printf("Seed: %s\nMap Size: %s\nAverage Offset: %s\n",
SEED, MAP_SIZE, avgOffSetInit);
System.out.println("-------------------------------------------");
for(int i = 1; i <= howManyMaps; i++){ // how many maps to generate
double[][] map = populateMap(new double[MAP_SIZE][MAP_SIZE]);
//printMap(map);
generateHeightMap.greyWriteImage(map);
fileName = "\\grayscale_map0" + i + ".PNG";
System.out.println("Output: " + PATH + fileName);
}
}
/*************************************************************************************
* #param requires a 2d map array of 0-1 values, and a valid file path
* #post creates a image file saved to path + file_name
************************************************************************************/
private static void greyWriteImage(double[][] data) {
BufferedImage image =
new BufferedImage(data.length, data[0].length, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < data[0].length; y++)
{
for (int x = 0; x < data.length; x++)
{// for each element in the data
if (data[x][y]>1){
// tells the image whether its white
data[x][y]=1;
}
if (data[x][y]<0){
// tells the image whether its black
data[x][y]=0;
}
Color col = // RBG colors
new Color((float)data[x][y],
(float)data[x][y],
(float)data[x][y]);
// sets the image pixel color equal to the RGB value
image.setRGB(x, y, col.getRGB());
}
}
try {
// retrieve image
File outputfile = new File( PATH + fileName);
outputfile.createNewFile();
ImageIO.write(image, "png", outputfile);
} catch (IOException e) {
throw new RuntimeException("I didn't handle this very well. ERROR:\n" + e);
}
}
/****************************************************************************
* #param requires map double[MAPSIZE][MAPSIZE]
* #return returns populated map
*
* [1] Taking a square of four points, generate a random value at the square
* midpoint, where the two diagonals meet. The midpoint value is calcul-
* ated by averaging the four corner values, plus a random amount. This
* gives you diamonds when you have multiple squares arranged in a grid.
*
* [2] Taking each diamond of four points, generate a random value at the
* center of the diamond. Calculate the midpoint value by averaging the
* corner values, plus a random amount generated in the same range as
* used for the diamond step. This gives you squares again.
*
* '*' equals a new value
* '=' equals a old value
*
* * - - - * = - - - = = - * - = = - = - = = * = * =
* - - - - - - - - - - - - - - - - * - * - * = * = *
* - - - - - - - * - - * - = - * = - = - = = * = * =
* - - - - - - - - - - - - - - - - * - * - * = * = *
* * - - - * = - - - = = - * - = = - = - = = * = * =
* A B C D E
*
* A: Seed corners
* B: Randomized center value
* C: Diamond step
* D: Repeated square step
* E: Inner diamond step
*
* Rinse and repeat C->D->E until data map is filled
*
***************************************************************************/
private static double[][] populateMap(double[][] map) {
// assures us we have a fresh map each time
double avgOffSet = avgOffSetInit;
// assigns the corners of the map values to SEED
map[0][0] =
map[0][MAP_SIZE-1] =
map[MAP_SIZE-1][0] =
map[MAP_SIZE-1][MAP_SIZE-1] = SEED;
// square and diamond loop start
for(int sideLength = MAP_SIZE-1; sideLength >= 2; sideLength /=2,avgOffSet/= 2.0) {
int halfSide = sideLength / 2;
double avgOfPoints;
/********************************************************************
* [1] SQUARE FRACTAL [1]
*********************************************************************/
// loops through x & y values of the height map
for(int x = 0; x < MAP_SIZE-1; x += sideLength) {
for(int y = 0; y <MAP_SIZE-1; y += sideLength) {
avgOfPoints = map[x][y] + //top left point
map[x + sideLength][y] + //top right point
map[x][y + sideLength] + //lower left point
map[x + sideLength][y + sideLength];//lower right point
// average of surrounding points
avgOfPoints /= 4.0;
// random value of 2*offset subtracted
// by offset for range of +/- the average
map[x+halfSide][y+halfSide] = avgOfPoints +
(RAND.nextDouble()*2*avgOffSet) - avgOffSet;
}
}
/********************************************************************
* [2] DIAMOND FRACTAL [2]
*********************************************************************/
for(int x=0; x < MAP_SIZE-1; x += halfSide) {
for(int y = (x + halfSide) % sideLength; y < MAP_SIZE-1;
y += sideLength) {
avgOfPoints =
map[(x - halfSide + MAP_SIZE) % MAP_SIZE][y] +//left of center
map[(x + halfSide) % MAP_SIZE][y] + //right of center
map[x][(y + halfSide) % MAP_SIZE] + //below center
map[x][(y - halfSide + MAP_SIZE) % MAP_SIZE]; //above center
// average of surrounding values
avgOfPoints /= 4.0;
// in range of +/- offset
avgOfPoints += (RAND.nextDouble()*2*avgOffSet) - avgOffSet;
//update value for center of diamond
map[x][y] = avgOfPoints;
// comment out for non wrapping values
if(x == 0) map[MAP_SIZE-1][y] = avgOfPoints;
if(y == 0) map[x][MAP_SIZE-1] = avgOfPoints;
} // end y
} // end x
} // end of diamond
return map;
} // end of populateMap
/*************************************************************************************
* #param requires a 2d map array to print the values of at +/-0.00
************************************************************************************/
#SuppressWarnings("unused")
private static void printMap(double[][] map) {
System.out.println("---------------------------------------------");
for (int x = 0; x < map.length; x++) {
for (int y = 0; y < map[x].length; y++) {
System.out.printf("%+.2f ", map[x][y] );
}
System.out.println();
}
}
} // end of class
Is it possible that avgOffSet must be initialized before creating each map (start of populateMap)?
It is being divided by 2 but never reset to 1. I suppose each map is independent, that is, does not depend on the previous one, so there is no reason to not reset the variable. But I do not know that algorithm and have no time to learn it... [:-|
private static double[][] populateMap(double[][] map) {
avgOffSet = 1; // missing this one
map[0][0] = ...
if this is correct I would suggest that avgOffset should be a variable; eventually create a field avgOffsetInitial with the initial value (instead of the current field).

move across the same distance of a curve at increasing speeds

I have an object that I am trying to get to move in a smooth "arc". The x value of the object does not actually change, but the y value does.
The y value starts at -108, and needs to get to -37.5. Every iteration I want it to move the same distance in a shorter time. The issue is that it needs to decelerate and stop at -37.5 (this would be for half of the motion). When the current code runs the time stays the same, the distance increases. this does work for the first iteration.
This is what I have:
private void jump() {
int startV = 10;
float yVal;
float velocity;
int airTime = 1;
float currY = -108;
Main main = New Main();
// main.iter is the iteration
velocity = startV * (1 + (main.iter / 10));
while (airtime != 0) {
yVal = yVal + velocity;
velocity = velocity - (1 + (main.iter / 10));
if (currY < yVal) {
airtime++;
}
else {
airtime--;
}
}
yVal = -108;
}
EDIT:
main.iter is an int that increments by one

Most efficient way to find distance between two circles in java?

So apparently calculating square roots is not very efficient, which leaves me wondering what the best way is to find out the distance (which I've called range below) between two circles is?
So normally I would work out:
a^2 + b^2 = c^2
dy^2 + dx^2 = h^2
dy^2 + dx^2 = (r1 + r2 + range)^2
(dy^2 + dx^2)^0.5 = r1 + r2 + range
range = (dy^2 + dx^2)^0.5 - r1 - r2
Trying to avoid the square root works fine when you just look for the situation when "range" is 0 for collisions:
if ( (r1 + r2 + 0 )^2 > (dy^2 + dx^2) )
But if I'm trying to work out that range distance, I end up with some unwieldy equation like:
range(range + 2r1 + 2r2) = dy^2 + dx^2 - (r1^2 + r2^2 + 2r1r2)
which isn't going anywhere. At least I don't know how to solve it for range from here...
The obvious answer then is trignometry and first find theta:
Tan(theta) = dy/dx
theta = dy/dx * Tan^-1
Then the find the hypotemuse
Sin(theta) = dy/h
h = dy/Sin(theta)
Finally work out the range
range + r1 + r2 = dy/Sin(theta)
range = dy/Sin(theta) - r1 - r2
So that's what I've done and have got a method that looks like this:
private int findRangeToTarget(ShipEntity ship, CircularEntity target){
//get the relevant locations
double shipX = ship.getX();
double shipY = ship.getY();
double targetX = target.getX();
double targetY = target.getY();
int shipRadius = ship.getRadius();
int targetRadius = target.getRadius();
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.atan( ( dY / dX ) );
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
// finally range between ship/target is:
int range = (int) (hypotemuse - shipRadius - targetRadius);
return range;
}
So my question is, is using tan and sin more efficient than finding a square root?
I might be able to refactor some of my code to get the theta value from another method (where I have to work it out) would that be worth doing?
Or is there another way altogether?
Please excuse me if I'm asking the obvious, or making any elementary mistakes, it's been a long time since I've used high school maths to do anything...
Any tips or advice welcome!
****EDIT****
Specifically I'm trying to create a "scanner" device in a game that detects when enemies/obstacles are approaching/ going away etc. The scanner will relay this information via an audio tone or a graphical bar or something. Therefore although I don't need exact numbers, ideally I would like to know:
target is closer/further than before
target A is closer/further than target B, C, D...
A (linear hopefully?) ratio that expresses how far a target is from the ship relative to 0 (collision) and max range (some constant)
some targets will be very large (planets?) so I need to take radius into account
I'm hopeful that there is some clever optimisation/approximation possible (dx + dy + (longer of dx, dy?), but with all these requirements, maybe not...
Math.hypot is designed to get faster, more accurate calculations of the form sqrt(x^2 + y^2). So this should be just
return Math.hypot(x1 - x2, y1 - y2) - r1 - r2;
I can't imagine any code that would be simpler than this, nor faster.
If you really need the accurate distance, then you can't really avoid the square root. Trigonometric functions are at least as bad as square root calculations, if not worse.
But if you need only approximate distances, or if you need only relative distances for various combinations of circles, then there are definitely things you can do. For example, if you need only relative distances, note that squared numbers have the same greater-than relationship as do their square roots. If you're only comparing different pairs, skip the square root step and you'll get the same answer.
If you only need approximate distances, then you might consider that h is roughly equal to the longer adjacent side. This approximation is never off by more than a factor of two. Or you could use lookup tables for the trigonometric functions -- which are more practical than lookup tables for arbitrary square roots.
I tired working out whether firstly the answers when we use tan, sine is same as when we use sqrt functions.
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
double shipX = 5;
double shipY = 5;
double targetX = 1;
double targetY = 1;
int shipRadius = 2;
int targetRadius = 1;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
System.out.println(hypotemuse);
// finally range between ship/target is:
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
hypotemuse = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
System.out.println(hypotemuse);
range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
}
The answer which i got was :
4.700885452542996
1.7008854
5.656854249492381
2.6568542
Now there seems a difference between the value with sqrt ones being more correct.
talking abt the performance :
Consider your code snippet :
i calculated the time of performance- which comes out as:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
long lStartTime = new Date().getTime(); //start time
double shipX = 555;
double shipY = 555;
double targetX = 11;
double targetY = 11;
int shipRadius = 26;
int targetRadius = 3;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = dY / Math.sin(theta);
System.out.println(hypotemuse);
// finally range between ship/target is:
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
long lEndTime = new Date().getTime(); //end time
long difference = lEndTime - lStartTime; //check different
System.out.println("Elapsed milliseconds: " + difference);
}
Answer - 639.3204215458475,
610.32043,
Elapsed milliseconds: 2
And when we try out with sqrt root one:
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
long lStartTime = new Date().getTime(); //start time
double shipX = 555;
double shipY = 555;
double targetX = 11;
double targetY = 11;
int shipRadius = 26;
int targetRadius = 3;
//get the difference in locations:
double dX = shipX - targetX;
double dY = shipY - targetY;
// find angle
double theta = Math.toDegrees(Math.atan( ( dY / dX ) ));
// find length of line ship centre - target centre
double hypotemuse = Math.sqrt(Math.pow(dX,2) + Math.pow(dY,2));
System.out.println(hypotemuse);
float range = (float) (hypotemuse - shipRadius - targetRadius);
System.out.println(range);
long lEndTime = new Date().getTime(); //end time
long difference = lEndTime - lStartTime; //check different
System.out.println("Elapsed milliseconds: " + difference);
}
Answer -
769.3321779309637,
740.33215,
Elapsed milliseconds: 1
Now if we check for the difference the difference between the two answer is also huge.
hence i would say that if you making a game more accurate the data would be more fun it shall be for the user.
The problem usually brought up with sqrt in "hard" geometry software is not its performance, but the loss of precision that comes with it. In your case, sqrt fits the bill nicely.
If you find that sqrt really brings performance penalties - you know, optimize only when needed - you can try with a linear approximation.
f(x) ~ f(X0) + f'(x0) * (x - x0)
sqrt(x) ~ sqrt(x0) + 1/(2*sqrt(x0)) * (x - x0)
So, you compute a lookup table (LUT) for sqrt and, given x, uses the nearest x0. Of course, that limits your possible ranges, when you should fallback to regular computing. Now, some code.
class MyMath{
private static double[] lut;
private static final LUT_SIZE = 101;
static {
lut = new double[LUT_SIZE];
for (int i=0; i < LUT_SIZE; i++){
lut[i] = Math.sqrt(i);
}
}
public static double sqrt(final double x){
int i = Math.round(x);
if (i < 0)
throw new ArithmeticException("Invalid argument for sqrt: x < 0");
else if (i >= LUT_SIZE)
return Math.sqrt(x);
else
return lut[i] + 1.0/(2*lut[i]) * (x - i);
}
}
(I didn't test this code, please forgive and correct any errors)
Also, after writing this all, probably there is already some approximate, efficient, alternative Math library out there. You should look for it, but only if you find that performance is really necessary.

Divide a 2D path created from points XY into equal chunks Java

I have an array of points A,B,C,D,E...N which when connected make a path.
How can i divide this path to equal chunks and get position of each chunk XY ?
EDIT : As user Hedja suggested i have created function to process this problem, but i cannot detect situation where chunk is splitted on two subpaths
public ArrayList<PointF> getPositions(ArrayList<PointF> mInput,float mChunkSize){
ArrayList<PointF> mResult = new ArrayList<PointF>();
float mModulo = 0f;
for (int i = 0;i<mInput.size()-1;i++){
//distance to next
float mDistanceAB = MyGameMath.distance(mInput.get(i).x, mInput.get(i).y,mInput.get(i+1).x,mInput.get(i+1).y);
//how many parts will fit
float mCountParts = (float) (mDistanceAB/mChunkSize); //how much parts will fit
//if distance is greater than chunk size
if (Math.abs(mDistanceAB)>=mChunkSize) {
Log.i("Chunk","Index "+(i)+" -> "+(i+1)+" = "+mCountParts+", rest="+mModulo);
float dx = mInput.get(i+1).x-mInput.get(i).x;
float dy = mInput.get(i+1).y-mInput.get(i).y;
float ux = dx/mDistanceAB;
float uy = dy/mDistanceAB;
for (int y=0;y<=mCountParts;y++){
//for every part
float nx = mInput.get(i).x+ux*mChunkSize*y;
float ny = mInput.get(i).y+uy*mChunkSize*y;
//Log.i("Chunk","at:"+nx+","+ny);
mResult.add(new PointF(nx, ny));
}
}
mModulo = mDistanceAB%mChunkSize; //how much left from previous subpath
}
return mResult;
}
So I assume you have something similar to this where Point is an object with attributes x and y.
Point[] points = new Points[]{ //Your Points }
List<Point> chunkedPoints = new ArrayList<Point>();
I also assume by "equal chunks" you mean the distance of each path.
First you'll iterate through the array, as you won't need to calculate the "next point" after the last point, you can add it at the end.:
for(int i = 0; i < points.length-1; i++) { //Skip the last element
//chunking here
}
chunkedPoints.add(points[points.length-1]); //Add the last element
You'll need to find the Unit Vector, that is, the direction you travel to get to the next point. So first you need to get the difference in x and y from one point and the next:
double dx = point[i].x - point[i+1].x;
double dy = point[i].y - point[i+1].y;
Then the distance from that point to the next (simple Pythagoras):
double distance = Math.sqrt(dx*dx+dy*dy);
The unit vector can now be calculated
double ux = dx/distance;
double uy = dy/distance;
So now you know where to travel, you need to specify how far you want to travel along it, I'll call this CHUNK_SIZE.
double nx = point[i].x + ux*CHUNK_SIZE;
double ny = point[i].y + uy*CHUNK_SIZE;
nx and ny is the co-ordinate of your new point. However, you need to check if you've passed the next point so that you can stop. Your problem doesn't specify what you do when you reach an end of a subpath without travelling the chunk size so I'll assume you simply stop at it, so the code becomes:
double nx = point[i].x;
double ny = point[i].y;
for(
//This part can be tidier
int count = 0;
count < CHUNK_SIZE && nx+ux != points[i+1].x && ny+uy != points[i+1].y;
count++
) {
nx += ux;
ny += uy;
}
Point newPoint = new Point(nx, ny);
Now you have your new Point, you can start from there, aim for the same point as before or if it's the same as the next point, start from the point after that. So your loop is now something like
chunkedPoints.add(points[0]);
for(int i = 0; i < points.length-1; i++) { //Skip the last element
Point newPoint;
do {
//chunking
newPoint = new Point(nx, ny);
chunkedPoints.add(newPoint);
} while(!newPoint.equals(points[i+1]));
}
chunkedPoints.add(points[points.length-1]); //Add the last element
Hope that helped.
I haven't tested this, but I've done something very similar in the past, so it should work.
EDIT: Okay, I've seen your edit and honestly have no idea what your question is asking. Sorry.

Categories

Resources