float selRad = 5f;
void mousePressed() {
int selectedSizeBefore = selected.size();
selected.clear();
if (!beginNewPolygon) {
for (Polygon poly : polygons) {
boolean gotVec = false;
for (Vector vec : poly.vertices) {
if (dist(mouseX, mouseY, vec.x, vec.y) < selRad) {
selected.add(vec); gotVec = true;
}
}
if (!gotVec) {
if (poly.pointInPolygon((float)mouseX, (float)mouseY)) {
for (Vector vec : poly.vertices) selected.add(vec);
selected.add(poly); //solver.reset(grid);
}
}
}
} else {
if (newPolygon == null) newPolygon = new Polygon();
newPolygon.vertices.add(new Vector(mouseX, mouseY));
}
//if (selected.size() == 0 && selectedSizeBefore != 0) solver.reset(grid);
}
void mouseDragged() {
for (Object sel : selected) {
if (sel.getClass() == Vector.class) {
Vector vec = (Vector)sel;
vec.add(new PVector((float)(mouseX - pmouseX), (float)(mouseY - pmouseY)));
solver.reset(grid);
}
}
}
void keyTyped() {
if (key == 'n') beginNewPolygon = true;
if (key == 'd') DM += 1 - DM*2;
if (key == DELETE || key == BACKSPACE) {
Object remove = null;
for (Object sel : selected) {
if (sel.getClass() == Polygon.class) {polygons.remove(sel); solver.reset(grid); remove = sel;}
}
if (remove != null) selected.remove(remove);
}
}
public class Polygon {
ArrayList<Vector> vertices;
public Polygon() {
vertices = new ArrayList<Vector>();
}
public Polygon(Vector... vec) {
vertices = new ArrayList<Vector>();
for (Vector vv : vec) {
vertices.add(vv);
vv.polygon = this;
}
}
public void display() {
strokeWeight(2);
if (selected.contains(this)) {fill(255, 0, 0, 100); stroke(255, 0, 0);}
else {fill(180, 100); stroke(0);}
if (vertices.size() > 0) {
beginShape();
for (Vector vec : vertices) vertex(vec.x, vec.y);
vertex(vertices.get(0).x, vertices.get(0).y);
endShape();
for (Vector vec : vertices) vec.display();
}
}
public boolean pointInPolygon(float x, float y) {
return pointInPolygon(new Vector(x, y));
}
public boolean pointInPolygon(Vector iVec1) {
Vector iVec2 = new Vector(iVec1.x + random(200) + 10000, iVec1.y + random(-200, 200));
int ic = 0;
if (vertices.size() > 2) {
Vector prevVec = vertices.get(vertices.size() - 1);
for (Vector vec : vertices) {
if (intersection(iVec1, iVec2, vec, prevVec) != null) ic++;
prevVec = vec;
}
}
if (round((float)ic / 2) == (float)ic / 2) return false;
else return true;
}
}
public Vector intersection(Vector l1v1, Vector l1v2, Vector l2v1, Vector l2v2) {
float x1 = l1v1.x;
float y1 = l1v1.y;
float x2 = l1v2.x;
float y2 = l1v2.y;
float x3 = l2v1.x;
float y3 = l2v1.y;
float x4 = l2v2.x;
float y4 = l2v2.y;
float tol = 0.01f;
float d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (d == 0) return null;
float xr = ((x3 - x4) * (x1 * y2 - y1 * x2) -
(x1 - x2) * (x3 * y4 - y3 * x4)) / d;
float yr = ((y3 - y4) * (x1 * y2 - y1 * x2) -
(y1 - y2) * (x3 * y4 - y3 * x4)) / d;
if (dist(x1, y1, xr, yr) + dist(x2, y2, xr, yr) - dist(x1, y1, x2, y2) < tol &&
dist(x3, y3, xr, yr) + dist(x4, y4, xr, yr) - dist(x3, y3, x4, y4) < tol)
return new Vector(xr, yr);
else return null;
}
public class Vector extends PVector {
Polygon polygon;
float value = 0;
int count = 0;
float[] vValue;
PVector dir;
public Vector() {
super();
dir = new PVector();
vValue = new float[32];
}
public Vector(float x, float y) {
super(x, y);
dir = new PVector();
vValue = new float[32];
}
public void display() {
pushStyle();
if (selected.contains(this)) {
stroke(255, 0, 0);
strokeWeight(8);
} else {
stroke(0);
strokeWeight(5);
}
point(x, y);
popStyle();
}
}
public class Solver {
public Solver() {}
PVector nullV = new PVector(1, 0);
float highest = 0;
float lowest = 0;
int intermediate = 10000;
void update(Vector[][] grid) {
for (int i = 0; i < intermediate; i++) {
int i1 = (int)random(grid.length);
int j1 = (int)random(grid[0].length);
float bBxMin = 100000;
float bByMin = 100000;
float bBxMax = 0;
float bByMax = 0;
int i2, j2;
i2 = (int)random(grid.length);
j2 = (int)random(grid[0].length);
while (i1 == i2 && j1 == j2) {
i2 = (int)random(grid.length);
j2 = (int)random(grid[0].length);
}
Vector iVec1 = grid[i1][j1];
Vector iVec2 = grid[i2][j2];
boolean intersecting = false;
for (Polygon poly : polygons) {
Vector prevVec = poly.vertices.get(poly.vertices.size() - 1);
for (Vector vec : poly.vertices) {
if (intersection(iVec1, iVec2, vec, prevVec) != null) {intersecting = true; break;}
prevVec = vec;
}
if (intersecting) break;
}
iVec1.count++;
iVec2.count++;
if (!intersecting) {
iVec1.value++;
PVector iV1a = new PVector((iVec2.x - iVec1.x) * vectorScale,
(iVec2.y - iVec1.y) * vectorScale);
iVec1.dir.add(iV1a);
float aa1 = angleBetween(nullV, iV1a);
aa1 += PI;
aa1 /= 2 * PI;
iVec1.vValue[(int)(aa1 * iVec1.vValue.length)] += iVec1.mag() * vectorScale;
iVec2.value++;
PVector iV2a = new PVector((iVec1.x - iVec2.x) * vectorScale,
(iVec1.y - iVec2.y) * vectorScale);
iVec2.dir.add(iV2a);
float aa2 = angleBetween(nullV, iV2a);
aa2 += PI;
aa2 /= 2 * PI;
iVec2.vValue[(int)(aa2 * iVec2.vValue.length)] += iVec2.mag() * vectorScale;
}
}
highest = 0;
lowest = 100000;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
highest = max(highest, grid[i][j].value / ((float)grid[i][j].count + 1));
lowest = min(lowest, grid[i][j].value / ((float)grid[i][j].count + 1));
}
}
}
void reset(Vector[][] grid) {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
grid[i][j].value = 0;
grid[i][j].vValue = new float[32];
grid[i][j].count = 0;
grid[i][j].dir = new PVector();
}
}
highest = 0;
lowest = 0;
}
}
float angleBetween(PVector vv1, PVector vv2) {
float factor = vv1.x * vv2.y - vv1.y * vv2.x;
if (factor != 0) factor /= PApplet.abs(factor);
PVector newV1 = new PVector();
newV1.set(vv1);
newV1.normalize();
PVector newV2 = new PVector();
newV2.set(vv2);
newV2.normalize();
return PVector.angleBetween(newV1, newV2) * factor;
}
int colorGradient(float value, int[] colGrad) {
float d = value;
int ci = floor(d*((float)colGrad.length - 1));
int cj = ci + 1;
value = PApplet.abs(value);
if (ci < colGrad.length - 1) {
float d1 = d * (float)(colGrad.length - 1) - (float)ci;
float d2 = d *(float)(colGrad.length - 1) - (float)cj;
int a = (int)(d1 * alpha(colGrad[cj]) + abs(d2) * alpha(colGrad[ci]));
int r = (int)(d1 * red(colGrad[cj]) + abs(d2) * red(colGrad[ci]));
int g = (int)(d1 * green(colGrad[cj]) + abs(d2) * green(colGrad[ci]));
int b = (int)(d1 * blue(colGrad[cj]) + abs(d2) * blue(colGrad[ci]));
a = a << 24;
r = r << 16;
g = g << 8;
return a | r | g | b;
} else {
return colGrad[colGrad.length - 1];
}
}
/**
* Nils Seifert & Michael Muehlhaus
*
* www.muehlseife.de
*
* you can select & move the Vectors and Polygons
* for drawing a new polygon, hold 'n'
**/
ArrayList<Polygon> polygons;
ArrayList<Object> selected;
Vector[][] grid;
int gridSize = 20;
int gridBorder = 0;
float vectorScale = 0.3f;
int DM = 0;
Polygon newPolygon;
boolean beginNewPolygon = false;
Solver solver;
int[] colors = {color(0, 0, 255), color(255, 0, 255), color(255, 0, 0), color(255, 255, 0), color(0, 255, 0)};
void setup() {
size(800, 600, JAVA2D); smooth();
solver = new Solver();
grid = new Vector[(int)(width / gridSize) - 2 * gridBorder / gridSize + 1]
[(int)(height / gridSize) - 2 * gridBorder / gridSize + 1];
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
grid[i][j] = new Vector(i * gridSize + gridBorder, j * gridSize + gridBorder);
}
}
polygons = new ArrayList<Polygon>();
selected = new ArrayList<Object>();
polygons.add(new Polygon(new Vector(160, 60),
new Vector(160, 120),
new Vector(340, 120),
new Vector(340, 60)));
polygons.add(new Polygon(new Vector(160, 260),
new Vector(160, 420),
new Vector(240, 420),
new Vector(240, 260)));
polygons.add(new Polygon(new Vector(420, 240),
new Vector(420, 470),
new Vector(580, 470),
new Vector(580, 240)));
}
void vecPoint(float x, float y, float sz) {
beginShape();
vertex(x - sz / 2, y - sz / 2);
vertex(x - sz / 2, y + sz / 2);
vertex(x + sz / 2, y + sz / 2);
vertex(x + sz / 2, y - sz / 2);
vertex(x - sz / 2, y - sz / 2);
endShape();
}
void vecArrow(float x, float y, float dirX, float dirY, float sz) {
PVector dirN = new PVector(dirX, dirY);
dirN.normalize();
PVector vertical = new PVector(-dirN.y, dirN.x);
PVector dir = new PVector(dirX, dirY);
beginShape();
vertex(x + dir.x + dirN.x * sz, y + dir.y + dirN.y * sz); //spitze
vertex(x + vertical.x * sz, y + vertical.y * sz);
vertex(x - dirN.x * sz, y - dirN.y * sz);
vertex(x - vertical.x * sz, y - vertical.y * sz);
vertex(x + dir.x + dirN.x * sz, y + dir.y + dirN.y * sz);
endShape();
}
void vecCompass(PVector pos, float[] values, float scale) {
beginShape();
for (int i = 0; i < values.length; i++) {
vertex(pos.x + cos((float)i / 32f * PI * 2f + PI) * (values[i] * scale + 2),
pos.y + sin((float)i / 32f * PI * 2f + PI) * (values[i] * scale + 2));
}
vertex(pos.x + cos((float)0 / 32f * PI * 2f + PI) * (values[0] * scale + 2),
pos.y + sin((float)0 / 32f * PI * 2f + PI) * (values[0] * scale + 2));
endShape();
}
void draw() {
background(255);
solver.update(grid);
pushStyle();
noStroke(); //stroke(0); strokeWeight(1);
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
fill(colorGradient((grid[i][j].value / ((float)grid[i][j].count +1) - solver.lowest) / (solver.highest - solver.lowest), colors));
if (DM == 0) {
vecArrow(grid[i][j].x, grid[i][j].y, grid[i][j].dir.x / ((float)grid[i][j].count +1), grid[i][j].dir.y / ((float)grid[i][j].count +1), 2);
//vecCompass(grid[i][j], grid[i][j].vValue, 1 / ((float)grid[i][j].count +1));
} else vecPoint(grid[i][j].x, grid[i][j].y, 0.25 * (sqrt(sq(grid[i][j].dir.x / ((float)grid[i][j].count +1)) + sq(grid[i][j].dir.y / ((float)grid[i][j].count +1))) + 4));
}
}
popStyle();
for (Polygon poly : polygons) {poly.display();}
if (!keyPressed || (keyPressed && key != 'n')) {
if (beginNewPolygon = true) {
if (newPolygon != null) if (newPolygon.vertices.size() > 2) {polygons.add(newPolygon); solver.reset(grid);}
}
beginNewPolygon = false; newPolygon = null;
}
textAlign(LEFT, TOP);
if (beginNewPolygon) {
fill(0); text("draw polygon by clicking left mouse button", 4, 4);
if (newPolygon != null) if (newPolygon.vertices.size() > 0) {
strokeWeight(1.5);
noFill(); stroke(0, 125);
beginShape();
for (Vector vec : newPolygon.vertices) vertex(vec.x, vec.y);
vertex(mouseX, mouseY);
vertex(newPolygon.vertices.get(0).x, newPolygon.vertices.get(0).y);
endShape();
}
} else {fill(0); text("hold 'n' for drawing new polygon", 4, 4);}
text("press 'd' for changing display mode", 4, 16);
}
visibility analysis on a 2D map
there are 2 different display modes (1: vectors, 2: vector scales) you can change them by pressing 'd'
you can select & move the Vectors and Polygons
for drawing a new polygon, hold 'n'
for deleting polygons, select them and press the delete key