From f18f74ca2d4d0781e18a8f0b16a3c74d88aad3d2 Mon Sep 17 00:00:00 2001 From: Subrata Saha Date: Sun, 30 Nov 2014 19:24:28 -0500 Subject: [PATCH] Create polygon_triangulation.pde --- .../polygon_triangulation.pde | 494 ++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 polygon_triangulation/polygon_triangulation.pde diff --git a/polygon_triangulation/polygon_triangulation.pde b/polygon_triangulation/polygon_triangulation.pde new file mode 100644 index 0000000..2c0fc32 --- /dev/null +++ b/polygon_triangulation/polygon_triangulation.pde @@ -0,0 +1,494 @@ +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; + + void setup() { + size(600, 600); + f = createFont("Arial", 16, true); + background(102); + list = new CopyOnWriteArrayList(); + circle_list = new CopyOnWriteArrayList(); + rectX = width / 2 - rectSize; + rectY = (height - 30) - rectSize / 2; + polygonTriangulation = new PolygonTriangulation(); + ellipseMode(CENTER); + } + + boolean overRect(int x, int y, int width, int height) { + if (mouseX >= x && mouseX <= x + width && + mouseY >= y && mouseY <= y + height) { + return true; + } else { + 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; + } + + 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; + + } + + void draw() { + + if (mousePressed == true) { + if (overRect(rectX + threshold, rectY, rectSize, rectSize)) { + list = new ArrayList(); + circle_list = new ArrayList(); + 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(); + + 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); + point_list.add(point); + } + + Point point = new Point(); + point.setLocation(firstX1, firstY1); + point_list.add(point); + + polygonTriangulation = new PolygonTriangulation(point_list); + (new Thread(polygonTriangulation)).start(); + 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; + + 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; + } + } + + for (i = 0; i < list.size(); i++) { + MyClass mc = list.get(i); + line(mc.x1, mc.y1, mc.x2, mc.y2); + } + + for (i = 0; i < circle_list.size(); i++) { + CircleCoords circleCoords = circle_list.get(i); + ellipse(circleCoords.x1, circleCoords.y1, circleCoords.circleSize, circleCoords.circleSize); + fill(#9AB8B9); + } + + rect(rectX, rectY, rectSize, rectSize); + fill(#9AB8B9); + rect(rectX + threshold, rectY, rectSize, rectSize); + 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 MyClass { + + public float x1; + public float y1; + public float x2; + public float y2; + + public MyClass(float x1, float y1, float x2, float y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + } + + 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 Triangle { + + // coordinates + private Point a; + private Point b; + private Point c; + + public Point getA() { + return a; + } + + public Point getB() { + return b; + } + + 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 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); + + 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; + + 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 class PolygonTriangulation implements Runnable { + + private Vector points; + private Vector nonconvexPoints; + private Vector triangles; + private Triangle triangle; + + private boolean isCw; + + public PolygonTriangulation() { + } + + public PolygonTriangulation(Vector points) { + this.points = new Vector(); + for (int i = 0; i < points.size(); i++) + this.points.add(new Point(points.get(i))); + + nonconvexPoints = new Vector(); + triangles = new Vector(); + triangle = new Triangle(); + + calcPolyOrientation(); + calcNonConvexPoints(); + } + + 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); + } + + } + } + + 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; + } + } + + + 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 = succPointOfIndex.x * v1.y - succPointOfIndex.y * v1.x + v1.x * prevPointOfIndex.y - v1.y * prevPointOfIndex.x; + + isCw = (res <= 0 ? true : false); + + } + + + synchronized private boolean isEar(Point p1, Point p2, Point p3) { + + if (!(isConvex(p1, p2, p3))) return false; + + + for (int i = 0; i < nonconvexPoints.size(); i++) { + if (triangle.isInside(p1, p2, p3, nonconvexPoints.get(i))) + return false; + } + return true; + } + + + 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; + + while (points.size() > 3) { + + // step by step mode - then pause + if (stepbystep) { + try { + Thread.sleep(pausetime); + } catch (Exception ex) { + System.out.println(ex.toString()); + } + } + + + 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)); + + index = getIndex(index, -1); + + } else { + index = getIndex(index, 1); + } + } + + synchronized (this) { + triangles.add(new Triangle(points.get(0), points.get(1), points.get(2))); + } + finish = true; + } + + synchronized public Vector getTriangles() { + return triangles; + } + + } + + + +