As input I have a 2D array PointXY[][] clusters, which looks like this:
[[23.237633,53.78671], [69.15293,17.138134], [23.558687,45.70517]] . . .
[[47.851738,16.525734], [47.802097,16.689285], [47.946404,16.732542]]
[[47.89601,16.638218], [47.833263,16.478987], [47.88203,16.45793]]
[[47.75438,16.549816], [47.915512,16.506475], [47.768547,16.67624]]
.
.
.
So elements in array are of type PointXY[] defined like this:
public PointXY(float x, float y) {
this.x = x;
this.y = y;
}
what I would like to do is sort input clusters and write sorted to array PointXY[][] clustersSorted so that each PointXY (exept first row) in clusters gets compared to every value of first row.
In other words the elements from the blue set on picture below get compared to every value circled by red.
So I would like to compare each value from 2. Row onwards to every value in first row.
Comparing is done by calling Euclidian function.
public double euclidian(PointXY other) {
return Math.sqrt(Math.pow(this.x - other.x, 2)
+ Math.pow(this.y - other.y, 2));
}
Output should be of the same type 2D array but under each red circled point (which stays the same in the same place in output array) should be points from blue part that are closest (by euclidean distance) to the red circled value.
So it's a data structure for K-Means clustering, so that each cluster is a column (circled green) and the first point is a center (circled red) of cluster and all the other points (circled in yellow) in column are points assigned to center.
So the question is how to iterate over input array clusters, compare values as described, and write them into array clustersSorted.
I would like to calculate euclidean distance between each point in blue circled set with every value circled in red. And then sort them based on minimal euclidean distance. So in output array clustersSorted each point from blue circled set would be under closest point circled in red.
Create a temporary float/double array of size [n][(n-1) * n] where input matrix is of the size [n][n-1].
Compute the euclidean distances of all the points in the lower part of the matrix with all the points in the first row and store them at their respective positions in the temporary array.
Create a copy of each temporary sub-array.
Perform any sorting operation on the copy, preferably selection sort as you only need to sort the array partially until the lowest n-1 elements are found.
Finally, create a new output array of size [n][n-1], correspond the lowest euclidean distances to their points, and store the sorted (n-1) element groups of (n-1) points right below their closest reference points.
See another answer: Sorting a 2d array of objects by columns starting from the second row and transposing an array
Building sorted cluster. First row are the center points. Other points are grouped by the nearest center. In this case all points are grouped by the second center point:
PointXY[][] clusters = {
{new PointXY(23.237633, 53.78671),
new PointXY(69.15293, 17.138134),
new PointXY(23.558687, 45.70517)},
{new PointXY(47.851738, 16.525734),
new PointXY(47.802097, 16.689285),
new PointXY(47.946404, 16.732542)},
{new PointXY(47.89601, 16.638218),
new PointXY(47.833263, 16.478987),
new PointXY(47.88203, 16.45793)},
{new PointXY(47.75438, 16.549816),
new PointXY(47.915512, 16.506475),
new PointXY(47.768547, 16.67624)}};
// array of a center points
PointXY[] centers = clusters[0];
PointXY[][] clustersSorted = Arrays
// iterate over array of center points
.stream(centers)
// for each center point
.map(center -> Stream.of(center, Arrays
// iterate over array of clusters starting from the second row
.stream(clusters, 1, clusters.length)
// stream over the full array
.flatMap(Arrays::stream)
// filter nearest points to the current center point
.filter(point -> Arrays
// iterate over array of center points
.stream(centers)
// sort by euclidean distance from current point
.sorted(Comparator.comparingDouble(centerXY ->
Math.sqrt(Math.pow(centerXY.x - point.x, 2)
+ Math.pow(centerXY.y - point.y, 2))))
// find nearest center point to the current point
.findFirst()
// check this center point is the current center point
.get() == center)
// array of the nearest points to this center point
.toArray(PointXY[]::new))
// center point + array of its nearest points
.flatMap(element -> element instanceof PointXY ?
Stream.of((PointXY) element) :
Arrays.stream((PointXY[]) element))
// sorted cluster
.toArray(PointXY[]::new))
// sorted array of clusters
.toArray(PointXY[][]::new);
// output
Arrays.stream(clustersSorted).map(Arrays::toString).forEach(System.out::println);
[23.237633,53.78671]
[69.15293,17.138134, 47.851738,16.525734, 47.802097,16.689285, 47.946404,16.732542, 47.89601,16.638218, 47.833263,16.478987, 47.88203,16.45793, 47.75438,16.549816, 47.915512,16.506475, 47.768547,16.67624]
[23.558687,45.70517]
Class PointXY should look like this:
public static class PointXY {
double x, y;
public PointXY(double x, double y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return x + "," + y;
}
}
See another answer: Grouping all points starting from the second row by the nearest center point from the first row
To sort a 2d array of objects by columns, you can first transpose this array and sort each row, and then transpose it back. To sort a row of elements starting from the second one by the distance from the first one with a custom comparator - you can use Arrays.sort(T[],int,int,Comparator) method:
int m = 4;
int n = 3;
PointXY[][] clusters = {
{new PointXY(23.237633, 53.78671),
new PointXY(69.15293, 17.138134),
new PointXY(23.558687, 45.70517)},
{new PointXY(47.851738, 16.525734),
new PointXY(47.802097, 16.689285),
new PointXY(47.946404, 16.732542)},
{new PointXY(47.89601, 16.638218),
new PointXY(47.833263, 16.478987),
new PointXY(47.88203, 16.45793)},
{new PointXY(47.75438, 16.549816),
new PointXY(47.915512, 16.506475),
new PointXY(47.768547, 16.67624)}};
// transpose a matrix
PointXY[][] transposed = new PointXY[n][m];
IntStream.range(0, n).forEach(i ->
IntStream.range(0, m).forEach(j ->
transposed[i][j] = clusters[j][i]));
// sort each line starting from the second
// element by the distance from the first element
Arrays.stream(transposed).forEach(cluster ->
Arrays.sort(cluster, 1, cluster.length,
Comparator.comparingDouble(point ->
Math.sqrt(Math.pow(cluster[0].x - point.x, 2)
+ Math.pow(cluster[0].y - point.y, 2)))));
// transpose a matrix back
PointXY[][] clustersSorted = new PointXY[m][n];
IntStream.range(0, m).forEach(i ->
IntStream.range(0, n).forEach(j ->
clustersSorted[i][j] = transposed[j][i]));
// output
Arrays.stream(clustersSorted).map(Arrays::toString).forEach(System.out::println);
[23.237633,53.78671, 69.15293,17.138134, 23.558687,45.70517]
[47.75438,16.549816, 47.915512,16.506475, 47.768547,16.67624]
[47.89601,16.638218, 47.833263,16.478987, 47.946404,16.732542]
[47.851738,16.525734, 47.802097,16.689285, 47.88203,16.45793]
Class PointXY should look like this:
public class PointXY {
double x, y;
public PointXY(double x, double y) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return x + "," + y;
}
}
I'm using polygon on shape renderer and the problem is that the user should be able to add vertex whenever they want, basically the vertices are not set by me but by the user. What I did is whenever the user add a point, I add them to an arrayList.
ArrayList<Float> v = new ArrayList<Float>();
public void ontouch(screenX, screenY){
v.add(screenX);
v.add(screenY)
}
And then I have this problem when I try to render a polygon on a shapeRenderer
for(int i = 0; i < v.size; i++){
float[] vertices = new float[v.size()]
vertices[i - 1] = v.get(i - 1);
vertices[i] = v.get(i);
}
sr.polygon(v);
But I just get errors.
I am trying to achieve something like this, if you know a different way of doing this then that would be really helpful. By the way I'm also using box2d and this does not need to have collision it's just for the user visual.
The way I would personally do it is by having an LinkedList with Vector2 objects. Vector2 objects store two floats, so for every click, you get the x and y coordinates and make a new Vector2 object. By storing them in the LinkedList, you can retrieve the points at any time in the correct order so you can connect a line.
LinkedList<Vector2> v = new LinkedList<Vector2>();
public void ontouch(screenX, screenY){
v.add(new Vector2(screenX, screenY)); // add Vector2 into LinkedList
}
How you want to draw the lines or connect the points is up to you.
Another was is to just only keep the two most recent points that were clicked, and throw the others away. This would mean storing the lines instead of the points. If the lines are objects, then you can do this:
Vector2 previousPoint;
Vector2 currentPoint;
ArrayList<MyLineClass> lines = new ArrayList<MyLineClass>();
public void ontouch(screenX, screenY){
if(previousPoint == null){
previousPoint = new Vector2(screenX, screenY);
}else{
previousPoint = currentPoint;
currentPoint = new Vector2(screenX, screenY);
lines.add(new MyLineClass(currentPoint, previousPoint)
}
}
I wrote this off the cuff but I believe this example should work.
EDIT:
Good thing LibGDX is open source. If you want to use an array of float numbers, the method simply gets an x and y coordinate in alternating order. So for each index:
0 = x1
1 = y1
2 = x2
3 = y2
4 = x3
5 = y3
etc.
It's an odd method, but I suppose it works.
So i am using the Java Point3D object. I am wondering the best way to get X amount of points between two 3d points in space.
Point3D a = new Point3D(0, 0, 0);
Point3D b = new Point3D(1, 4, 9);
int count = 30 //Used to set how many points to represent the line
//This would return a list of points that represent the line
Point3D[] pointsBetween(a, b, count);
Would this be best achieved with vectors? I am also running this pretty heavily, so i am looking for the most efficient way to calculate this. Thanks!
Turns out it was vectors, Simply get a vector from point a to point b, then add in that direction (add divided by the amount of steps or count)
I need to convert a java.awt.geom.Area or java.awt.Shape to java.awt.Polygon. What I know about the are is: isSingular = true, isPolygonal = true. So I think a polygon shuld be able to describe the same area.
I'm not sure that it is worth converting, because Polygon is an old Java 1.0 class that can store only integer coordinates, so you might lose some precision.
Anyway, you can get a PathIterator from the Shape, and as you iterate it, add new points to a Polygon:
public static void main(String[] args) {
Area a = new Area(new Rectangle(1, 1, 5, 5));
PathIterator iterator = a.getPathIterator(null);
float[] floats = new float[6];
Polygon polygon = new Polygon();
while (!iterator.isDone()) {
int type = iterator.currentSegment(floats);
int x = (int) floats[0];
int y = (int) floats[1];
if(type != PathIterator.SEG_CLOSE) {
polygon.addPoint(x, y);
System.out.println("adding x = " + x + ", y = " + y);
}
iterator.next();
}
}
EDIT As Bill Lin commented, this code may give you a wrong polygon if the PathIterator describes multiple subpaths (for example in the case of an Area with holes). In order to take this into account, you also need to check for PathIterator.MOVETO segments, and possibly create a list of polygons.
In order to decide which polygons are holes, you could calculate the bounding box (Shape.getBounds2D()), and check which bounding box contains the other. Note that the getBounds2D API says that "there is no guarantee that the returned Rectangle2D is the smallest bounding box that encloses the Shape, only that the Shape lies entirely within the indicated Rectangle2D", but in my experience for polygonal shapes it would be the smallest, and anyway it is trivial to calculate the exact bounding box of a polygon (just find the smallest and biggest x and y coordinates).
I have a school assignment where I'm supposed to (among other things) rotate a polygon. I can not use any premade rotate functions, so I have an array of points. The array is set up like this:
intArray[2][amount_of_points] where intArray[0] equals the points x coordinate, and intArray[1] holds the y coordinates.
//x=pivot point x coordinate, y = pivot point y coordinate.
public int[][] rotate(int[][]matrix,int x, int y, double degrees){
double s=Math.sin(degrees);
double c=Math.cos(degrees);
for (int i=0;i<matrix.length;i++){
//translate to origin
int px=matrix[0][i]-x;
int py=matrix[1][i]-y;
//rotate
double xnew = (px*c)-(py*s);
double ynew = (px*s)+(py*c);
//translate back
px=(int)((xnew+x)+0.5);
py=(int)((ynew+y)+0.5);
matrix[0][i]=px;
matrix[1][i]=py;
}
This is my code so far, and it is definitely not working out for me. I tried to trim the code as much as I could. Any help would mean a lot!
edit: I'm not getting any errors when I run the code, no exceptions etc. The only problem is that the polygon isn't rotating the way I intend it to.
I've made a test polygon:
polyArray = new int [2][3];
polyArray[0][0]=400;
polyArray[1][0]=200;
polyArray[0][1]=300;
polyArray[1][1]=500;
polyArray[0][2]=500;
polyArray[1][2]=500;
Which I draw in a JPanel, then I run this array through the rotation method like this:
polyArray=mm.rotate(polyArray, polyArray[0][0], polyArray[1][0], Math.PI);
Using the top point as pivotpoint. The whole polygon is then deformed.
Although still not very clear on question, I feel your problem is with the loop.
matrix.length is 2. So, the code never uses these :
polyArray[0][2]=500;
polyArray[1][2]=500;
If you change the condition as below, it should work :
for (int i=0;i<matrix[0].length;i++)