How to make polygon from > 100 000 points? - java

I'm trying to make Polygons from my file (x, y, z).
I have a lot of lines so I don't know how many records should be in every Polygon.
I think that I should do it when I'm loading file:
while (file.hasNextDouble()) {
a = br.nextDouble();
b = br.nextInt();
c = br.nextInt();
vertices.add(new Vertice(a, b, c));
}
Please, tell me how should I fix that loading code. Could you tell me how can I add e.g. every third record (a, b, c) to a new Polygon?

To make a polygon every 3 vertices.
I didn't test it, but that's the idea:
int i = 0;
int polySize = 3;
List<Polygon> polyList = new List<Polygon>();
Polygon poly = new Polygon();
while (file.hasNextDouble()) {
a = br.nextDouble();
b = br.nextInt();
c = br.nextInt();
vertice = new Vertice(a, b, c);
poly.add(vertice);
if (i == polySize-1)
{
polyList.add(poly);
poly = new Polygon();
i = 0;
}
i++;
}
Hope it helps...

Related

Trouble understanding Vectors, my object gets stuck after a few iterations

Im trying to write a class that draws a square shape with 4 vertexes. I want each vertex to have its own velocity and path for each iteration in the drawloop. It seems to work for a few iterations until it gets "stuck" and Im having trouble understanding why that is. Any help or information regarding this is helpful, I suspect I dont have a full grasp of using vectors properly.Heres an image of when the code is running.
void draw() {
p.display();
//Stop loop setting
if (loop == 0) {
noLoop();
}
}
//----------------------------------------------------------------//
class Pillar
{
PVector v1Velocity,v2Velocity,v3Velocity,v4Velocity,
v1Pos,v2Pos,v3Pos,v4Pos,
v1End,v2End,v3End,v4End,
v1Acceleration,v2Acceleration,v3Acceleration,v4Acceleration,
origin;
float life,scale,randDegrees1,randDegrees2,randDegrees3,randDegrees4,maxVelocity;
Pillar (float _x, float _y, float _scale) {
scale = _scale; // scale of pillar
origin = new PVector(_x,_y); //pillar point of origin
v1Pos = new PVector(origin.x-(scale*1.5),origin.y); //vertex 1 start left
v2Pos = new PVector(origin.x,origin.y-scale); //vertex 2 start top
v3Pos = new PVector(origin.x+(scale*1.5),origin.y); //vertex 3 start right
v4Pos = new PVector(origin.x,origin.y+scale); //vertex 4 start bottom
v1End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
v2End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
v3End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
v4End = new PVector(origin.x+random(50,200),origin.y-random(50,200));
randDegrees1 = random(360);
randDegrees2 = random(360);
randDegrees3 = random(360);
randDegrees4 = random(360);//Fixa denna.
v1Velocity = new PVector(cos(radians(randDegrees1)),sin(radians(randDegrees1)));
v2Velocity = new PVector(cos(radians(randDegrees2)),sin(radians(randDegrees2)));
v3Velocity = new PVector(cos(radians(randDegrees3)),sin(radians(randDegrees3)));
v4Velocity = new PVector(cos(radians(randDegrees4)),sin(radians(randDegrees4)));
maxVelocity = 5;
life = 100;
}
void calculateVector() {
v1Acceleration = PVector.sub(v1End,v1Pos);
v1Velocity.add(v1Acceleration);
v2Acceleration = PVector.sub(v2End,v2Pos);
v2Velocity.add(v2Acceleration);
v3Acceleration = PVector.sub(v3End,v3Pos);
v3Velocity.add(v3Acceleration);
v4Acceleration = PVector.sub(v4End,v4Pos);
v4Velocity.add(v4Acceleration);
v1Acceleration.setMag(life);
v2Acceleration.setMag(life);
v3Acceleration.setMag(life);
v4Acceleration.setMag(life);
v1Velocity.limit(maxVelocity);
v2Velocity.limit(maxVelocity);
v3Velocity.limit(maxVelocity);
v4Velocity.limit(maxVelocity);
v1Pos.add(v1Velocity);
v2Pos.add(v2Velocity);
v3Pos.add(v3Velocity);
v4Pos.add(v4Velocity);
life -= 1;
}
void display () {
beginShape();
stroke(0,0,0,50);
vertex(v1Pos.x,v1Pos.y);
vertex(v2Pos.x,v2Pos.y);
vertex(v3Pos.x,v3Pos.y);
vertex(v4Pos.x,v4Pos.y);
endShape(CLOSE);
calculateVector();
}
}

Catmull Rom Spline implementation (LibGDX)

I want to generate a random spline across my screen.
Here is what I have so far:
public class CurvedPath {
Random rn;
CatmullRomSpline<Vector2> curve;
float[] xPts;
float[] yPts;
Vector2[] points;
public CurvedPath(){
points = new Vector2[10];
rn = new Random();
curve = new CatmullRomSpline<Vector2>(points,false);
for(int i = 0 ; i < 10; i++){
xPts[i] = rn.nextFloat()*SampleGame.WIDTH;
yPts[i] = SampleGame.HEIGHT*i/10;
}
}
}
I'm pretty confused on the documentation that has been provided on how to use the CatmullRomSpline object ( https://github.com/libgdx/libgdx/wiki/Path-interface-&-Splines )
Basically what I am trying to do here is generate 10 random points equally distributed across the height of my screen, and randomly placed along the width of the screen to create a randomized curved path.
So within the constructor's for loop you can see that I generate the x and y values of each control point for the spline.
How can I give input these points into the spline object and render it on the screen?
-thanks
update
Let me reword my question to be a little more specific..
I have my control points represented by xPts and yPts. Now I want to get the points that fall along the spline, how do I do this using these two vectors? The constructor for a CatmullRomSpline takes a Vector2, not two float[] 's
what you did. Fill with points:
curve = new CatmullRomSpline<Vector2>(points,false);
To get a point on the curve:
Vector2 point = new Vector2();
curve.valueAt(point, 0.5f);
valueAt() Parameter explanation:
1 (point) the point you are looking for is stored in the Vector2 object.
float between 0 and 1, 0 is the first point, 1 the last one. 0.5f is middle. This float represents the hole distance from first to last point.
Getting and render 100 points can look like this:
Vector2 point = new Vector2();
for (int i = 0; i <= 100; i++) {
curve.valueAt(point, i * 0.01f);
// draw using point.x and point.y
}
answer to you edited question:
for(int i = 0 ; i < 10; i++){
points[i].x = rn.nextFloat()*SampleGame.WIDTH;
points[i].y = SampleGame.HEIGHT*i/10;
}
curve = new CatmullRomSpline<Vector2>(points,false);
The process is also detailed here: https://github.com/libgdx/libgdx/wiki/Path-interface-&-Splines
/*members*/
int k = 100; //increase k for more fidelity to the spline
Vector2[] points = new Vector2[k];
/*init()*/
CatmullRomSpline<Vector2> myCatmull = new CatmullRomSpline<Vector2>(dataSet, true);
for(int i = 0; i < k; ++i)
{
points[i] = new Vector2();
myCatmull.valueAt(points[i], ((float)i)/((float)k-1));
}

Out of bounds but it shouldn't

public class Ctrl {
Graph g = new Graph();
Edge[] edges = new Edge[g.getM()];
int[] verteY = new int[g.getM()];
int[] verteX = new int[g.getM()];
int[] vCost = new int[g.getM()];
int contor=0;
public void add(int x,int y,int c) {
System.out.println("contor:" + this.contor);
System.out.println("M:" + g.getM());
verteX[this.contor] = x;
verteY[this.contor] = y;
vCost[this.contor] = c;
this.contor = this.contor + 1;
}
and the output is
contor:0
M:5
why do I get java.lang.ArrayIndexOutOfBoundsException: 0 then?
It seems likely that a newly-initalized Graph's getM() returns zero, making all four arrays zero-size.
If g.getM() later changes, the arrays don't automatically get resized.
My recommendation would be to use ArrayList instead of raw arrays. This would make it easy to append to them.

Collision Response method

Hi I try to implement a simple Sphere collision detection algorithm as explained here: http://wp.freya.no/3d-math-and-physics/simple-sphere-sphere-collision-detection-and-collision-response/
So I implement the method to check if Collision occurs:
private boolean advancedSphereSphere(Sphere a, Sphere b) {
Vector2D s = a.getPos().sub(b.getPos());
Vector2D v = a.getVelocity().sub(b.getVelocity());
float r = a.getRadius() + b.getRadius();
double c1 = s.dot(s) - r*r;
if(c1 < 0.0) {
timeToCollision = .0f;
return true;
}
double a1 = v.dot(v);
if(a1 < 0.00001f) {
return false;
}
double b1 = v.dot(s);
if(b1 >= 0.0) {
return false;
}
double d1 = b1*b1 - a1*c1;
if(d1 < 0.0) {
return false;
}
timeToCollision = (float) (-b1 - Math.sqrt(d1) / a1);
return true;
}
Then I have a onDraw method that loops to draw all necessary elements, like this:
protected void onDraw(Canvas canvas) {
flowPhysics(false);
for(Sphere s : mSpheres) {
s.draw(canvas);
}
invalidate();
}
and the problem occurs in flowPhysics(boolean) method, at this line:
for(int i=0; i < mSpheres.size(); ++i) {
for(int j=i+1; j < mSpheres.size(); ++j) {
Sphere a = mSpheres.get(i);
Sphere b = mSpheres.get(j);
if(advancedSphereSphere(a, b) || step) {
if(timeToCollision < dt && !step) {
flowPhysics(true);
}
if(step) {
sphereCollisionResponse(a, b);
}
}
}
}
When the advancedSphereSphere() is called, the first Sphere disappears, I checked and noticed that the problem is in that method at the first line:
Vector2D s = a.getPos().sub(b.getPos());
if I put something else here and don't subtract the b from a vectors, it draws the balls (but no collision occurs). The Java code above is mostly ported code from here: http://wp.freya.no/websvn/filedetails.php?repname=Public&path=%2Fopengl%2Fcollisiondetect%2Fcollisiondetect.cpp
Can u give me an idea on what is the problem?
Thanks
UPDATE
private void sphereCollisionResponse(Sphere a, Sphere b)
{
double m1, m2, x1, x2;
Vector2D v1, v2, v1x, v2x, v1y, v2y;
Vector2D x = new Vector2D(a.getPos().sub(b.getPos()));
x.normalize();
v1 = new Vector2D(a.getVelocity());
x1 = x.dot(v1);
v1x = new Vector2D(x.multiply(x1));
v1y = new Vector2D(v1.sub(v1x));
m1 = a.getMass();
x = new Vector2D(x.multiply(-1));
v2 = new Vector2D(b.getVelocity());
x2 = x.dot(v2);
v2x = new Vector2D(x.multiply(x2));
v2y = new Vector2D(v2.sub(v2x));
m2 = b.getMass();
Vector2D nn = new Vector2D(v1x.multiply(m1-m2));
Vector2D mm = new Vector2D(nn.divide(m1+m2));
Vector2D tt = new Vector2D(v2x.multiply(2*m2));
Vector2D rr = new Vector2D(tt.divide(m1+m2));
Vector2D gg = new Vector2D(mm.add(rr));
Vector2D ss = new Vector2D(gg.add(v1y));
Vector2D nva = ss;
a.setVelocity(nva);
Vector2D nvb = new Vector2D(v1x.multiply(2*m1).divide(m1+m2).add(v2x.multiply(m2-m2).divide(m1+m2).add(v2y)));
b.setVelocity(nvb);
}
If the problem is really in this line
Vector2D s = a.getPos().sub(b.getPos());
then I suspect the problem may lie in your Vector2D class. You should check that the sub method just returns a new Vector2D and does not modify the coordinates of the original vector a. Keeping your objects immutable as far as possible makes them safer to use.
Failing that, the answer is unit testing. Learning to use JUnit or TestNG will pay off in the long run, but even a few ad-hoc print statements might help you for now. You should be able to check the mathematics is correct independent of how the spheres appear on your screen, and doing this consistently will probably guide you towards a clearer design.
Just by testing that the position of each sphere is unchanged after the collision, and that the velocities are as expected in a few simple cases, you are quite likely to discover the bug in your code. For example, if both velocities are zero beforehand then they should be zero afterwards. If the collision is elastic and one sphere (A) collides head-on with another stationary sphere (B), sphere A should be stationary afterwards and sphere B should have the velocity that A started with.
I haven't checked the maths in your code at http://pastie.org/2499691 but when I set up a few simple classes to fill the dependencies and give it some reasonable starting conditions, it doesn't conserve momentum, so I can believe for some values the balls could end up flying off the screen at the speed of light.
Once you have the physics right, you can work on any remaining problems with the display of the spheres secure in the knowledge that the problem must indeed lie there.

How to avoid overlapping polygon

I created a program to draw many polygons automatically everytimes user presses a button. The points of the polygon are generated automatically using the random function. The problem is that, since the points of the polygon were randomly generated, some of the polygon are overlap with other polygon. How can I avoid this, so that every polygon shown without being overlapped?
.....
List<Polygon> triangles = new LinkedList<Polygon>();
Random generator = new Random();
public void paintComponent(Graphics g) {
for(int i = 0; i < 10; i++) {
double xWidth = generator.nextDouble() * 40.0 + 10.0;
double yHeight = generator.nextDouble() * 40.0 + 10.0;
xCoord[0] = generator.nextInt(MAX_WIDTH);
yCoord[0] = generator.nextInt(MAX_HEIGHT);
xCoord[1] = (int) (xCoord[0] - xWidth);
xCoord[2] = (int) (xCoord[1] + (xWidth/2));
yCoord[1] = yCoord[0];
yCoord[2] = (int) (yCoord[1] - yHeight);
triangles.add( new Polygon(xCoord,yCoord, 3));
}
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1));
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.00f));
g2.setPaint(Color.black);//set the polygon line
for (Polygon triangle : triangles) g2.drawPolygon(triangle);
Polygon[] triArray = triangles.toArray(new Polygon[triangles.size()]);
for (Polygon p:triArray) triangles.remove (p);
}
Check out the game programming wiki on Polygon Collision:
http://gpwiki.org/index.php/Polygon_Collision
You could break your canvas into 10 regions and constrain your polygons each to their own region. To do this, you could use your i value and a %100 (or other suitable magnitude) of your randomly generated value and apply them to your x coordinates and y coordinates as applicable. The result would be a grid of similarly constrained(no larger than the grid cell), but randomly shaped, Polygons.
EDIT:
Taking another look and fooling around a bit, I took the general concept as I described above and made a stab at an implementation:
public void paintComponent(Graphics g) {
int[] xCoord = new int[3];
int[] yCoord = new int[3];
int colCnt = 5;
int rowCnt = 2;
int maxCellWidth = getWidth() / colCnt;
int maxCellHeight = getHeight() / rowCnt;
for (int i = 0; i < (colCnt * rowCnt); i++) {
int xMultiple = i % colCnt;
int yMultiple = i / colCnt;
for (int j = 0; j < 3; j++) {
xCoord[j] = generator.nextInt(maxCellWidth)
+ (maxCellWidth * xMultiple);
yCoord[j] = generator.nextInt(maxCellHeight)
+ (maxCellHeight * yMultiple);
}
triangles.add(new Polygon(xCoord, yCoord, 3));
}
//... the rest of your method
}
As you can see, all of the Polygons have all points randomly generated, as opposed to your method of generating the first point and then making the rest relative to the first. There is a sense of randomness that is lost, however, as the Polygons are laid out in a grid-like pattern.
Create Area objects from your new polygon as well as for all existing polygons.
Subtract the new polygon's area from the existing ones. If the subtract changed the area, the polygons overlap.
Area newArea = new Area(newPolygon);
Area existingArea = new Area(existingPolygon);
Area existingAreaSub = new Area(existingPolygon); existingAreaSub.subtract(newArea);
boolean intersects = existingAreaSub.equals(existingArea);
You could implement a method Polycon.containsPoint( x, y ) and repeat your random generation until this method returns false for all drawn Polygons.
I have achieved this in Android Using Kotlin (See github project) by using JTS see here
Step-1:
Add JTS library to your project
implementation group: 'org.locationtech.jts', name: 'jts-core', version: '1.15.0'
Step-2:
Create JTS polygon objects for both polygon
// create polygons One
var polygoneOneArray: ArrayList<Coordinate> = ArrayList()
for (points in polygonOnePointsList) {
polygoneOneArray.add(Coordinate(points.latitude(), points.longitude()))
}
val polygonOne: org.locationtech.jts.geom.Polygon = GeometryFactory().createPolygon(
polygoneOneArray.toTypedArray()
)
// create polygons Two
var polygoneTwoArray: ArrayList<Coordinate> = ArrayList()
for (points in polygoneTwoPointsList) {
polygoneTwoArray.add(Coordinate(points.latitude(), points.longitude()))
}
val polygonTwo: org.locationtech.jts.geom.Polygon = GeometryFactory().createPolygon(
polygoneTwo.toTypedArray()
)
Step-3:
Get Common Area of both Polygon
val intersection: org.locationtech.jts.geom.Geometry = polygonOne.intersection(polygonTwo)
Step-4:
Remove common Area from polygonTwo
val difference: org.locationtech.jts.geom.Geometry = polygonTwo.difference(intersection)
Step-5:
Merge Both polygonOne and update polygonTwo
val union: org.locationtech.jts.geom.Geometry = mergePolygonList.get(0).polygons.union(difference)
Step-5:
Now pick points from Geometry and draw a final merged Polygon
val array: ArrayList<Coordinate> = union.coordinates.toList() as ArrayList<Coordinate>
val pointList: ArrayList<Point> = ArrayList()
for (item in array) {
pointList.add(Point.fromLngLat(item.y, item.x))
}
var list: ArrayList<List<Point>> = ArrayList<List<Point>>()
list.add(pointList)
style.addSource(
GeoJsonSource(
"source-id${timeStamp}",
Feature.fromGeometry(Polygon.fromLngLats(list))
)
)

Categories