如何计算角度以创建矢量偏移以定义平行路径?

时间:2015-12-16 21:07:03

标签: c++ math openframeworks

我有一系列由一系列点定义的参考路径。给定起始点和给定方向上的附加点,我需要有效地将点创建的路径分成两个不同的路径(方向),允许我独立地绘制和使用两个路径。以下屏幕截图显示了8个路径示例。 "起点"就是那个带有白色圆圈的人。如果你从起点到下一个点定位自己,那么红色圆圈建议的路径总是应该是"右边"由给定点定义的路径。

在屏幕中,路径2,3,5,6和7是正确的。在路径1,4和8中,基本上当路径从右侧开始并向左移动时,并行路径点的位置是正确的,但它们在某些情况下交换(绿色在哪里为红色)应该是,等)。

enter image description here

我以某种方式滥用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);
    }
}

1 个答案:

答案 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);
    }
}