实现凸多边形的Cyrus Beck算法

时间:2018-11-13 08:10:55

标签: c++ opengl graphics computational-geometry

我尝试对凸多边形实施Cyrus Beck算法。我遇到的问题是找到法向矢量的方向,因为它们必须始终指向内部。为了解决这个问题,我找到了质心的坐标,该质心始终位于凸多边形内。在我测试的情况下,这种方法似乎可行。这是傻瓜证明吗?有更好的选择吗?

CyrusBeck.cpp

#include<iostream>
#include<cmath>
#include"graphics.hpp"

#define P pair<double, double>

vector<P> V, N;
P C;

double dot(P A, P B){
  return (A.first*B.first + A.second*B.second);
}

P operator - (const P &A, const P &B){
  return make_pair(A.first-B.first, A.second-B.second);
}

P operator + (const P &A, const P &B){
  return make_pair(A.first+B.first, A.second+B.second);
}

P operator * (const P &A, const double t){
  return make_pair(t*A.first, t*A.second);
}

void computeNormal(int n = V.size()){
  double m;
  P prev = V[0];
  double x=-1, y;
  for(int i=1; i<n; ++i){
    m = -(V[i].first-prev.first)/(V[i].second-prev.second);
    P d = V[i]-prev;
    int lr=1, tb=1;
    if(V[i-1].first>C.first)
      lr = -1;
    if(V[i-1].second>C.second)
      tb=-1;
    N[i-1].first = lr*abs(cos(atan(m)));
    N[i-1].second = tb*abs(sin(atan(m)));
    prev = V[i];
  }
  m = -(V[0].first-prev.first)/(V[0].second-prev.second);
  int lr=1, tb=1;
  if(V[n-1].first>C.first)
    lr = -1;
  if(V[n-1].second>C.second)
    tb=-1;
  N[n-1].first = lr*abs(cos(atan(m)));
  N[n-1].second = tb*abs(sin(atan(m)));
}

int check(P A, P B, int n){
    P p = B - V[0];
    double d1 = dot(p, N[0]);
    P q = A - V[0];
    double d2 = dot(q, N[0]);
    if(d1<0&&d2<0)
      return 0;
    if(d1>=0&&d2>=0)
      return 1;
    return -1;
}

void Clip(P A, P B, double &tE, double &tL, int n = V.size()){
  tE = 0; tL = 1;
  for(int i=0; i<n; ++i){
    double d = dot((B-A), N[i]);
    if(d==0)
      continue;
    double t = dot((A-V[i]), N[i])/dot((A-B), N[i]);
    if(d>0&&t>tE)
      tE = t;
    else if(d<0&&t<tL)
      tL = t;
  }
}

void display(){
  cout<<"Enter the number of vertices\n";
  int n;  cin>>n;
  V.resize(n);
  N.resize(n);
  cout<<"Enter the coordinates of the vertices in order\n";
  for(int i=0; i<n; ++i){
    cin>>V[i].first>>V[i].second;
    C = C + V[i];
  }
  C.first/=n; C.second/=n;
  drawPolygon(V, n, white);
  glutSwapBuffers();
  cout<<"Enter the co-ordinates of the line(4)\n";
  P A, B;
  cin>>A.first>>A.second>>B.first>>B.second;
  drawLine(A.first, A.second, B.first, B.second, red);
  glutSwapBuffers();
  char c = '\0';
  while(c!='Y'&&c!='y'){
    cout<<"Clip? (Y/N)\n";
    cin>>c;
  }
  computeNormal();
  int chk = check(A, B, n);
  glClearColor(0, 0, 0, 1);
  glClear(GL_COLOR_BUFFER_BIT);
  drawPolygon(V, n, white);
  if(chk==-1){
    double tE, tL;
    Clip(A, B, tE, tL);
    if(tE>tL)
      chk = 0;
    else{
      P E = A + (B-A)*tE;
      P L = A + (B-A)*tL;
      drawLine(E.first, E.second, L.first, L.second, blue);
    }
  }
  if(chk==1)
    drawLine(A.first, A.second, B.first, B.second, blue);
  glutSwapBuffers();
}

int main(int argc, char *argv[]){
  init(&argc, argv);
}

graphics.hpp

#ifndef GRAPHICS_H
#define GRAPHICS_H

#include<GL/glut.h>
#include<vector>
using namespace std;

extern float red[3];
extern float green[3];
extern float blue[3];
extern float white[3];

int roundoff(double x);
void init(int* argc, char** argv);
void putpixel(float x, float y, float z, float a[3]);
void drawLine(double x1, double y1, double x2, double y2, float a[3]);
void drawRectangle(double x1, double y1, double x2, double y2, float a[3]);
void drawPolygon(vector<pair<double, double>> v, int n, float a[3]);
void MatrixMultiply(vector<vector<double>> &mat1, vector<vector<double>> &mat2, vector<vector<double>> &res,
                    int n, int m, int r);
void display();

#endif

graphics.cpp

#include<iostream>
#include"graphics.hpp"

float red[3] = { 1.0f, 0.0f, 0.0f };
float green[3] = { 0.0f, 1.0f, 0.0f };
float blue[3] = { 0.0f, 0.0f, 1.0f };
float white[3] = { 1.0f, 1.0f, 1.0f };

int roundoff(double x){
  if (x < 0.0)
    return (int)(x - 0.5);
  else
    return (int)(x + 0.5);
}

void init(int *argc, char** argv){
  glutInit(argc, argv);                 // Initialize GLUT
  glutInitWindowSize(800, 800);   // Set the window's initial width & height
  glutInitWindowPosition(0, 0); // Position the window's initial top-left corner
  glutCreateWindow("Graphics"); // Create a window with the given title
  gluOrtho2D(0, 800, 0, 800);  //  specifies the projection matrix
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
  glClear(GL_COLOR_BUFFER_BIT);         // Clear the color buffer (background)
  glutDisplayFunc(display); // Register display callback handler for window re-paint
  glutMainLoop();           // Enter the event-processing loop
}

void putpixel(float x, float y, float z, float a[3]){
  glPointSize(2);
  glBegin(GL_POINTS); // HERE THE POINTS SHOULD BE CREATED
  glColor3f(a[0], a[1], a[2]);
  glVertex3f(x, y, z);    //  Specify points in 3d plane
  std::cout<<x<<' '<<y<<' '<<z<<'\n';
  glEnd();
}

void drawLine(double x1, double y1, double x2, double y2, float a[3]){
  glLineWidth(2.5); 
  glColor3f(a[0], a[1], a[2]);
  glBegin(GL_LINES);
    glVertex2d(x1, y1);
    glVertex2d(x2, y2);
  glEnd();
}

void drawRectangle(double x1, double y1, double x2, double y2, float a[3]){
  glColor3f(a[0], a[1], a[2]);
  glRectd(x1, y1, x2, y2);
}

void drawPolygon(vector<pair<double, double>> v, int n, float a[3]){
  glColor3f(a[0], a[1], a[2]);
  glBegin(GL_POLYGON);
    for(int i=0; i<n; ++i)
      glVertex2d(v[i].first, v[i].second);
  glEnd();
}

void MatrixMultiply(vector<vector<double>> &mat1, vector<vector<double>> &mat2, vector<vector<double>> &res,
                    int n, int m, int r){ 
  int x, i, j;  
  for(i = 0; i < n; i++){ 
    for (j = 0; j < r; j++){ 
      res[i][j] = 0; 
      for (x = 0; x < m; x++){
        res[i][j] += mat1[i][x] * mat2[x][j]; 
      } 
    } 
  }
}

0 个答案:

没有答案