I'm making an ellipsoid out of voxels, and I have an implementation, but it's not working correctly, for the past few hours I've been trying things with no success.
Here's how it works:
It draws 2D ellipses down the Z axis using the Bresenham circle algorithm
It calculates the coordinates of a circle going forward and one going side to side
It uses those coordinates as radii for X and Y
Here's what works:
Spheres are perfect
Ellipsoids are perfect when
z > x and z > y
x == y
Here's what doesn't:
Ellipsoids when x != y
Example when y > x http://postimage.org/image/gslvykrgd/
The same thing happens when x > y only flipped
I'm guessing its because I'm drawing the slices from center to front every time, but I don't know. Below is my implementation, it's a mess. I quickly cleaned it up a bit so it's understandable to some degree. Also I'm saving optimisations for later, I just want it working now.
I won't show my implementation of the circle algorithm itself, because I KNOW that it works and it would just make this question longer. So I'll explain the two functions for it instead.
private List<Integer> getSlice(int rx, int ry) gets the raw result from a run of the Bresenham circle algorithm, no symmetry needed. It returns the result as a list of the x, y results in that order.
public void generateEllipse(int z, int cx, int cy, int cz, int rx, int ry) generates an ellipse with the given information and plots down the coordinates using symmetry, these will be rendered on the screen.
ArrayList<Integer> s = getSlice(rz, rx);
ArrayList<Integer> s2 = getSlice(rz, ry);
int cap = Math.max(s2.size(), s.size());
while (s.size() > 1)
{
int x = 0;
int z = 0;
int z2 = 0;
int y2 = 0;
int i = cap - 2;
if (s.size() > i)
{
z = s.get(i);
x = s.get(i + 1);
s.remove(i + 1);
s.remove(i);
}
if (s2.size() > i)
{
z2 = s2.get(i);
y2 = s2.get(i + 1);
s2.remove(i + 1);
s2.remove(i);
}
if (x != 0 && y2 != 0)
generateEllipse(z, cx, cy, cz, x, y2);
cap = Math.max(s2.size(), s.size());
I asked a similar question a week or two back (yeah I've been having problems for that long :() and got an answer, I implemented it and it worked, but I wasn't satisfied, I want to avoid floating point numbers all together. See 3D Ellipsoid out of discrete units.
With that I was having problems with rounding off the numbers and getting uneven slices, so spheres were impossible. Ironically, now spheres are the only thing possible (other than front to back ellipses).
EDIT:
I got x > y working by adding
else if (y2 < x && ry - y2 != 0)
generateEllipse(z, cx, cy, cz, x, ry - y2);
and || r - y2 == 0 to the first test at the bottom.
I'm not too sure why that worked, I'm figuring that out now. But I'm still having problems with y > x. Anyone?
EDIT2:
Now that I look at it, it's different than the y = x ellipsoid, back to the drawing board.
EDIT3:
Last night I was thinking about this and I think I've figured it out, this isn't an answer to my own question, but I guess pointing out what I'm seeing to be wrong. I'm testing for the first list and drawing coordinates decrementally from the size of the largest list.
That's badness because the two lists aren't guaranteed equal lengths, that's a failure on my part for trying to rush an algorithm.
In the picture, you can't see, but the little ellipse is actually a few blocks away from the big ellipse. This is caused when from ellipses not being drawn, which is caused by lists not having data. The actual little ellipse big ellipse is caused because the algorithm draws two octants, both of which are stored into the list from getSlice(...).
So how can I fix this problem? I haven't implemented anything yet and probably won't for a while (it's early) but this is what my brain cranked out. Again, this is not an answer to the question, just thoughts.
I iterate for while(!s.isEmpty()) and define two new values outside the loop: incX = s.size and incY = s1.size I test to see if their z values match, if not, then I correct it. I'm thinking I'll get the values, test the largest list and if they don't match then decrement the inc value of the smallest list by two and get the old values.
I test for !s.isEmpty() because the two lists will be empty at the same time. Also drawing ellipses, I'll use whichever one z value, because, again, they both should be equal.
If that's wrong, then I guess I have this document I found to go through: http://www.cs.sunysb.edu/vislab/wordpress/pdf/398.pdf.
Thank you for anyone who viewed this (even though I didn't get any replies :(), I'm setting this answer because the problem is solved, the code is as follows:
ArrayList<Integer> s = getSlice(rz, rx);
ArrayList<Integer> s2 = getSlice(rz, ry);
boolean yMax = Math.max(s2.size(), s.size()) == s2.size();
int decX = s.size() - 1;
int decY = s2.size() - 1;
boolean done = false;
while (!done)
{
int x = 0;
int z = 0;
int z2 = 0;
int y = 0;
y = s2.get(decY--);
z2 = s2.get(decY--);
x = s.get(decX--);
z = s.get(decX--);
if (z != z2)
{
if (yMax)
{
decX += 2;
x = s.get(decX);
s2.remove(decY + 2);
s2.remove(decY + 1);
}
else
{
decY += 2;
y = s2.get(decY);
s.remove(decX + 2);
s.remove(decX + 1);
}
z = z < z2 ? z : z2;
}
else
{
s.remove(decX + 2);
s.remove(decX + 1);
s2.remove(decY + 2);
s2.remove(decY + 1);
}
if (y != 0 && x != 0)
generateEllipse(z, cx, cy, cz, x, y);
done = yMax ? s2.isEmpty() : s.isEmpty();
}
All that needs to be done now is optimisation. I'm still going to read that paper, it covers other topics that are interesting and useful for my program :).
The issue was that I was not accounting for the different sizes of each list, if a curve is less steep than the other it will have more coordinates. Z will always be the same when rx == ry. This allowed me to draw spheres and forward to back ellipsoids.
When they are not the same the z will change because the curve will be faster / slower. When this happened while I was testing for the first list it would ignore those because iteration would stop before it got to them.
The big ellipse, little ellipse was caused because they were drawn backwards, so the outer octant was drawn first which happens to have less total values.
In the near future I will put up a much more detailed answer and a much more elegant implementation. I'm just putting up this answer to let any passersby know that the problem is resolved. I want no one to ever go through the frustration I did trying to figure this whole thing out! It's amazing how the most difficult problems are caused by the silliest things.
Related
I am currently trying to put together an algorithm where I can know if there is an obstruction between two defined points in a plane.
Here is an example image.
We can see with the image that point 1, 2, 3, & 6 are all accessible from the origin point. Points 4 and 5 are not. You pass through the polygon.
The code I am using is the following. pStartPoint and pEndPoint is the line from the origin to the point in question. The function checks all edges to see if the line passes through the edge.
public double GetSlopeOfLine(Point a, Point b){
double x = b.y - a.y;
double y = b.x - a.x;
return (x / y);
}
public double GetOffsetOfLine(double x, double y, double slope){
return (y - (slope * x));
}
public boolean IsPointAccessable(Point pStartPoint, Point pEndPoint){
//Define the equation of the line for these points. Once we have slope and offset the equation is
//y = slope * x + offset;
double slopeOfLine = GetSlopeOfLine(pStartPoint, pEndPoint);
double offSet = GetOffsetOfLine(pStartPoint.x, pStartPoint.y, slopeOfLine);
//Collision detection for each side of each obstacle. Once we get the point of collision, does it lie on the
//line in between the two points? If so, collision, and I can't reach that point yet.
for (Iterator<Obstacles> ObstacleIt = AdjustedObstaclesList.iterator(); ObstacleIt.hasNext();) {
Obstacles pObstacle = ObstacleIt.next();
int NumberOfEdges = pObstacle.getPoints().size();
for(int i=0; i<NumberOfEdges; i++){
//Get Edge[i];
int index = i;
Point pFirstPoint = (Point)pObstacle.getPoints().get(index);
if(i >= NumberOfEdges - 1)
index = 0;
else
index = i+1;
Point pNextPoint = (Point)pObstacle.getPoints().get(index);
double slopeOfEdge = GetSlopeOfLine(pFirstPoint, pNextPoint);
double offsetEdge = GetOffsetOfLine(pNextPoint.x, pNextPoint.y, slopeOfEdge);
int x = Math.round((float) ((-offSet + offsetEdge) / (slopeOfLine - slopeOfEdge)));
int y = Math.round((float) ((slopeOfLine * x) + offSet));
//If it lies on either point I could be looking at two adjacent points. I can still reach that point.
if(x > pStartPoint.x && x < pEndPoint.x && y > pStartPoint.y && y < pEndPoint.y &&
x > pFirstPoint.x && x < pNextPoint.x && y > pFirstPoint.y && y < pNextPoint.y){
return false;
}
}
}
return true;
}
If the line passes through and the point where the lines cross is found between pStartPoint and pEndPoint I am assuming that pEndPoint cannot be reached.
This function is not working and I am wondering if it has something to do with the fact that the origin is not at the bottom left but at the top left and that (width, height) of my window is located in the bottom right. Therefore the coordinate plane is messed up.
My mind must be mush because I cannot think how to adjust for this and if that is truly my mistake as I cannot seem to fix the error. I thought adjusting the slope and offset by multiplying each by -1 might have been the solution but that doesn't seem to work.
Is my solution the right one? Does my code seem correct in checking for an intersect point? Is there a better solution to see if a point is accessible.
There is also going to be the next step after this where once I determine what points are accessible if I am now on one of the points of the polygon. For example, from point 1 what points are accessible without crossing into the polygon?
First, I would like to say that using slopes for this kind of task is do-able, but also difficult due to the fact that they are very volatile in the sense that they can go from negative infinity to infinity with a very small change in the point. Here's a slightly different algorithm, which relies on angles rather than slopes. Another advantage of using this is that the coordinate systems don't really matter here. It goes like this (I reused as much of your existing code as I could):
public boolean IsPointAccessable(Point pStartPoint, Point pEndPoint) {
//Collision detection for each side of each obstacle. Once we get the point of collision, does it lie on the
//line in between the two points? If so, collision, and I can't reach that point yet.
for (Iterator<Obstacles> ObstacleIt = AdjustedObstaclesList.iterator(); ObstacleIt.hasNext();) {
Obstacles pObstacle = ObstacleIt.next();
int NumberOfEdges = pObstacle.getPoints().size();
for(int i=0; i<NumberOfEdges; i++){
//Get Edge[i];
int index = i;
Point pFirstPoint = (Point)pObstacle.getPoints().get(index);
if(i >= NumberOfEdges - 1)
index = 0;
else
index = i+1;
Point pNextPoint = (Point)pObstacle.getPoints().get(index);
// Here is where we get a bunch of angles that encode in them important info on
// the problem we are trying to solve.
double angleWithStart = getAngle(pNextPoint, pFirstPoint, pStartPoint);
double angleWithEnd = getAngle(pNextPoint, pFirstPoint, pEndPoint);
double angleWithFirst = getAngle(pStartPoint, pEndPoint, pFirstPoint);
double angleWithNext = getAngle(pStartPoint, pEndPoint, pNextPoint);
// We have accumulated all the necessary angles, now we must decide what they mean.
// If the 'start' and 'end' angles are different signs, then the first and next points
// between them. However, for a point to be inaccessible, it also must be the case that
// the 'first' and 'next' angles are opposite sides, as then the start and end points
// Are between them so a blocking occurs. We check for that here using a creative approach
// This is a creative way of checking if two numbers are different signs.
if (angleWithStart * angleWithEnd <= 0 && angleWithFirst * angleWithNext <= 0) {
return false;
}
}
}
return true;
}
Now, all that is left to do is find a method that calculates the signed angle formed by three points. A quick google search yielded this method (from this SO question):
private double getAngle(Point previous, Point center, Point next) {
return Math.toDegrees(Math.atan2(center.x - next.x, center.y - next.y)-
Math.atan2(previous.x- center.x,previous.y- center.y));
}
Now, this method should work in theory (I am testing to be sure and will edit my answer if I find any issues with signs of angles or something like that). I hope you get the idea and that my comments explain the code well enough, but please leave a comment/question if you want me to elaborate further. If you don't understand the algorithm itself, I recommend getting a piece of paper out and following the algorithm to see what exactly is going on. Hope this helps!
EDIT: To hopefully aid in better understanding the solution using angles, I drew a picture with the four base cases of how the start, end, first, and next could be oriented, and have attached it to this question. Sorry for the sloppiness, I drew it rather quickly, but this should in theory make the idea clearer.
If you have a low segment count (for instance, your example only shows 12 segments for three shapes, two shapes of which we know we can ignore (because of bounding box checks), then I would recommend simply performing line/line intersection checking.
Point s = your selected point;
ArrayList<Point> points = polygon.getPoints();
ArrayList<Edge> edges = polygon.getEdges();
for(Point p: points) {
Line l = new Line(s, p);
for(Edge e: edges) {
Point i = e.intersects(l);
if (i != null) {
System.out.println("collision", i.toString());
}
}
}
With an intersects method that is pretty straight forward:
Point intersects(Line l) {
// boring variable aliassing:
double x1 = this.p1.x,
y1 = this.p1.y,
x2 = this.p2.x,
y2 = this.p2.y,
x3 = l.p1.x,
y2 = l.p1.y,
x3 = l.p2.x,
y2 = l.p2.y,
// actual line intersection algebra:
nx = (x1 * y2 - y1 * x2) * (x3 - x4) -
(x1 - x2) * (x3 * y4 - y3 * x4),
ny = (x1 * y2 - y1 * x2) * (y3 - y4) -
(y1 - y2) * (x3 * y4 - y3 * x4),
d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (d == 0) return null;
return new Point(nx/d, ny/d);
}
For a Minecraft project, I wanted to make the player face (0, 60, 0) gradually. So far, everything I have tried seems to fail when the player moves more than 720° around (0, 60, 0).
Anyone have an idea on how to make the camera move seamlessly to (0, 60, 0)?
Thank you!
Here is my code so far (that runs in a loop when toggled):
int x = 0;
int y = 60;
int z = 0;
player = Minecraft.getMinecraft().thePlayer;
double dirx = player.posX - 0;
double diry = player.posY - 60;
double dirz = player.posZ - 0;
double len = Math.sqrt(dirx*dirx + diry*diry + dirz*dirz);
dirx /= len;
diry /= len;
dirz /= len;
double pitch = Math.asin(diry);
double yaw = Math.atan2(dirz, dirx);
//to degree
pitch = pitch * 180.0 / Math.PI;
yaw = yaw * 180.0 / Math.PI;
yaw += 90f;
if(yaw > player.rotationYaw) {
player.rotationYaw++;
} else if(yaw < player.rotationYaw) {
player.rotationYaw--;
}
This code without the if statement works properly. The yaw and pitch variables are in degrees.
What I am having trouble with is the fact that whenever I turn around (0, 60, 0) for a few times, the screen suddenly does a 360° turn, for no apparent reason.
This is a common problem. Or rather, the problem that people have commonly is they want to do "something across time" and don't know how to make it go "across time."
You need to lerp the camera a small distance each tick until the desired direction is achieved. You either need to:
a) create an event handler and subscribe to one of the TickEvents (pick an appropriate one, and then make sure to pick a phase, either Phase.START or Phase.END, or your code will run multiple times a frame).
b) in whatever method your code is already in (Note: this code must already be called once a tick) and do the lerping there.
Don't know how to calculate lerp? Stack Overflow already has that answered.
I am working on a sample project in Java, specifically Android, with OpenGL ES 2.0. I am looking to create a terrain for a player to move across. The player needs to move up and down the terrains hieght following the heightmap. The terrain is not flat. I am using Blender to create the terrain and heightmap. The terrain is being imported as an obj file.
The import and the drawing is working fine but i am having issues making the coordinates follow the heightmap. It doesn't seem to follow it 100%. The player moves up or down too soon every so often or he drops below the terrain.
What I Have So Far:
1)What I am doing is importing the OBJ file into project. Reading the farthest point from terrain object and using this as the object length ( this value * 2 ). This tells me how many vertices are in the object along one side.
2)I then get the difference in the players position to terrain origin in world coordinates. I take the x and z values and divide each by the OBJ object length*2 to give the region of the terrain the object is in. This will give me the percentage of where the x and z position the player is in reference to the terrain.
3) I open the heightmap and multiply the percentages above to the image of the heightmap to get the x and y position on the heightmap to read the height from.
Below is what I am working with.
public float getHeightOfTerrain(float worldX, float worldZ){
// worldX and worldZ are the players position
// Currentmatrix is the matrix used for positioning the terrain
float terrainX = worldX - CurrentMatrix[12] + objLength;
float terrainZ = worldZ - CurrentMatrix[14] + objLength;
return getHeight(terrainX, terrainZ);
}
................
float MAX_HEIGHT = 20;
float MAX_PIXEL_COLOR = 256*256*256;
................
public float getHeight(float x, float z){
float posX = x / (objLength*2);
float posZ = z / (objLength*2);
if(posX < 0 || posX > 1 || posZ < 0 || posZ > 1){ // if over 1 which is 100% of terrain then return
return 0;
}
float imgX = posX * bitmapOfMap.getWidth();
float imgZ = bitmapOfMap.getHeight() - (posZ * bitmapOfMap.getHeight()); // subtract BC bitmap y reads in reverse
if(imgX < 0 || imgX >= bitmapOfMap.getWidth() || imgZ < 0 || imgZ >= bitmapOfMap.getHeight()){ // if over then return
return 0;
}
float height = bitmapOfMap.getPixel((int)imgX, (int)imgZ);
height += MAX_PIXEL_COLOR/2f;
height /= MAX_PIXEL_COLOR/2f;
height *= MAX_HEIGHT;
return height;
}
The smaller the terrain height, the better this setup works. The bigger change in terrain height, the worse this system works. I have tried different obj and heightmaps, recreating over and over thinking this may be the issue but the same problems exist.
Am I doing this completely wrong? Any help would be appreciated. Anyone know a better way? I really want to keep my OBJ file import and read from that for customization.
I went ahead and created the terrain just by the heightmap, no OBJ import. Then applied my code above and had the same exact issue. So I dug a bit deeper in what is exactly going on step by step. It all started from the way I was keep track of the terrains location on x, y, and z then subtract that from the players position. I was tracking the players position from a seperate array of x, y, z and then terrains position from the matrix[12], matrix[13], matrix[14] as x, y, z.
This was the issue. I can't use the floats in the matrices as positioning relative values. I had to keep a seperate x, y, z for the terrain as well.
So from.....
float terrainX = worldX - CurrentMatrix[12] + objLength;
float terrainZ = worldZ - CurrentMatrix[14] + objLength;
to
float x, y, z = 0;
.....
float terrainX = z;
float terrainZ = x;
Now the model works perfect! .... moves up and down the terrain appropriately following the heightmap. I hope this helps anyone that may be having the same issue.
I've been thinking on some fast and brilliant pixel - perfect collision detection between a circle and any sprite. I need to get 2 points of collision to be able to calculate a normal vector out of them later. I managed to come up with some solution but the more scaling is done in my game, the more inaccurate and unprecise this collision is...It seems as if the code I posted below, was good and correct becouse I have been checking it already a few times and spent a few days reading it again and again... I also checked visually that the collision masks and areas of collision are calculated perfectly fine in the code below so the problem definitely doesn't lay there but in this method.
So I guess that the problem here is the loss of data in floating point arithmetic unless somebody finds a flaw in this method?
If however the problem is really with the float loss of data, what other solution would you recommend to find 2 points of collision between circle and any other sprite in pixel perfect? I really liked my solution becouse it was relatively fast
int xOffset1 = (int)colRectLeft; // left boundary of the collision area for the first sprite
int xOffset2 = (int)colCircleLeft; // left boundary of the collision area for the circle sprite
int yOffset1 = (int)colRectBottom; // bottom boundary of the collision area for the first sprite
int yOffset2 = (int)colCircleBottom; // bottom boundary of the collision area for the circle sprite
int width = (int)(colCircleRight - colCircleLeft); //width of the collision area - same for both sprites
int height = (int)(colCircleTop - colCircleBottom); // height of the collision area same for both sprites
// Pixel-perfect COLLISION DETECTION between circle and a sprite
// my custom vector classes - nothing special
Math2D.Vector_2 colRightPoint = new Math2D.Vector_2(-1, -1); // The right point of collision lying on the circle's circumference
Math2D.Vector_2 colLeftPoint = new Math2D.Vector_2(-1, -1); // the left point of collision lying on the circle's circumference
boolean colRightFound = false;
boolean colLeftFound = false;
// I'm going through y in the circle's area of collision
for (float y = yOffset2; y < yOffset2 + height; y += 1)
{
// from equation: (x-Sx)^2 + (y-Sy)^2 = r^2
// x1/2 = (+-)sqrt(r^2 - (y - Sy)^2) + Sx
//(Sx, Sy) is (circle's radius, circle's radius) becouse I want the points on the circle's circumference to have positive coordinates
float x1 = (float) (Math.sqrt(radius*radius - (y - radius)*(y - radius)) + radius); // the right pixel on the circumference
float x2 = (float) (-x1 + 2*radius); // the left pixel on the circumference
//first I check if the calculated x is inside of the previously calculated area of collision for both circle's area and a sprite's area
if (x1 >= xOffset2 &&
x1 <= xOffset2 + width &&
xOffset1 + x1 - xOffset2 < rectFrameW &&
yOffset1 + (int)y-yOffset2 < rectFrameH &&
yOffset1 + (int)y-yOffset2 > 0 &&
xOffset1 + x1 - xOffset2 > 0)
{
//I don't have to check if the point on the circle's circumference is opaque becouse it's always so just check if the same point translated to sprite's area of collision is opaque
boolean opaqueRectPixel = go.gameData.images.get(go.pic_nr)
.collision_mask[(int)((yOffset1 + (int)y-yOffset2)*rectFrameW +
(xOffset1 + x1 - xOffset2))];
if(opaqueRectPixel)
{
if(!colRightFound)
{
colRightPoint.x = (xOffset1 + x1 - xOffset2);
colRightPoint.y = (yOffset1 + (int)y - yOffset2);
colRightFound = true;
}
else if(!colLeftFound)
{
colLeftPoint.x = (xOffset1 + x1 - xOffset2);
colLeftPoint.y = (yOffset1 + (int)y - yOffset2);
}
}
}
//the same logic for the left point on the circle's circumference
if (x2 >= xOffset2 &&
x2 <= xOffset2 + width &&
xOffset1 + x2 - xOffset2 < rectFrameW &&
yOffset1 + (int)y-yOffset2 < rectFrameH &&
yOffset1 + (int)y-yOffset2 > 0 &&
xOffset1 + x2 - xOffset2 > 0)
{
boolean opaqueRectPixel = go.gameData.images.get(go.pic_nr)
.collision_mask[(int)((yOffset1 + (int)y-yOffset2)*rectFrameW +
(xOffset1 + x2 - xOffset2))];
if(opaqueRectPixel)
{
if(!colLeftFound)
{
colLeftPoint.x = (xOffset1 + x2 - xOffset2);
colLeftPoint.y = (yOffset1 + (int)y - yOffset2);
colLeftFound = true;
}
else if(!colRightFound)
{
colRightPoint.x = (xOffset1 + x2 - xOffset2);
colRightPoint.y = (yOffset1 + (int)y - yOffset2);
}
}
}
// if both points are already found, finish
if(colLeftFound && colRightFound)
break;
}
edit: Actually, what I'm doing in this method is finding points of intersection between circle and a sprite
edit: Ok, I'm uploading images to describe my algorithm a bit better. I really tried my best to explain it but if there's still something missing, let me know please!
Also I would accept any other good solutions to find intersection points between a circle and any sprite in pixel perfect, if you don't want to check my code :(... Eh, I'm always having problems with collisions...
If you absolutely want (or need) pixel perfect, your solution looks good.
don't forget to first make a rectangle-to-rectangle collision before testing a pixel perfect detection, to avoid unneeded processings.
If you want another accurate method which maybe more efficient, look for Separating Axis Theorem.
You can find more information about it here :
http://rocketmandevelopment.com/blog/separation-of-axis-theorem-for-collision-detection/
and here :
http://www.metanetsoftware.com/technique/tutorialA.html
The last one have nice interactive explanation and demonstration. Enjoy :)
...as I was not able to show the raster in the comments:
I did not mentally parse your code, however from the image I see that you try to detect borderline collisions. Putting round or diagonal (border)lines into a raster may cause occasions, where two crossing lines do not overlay each other - like this:
1 2
2 1
whereby 1 would be line 1 and 2 would be line 2.
However I still like the idea of checking border lines combined with rectangle pre-checks. If you would render an array of raster proved-closed line coordinates by sprites you could check them against each other. This could also be enriched by border line segmenting (such as North, East, West and South or a bit more fine grain - I guess there is an optimum). A diagonal proved-closed line in the check data set must represent something like this:
x _
x x
whereby the x represent the pixels of your line and the _ is an empty raster seat.
I want to fill a polygon with the scanline algorith. for this I have to know all points where the scanline comes in contact with the polygon.
I wrote a loop for this, but its obviously not working (it never adds a point to the list which means it can't find any points which cuts the polygon)
I can create a Polygon and have all Edges from it.
Here is my code for getting the points of the scanline which intersect the polygon
xmin, xmax, ymin and ymax are the max points from the polygon. They are also correct. contains() checks, if a Point is inside the polygon, with using the java.awt.Polygon class. This is working too.
wasInside contains a boolean, which saves the old state, if the last point checked was inside the polygon or not.
boolean wasInside = false;
ArrayList<Point> intersectionPoints = new ArrayList<Point>();
for (int yTemp = ymin; yTemp <= ymax; yTemp++) {
for (int xTemp = xmin; xTemp <= xmax; xTemp++) {
if (wasInside != this.contains(new Point(xTemp, yTemp))) {
intersectionPoints.add(new Point(xTemp, yTemp));
wasInside = !wasInside;
}
}
}
I have run your code in a minimal frame. It works, there is nothing wrong with it.
I suggest you check these pitfalls:
Polygon.contains() checks literally if a point is inside. So e.g. if your polygon is a rectangle starting at point (10, 10), then contains(10, 10) will return false. Only contains(11, 11) will return true. So you are not finding the real intersection points, but the first (and last) points inside.
(Sorry, I've stumbled upon it myself) Make sure x and y are confused nowhere.
Check the orientation: if you work with canvas, (0, 0) is the upper left point. But if you take a Math book and look at a Cartesian diagram, (0, 0) is the bottom left point - unless you have negative values. Could the orientation be confused somewhere?
How do you check if some points were added to intersectionPoints? This should work: System.out.println("Nb of intersection points found: " + intersectionPoints.size());
After this, it should work for you. You might want to print out what is checked for better understanding:
for (int xTemp = xmin; xTemp <= xmax; xTemp++) {
System.out.println("Check: " + xTemp + ", " + yTemp);
if (wasInside != this.contains(new Point(xTemp, yTemp))) {
System.out.println(" - Inside! Bash!");
intersectionPoints.add(new Point(xTemp, yTemp));
wasInside = !wasInside;
}
}