diff --git a/polygon_triangulation/polygon_triangulation.pde b/polygon_triangulation/polygon_triangulation.pde index 2c0fc32..1515394 100644 --- a/polygon_triangulation/polygon_triangulation.pde +++ b/polygon_triangulation/polygon_triangulation.pde @@ -1,37 +1,47 @@ -import java.util.*; -import java.awt.Point; -import java.util.Vector; -import java.util.concurrent.*; - - - PFont f; - float mx, my, mxNext, myNext; - int i; - boolean accept = false; - int count = 0; - int rectX, rectY; // Position of square button - int circleX, circleY; // Position of circle button - int rectSize = 40; - int circleSize = 10; - int threshold = 60; - color inside = color(204, 102, 0); - color[] mycolors = {#47586c, #bd776d, #012f46, #2A3A55, #552A3C, #FAD930, #FF600F, #729DD8, #9DAA76, #AA7692, #9376AA, #B9351E, #E32E2E, #29333E, #F50202, #4B3C50, #5D6293}; - - boolean finish = false, accept_me = true; - - List list; - List circle_list; - PolygonTriangulation polygonTriangulation; +import java.util.ArrayList; +import java.util.List; + +PFont f; +float mx,my,mxNext,myNext,intersect_x,intersect_y; +int i; +boolean accept=false; +int count=0; +int rectX,rectY; // Position of square button +int circleX,circleY; // Position of circle button +int rectSize=40; +int circleSize=10; +int threshold=60; +color inside=color(204,102,0); +color[]mycolors={#47586c, #bd776d, #012f46, #2A3A55, #552A3C, #FAD930, #FF600F, #729DD8, #9DAA76, #AA7692, #9376AA, #B9351E, #E32E2E, #29333E, #F50202, #4B3C50, #5D6293}; +boolean accept_me=true; +List list; +List circle_list; +PolygonTriangulation polygonTriangulation; + +public class Line { + + public float x1; + public float y1; + public float x2; + public float y2; + + public Line(float x1, float y1, float x2, float y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } +} + void setup() { size(600, 600); f = createFont("Arial", 16, true); background(102); - list = new CopyOnWriteArrayList(); - circle_list = new CopyOnWriteArrayList(); + list = new ArrayList(); + circle_list = new ArrayList(); rectX = width / 2 - rectSize; rectY = (height - 30) - rectSize / 2; - polygonTriangulation = new PolygonTriangulation(); ellipseMode(CENTER); } @@ -43,122 +53,162 @@ import java.util.concurrent.*; return false; } } - - boolean is_simple_polygon(List list){ - - for(int i = 0; i < list.size(); i++){ - for(int j = i + 2; j < list.size(); j++){ - MyClass cl1 = list.get(i); - MyClass cl2 = list.get(j); - boolean is_line_intersect = is_line_intersect(cl1.x1, cl1.y1, cl1.x2, cl1.y2, cl2.x1, cl2.y1, cl2.x2, cl2.y2); - if(is_line_intersect) return false; - } - } - - return true; + + void arrow(int x1, int y1, int x2, int y2) { + line(x1, y1, x2, y2); + pushMatrix(); + translate(x2, y2); + float a = atan2(x1 - x2, y2 - y1); + rotate(a); + line(0, 0, -10, -10); + line(0, 0, 10, -10); + popMatrix(); + } + + + boolean is_simple_polygon(List list) { + + for (int i = 0; i < list.size(); i++) { + for (int j = i + 2; j < list.size(); j++) { + Line cl1 = list.get(i); + Line cl2 = list.get(j); + boolean _is_line_intersect = is_line_intersect(cl1.x1, cl1.y1, cl1.x2, cl1.y2, cl2.x1, cl2.y1, cl2.x2, cl2.y2); + if (_is_line_intersect) return false; + } + } + return true; } - - boolean is_line_intersect(float p0_x, float p0_y, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y){ + + boolean is_line_intersect(float p0_x, float p0_y, float p1_x, float p1_y, float p2_x, float p2_y, float p3_x, float p3_y) { + float s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t; - s10_x = p1_x - p0_x; - s10_y = p1_y - p0_y; - s32_x = p3_x - p2_x; - s32_y = p3_y - p2_y; - - denom = s10_x * s32_y - s32_x * s10_y; - if (denom == 0) - return false; // Collinear - boolean denomPositive = denom > 0; - - s02_x = p0_x - p2_x; - s02_y = p0_y - p2_y; - s_numer = s10_x * s02_y - s10_y * s02_x; - if ((s_numer < 0) == denomPositive) - return false; // No collision - - t_numer = s32_x * s02_y - s32_y * s02_x; - if ((t_numer < 0) == denomPositive) - return false; // No collision - - if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive)) - return false; // No collision - // Collision detected - t = t_numer / denom; - - return true; - - } + s10_x = p1_x - p0_x; + s10_y = p1_y - p0_y; + s32_x = p3_x - p2_x; + s32_y = p3_y - p2_y; + + denom = s10_x * s32_y - s32_x * s10_y; + if (denom == 0) + return false; // Collinear + boolean denomPositive = denom > 0; + + s02_x = p0_x - p2_x; + s02_y = p0_y - p2_y; + s_numer = s10_x * s02_y - s10_y * s02_x; + if ((s_numer < 0) == denomPositive) + return false; // No collision + + t_numer = s32_x * s02_y - s32_y * s02_x; + if ((t_numer < 0) == denomPositive) + return false; // No collision + + if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive)) + return false; // No collision + // Collision detected + t = t_numer / denom; + + intersect_x = p0_x + (t * s10_x); + intersect_y = p0_y + (t * s10_y); + + ellipse(intersect_x, intersect_y, 16, 16); + arrow((int) rectX, (int) rectY - 80, (int) intersect_x, (int) intersect_y + 5); + return true; + } - void draw() { + void mousePressed() { + if (overRect(rectX + threshold, rectY, rectSize, rectSize)) { + list = new ArrayList(); + circle_list = new ArrayList(); + background(102); + count = 0; + accept_me = true; + + } else if (overRect(rectX, rectY, rectSize, rectSize)) { + if (list.size() <= 0) { + textFont(f, 20); + text("PLEASE, INPUT POINTS!!!", 180, rectY - 60); + text("PLEASE, PRESS RESET BUTTON!!!", 180, rectY - 40); + } else if (!is_simple_polygon(list)) { - if (mousePressed == true) { - if (overRect(rectX + threshold, rectY, rectSize, rectSize)) { - list = new ArrayList(); - circle_list = new ArrayList(); + textFont(f, 20); + text("NOT A SIMPLE POLYGON!!!", 180, rectY - 60); + + text("PLEASE, PRESS RESET BUTTON!!!", 180, rectY - 40); + + } else { background(102); - count = 0; - accept_me = true; - finish = false; - polygonTriangulation = new PolygonTriangulation(); - - } else if (overRect(rectX, rectY, rectSize, rectSize)) { - - if(!is_simple_polygon(list)){ - textFont(f, 20); - text("NOT A SIMPLE POLYGON!!!", 180, rectY - 60); - //fill(mycolors[int(random(0, 17))]); - text("PLEASE, PRESS RESET BUTTON!!!", 180, rectY - 40); - //fill(mycolors[int(random(0, 17))]); - }else{ - Vector point_list = new Vector(); + List point_list = new ArrayList(); float firstX1 = list.get(0).x1; float firstY1 = list.get(0).y1; - for (i = 0; i < list.size() - 1; i++) { - MyClass cl = list.get(i); - Point point = new Point(); - point.setLocation(cl.x1, cl.y1); + for (i = 0; i < list.size(); i++) { + Line cl = list.get(i); + Point point = new Point(cl.x1, cl.y1); point_list.add(point); } - Point point = new Point(); - point.setLocation(firstX1, firstY1); + Point point = new Point(firstX1, firstY1); + point_list.add(point); polygonTriangulation = new PolygonTriangulation(point_list); - (new Thread(polygonTriangulation)).start(); - count = 0; + + polygonTriangulation.runPolygonTriangulation(); + + List triangle_list = polygonTriangulation.getTriangles(); + + for (i = 0; i < triangle_list.size(); i++) { + Triangle triangle = triangle_list.get(i); + + fill(mycolors[int(random(0, 17))]); + beginShape(); + vertex(triangle.getA().getX(), triangle.getA().getY()); + vertex(triangle.getB().getX(), triangle.getB().getY()); + vertex(triangle.getC().getX(), triangle.getC().getY()); + endShape(CLOSE); + } - } else if (count == 0) { - mx = mouseX; - my = mouseY; - count = 2; - CircleCoords circleCoords = new CircleCoords(mx, my, circleSize); - circle_list.add(circleCoords); - } else if (count == 1) { - mxNext = mouseX; - myNext = mouseY; - - MyClass myClass = new MyClass(mx, my, mxNext, myNext); - list.add(myClass); - println(list.size()); - - CircleCoords circleCoords = new CircleCoords(mxNext, myNext, circleSize); - circle_list.add(circleCoords); - - mx = mxNext; - my = myNext; - count = 2; - } - } else { - if (count != 0) { - count = 1; + textFont(f, 12); + int size = circle_list.size() - 1; + int triangle_size = triangle_list.size() - 1; + if (accept_me) { + text("NUMBER OF VERTICES: " + size, rectX - 30, rectY - 60); + fill(mycolors[int(random(0, 17))]); + text("NUMBER OF TRIANGLES: " + triangle_size, rectX - 30, rectY - 40); + fill(mycolors[int(random(0, 17))]); + } + count = 0; } + } else if (count == 0) { + mx = mouseX; + my = mouseY; + count = 2; + CircleCoords circleCoords = new CircleCoords(mx, my, circleSize); + circle_list.add(circleCoords); + } else if (count == 1) { + mxNext = mouseX; + myNext = mouseY; + + Line myClass = new Line(mx, my, mxNext, myNext); + list.add(myClass); + CircleCoords circleCoords = new CircleCoords(mxNext, myNext, circleSize); + circle_list.add(circleCoords); + + mx = mxNext; + my = myNext; + count = 2; + } + } + + + void draw() { + if (count != 0) { + count = 1; } for (i = 0; i < list.size(); i++) { - MyClass mc = list.get(i); + Line mc = list.get(i); line(mc.x1, mc.y1, mc.x2, mc.y2); } @@ -169,326 +219,241 @@ import java.util.concurrent.*; } rect(rectX, rectY, rectSize, rectSize); - fill(#9AB8B9); + fill(#9AB8B9); rect(rectX + threshold, rectY, rectSize, rectSize); - fill(#9AB8B9); - + fill(#9AB8B9); + textFont(f, 10); text("EXECUTE", rectX, rectY - 5); text("RESET", rectX + threshold, rectY - 5); textFont(f, 13); text("SIMPLE POLYGON TRIANGULATION", 180, 15); - - - if (!finish && accept_me) { - try { - Thread.sleep(10); - } catch (Exception ex) { - System.out.println(ex.toString()); - } - synchronized (this) { - - try { - Vector triangle_list = polygonTriangulation.getTriangles(); - - if (triangle_list != null) { - for (Triangle triangle : triangle_list) { - triangle((float) triangle.getA().getX(), (float) triangle.getA().getY(), (float) triangle.getB().getX(), (float) triangle.getB().getY(), (float) triangle.getC().getX(), (float) triangle.getC().getY()); - } - } - } catch (Exception x) { - } - } - } else if (finish && accept_me) { - try { - Thread.sleep(1000); - } catch (Exception ex) { - System.out.println(ex.toString()); - } - synchronized (this) { - Vector triangle_list = polygonTriangulation.getTriangles(); + } - println("NUMBER OF TRIANGLES: " + triangle_list.size()); - for (Triangle triangle : triangle_list) { - println(triangle.getA()); - println(triangle.getB()); - println(triangle.getC()); - println("^^^^^^^^--------------------------------------------------^^^^^^^"); - triangle((float) triangle.getA().getX(), (float) triangle.getA().getY(), (float) triangle.getB().getX(), (float) triangle.getB().getY(), (float) triangle.getC().getX(), (float) triangle.getC().getY()); - fill(mycolors[int(random(0, 17))]); - } - textFont(f, 12); - text("NUMBER OF VERTICES: " + String.valueOf(circle_list.size() - 1), rectX - 30, rectY - 60); - fill(mycolors[int(random(0, 17))]); - text("NUMBER OF TRIANGLES: " + triangle_list.size(), rectX - 30, rectY - 40); - fill(mycolors[int(random(0, 17))]); - } - - accept_me = false; - } +public class CircleCoords { + public float x1; + public float y1; + public int circleSize; + public CircleCoords(float x1, float y1, int circleSize) { + this.x1 = x1; + this.y1 = y1; + this.circleSize = circleSize; } +} - public class MyClass { - public float x1; - public float y1; - public float x2; - public float y2; +public class Point { + public float x; + public float y; - public MyClass(float x1, float y1, float x2, float y2) { - this.x1 = x1; - this.y1 = y1; - this.x2 = x2; - this.y2 = y2; - } + public float getX() { + return x; } - public class CircleCoords { - public float x1; - public float y1; - public int circleSize; - - public CircleCoords(float x1, float y1, int circleSize) { - this.x1 = x1; - this.y1 = y1; - this.circleSize = circleSize; - } + public float getY() { + return y; + } + public Point(float x, float y) { + this.x = x; + this.y = y; } - public class Triangle { + public Point(Point point) { + this.x = point.x; + this.y = point.y; + } - // coordinates - private Point a; - private Point b; - private Point c; + public Point() { + } +} - public Point getA() { - return a; - } +public class PolygonTriangulation { - public Point getB() { - return b; - } + public List points; + public List nonconvexPoints; + public List triangles; - public Point getC() { - return c; - } + public boolean isCw; - public Triangle() { - } + public PolygonTriangulation(List points) { + this.points = new ArrayList(); + for (int i = 0; i < points.size(); i++) + this.points.add(new Point(points.get(i))); + nonconvexPoints = new ArrayList(); - public Triangle(Point a, Point b, Point c) { - this.a = a; - this.b = b; - this.c = c; - } + triangles = new ArrayList(); + calcPolyOrientation(); + calcNonConvexPoints(); + } - public boolean isInside(Point p) { - // interpret v1 and v2 as vectors - Point v1 = new Point(b.x - a.x, b.y - a.y); - Point v2 = new Point(c.x - a.x, c.y - a.y); + public void calcNonConvexPoints() { + if (points.size() <= 3) return; + + Point p; + Point v; + Point u; + // result value of test function + int res = 0; + for (int i = 0; i < points.size() - 1; i++) { + p = points.get(i); + Point tmp = points.get(i + 1); + v = new Point(); // interpret v as vector from i to i+1 + v.x = tmp.x - p.x; + v.y = tmp.y - p.y; + + if (i == points.size() - 2) + u = points.get(0); + else + u = points.get(i + 2); - double det = v1.x * v2.y - v2.x * v1.y; - Point tmp = new Point(p.x - a.x, p.y - a.y); - double lambda = (tmp.x * v2.y - v2.x * tmp.y) / det; - double mue = (v1.x * tmp.y - tmp.x * v1.y) / det; + res = (int) (u.x * v.y - u.y * v.x + v.x * p.y - v.y * p.x); + if ((res > 0 && isCw) || (res <= 0 && !isCw)) { + nonconvexPoints.add(tmp); + } - return (lambda >= 0 && mue >= 0 && (lambda + mue) <= 1); } + } - public boolean isInside(Point x, Point y, Point z, Point p) { - Point v1 = new Point(y.x - x.x, y.y - x.y); - Point v2 = new Point(z.x - x.x, z.y - x.y); - - double det = v1.x * v2.y - v2.x * v1.y; - Point tmp = new Point(p.x - x.x, p.y - x.y); - double lambda = (tmp.x * v2.y - v2.x * tmp.y) / det; - double mue = (v1.x * tmp.y - tmp.x * v1.y) / det; - - return (lambda > 0 && mue > 0 && (lambda + mue) < 1); + public void calcPolyOrientation() { + if (points.size() < 3) return; + + int index = 0; + Point pointOfIndex = points.get(0); + for (int i = 1; i < points.size(); i++) { + if (points.get(i).x < pointOfIndex.x) { + pointOfIndex = points.get(i); + index = i; + } else if (points.get(i).x == pointOfIndex.x && points.get(i).y > pointOfIndex.y) { + pointOfIndex = points.get(i); + index = i; + } } - } + Point prevPointOfIndex; + if (index == 0) + prevPointOfIndex = points.get(points.size() - 1); + else + prevPointOfIndex = points.get(index - 1); + Point v1 = new Point(pointOfIndex.x - prevPointOfIndex.x, pointOfIndex.y - prevPointOfIndex.y); + Point succPointOfIndex; + if (index == points.size() - 1) + succPointOfIndex = points.get(0); + else + succPointOfIndex = points.get(index + 1); + int res = (int) (succPointOfIndex.x * v1.y - succPointOfIndex.y * v1.x + v1.x * prevPointOfIndex.y - v1.y * prevPointOfIndex.x); - public class PolygonTriangulation implements Runnable { + isCw = (res <= 0 ? true : false); - private Vector points; - private Vector nonconvexPoints; - private Vector triangles; - private Triangle triangle; + } - private boolean isCw; + public boolean isEar(Point p1, Point p2, Point p3) { + if (!(isConvex(p1, p2, p3))) return false; - public PolygonTriangulation() { + for (int i = 0; i < nonconvexPoints.size(); i++) { + if (new Triangle().isInside(p1, p2, p3, nonconvexPoints.get(i))) + return false; } + return true; + } - public PolygonTriangulation(Vector points) { - this.points = new Vector(); - for (int i = 0; i < points.size(); i++) - this.points.add(new Point(points.get(i))); + public boolean isConvex(Point p1, Point p2, Point p3) { + Point v = new Point(p2.x - p1.x, p2.y - p1.y); + int res = (int) (p3.x * v.y - p3.y * v.x + v.x * p1.y - v.y * p1.x); + return !((res > 0 && isCw) || (res <= 0 && !isCw)); + } - nonconvexPoints = new Vector(); - triangles = new Vector(); - triangle = new Triangle(); - calcPolyOrientation(); - calcNonConvexPoints(); + public int getIndex(int index, int offset) { + int newindex; + if (index + offset >= points.size()) + newindex = points.size() - (index + offset); + else { + if (index + offset < 0) + newindex = points.size() + (index + offset); + else + newindex = index + offset; } + return newindex; + } - synchronized private void calcNonConvexPoints() { - - if (points.size() <= 3) return; - - Point p; - Point v; - Point u; - int res = 0; - for (int i = 0; i < points.size() - 1; i++) { - p = points.get(i); - Point tmp = points.get(i + 1); - v = new Point(); // interpret v as vector from i to i+1 - v.x = tmp.x - p.x; - v.y = tmp.y - p.y; - - if (i == points.size() - 2) - u = points.get(0); - else - u = points.get(i + 2); - - res = u.x * v.y - u.y * v.x + v.x * p.y - v.y * p.x; - - if ((res > 0 && isCw) || (res <= 0 && !isCw)) { - nonconvexPoints.add(tmp); - } + public void runPolygonTriangulation() { + if (points.size() <= 3) { + textFont(f, 20); + text("EDGES SHOULD BE >= 3!!!", 180, rectY - 60); + text("PLEASE, PRESS RESET BUTTON!!!", 180, rectY - 40); - } + accept_me = false; + return; } - synchronized private void calcPolyOrientation() { - if (points.size() < 3) return; - - int index = 0; - Point pointOfIndex = points.get(0); - for (int i = 1; i < points.size(); i++) { - if (points.get(i).x < pointOfIndex.x) { - pointOfIndex = points.get(i); - index = i; - } else if (points.get(i).x == pointOfIndex.x && points.get(i).y > pointOfIndex.y) { - pointOfIndex = points.get(i); - index = i; - } - } + triangles.clear(); + int index = 1; - - Point prevPointOfIndex; - if (index == 0) - prevPointOfIndex = points.get(points.size() - 1); - else - prevPointOfIndex = points.get(index - 1); - Point v1 = new Point(pointOfIndex.x - prevPointOfIndex.x, pointOfIndex.y - prevPointOfIndex.y); - - Point succPointOfIndex; - if (index == points.size() - 1) - succPointOfIndex = points.get(0); - else - succPointOfIndex = points.get(index + 1); + while (points.size() > 3) { - - int res = succPointOfIndex.x * v1.y - succPointOfIndex.y * v1.x + v1.x * prevPointOfIndex.y - v1.y * prevPointOfIndex.x; + if (isEar(points.get(getIndex(index, -1)), points.get(index), points.get(getIndex(index, 1)))) { + triangles.add(new Triangle(points.get(getIndex(index, -1)), points.get(index), points.get(getIndex(index, 1)))); + points.remove(points.get(index)); - isCw = (res <= 0 ? true : false); - - } - - - synchronized private boolean isEar(Point p1, Point p2, Point p3) { - - if (!(isConvex(p1, p2, p3))) return false; + index = getIndex(index, -1); - - for (int i = 0; i < nonconvexPoints.size(); i++) { - if (triangle.isInside(p1, p2, p3, nonconvexPoints.get(i))) - return false; + } else { + index = getIndex(index, 1); } - return true; } + triangles.add(new Triangle(points.get(0), points.get(1), points.get(2))); - - synchronized private boolean isConvex(Point p1, Point p2, Point p3) { - Point v = new Point(p2.x - p1.x, p2.y - p1.y); - int res = p3.x * v.y - p3.y * v.x + v.x * p1.y - v.y * p1.x; - return !((res > 0 && isCw) || (res <= 0 && !isCw)); - } - - - synchronized private int getIndex(int index, int offset) { - int newindex; - //System.out.println("size " + points.size() + " index:" + index + " offset:" + offset); - if (index + offset >= points.size()) - newindex = points.size() - (index + offset); - else { - if (index + offset < 0) - newindex = points.size() + (index + offset); - else - newindex = index + offset; - } - - return newindex; - } - - public void run() { - boolean stepbystep = true; - int pausetime = 1000; - - if (points.size() <= 3) return; + } - triangles.clear(); - int index = 1; + public List getTriangles() { + return triangles; + } - while (points.size() > 3) { - // step by step mode - then pause - if (stepbystep) { - try { - Thread.sleep(pausetime); - } catch (Exception ex) { - System.out.println(ex.toString()); - } - } +} +public class Triangle { - if (isEar(points.get(getIndex(index, -1)), points.get(index), points.get(getIndex(index, 1)))) { - - synchronized (this) { - triangles.add(new Triangle(points.get(getIndex(index, -1)), points.get(index), points.get(getIndex(index, 1)))); - } - - points.remove(points.get(index)); + // coordinates + private Point a; + private Point b; + private Point c; - index = getIndex(index, -1); + public Point getA() { + return a; + } - } else { - index = getIndex(index, 1); - } - } - - synchronized (this) { - triangles.add(new Triangle(points.get(0), points.get(1), points.get(2))); - } - finish = true; - } + public Point getB() { + return b; + } - synchronized public Vector getTriangles() { - return triangles; - } + public Point getC() { + return c; + } + public Triangle() { } + public Triangle(Point a, Point b, Point c) { + this.a = a; + this.b = b; + this.c = c; + } + public boolean isInside(Point x, Point y, Point z, Point p) { + Point v1 = new Point(y.x - x.x, y.y - x.y); + Point v2 = new Point(z.x - x.x, z.y - x.y); + double det = v1.x * v2.y - v2.x * v1.y; + Point tmp = new Point(p.x - x.x, p.y - x.y); + double lambda = (tmp.x * v2.y - v2.x * tmp.y) / det; + double mue = (v1.x * tmp.y - tmp.x * v1.y) / det; + return (lambda > 0 && mue > 0 && (lambda + mue) < 1); + } +}