我有一系列由一系列点定义的参考路径。给定起始点和给定方向上的附加点,我需要有效地将点创建的路径分成两个不同的路径(方向),允许我独立地绘制和使用两个路径。以下屏幕截图显示了8个路径示例。 "起点"就是那个带有白色圆圈的人。如果你从起点到下一个点定位自己,那么红色圆圈建议的路径总是应该是"右边"由给定点定义的路径。
在屏幕中,路径2,3,5,6和7是正确的。在路径1,4和8中,基本上当路径从右侧开始并向左移动时,并行路径点的位置是正确的,但它们在某些情况下交换(绿色在哪里为红色)应该是,等)。
我以某种方式滥用atan2()
(我认为)来获得正确的角度和/或计算位置。对于第一点和最后一点,我计算与相邻点的角度,并绘制红色和绿色路径指向与该角度成90度的偏移。对于路径中间的点,我查看前一点的角度和下一点的角度,并以一定的角度放置点。
如何正确计算这些角度,以便在参考线的正确一侧获得红色和绿色平行路径点?
问题可能发生在TestLine::calculateParallelPoints()
。
我使用了openFrameworks 0.90。这是代码:
ofApp.h
#pragma once
#include "ofMain.h"
#include "TestLine.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
int sectors_wide;
int sectors_tall;
vector<TestLine> testLines;
};
ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofSetBackgroundColorHex(0x000000);
sectors_wide = 4;
sectors_tall = 2;
TestLine t1 = TestLine(0,0,sectors_wide,sectors_tall);
t1.raw_points.push_back(ofPoint(0.9,0.5));
t1.raw_points.push_back(ofPoint(0.8,0.6));
t1.raw_points.push_back(ofPoint(0.7,0.4));
t1.raw_points.push_back(ofPoint(0.6,0.6));
t1.raw_points.push_back(ofPoint(0.5,0.4));
t1.raw_points.push_back(ofPoint(0.4,0.4));
t1.raw_points.push_back(ofPoint(0.3,0.5));
testLines.push_back(t1);
TestLine t2 = TestLine(1,0,sectors_wide,sectors_tall);
t2.raw_points.push_back(ofPoint(0.3,0.5)); //
t2.raw_points.push_back(ofPoint(0.4,0.4));
t2.raw_points.push_back(ofPoint(0.5,0.4));
t2.raw_points.push_back(ofPoint(0.6,0.6));
t2.raw_points.push_back(ofPoint(0.7,0.4));
t2.raw_points.push_back(ofPoint(0.8,0.6));
t2.raw_points.push_back(ofPoint(0.9,0.5));
testLines.push_back(t2);
TestLine t3 = TestLine(2,0,sectors_wide,sectors_tall);
t3.raw_points.push_back(ofPoint(0.1,0.2));
t3.raw_points.push_back(ofPoint(0.7,0.4));
t3.raw_points.push_back(ofPoint(0.4,0.45));
t3.raw_points.push_back(ofPoint(0.6,0.5));
t3.raw_points.push_back(ofPoint(0.9,0.9));
testLines.push_back(t3);
TestLine t4 = TestLine(3,0,sectors_wide,sectors_tall);
t4.raw_points.push_back(ofPoint(0.5,0.5));
t4.raw_points.push_back(ofPoint(0.9,0.5));
t4.raw_points.push_back(ofPoint(0.5,0.1));
t4.raw_points.push_back(ofPoint(0.1,0.1));
t4.raw_points.push_back(ofPoint(0.1,0.8));
t4.raw_points.push_back(ofPoint(0.8,0.6));
testLines.push_back(t4);
TestLine t5 = TestLine(0,1,sectors_wide,sectors_tall);
t5.raw_points.push_back(ofPoint(0.4,0.4));
t5.raw_points.push_back(ofPoint(0.6,0.5));
t5.raw_points.push_back(ofPoint(0.8,0.4));
testLines.push_back(t5);
TestLine t6 = TestLine(1,1,sectors_wide,sectors_tall);
t6.raw_points.push_back(ofPoint(0.7,0.1));
t6.raw_points.push_back(ofPoint(0.2,0.3));
t6.raw_points.push_back(ofPoint(0.7,0.5));
testLines.push_back(t6);
TestLine t7 = TestLine(2,1,sectors_wide,sectors_tall);
t7.raw_points.push_back(ofPoint(0.2,0.1));
t7.raw_points.push_back(ofPoint(0.7,0.3));
t7.raw_points.push_back(ofPoint(0.2,0.5));
testLines.push_back(t7);
TestLine t8 = TestLine(3,1,sectors_wide,sectors_tall);
t8.raw_points.push_back(ofPoint(0.8,0.5));
t8.raw_points.push_back(ofPoint(0.6,0.4));
t8.raw_points.push_back(ofPoint(0.4,0.5));
testLines.push_back(t8);
// Convert raw points to real points in the grid space
for (int i = 0; i < testLines.size(); i++) {
testLines[i].processRawPoints();
testLines[i].calculateParallelPoints();
}
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
ofSetBackgroundColorHex(0x000000);
ofSetColor(255, 255, 255);
for (int i = 0; i < testLines.size(); i++) {
testLines[i].displayTestLine();
}
}
TestLine.h
#include "ofMain.h"
class TestLine {
public:
TestLine(float _x, float _y, int _sec_wide, int _sec_tall);
void displayTestLine();
void calculateParallelPoints();
void processRawPoints();
float x_coord;
float y_coord;
float x_min;
float x_max;
float y_min;
float y_max;
vector<float> angles;
vector<ofPoint> raw_points;
vector<ofPoint> points;
vector<ofPoint> forward_points;
vector<ofPoint> reverse_points;
ofPolyline line;
ofPolyline forward_line;
ofPolyline reverse_line;
};
TestLine.cpp
#include "TestLine.h"
TestLine::TestLine(float _x, float _y, int _sec_wide, int _sec_tall){
x_coord = _x;
y_coord = _y;
int w = ofGetWindowWidth();
int h = ofGetWindowHeight();
float allowed_w = (float)w / _sec_wide;
float allowed_h = (float)h / _sec_tall;
x_min = x_coord * allowed_w;
x_max = x_min + allowed_w;
y_min = y_coord * allowed_h;
y_max = y_min + allowed_h;
}
void TestLine::calculateParallelPoints(){
for (int i = 0; i < points.size(); i++) {
if (i == 0) {
ofVec2f v2 = points[i];
ofVec2f v1 = points[i+1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << "Start: " << angle << endl;
}
if (i > 0 && i < points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float back_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
v2 = points[i];
v1 = points[i+1];
float front_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
float final_angle = (back_angle + front_angle) / 2;
cout << "BACK ANGLE: " << back_angle << ", FRONT ANGLE: " << front_angle << ", FINAL ANGLE: " << final_angle << endl;
float prev_x = points[i-1].x;
float prev_y = points[i-1].y;
float this_x = points[i].x;
float this_y = points[i].y;
float next_x = points[i+1].x;
float next_y = points[i+1].y;
angles.push_back(final_angle);
}
if (i == points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << "End: " << angle << endl;
}
line.addVertex(points[i]);
}
// Now using the points and the angles to calculate the forward and reverse points
for (int i = 0; i < points.size(); i++) {
float forward_angle = angles[i] + 90;
float reverse_angle = angles[i] - 90;
// cout << forward_angle << ", " << reverse_angle << endl;
float forward_x = points[i].x + cos(ofDegToRad(forward_angle)) * 8;
float forward_y = points[i].y + sin(ofDegToRad(forward_angle)) * 8;
forward_points.push_back(ofPoint(forward_x, forward_y));
float reverse_x = points[i].x + cos(ofDegToRad(reverse_angle)) * 8;
float reverse_y = points[i].y + sin(ofDegToRad(reverse_angle)) * 8;
reverse_points.push_back(ofPoint(reverse_x, reverse_y));
}
}
void TestLine::processRawPoints(){
for (int i = 0; i < raw_points.size(); i++) {
float newx = ofMap(raw_points[i].x, 0, 1, x_min, x_max);
float newy = ofMap(raw_points[i].y, 0, 1, y_min, y_max);
points.push_back(ofPoint(newx,newy));
}
}
void TestLine::displayTestLine(){
ofSetColor(128,128,128);
line.draw();
ofSetColor(255, 255, 255);
ofDrawCircle(points[0].x, points[0].y, 3);
ofSetColor(255, 0, 0);
for (int i = 0; i < forward_points.size(); i++) {
ofDrawCircle(forward_points[i].x, forward_points[i].y, 2);
}
ofSetColor(0, 255, 0);
for (int i = 0; i < reverse_points.size(); i++) {
ofDrawCircle(reverse_points[i].x, reverse_points[i].y, 2);
}
}
答案 0 :(得分:0)
我最终用几个条件语句来处理这个问题,尽管我觉得用trig来处理它可能是更好的方法。这是修改后的TestLine.cpp
文件。
<强> TestLine.cpp 强>
#include "TestLine.h"
TestLine::TestLine(float _x, float _y, int _sec_wide, int _sec_tall){
x_coord = _x;
y_coord = _y;
int w = ofGetWindowWidth();
int h = ofGetWindowHeight();
float allowed_w = (float)w / _sec_wide;
float allowed_h = (float)h / _sec_tall;
x_min = x_coord * allowed_w;
x_max = x_min + allowed_w;
y_min = y_coord * allowed_h;
y_max = y_min + allowed_h;
}
void TestLine::calculateParallelPoints(){
for (int i = 0; i < points.size(); i++) {
if (i == 0) {
ofVec2f v2 = points[i];
ofVec2f v1 = points[i+1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << endl;
cout << "Start: " << angle << endl;
}
if (i > 0 && i < points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float back_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
v2 = points[i];
v1 = points[i+1];
float front_angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
float final_angle = (back_angle + front_angle) / 2; // back_angle + front_angle
float prev_x = points[i-1].x;
float prev_y = points[i-1].y;
float this_x = points[i].x;
float this_y = points[i].y;
float next_x = points[i+1].x;
float next_y = points[i+1].y;
// Here is the addition that addressed the problem.
if ((prev_x > this_x && prev_y <= this_y && next_x < this_x && next_y < this_y) ||
(prev_x > this_x && prev_y > this_y && next_x < this_x && next_y >= this_y)) {
final_angle += 180;
}
cout << "BACK ANGLE: " << back_angle << ", FRONT ANGLE: " << front_angle << ", FINAL ANGLE: " << final_angle << endl;
angles.push_back(final_angle);
}
if (i == points.size() - 1) {
ofVec2f v1 = points[i];
ofVec2f v2 = points[i-1];
float angle = ofRadToDeg(atan2(v1.y - v2.y, v1.x - v2.x));
angles.push_back(angle);
cout << "End: " << angle << endl << endl;
}
line.addVertex(points[i]);
}
// Now using the points and the angles to calculate the forward and reverse points
for (int i = 0; i < points.size(); i++) {
float forward_angle = angles[i] + 90;
float reverse_angle = angles[i] - 90;
// cout << forward_angle << ", " << reverse_angle << endl;
float forward_x = points[i].x + cos(ofDegToRad(forward_angle)) * 8;
float forward_y = points[i].y + sin(ofDegToRad(forward_angle)) * 8;
forward_points.push_back(ofPoint(forward_x, forward_y));
float reverse_x = points[i].x + cos(ofDegToRad(reverse_angle)) * 8;
float reverse_y = points[i].y + sin(ofDegToRad(reverse_angle)) * 8;
reverse_points.push_back(ofPoint(reverse_x, reverse_y));
}
}
void TestLine::processRawPoints(){
for (int i = 0; i < raw_points.size(); i++) {
float newx = ofMap(raw_points[i].x, 0, 1, x_min, x_max);
float newy = ofMap(raw_points[i].y, 0, 1, y_min, y_max);
points.push_back(ofPoint(newx,newy));
}
}
void TestLine::displayTestLine(){
ofSetColor(128,128,128);
line.draw();
ofSetColor(255, 255, 255);
ofDrawCircle(points[0].x, points[0].y, 3);
ofSetColor(255, 0, 0);
for (int i = 0; i < forward_points.size(); i++) {
ofDrawCircle(forward_points[i].x, forward_points[i].y, 2);
}
ofSetColor(0, 255, 0);
for (int i = 0; i < reverse_points.size(); i++) {
ofDrawCircle(reverse_points[i].x, reverse_points[i].y, 2);
}
}