We are about to switch to a new forum software. Until then we have removed the registration on this forum.
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 :)