Random Polygons on sphere (mesh- ToxicLibs)

edited November 2015 in Library Questions

hi, i had saved this sketch from the old forum (this is in processing-2 but it works with processing-3 as well)

import toxi.geom.*;
import toxi.geom.mesh2d.*;
import toxi.geom.mesh.*;
import toxi.processing.*;

import processing.opengl.*;
import java.util.*;

// radius of the root delaunay triangle which encompasses (MUST) all other points
float DELAUNAY_SIZE = 10000;
// sphere radius
float EARTH_RADIUS=300;

ToxiclibsSupport gfx;

// Perimeter polygon
Polygon2D poly;

// list of 2D triangles (intermediate result of Delaunay triangulation)
List<Triangle2D> tesselated;

// 3D mesh
TriangleMesh mesh;

// grid resolution for adding inliers
int res=1;

void setup() {
  size(1024, 768, OPENGL);
  smooth();
  gfx = new ToxiclibsSupport(this);

  // create a regular polygon by sampling a circle
  poly=new Polygon2D();

  poly.add(new Vec2D(width/2, height/2-100));
  poly.add(new Vec2D( (width/2)-100, (height/2)+100));
  poly.add(new Vec2D((width/2)-100, (height/2)+200));
  poly.add(new Vec2D(width/2+200, (height/2)+200));//
  poly.add(new Vec2D(width/2, height/2-100));
  poly.add(new Vec2D( (width/2)+300, (height/2)+100));
  poly=new Circle(30).toPolygon2D(20);

  tesselated=tesselatePolygon(poly, res);
  poly.flipVertexOrder();
  print(poly.isClockwise());
}

void draw() {
  background(255);
  // switch between 2D/3D modes
  if (mesh==null) {
    translate(width/2, height/2);
    noFill();
    // draw original poly
    pushStyle();
    stroke(255, 0, 0);
    strokeWeight(2);
    gfx.polygon2D(poly);
    popStyle();
    // then tesselated version to compare
    stroke(0, 0, 255);


    pushStyle();
    beginShape(TRIANGLES);
    for (Triangle2D t : tesselated) {
      gfx.triangle(t);
    }  
    endShape();
    popStyle();
  } else {
    lights();
    translate(width/2, height/2, 0);
    rotateX(mouseY*0.01);
    rotateY(mouseX*0.01);
    fill(255);
    noStroke();
    // sphere(EARTH_RADIUS*0.99);
    fill(255, 0, 64);
    stroke(0);
    gfx.mesh(mesh, true, 20);
  }
}

void keyPressed() {
  if (key>='0' && key<='9') {
    res=(key-'0')*2;
    // resample polygon with new resolution
    tesselated=tesselatePolygon(poly, res);
    if (mesh!=null) {
      mesh=buildSurfaceMesh(tesselated, EARTH_RADIUS);
    }
  }
  if (key=='r') {
    // randomize position of polygon (coords are in lon/lat space)
    poly=new Circle(new Vec2D(random(-180, 180), random(-30, 30)), 30).toPolygon2D(30);
    tesselated=tesselatePolygon(poly, res);
    // update mesh, if needed...
    if (mesh!=null) {
      mesh=buildSurfaceMesh(tesselated, EARTH_RADIUS);
    }
  }
  if (key=='m') {
    // toggle between 2d/3d
    if (mesh==null) {
      mesh=buildSurfaceMesh(tesselated, EARTH_RADIUS);
    } else {
      mesh=null;
    }
  }
}

// tesselates polygon with additional/optional inliers
List<Triangle2D> tesselatePolygon(Polygon2D poly, int num) {
  List<Triangle2D> result=new ArrayList<Triangle2D>();
  // a Voronoi diagram relies on a Delaunay triangulation behind the scenes
  Voronoi voronoi = new Voronoi(DELAUNAY_SIZE);
  // add perimeter points
  for (Vec2D v : poly.vertices) {
    voronoi.addPoint(v);
  }
  // add random inliers
  for (Vec2D v : createInsidePoints (poly, num)) {
    voronoi.addPoint(v);
  }
  // get filtered delaunay triangles:
  // ignore any triangles which share a vertex with the initial root triangle
  // or whose centroid is outside the polygon
  for (Triangle2D t : voronoi.getTriangles ()) {
    if (abs(t.a.x)!=DELAUNAY_SIZE && abs(t.a.y)!=DELAUNAY_SIZE) {
      if (poly.containsPoint(t.computeCentroid())) {
        result.add(t);
      }
    }
  }
  return result;
}

// compute bounding rect of a polygon
// (will be unnecessary from toxiclibs-0021 onwards)
Rect computeBounds(Polygon2D poly) {
  Vec2D min=Vec2D.MAX_VALUE.copy();
  Vec2D max=Vec2D.MIN_VALUE.copy();
  for (Vec2D v : poly.vertices) {
    min.minSelf(v);
    max.maxSelf(v);
  }
  return new Rect(min, max);
}

// create list of grid points within polygon
List<Vec2D> createInsidePoints(Polygon2D poly, int num) {
  List<Vec2D> points=new ArrayList<Vec2D>(num);
  Rect bounds=computeBounds(poly);
  for (int y=0; y<num; y++) {
    float yy=map(y, 0, num, bounds.getTop(), bounds.getBottom());
    for (int x=0; x<num; x++) {
      Vec2D p=new Vec2D(map(x, 0, num, bounds.getLeft(), bounds.getRight()), yy);
      if (poly.containsPoint(p)) {
        points.add(p);
      }
    }
  }
  return points;
}

// converts a list of 2D triangles into a 3D mesh on a sphere
TriangleMesh buildSurfaceMesh(List<Triangle2D> tris, float radius) {
  TriangleMesh mesh=new TriangleMesh();
  for (Triangle2D t : tris) {
    // ensure all triangles have same orientation
    if (!t.isClockwise()) {
      t.flipVertexOrder();
    }
    // lat/lon => spherical => cartesian mapping
    Vec3D a = new Vec3D(radius, radians(t.a.x), radians(t.a.y)).toCartesian();
    Vec3D b = new Vec3D(radius, radians(t.b.x), radians(t.b.y)).toCartesian();
    Vec3D c = new Vec3D(radius, radians(t.c.x), radians(t.c.y)).toCartesian();
    // add 3D triangle to mesh
    mesh.addFace(a, b, c);
  }
  // needed for smooth shading
  mesh.computeVertexNormals();
  return mesh;
}

to my understanding, it creates a polygon from sampling a circle, tesselates the polygon by a resolution and and then creates a mesh for each triangle..it works nice.. howerer if i try to apply this to any other random polygon it does not work..if you comment out 2 lines

tesselated=tesselatePolygon(poly, res);

and the the first translate inside draw()

   void draw() {
      background(255);
      // switch between 2D/3D modes
      if (mesh==null) {
        translate(width/2, height/2);
        noFill();
        // draw original poly

you get the same version but with a custom polygon with 5 points, if you press 'm' it draws the 3D version on a sphere. it is a mess

the question: does anyone know why it does not work on a regular polygon?? to my understanding both versions are just triangles that are converted into mesh?

what i am trying to do is convert this

into a 3D on sphere,but it creates the same mesh when applying the buildSurfaceMesh on each tesselated polygon (each country is a polygon)

any ideas or thoughts on why this my not work on custom polygons greatly appreciated :)

Tagged:
Sign In or Register to comment.