Determine touch/click of 4 Polygons from a Rectangle using libgdx - java

I'm currently working with libgdx, and am trying to get 4 equal Polygons from a Rectangle:
Rectangle myRect = Rectangle(0, 0, 171, 171);
I am looking to determine the 4 Polygons that represent each side of the Rectangle
This is my first day working with this engine, and I am a bit rusty on my geometry, so I'm looking for any help I can get. Essentialy, I'm going to use these Polygons to determine whether a specified X,Y pair is within them.
Thanks for the help.

You could find the mid point of the rectangle fairly easily, just average the height and width. From there you could manually construct a polygon, jumping from corner to corner to midpoint. You would lose some precision due to rounding, but you can use getX() and getWidth() if you need double precision.
public Polygon[] findTris(Rectangle rectangle){
//Creating a list of the x points of the rectangle, ordered clockwise.
new int[] xpoints = new int[5];
xpoints[0] = rectangle.x;
xpoints[1] = rectangle.x+rectangle.width;
xpoints[2] = rectangle.x+rectangle.width;
xpoints[3] = rectangle.x;
xpoints[4] = rectangle.x;
//Doing the same for y points.
int[] ypoints = new int[5];
ypoints[0] = rectangle.y;
ypoints[1] = rectangle.y;
ypoints[2] = rectangle.y+rectangle.height;
ypoints[3] = rectangle.y+rectangle.height;
ypoints[4] = rectangle.y;
//Finding the midpoint.
int midx = (rectangle.x+rectangle.width)/2;
int midy = (rectangle.y+rectangle.height)/2;
//Creating an array to hold the polygons.
Polygon[] polys = new Polygon[4];
//Creating the polygons.
for(int i = 0; i < 4; i++){
int[] triXPoints = {xpoints[i], xpoints[i+1], midx};
int[] triYPoints = {ypoints[i], ypoints[i+1], midy};
polys[i] = Polygon(xpoints,ypoints,3);
}
return polys;
}
Now that will work fine, but if all you are trying to do is find the mouse position in a square, you can use mouse maps. A mouse map is an image with distinctly different colors in each region that you want to be able to recognize the mouse in. You would store the map as a BufferedImage and whenever you needed to find the region the mouse was in, you can get the color of the buffered image at the appropriate position on the BufferedImage.
Here is the idea:
http://i.stack.imgur.com/iFPsl.png

Related

Java geotools how to create coverage grid

How to create grid coverage when each cell is 5M ?
I found this :
GridCoverage2D coverage = reader.read(null);
// direct access
DirectPosition position = new DirectPosition2D(crs, x, y);
double[] sample = (double[]) coverage.evaluate(position); // assume double
// resample with the same array
sample = coverage.evaluate(position, sample);
Source : https://docs.geotools.org/latest/userguide/library/coverage/grid.html
I didn't found a lot of tutorial about how to create grid coverage on geotools...
To create an empty coverage you need to use the GridCoverageFactory and one of the create methods. Since you are not constructing from an existing image you need to provide some memory for your raster to be stored in (this can also hold any initial values you want). For this your choices are a float[][] or a WritableRaster. Finally, you need a Envelope to say where the coverage is and what it's resolution is (otherwise it is just an array of numbers), I favour using a ReferencedEnvelope so that I know what the units are etc, so in the example below I have used EPSG:27700 which is the OSGB national grid so I know that it is in metres and I can define the origin somewhere in the South Downs. By specifying the lower left X and Y coordinates and the upper right X and Y as resolution times the width and height (plus the lower left corner) the maths all works out to make sure that the size of my pixels is resolution.
So keeping it simple for now you could do something like:
float[][] data;
int width = 100;
int height = 200;
data = new float[width][height];
int resolution = 5;
for(int i=0;i<width;i++){
for(int j=0;j<height;j++ ){
data[i][j] = 0.0f;
}
}
GridCoverageFactory gcf = new GridCoverageFactory();
CoordinateReferenceSystem crs = CRS.decode("EPSG:27700");
int llx = 500000;
int lly = 105000;
ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(llx, llx + (width * resolution), lly, lly + (height * resolution),
crs);
GridCoverage2D gc = gcf.create("name", data, referencedEnvelope);
If you want more bands in your coverage then you need to use a WriteableRaster as the base for your coverage.
WritableRaster raster2 = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_INT, width,
height, 3, null);
for (int i = 0; i < width; i++) {//width...
for (int j = 0; j < height; j++) {
raster2.setSample(i, j, 0, rn.nextInt(200));
raster2.setSample(i, j, 1, rn.nextInt(200));
raster2.setSample(i, j, 2, rn.nextInt(200));
}
}

Create polygon of non-transparent parts of image

What I am trying to achieve is getting a mask of an image, converting it into an Array with the dimensions (image.getWidth(), image.getHeight()), then getting all the pixels and seeing if they have an alpha value of 0.
IF they do, then:
add value 1 for the x, y co-ordinate that I am examining at the moment.
ELSE:
add value 0 for the x, y co-ordinate that I am examining at the moment.
Up to this point, I know how to program this. If you are interested, this is the code I am using:
private int[] createMask(BufferedImage image) {
final int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
final int width = image.getWidth();
final int height = image.getHeight();
final boolean hasAlphaChannel = image.getAlphaRaster() != null;
int[][] result = new int[height][width];
if (hasAlphaChannel) {
for (int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += 4) {
int alpha = pixels[pixel];
if(alpha != 0) {
result[row][col] = 1;
} else {
result[row][col] = 0;
}
if (col == width) {
col = 0;
row++;
}
}
}
return result;
}
After I get this mask, I am attempting to use this Array to draw a Polygon via this code, or an alternation of it (obtained from http://docs.oracle.com/javase/tutorial/2d/geometry/arbitrary.html) :
int x1Points[] = {0, 100, 0, 100};
int y1Points[] = {0, 50, 50, 0};
GeneralPath polygon =
new GeneralPath(GeneralPath.WIND_EVEN_ODD,
x1Points.length);
polygon.moveTo(x1Points[0], y1Points[0]);
for (int index = 1; index < x1Points.length; index++) {
polygon.lineTo(x1Points[index], y1Points[index]);
};
polygon.closePath();
g2.draw(polygon);
However, I need to create a method which gives me all the co-ordinates in an Array consisting of Point objects to go around the image to essentially create a "mask".
public Point[] getCords(int[] mask) {
ArrayList<Point> points = new ArrayList<Point>(); //you can change this to whatever you want to use
//get coords to surround the mask
// >> involving `0` (for transparent) and `1` (non transparent)
// >> these are contained in the `mask` Array...
return points.toArray(new Points[0]);
So, to conclude:
I require to obtain a polygon that outlines an image's visible pixels from an int[] array which contains the values 1's and 0's, the former for non-transparent pixel and latter for transparent pixel, respectively.
(link to related java code below)
To create the mask border, do the following: for each pair of coordinates (x,y) check if any one of 8 its neighboring points is outside the mask. However, keep in mind that the resulting mask isn't necessarily 1 pixel wide and vectorizing it might be non-trivial, as in this example (white is the masked area, red is the mask border inside the mask, black is unmasked area):
Luckily, even if you get a wider-than-1-pixel border in some places in your mask, you can workaround that by rejecting some pixels of the mask from that mask building a submask that is polygonizable. The following image shows the submask's border in blue:
I implemented such algorithm a while ago. There is the code you can use, but it is quite tightly coupled with my solution, however you could find some insights in it: Thick mask border resolution. Its idea is that from the initial mask you build a submask by flood-filling original mask with a predicate that checks that a cell of submask's border has at most 2 cardinal direction neighbors (ordinal direction neighbors don't matter here).
Once you got the blue submask's border, build a graph where vertices are points of submask's border, and edges are between cardinally neighboring points. Then traverse each component of that graph, and for each component you get a list of points that form your polygons.

Generate vertices for a polygon

I'm trying to make a useful/generic 2D polygon class for an OpenGL ES renderer.
When I create a polygon, I give it several parameters:
Polygon(Vector3 centerpoint, int numVertices, float inPolySize)
Then, I try to generate the vertices. This is where i'm having a tough time. I need to determine the number of vertices, get an angle, find the x/y position of that angle, someone take the size into account, AND offset by the position.
OpenGL works with big arrays of data. Nothing is nice like Lists of Vector3's. Instead it's float[] arrays, with the first index being X1, second being Y1, third being Z1, fourth being X2, etc...
final int XPOS = 0;
final int YPOS = 1;
final int ZPOS = 2;
int mvSize = 3; // (x, y, z);
float[] vertices = new float[mvSize * mNumVertices];
for (int verticeIndex = 0; verticeIndex < mNumVertices; verticeIndex++)
{
double angle = 2 * verticeIndex * Math.PI / mNumVertices;
vertices[mvSize * verticeIndex + XPOS] = (((float)Math.cos(angle)) * mPolygonSize) + mPosition.GetX();
vertices[mvSize * verticeIndex + YPOS] = (((float)Math.sin(angle)) * mPolygonSize) + mPosition.GetY();
vertices[mvSize * verticeIndex + ZPOS] = mPolygonSize + mPosition.GetZ();
}
Unfortunatley, my triangle is never quite right. It's skewed a lot, the size doesn't seem right...
I figure i'm throwing the size into the wrong formula, can anyone help?
EDIT:
Here's some sample data
Polygon test = new Polygon( new Vector3(0, 1, 0), 3, .5f);
vertices[0] = -0.25
vertices[1] = 1.4330127
vertices[2] = 0.0
vertices[3] = -0.25
vertices[4] = 0.5669873
vertices[5] = 0.0
vertices[6] = 0.5
vertices[7] = 1.0
vertices[8] = 0.0
vertices[9] = -0.25
vertices[10] = 1.4330127
vertices[11] = 0.0
I can't believe I was this stupid. Basically, my render window was smaller than my screen. If my screen is a rectangle, my render window was a square.
This being the case, any triangle I draw that was up was clipped by my render window. To me, it looked like the triangle was skewed. Really, it was just clipped!
The Java math library takes radians as input, not degrees. I didn't see the angles you were using for your calculation, but if you're not converting to radians from degrees, you will get some skewed looking shapes, and would explain that your calculations are correct, but the expected result is off.

Getting circle vector from OpenCV Mat in Android?

I can't get the circle vectors values from the OpenCV Mat in Android. I want to use this function:
HoughCircles(Mat image, Mat circles, int method, double dp, double minDist)
And then I want to show the circles that were found. Where I'm stuck is how to use the circles parameter in this function.
So, the question is: how can I get numbers of 3-element vectors and values of every element in vector from Mat type of OpenCV in Android?
Once you have your circles Mat
for (int i = 0; i < circles.cols(); i++)
{
double vCircle[] = circles.get(0,i);
double x = vCircle[0];
double y = vCircle[1];
double radius = vCircle[2];
}
Ideally you would want to use a vector<Vec3f> list to process the circles like this:
vector<Vec3f> circles;
// do HoughCircles...
for(size_t i = 0; i < circles.size(); i++)
{
Vec3f circle = circles[i];
Point2f center(circle[0] /* x */, circle[1] /* y */);
float radius = circle[2];
// use the circle...
}
EDIT : I tried the code just using a Mat, and it appears that the circle parameters are stored as a 1xN matrix with elements of type CV_32FC3, and where N is the number of circles detected. So, each column contains the (x, y, radius) vector you need.
Here is a sample I wrote in C++ showing this:
Mat circleImage = imread("circle.png", 0);
Mat circleDisp;
cvtColor(circleImage, circleDisp, CV_GRAY2RGB);
Mat circles;
HoughCircles(circleImage, circles, CV_HOUGH_GRADIENT, 2, circleImage.rows >> 2, 200, 100);
for( size_t i = 0; i < circles.cols; i++ )
{
Vec3f vCircle = circles.at<Vec3f>(i);
Point center(cvRound(vCircle[0]), cvRound(vCircle[1]));
int radius = cvRound(vCircle[2]);
// draw the circle center
circle( circleDisp, center, 3, Scalar(0,255,0), -1, 8, 0 );
// draw the circle outline
circle( circleDisp, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
namedWindow( "circles", 1 );
imshow( "circles", circleDisp );
waitKey();
Hope that helps!
Just cast your Mat to vector:
HoughCircles(Mat image, Mat circles, int method, double dp, double minDist);
vector<Vec3f> myCircles = (vector<Vec3f>)circles;
Or, simpler
HoughCircles(Mat image, vector<Vec3f>& circles,
int method, double dp, double minDist);
Note
This is only true for OpenCV 2.3.1.

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