Created
May 20, 2017 15:38
-
-
Save m13253/96e21f4620008f4bf4880c0830b12651 to your computer and use it in GitHub Desktop.
Program to draw a rotating tag cloud, using Processing schetchbook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
TagCloud.pde | |
Copyright (C) 2017 StarBrilliant <m13253@hotmail.com> | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
import java.util.*; | |
final String names[] = { | |
"北京", "天津", "河北", "山西", "内蒙古", "辽宁", "吉林", "黑龙江", "上海", | |
"江苏", "浙江", "安徽", "福建", "江西", "山东", "河南", "湖北", "湖南", | |
"广东", "广西", "海南", "重庆", "四川", "贵州", "云南", "西藏", "陕西", | |
"甘肃", "青海", "宁夏", "新疆", "香港", "澳门", "台湾" | |
}; | |
double radians(double degrees) { | |
return degrees * Math.PI / 180; | |
} | |
int blendColors(int c1, int c2, double factor) { | |
double lc1 = Math.pow(c1 / 255.0, 1/2.2); | |
double lc2 = Math.pow(c2 / 255.0, 1/2.2); | |
double lc = lc1 * factor + lc2 * (1-factor); | |
double c = Math.pow(lc, 2.2) * 255; | |
int ic = (int) Math.round(c); | |
return Math.max(Math.min(ic, 255), 0); | |
} | |
double[] matmul(double[] a, double[] b) { | |
double[] result = new double[9]; | |
for(int i = 0; i < 3; ++i) { | |
for(int j = 0; j < 3; ++j) { | |
for(int k = 0; k < 3; ++k) { | |
result[i * 3 + j] += a[i * 3 + k] * b[k * 3 + j]; | |
} | |
} | |
} | |
return result; | |
} | |
void drawPentagon(float x, float y, float r) { | |
beginShape(); | |
vertex(x, y - r); | |
vertex(x + 0.9510565162951535*r, y - 0.30901699437494745*r); | |
vertex(x + 0.5877852522924731*r, y + 0.8090169943749475*r); | |
vertex(x - 0.5877852522924731*r, y + 0.8090169943749475*r); | |
vertex(x - 0.9510565162951535*r, y - 0.30901699437494745*r); | |
endShape(CLOSE); | |
} | |
class Stage { | |
float width; | |
float height; | |
float radius; | |
double[] rot; | |
ArrayList<PentagonObject> items; | |
Stage(float width, float height, float radius) { | |
this.width = width; | |
this.height = height; | |
this.radius = radius; | |
rot = new double[9]; | |
rot[0] = 1; | |
rot[4] = 1; | |
rot[8] = 1; | |
items = new ArrayList<PentagonObject>(); | |
textFont(createFont("Microsoft YaHei UI", 256)); | |
textAlign(CENTER, TOP); | |
} | |
void addDemoGrid() { | |
for(int i = -90; i <= 90; i += 30) { | |
for(int j = -180; j < 180; j += 30) { | |
String coord = String.format("(%d,%d)", i, j); | |
PentagonObject item = new PentagonObject(this, coord); | |
item.lat = (float) (radians(i)); | |
item.lon = (float) (radians(j)); | |
items.add(item); | |
} | |
} | |
} | |
void addItem(String name) { | |
PentagonObject item = new PentagonObject(this, name); | |
item.lat = (float) Math.asin(Math.random()); | |
if(Math.random() < 0.5) { | |
item.lat = -item.lat; | |
} | |
item.lon = (float) (Math.random() * 2 * Math.PI - Math.PI); | |
items.add(item); | |
} | |
void distribute() { | |
int rows = 4; | |
} | |
void rotate(double x, double y) { | |
double sinx = Math.sin(x); | |
double cosx = Math.cos(x); | |
double[] rotx = new double[] { | |
cosx, 0, sinx, | |
0, 1, 0, | |
-sinx, 0, cosx | |
}; | |
double[] tmp = matmul(rotx, rot); | |
double siny = Math.sin(y); | |
double cosy = Math.cos(y); | |
double[] roty = new double[] { | |
1, 0, 0, | |
0, cosy, -siny, | |
0, siny, cosy | |
}; | |
rot = matmul(roty, tmp); | |
double norm = 0; | |
for(int i = 0; i < 9; ++i) { | |
norm += rot[i] * rot[i]; | |
} | |
norm = Math.sqrt(norm / 3); | |
for(int i = 0; i < 9; ++i) { | |
rot[i] /= norm; | |
} | |
} | |
void draw() { | |
for(PentagonObject i : items) { | |
i.calcPersp(radians(90)); | |
} | |
Collections.sort(items); | |
for(PentagonObject i : items) { | |
i.draw(); | |
} | |
} | |
} | |
class PentagonObject implements Comparable<PentagonObject> { | |
Stage stage; | |
String name; | |
float lat; | |
float lon; | |
float perspX; | |
float perspY; | |
float perspZ; | |
float perspS; | |
PentagonObject(Stage stage, String name) { | |
this.stage = stage; | |
this.name = name; | |
} | |
void calcPersp(double fov) { | |
double focal = stage.width / (2 * Math.tan(fov / 2)); | |
double xx = stage.radius * Math.cos(lat) * Math.sin(lon); | |
double yy = - stage.radius * Math.sin(lat); | |
double zz = - stage.radius * Math.cos(lat) * Math.cos(lon); | |
double xr = stage.rot[0] * xx + stage.rot[1] * yy + stage.rot[2] * zz; | |
double yr = stage.rot[3] * xx + stage.rot[4] * yy + stage.rot[5] * zz; | |
double zr = stage.rot[6] * xx + stage.rot[7] * yy + stage.rot[8] * zz; | |
double z = zr + stage.radius; | |
double depth = z + focal; | |
double scale = focal / depth; | |
double x = xr * scale; | |
double y = yr * scale; | |
perspX = (float) (x + stage.width / 2); | |
perspY = (float) (y + stage.height / 2); | |
perspZ = (float) z; | |
perspS = (float) scale; | |
} | |
@Override | |
public int compareTo(PentagonObject that) { | |
if(this.perspZ < that.perspZ) { | |
return 1; | |
} else if(this.perspZ == that.perspZ) { | |
return 0; | |
} else { | |
return -1; | |
} | |
} | |
void draw() { | |
double alpha = 1 - perspZ / (2 * stage.radius); | |
fill( | |
blendColors(0x00, 0xfd, alpha), | |
blendColors(0x00, 0xf6, alpha), | |
blendColors(0x00, 0xe3, alpha) | |
); | |
drawPentagon(perspX, perspY, 10 * perspS); | |
fill( | |
blendColors(0x26, 0xfd, alpha), | |
blendColors(0x8b, 0xf6, alpha), | |
blendColors(0xd2, 0xe3, alpha) | |
); | |
textSize(20 * perspS); | |
text(name, perspX, perspY + 20 * perspS); | |
} | |
} | |
Stage stage; | |
void setup() { | |
size(480, 640); | |
stage = new Stage(480, 640, 320); | |
// stage.addDemoGrid(); | |
for(String name : names) { | |
stage.addItem(name); | |
} | |
} | |
void draw() { | |
background(0xfd, 0xf6, 0xe3); | |
noStroke(); | |
stage.draw(); | |
} | |
void mouseDragged() { | |
stage.rotate((pmouseX - mouseX) / stage.radius, (mouseY - pmouseY) / stage.radius); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment