I have a small block of code that is reading Line2D values from an array called lineList (in a different class) and storing them in the new array called list. from here I have been trying to convert all of the line values into Polygon points (a point for each x, y coordinate of a line end).
so far I have it working but its not working for the very first point of the first line in the array (that's what I suspect it is) that is added and I am having trouble finding a solution to this as I have tried including this in the first if statement.
I will greatly appreciate any help that anyone is able to provide for me on this.
Below is the code I am using for adding the points from the Line2D values:
Polygon p = new Polygon();
ArrayList<Line2D> list = new ArrayList<Line2D>();
Color pixel;
boolean firstTime = true;
list = segmentation.getLineList();
//loop through lineList and add all x and y coordinates to relative x and y arrays
for(int i = 0; i < list.size(); i++) {
if(firstTime == true){
Line2D line = list.get(i);
Point2D startPoint = line.getP1();
Point2D endPoint = line.getP2();
int startX = (int) startPoint.getX();
int startY = (int) startPoint.getY();
int endX = (int) endPoint.getX();
int endY = (int) endPoint.getY();
p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);
p.addPoint(p.xpoints[i] = endX, p.ypoints[i] = endY);
startPoint = null;
endPoint = null;
line = null;
firstTime = false;
}
else {
Line2D line = list.get(i);
Point2D endPoint = line.getP2();
int endX = (int) endPoint.getX();
int endY = (int) endPoint.getY();
p.addPoint(p.xpoints[i] = endX, p.ypoints[i] = endY);
endPoint = null;
line = null;
}
}
Below is an example of the first point (lower most point) not being included in the polygon points.
Seems like a lot of duplicated code to me. Before we try any more debugging, let's refactor the code and make it simpler to understand and debug.
Refactoring
The first bit of code we can pull out is the code to add a point to the Polygon. Here's the new method.
protected void addPoint(Polygon p, Point2D point) {
int x = (int) point.getX();
int y = (int) point.getY();
p.addPoint(x, y);
}
Now, I didn't get to this in one refactoring. I first pulled out the end point code, because it was identical. After reflecting on the code some more, I generalized it so I could use it for the start point code.
When I first saw this line of code
p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);
I thought, WTF? I'd never seen anyone set values in a method call. In a where clause, sure.
After about 5 minutes of thought, I realized that the Polygon class internal values were being set after the execution of the addPoint method. While this might be useful with some other method call, it's not necessary here. The method call can be simplified to
p.addPoint(x, y);
Java developers, if you need yet another reason for making your class variables non-public, this is a real good one. Keeps people from setting your class variables after you've set them in your setter method.
Priming Read
We can get rid of the first time switch, and a lot of code, if we use a little known algorithm called the priming read.
Most for loops have the input statement as the first statement in the loop. The for (String s : stringList) construction of a loop hides the fact that the input statement is the first statement in the loop.
But sometimes, you have a method where you need a priming read. This method is one of those times.
In pseudo code, a priming read works like this.
Read input
for loop
process input
read input
end loop
process last input
By using a priming read, I was able to greatly simplify the createPolygon method.
Any Cobol programmer reading this thought, "Yep, the priming read."
Java programmers, keep this priming read idea in your mind. You won't use it that often, but as you see, it greatly reduces the amount of code you need in certain cases.
Refactored Code
public Polygon createPolygon(Segmentation segmentation) {
Polygon p = new Polygon();
List<Line2D> list = segmentation.getLineList();
if (list.size() < 2) return p;
Line2D line = list.get(0);
addPoint(p, line.getP1());
// loop through lineList and add all x and y coordinates to relative x
// and y arrays
for (int i = 1; i < list.size(); i++) {
addPoint(p, line.getP2());
line = list.get(i);
}
addPoint(p, line.getP2());
return p;
}
protected void addPoint(Polygon p, Point2D point) {
int x = (int) point.getX();
int y = (int) point.getY();
p.addPoint(x, y);
}
I did two additional things to the code.
I added a test for less than 2 lines. Basically, it takes at least 2 lines to create a triangle (polygon). There was no point executing the method for 1 line or zero lines.
I changed the ArrayList reference to List. In Java, it's better to use an interface over a concrete class. Since the only List method we're using in the code is the get method, we can use the interface. The advantage to using the interface is that the createPolygon method doesn't care whether or not the getLineList method returns an ArrayList, a LinkedList, or a custom class that implements List. This makes future modifications easier.
Related
Is there an efficient algorithm to find straight lines from an unsorted collection of x/y coordinates?
It would be ideal if:
a line is only recognized if at least n (more than two) points are aligned.
It allows a tolerance, so for example the following three coordinates would be considered a (horizontal) line: 10/100, 20/99, 30/100.
Is there some kind of standard approach to solve this? Maybe any (java) libraries? How would you solve it?
I would suggest using two maps, one for horizontal lines and one for vertical ones.
for every point, the key is the X or Y coordinate and the value is the point (use a list of points as values). Now go over the maps, and for each key show the points if there are more than one point, for each key, you should also count the points in the next keys (like in the case of 99 and 100).
I'm not sure if there'd be an efficient algorithm unless you already know of some relationship between the points.
The algorithm I outline below I guess would run in n^4 time.
You'd have something like
public class Line
{
static float tolerance;
float m, cLower, cUpper;
ArrayList<Point> onThisLine = new ArrayList<Point>();
public Line(double m, double c)
{
this.m = m;
cLower = c-tolerance;
cUpper = c+tolerance;
}
public boolean fitsInLine(Point xy)
{...}
public void addToList(Point xy)
{...}
}
where m and c represent what we learned in high school as the gradient and constant of the straight line.
For each point you'd have to compare it to every other point, generate a Line object, and then compare the new Line object to every existing Line and if it doesn't already exist then add it. Note that due to the slight tolerance you allow you consequentially have to allow for a similarity between Lines.
For example, y=-x/10+101 and y=100 are very similar line equations.
Finally, for each Line object you could get the size of the ArrayList keeping Points that fit on it, and throw away Lines that have less Points than what you want.
If you take a pair of points Pi and Pj, you can check in O(n) time which points lie on or near the line Pi Pj. There are O(n2) pairs, so you get an algorithm which is O(n3). Of course, if Pk is exactly on the line Pi Pj, you should no longer check lines Pi Pk and Pj Pk, because they will contain the same points as Pi Pj. However, this is not true if Pk is just close to Pi Pj.
I have made the algorithm displayed below. What it does is it calculates the formula of the line: y= kx+l; Then it makes two lines parallel to that one, one slightly raised and one slightly lowered->(y = kx+l-d and y=kx+l+d, d=tolerance). Then it goes through the rest of points and calculates the y for their x for the upper and lower parallel. If it's real value is between the calculated values it counts as beeing on the line.This is O(n^3).
Code:
public static void main(String[] args) {
Point[] points = generatePoints(5);
List<Set<Point>> lines = findLines(points,2,3);
lines.forEach((line)->{
System.out.println(Arrays.toString(line.toArray()));
});
}
private static List<Set<Point>> findLines(Point[] points,int tolerance,int minNumberOfPoints) {
List<Set<Point>> lines = new LinkedList<>();
for(int i=0;i<points.length;i++){
for(int j=i+1;j<points.length;j++){
//check if that line was all ready found
boolean hasBoth = false;
for(Set<Point> line:lines){
hasBoth =Boolean.logicalAnd(line.contains(points[i]),line.contains(points[j]));
if(hasBoth)
break;
}
if(hasBoth)
break;
int x1 = points[i].getX();
int y1 = points[i].getY();
int x2 = points[j].getX();
int y2 = points[j].getY();
double k = (double)(y1-y2)/(double)(x1-x2);
double l = y1-k*x1;
//y = kx + l -> line
//y1 = kx + l - tolerance -> lower parallel line
//y2 = kx + l + tolerance -> upper parallel line
//take a third point if for its x it gives a y3 where y1<=y3<=y2 then it should be part of the line
Set<Point> line = new HashSet<>();
line.add(points[i]);
line.add(points[j]);
for(int z=j+1;z<points.length;z++){
int x3 = points[z].getX();
int y3 = points[z].getY();
double y1Line = k*x3+l-tolerance;
double y2Line = k*x3+l+tolerance;
if(y1Line<=y3 && y3<=y2Line)
line.add(points[z]);
}
lines.add(line);
}
}
lines = lines.stream().filter((set)->{
return set.size()>=minNumberOfPoints;
}).collect(Collectors.toList());
return lines;
}
private static Point[] generatePoints(int number) {
Point[] points = new Point[number];
Random r = new Random();
for(int i=0;i<number;i++){
points[i] = new Point(r.nextInt(10), r.nextInt(10));
}
return points;
}
private static class Point{
private int x;
private int y;
public Point(int x,int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public String toString() {
return "("+x+","+y+")";
}
}
You could use Hough transformation to detect lines. I experienced hough transformation while detecting features in images. It basically uses polar representation of lines to detect them. Although I think opencv is out of the context for what you want to do, I still want to share the hough line detection page with you which explains the algorithm pretty clearly.
http://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.html
There is also this source which I had found to be useful :
https://www.cs.sfu.ca/~hamarneh/ecopy/compvis1999_hough.pdf
for some reason in my ray tracer if I try to limit the number of recursive calls in my ray tracer my reflectance doesn't work.
Here is my reflectance code:
public static int recursionLevel;
public int maxRecursionLevel;
public Colour shade(Intersection intersection, ArrayList<Light> lights, Ray incidenceRay) {
recursionLevel++;
if(recursionLevel<maxRecursionLevel){
Vector3D reflectedDirection = incidenceRay.direction.subtractNormal(intersection.normal.multiply(2).multiply(incidenceRay.direction.dot(intersection.normal)));
Ray reflectiveRay = new Ray(intersection.point, reflectedDirection);
double min = Double.MAX_VALUE;
Colour tempColour = new Colour();
for(int i = 0; i<RayTracer.world.worldObjects.size(); i++){
Intersection reflectiveRayIntersection = RayTracer.world.worldObjects.get(i).intersect(reflectiveRay);
if (reflectiveRayIntersection != null && reflectiveRayIntersection.distance<min){
min = reflectiveRayIntersection.distance;
recursionLevel++;
tempColour = RayTracer.world.worldObjects.get(i).material.shade(reflectiveRayIntersection, lights, reflectiveRay);
recursionLevel--;
}
}
return tempColour;
}else{
return new Colour(1.0f,1.0f,1.0f);
}
}
If I get rid of the if statement it works, though I run out of memory if I place too many reflective objects. I'm not sure what could be causing this.
The problem is that you're using recursionLevel as global state, but it really should be local state. Also, with every recursive call to shade(), you're incrementing it twice and only decrementing it once. I would refactor your code as follows:
Delete the recursionLevel global
Add a recursionLevel parameter to your shade() method
Keep your if(recursionLevel < maxRecursionLevel) check
Remove the recursionLevel increments and decrements around the recursive call to shade()
Modify the recursive call to shade() such that it calls shade(..., recursionLevel + 1)
So here's the thing, I'm supposed to read a document and import some data.
A line in the document looks like this "A 0 2 5 20 23 25." (.txt).
I can write a method that finds this line and the values but my problem is to draw the actual graph whith the values. X of the graph will be fixed for 10 between each value and the values in the file corresponds to Y. I want to come up with a method that takes the first Y(0), and Draws a straight line to the next Y(2) and from 2-5 etc.
I fail to do this, my method only Draws a line from 0-2 and 5-20 and 23-25.
Book hasn't talked about array's yet so I should do this without arrays, I try to do it as I read the file but..
Here is a bit of my code anyway, any tips?? Much appreciated
public static void drawGraph(String letter, Scanner input, Graphics g){
while (input.hasNextLine()){
int x = 1;
String text = input.nextLine();
Scanner data = new Scanner(text);
String foundLetter = data.next();
if(foundLetter.equalsIgnoreCase(letter)){
while(data.hasNextInt()){
int count = data.nextInt();
//This is where I get Stuck
g.drawLine((x-1)*10, y1, 10*x);
x++;
}
}
}
}
I have made an template drawingpanel for the plot divided into sections of 10's
Thanks,
You have to memorize the last y value, then draw a line from (x-1, last y) to (x, y).
int lastY = data.nextInt();
while (data.hasNextInt()) {
int nextY = data.nextInt();
g.drawLine((x-1)*10, lastY, 10*x, nextY);
x++;
lastY = nextY;
}
Im having problems with removing items from an arraylist using an iterator. My aim is to retrieve points within a certain radius and cluster them into a set of groups. I am using the initial points as a reference. The code has an initial for loop that will run through each place, then for each place an inner for loop is created to check the radius between the reference place and the rest of places. If the radius between both reference place and other place is less than a threshold i set, it will be added to the arraylist grouped with other similar points. As they are added to groups they will be removed from the original arraylist.
However i am getting problems such as it either only performs the outer for loop once or i get an IllegalStateException.
Here is the code:
HashMap<Place, ArrayList<Place>> sets = new HashMap<Place, ArrayList<Place>>();
private void cluster(ArrayList<Place> places) {
for (Iterator<Place> iterator = places.iterator(); iterator.hasNext();) {
Place pl = iterator.next();
ArrayList<Place> subset = new ArrayList<Place>(); // Group
GeoPoint g = new GeoPoint((int) (pl.getGeometry().getLocation()
.getLat() * 1e6), (int) (pl.getGeometry().getLocation()
.getLng() * 1e6));
Point point = new Point();
mapView.getProjection().toPixels(g, point);
sets.put(pl, subset);
subset.add(pl);
iterator.remove();
for (Iterator<Place> iterator2 = places.iterator(); iterator2
.hasNext();) {
Place pl2 = iterator2.next();
int threshold = 100;
GeoPoint g2 = new GeoPoint((int) (pl2.getGeometry()
.getLocation().getLat() * 1e6), (int) (pl2
.getGeometry().getLocation().getLng() * 1e6));
Point point2 = new Point();
mapView.getProjection().toPixels(g2, point);
int dx = Math.abs(point2.x - point.x);
int dy = Math.abs(point2.y - point.y);
if (dx < threshold && dy < threshold) {
subset.add(pl2);
iterator2.remove();
}
}
}
}
Sorry for the info overload, would really appreciate the help.
Thanks in advance peeps
Rehan
You are stepping the outer iterator inside the inner loop. It looks like these lines might be in error:
for (Iterator<Place> iterator2 = places.iterator(); iterator.hasNext();) {
Place pl2 = iterator.next();
Looks like maybe you copied and pasted without changing the terminating condition in the loop and the following line:
for (Iterator<Place> iterator2 = places.iterator(); iterator2.hasNext();) {
Place pl2 = iterator2.next();
running multiple iterators over the same list isnt allowed. So you will get a concurrentmodification exception. Better make a copy of the array list, in the inner loop update the data in the position of copy where you want to update. In short,change your logic
I guess you gets exception because you change list while iterating it.
At first, I would use for (... in ...) construction.
Second, I think you have to copy places an iterating it, but deleting from places.
I'm working on a self-assigned project over break, and am running into one major sticking point. This is a basic line-recognition program in Java.
I have a Points class which creates the Point from the ordered pairs & sends it to the Line class for slope & intercept calculation. The results are sent back to the Points class which deposits the results into the ArrayList linelist. There are three parts to each Line object: the slope & intercept integers and the Point from which they were calculated from.
From a loop, how can I access the slope & intercept variables from each object in the linelist for comparison? Since I don't want to compare the points, just the slope & intercept, the equals() method is not what I need.
It sounds like you want something like this:
class Point {
final int x;
final int y;
Point(int x, int y) { this.x = x; this.y = y; }
}
class Line {
final int slope;
final int intercept;
Line(Point p1, Point p2) {
this.slope = ...;
this.intercept = ...;
}
}
class Points {
public void doIt(ArrayList<Point> points) {
ArrayList<Line> lines = new ArrayList<Line>();
for (int i = 0; i < points.size(); i++) {
for (int j = i + 1; j < points.size(); j++) {
lines.add(new Line(points.get(i), points.get(j));
}
}
for (int i = 0; i < lines.size(); i++) {
for (int j = i + 1; j < lines.size(); j++) {
Line line1 = lines.get(i);
Line line2 = lines.get(j);
if (line1.slope == line2.slope && line1.intercept == line2.intercept) {
// blah blah blah
}
}
}
}
}
(For the peanut gallery, yes there is scope for micro-optimization. But no, it isn't worth the effort unless you've profiled the program and found there to be a real and significant bottleneck.)
[For a more elegant and scalable solution, override the equals(Object) (and hashcode()) methods on Line class and replace the lines list with a TreeSet. This will reduce O(N**2) comparisons to O(NlogN) comparisons. But that's overkill for a basic programming exercise.]
From a loop, how can I access the slope & intercept variables from each object in the linelist for comparison?
Just add another loop over the same list inside the loop and do the comparison in there.
You could have your Line object implement the Comparable interface. You could then put the comparison logic within the Line class in the compareTo method. The logic there will test whether the slope and the intercept match, and if so return 0. Other results could return 1 or -1 to enforce ordering, if you want.
Obviously, you don't need to implement this interface to effect your desired results. However, as this is homework, doing so will allow you to play around with some features of the JDK, like using sorted Lists, etc. With a sorted list, for example, you could obviate the need for a nested loop, as you would only need to compare the object in question against one you just removed from the Iterator in the previous iteration to see if you need to add it to an existing linelist or start a new one.