Skip to content

Instantly share code, notes, and snippets.

@m13253
Created May 20, 2017 15:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m13253/96e21f4620008f4bf4880c0830b12651 to your computer and use it in GitHub Desktop.
Save m13253/96e21f4620008f4bf4880c0830b12651 to your computer and use it in GitHub Desktop.
Program to draw a rotating tag cloud, using Processing schetchbook
/*
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