如果你想绘制一个由交叉点组成的形状,那么你在beginShape()/endShape() 的正确轨道上。
目前,您似乎将所有点放在px、py:交点以及定义用于首先计算交点的线的点。
您可能希望将两者分开,例如一对数组仅用于定义线的点,另一对 x,y 数组仅用于交点。您只需要遍历相交的坐标即可在beginShape()/endShape() 之间放置vertex(x, y) 调用。这是您代码的修改版本来说明这个想法:
//Run in Processing.
//Press r to refresh.
//Top and bottom points are added to px and py when refreshed (filled in black).
//Intersection points are added to px and py when detected (filled in red).
int l = 4; //set number of lines
float[] r1 = new float[l];
float[] r2 = new float[l];
float[] px = {}; //array to save x positions of all possible points
float[] py = {}; //array to save y positions of all possible points
float[] ipx = {}; // array to save x for intersections only
float[] ipy = {}; // array to save y for intersections only
boolean added = false;
void setup(){
size(800, 800);
background(255);
refresh();
}
void draw(){
background(255);
stroke(0, 150, 255, 150);
strokeWeight(1);
for(int i=0; i < r1.length; i++){
for(int j=0; j < r1.length; j++){
if(i>j){
boolean hit = lineLine(r1[i], 0, r2[i], height, r1[j], 0, r2[j], height);
if (hit) stroke(255, 150, 0, 150);
else stroke(0, 150, 255, 150);
}
line(r1[i], 0, r2[i], height);
}
}
added = true;
// draw intersections
beginShape();
for(int i = 0 ; i < ipx.length; i++){
vertex(ipx[i], ipy[i]);
}
endShape();
//print(px.length);
//println(px.length, py.length);
}
//source: http://jeffreythompson.org/collision-detection/line-line.php
boolean lineLine(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
// calculate the distance to intersection point
float uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
float uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1));
// if uA and uB are between 0-1, lines are colliding
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
// optionally, draw a circle where the lines meet
float intersectionX = x1 + (uA * (x2-x1));
float intersectionY = y1 + (uA * (y2-y1));
fill(255,0,0);
noStroke();
ellipse(intersectionX,intersectionY, 20,20);
if(added==false){
px = append(px, intersectionX);
py = append(py, intersectionY);
// store intersections
ipx = append(ipx, intersectionX);
ipy = append(ipy, intersectionY);
}
return true;
}
return false;
}
void refresh(){
added = false;
px = new float[0];
py = new float[0];
ipx = new float[0];
ipy = new float[0];
r1 = new float[l];
r2 = new float[l];
px = append(px, 0);
py = append(py, 0);
px = append(px, 0);
py = append(py, height);
px = append(px, width);
py = append(py, 0);
px = append(px, width);
py = append(py, height);
for(int i=0; i< r1.length; i++){
r1[i] = random(800);
}
for(int i=0; i< r2.length; i++){
r2[i] = random(800);
}
for(int i=0; i < r1.length; i++){
stroke(0);
line(r1[i], 0, r2[i], height);
px = append(px, r1[i]);
py = append(py, 0);
px = append(px, r2[i]);
py = append(py, height);
}
}
void keyReleased() {
if (key == 'r') refresh();
}
请记住,这个 simlpy 按照计算交点的顺序绘制点。在美好的一天,你会得到这样的东西:
不排除多边形顶点顺序错误(缠绕)的可能性:
你也可能会得到凹多边形。
如果您只需要这些交点的外“外壳”,您可能需要 convex hull algorithm 之类的东西
至少在视觉上分割形状的一个选项可能是使用beginShape(TRIANGLES); 和endShape(CLOSE);,它应该遍历点并为每个坐标三元组绘制一个三角形,但是给定随机点和交叉点的数量您最终可能会丢失一两个三角形(例如 6 个点 = 2 个三角形、7 个点 = 2 个三角形和 1 个点且没有丢失对)
我唯一的其他注意事项是语法:数组可以开始使用,但您可能需要查看 ArrayList 和 PVector。这将允许您使用具有 x、y 属性的 PVector 实例的单个动态数组。
更新
总体上可以简化代码。如果我们取出与线交叉点相关的代码,我们可以摆脱类似的情况:
int l = 4; //set number of random lines
float[] r1 = new float[l]; // random x top
float[] r2 = new float[l]; // random x bottom
void setup() {
size(800, 800);
strokeWeight(3);
stroke(0, 150, 255, 150);
refresh();
}
void draw() {
background(255);
// random lines
for (int i=0; i < r1.length; i++) {
line(r1[i], 0, r2[i], height);
}
// borders
line(0, 0, width, 0);
line(width, 0, width - 1, height - 1);
line(0, height - 1, width - 1, height - 1);
line(0, 0, 0, height - 1);
}
void refresh() {
r1 = new float[l];
r2 = new float[l];
for (int i=0; i< r1.length; i++) {
r1[i] = random(800);
r2[i] = random(800);
}
}
void keyReleased() {
if (key == 'r') refresh();
}
如果我们要使用基本的Line 类并使用PVector 和ArrayList,我们可以将上面的内容重写为:
int numRandomLines = 4;
ArrayList<PVector> points = new ArrayList<PVector>();
void setup() {
size(800, 800);
stroke(0, 150, 255, 150);
strokeWeight(3);
refresh();
}
void refresh(){
// remove previous points
points.clear();
//add borders
points.add(new PVector(0, 0)); points.add(new PVector(width, 0));
points.add(new PVector(width, 0));points.add(new PVector(width - 1, height - 1));
points.add(new PVector(0, height - 1));points.add(new PVector(width - 1, height - 1));
points.add(new PVector(0, 0)); points.add(new PVector(0, height - 1));
// add random lines
for (int i=0; i< numRandomLines; i++) {
points.add(new PVector(random(800), 0)); points.add(new PVector(random(800), height));
}
}
void draw(){
background(255);
beginShape(LINES);
for(PVector point : points) vertex(point.x, point.y);
endShape();
}
void keyReleased() {
if (key == 'r') refresh();
}
并将一对点 (PVector) 分组到 Line 类中:
int numRandomLines = 4;
ArrayList<Line> lines = new ArrayList<Line>();
void setup() {
size(800, 800);
stroke(0, 150, 255, 150);
strokeWeight(3);
refresh();
}
void refresh(){
// remove previous points
lines.clear();
//add borders
lines.add(new Line(new PVector(0, 0), new PVector(width, 0)));
lines.add(new Line(new PVector(width, 0), new PVector(width - 1, height - 1)));
lines.add(new Line(new PVector(0, height - 1), new PVector(width - 1, height - 1)));
lines.add(new Line(new PVector(0, 0), new PVector(0, height - 1)));
// add random lines
for (int i=0; i< numRandomLines; i++) {
lines.add(new Line(new PVector(random(800), 0), new PVector(random(800), height)));
}
}
void draw(){
background(255);
for(Line line : lines) line.draw();
}
void keyReleased() {
if (key == 'r') refresh();
}
class Line{
PVector start;
PVector end;
Line(PVector start, PVector end){
this.start = start;
this.end = end;
}
void draw(){
line(start.x, start.y, end.x, end.y);
}
}
在这个阶段,要获得您的图表所描述的各个形状,我们可以作弊并使用像 OpenCV 这样的计算机视觉库。这当然是矫枉过正(因为我们将get() 一个PImage 绘图的副本,将其转换为OpenCV 图像)然后只需使用findContours() 来获取每个形状/轮廓。
回到原来的做法,线对线交集功能可以集成到Line类中:
int numRandomLines = 4;
ArrayList<Line> lines = new ArrayList<Line>();
ArrayList<PVector> intersections = new ArrayList<PVector>();
void setup() {
size(800, 800);
strokeWeight(3);
refresh();
}
void refresh(){
// remove previous points
lines.clear();
intersections.clear();
//add borders
lines.add(new Line(new PVector(0, 0), new PVector(width, 0)));
lines.add(new Line(new PVector(width, 0), new PVector(width - 1, height - 1)));
lines.add(new Line(new PVector(0, height - 1), new PVector(width - 1, height - 1)));
lines.add(new Line(new PVector(0, 0), new PVector(0, height - 1)));
// add random lines
for (int i=0; i< numRandomLines; i++) {
lines.add(new Line(new PVector(random(800), 0), new PVector(random(800), height)));
}
// compute intersections
int numLines = lines.size();
// when looping only check if lineA intersects lineB but not also if lineB intersects lineA (redundant)
for (int i = 0; i < numLines - 1; i++){
Line lineA = lines.get(i);
for (int j = i + 1; j < numLines; j++){
Line lineB = lines.get(j);
// check intersection
PVector intersection = lineA.intersect(lineB);
// if there is one, append the intersection point to the list
if(intersection != null){
intersections.add(intersection);
}
}
}
}
void draw(){
background(255);
stroke(0, 150, 255, 150);
// draw lines
for(Line line : lines) line.draw();
stroke(255, 0, 0, 150);
// draw intersections
for(PVector intersection : intersections) ellipse(intersection.x, intersection.y, 9, 9);
}
void keyReleased() {
if (key == 'r') refresh();
}
class Line{
PVector start;
PVector end;
Line(PVector start, PVector end){
this.start = start;
this.end = end;
}
void draw(){
line(start.x, start.y, end.x, end.y);
}
//source: http://jeffreythompson.org/collision-detection/line-line.php
//boolean lineLine(float this.start.x, float this.start.y, float this.end.x, float this.end.y,
//float other.start.x, float other.start.y, float other.end.x, float other.end.y) {
PVector intersect(Line other) {
// calculate the distance to intersection point
float uA = ((other.end.x-other.start.x)*(this.start.y-other.start.y) - (other.end.y-other.start.y)*(this.start.x-other.start.x)) / ((other.end.y-other.start.y)*(this.end.x-this.start.x) - (other.end.x-other.start.x)*(this.end.y-this.start.y));
float uB = ((this.end.x-this.start.x)*(this.start.y-other.start.y) - (this.end.y-this.start.y)*(this.start.x-other.start.x)) / ((other.end.y-other.start.y)*(this.end.x-this.start.x) - (other.end.x-other.start.x)*(this.end.y-this.start.y));
// if uA and uB are between 0-1, lines are colliding
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
// optionally, draw a circle where the lines meet
float intersectionX = this.start.x + (uA * (this.end.x-this.start.x));
float intersectionY = this.start.y + (uA * (this.end.y-this.start.y));
return new PVector(intersectionX, intersectionY);
}
return null;
}
}
下一步将是一个更复杂的算法,用于根据 x、y 位置(例如从上到下、从左到右)对点进行排序,迭代通过距离和角度比较第一个点与其余点并尝试工作如果具有最小距离和角度变化的连续点连接起来。
在网上快速浏览一下,我可以看到这样的算法,例如: