topical media & game development

talk show tell print

basic-visual-03-lineconics.c

? / basic-visual-03-lineconics.c


  // ------------------------------------------------------------------------
  // This program is complementary material for the book:
  //
  // Frank Nielsen
  //
  // Visual Computing: Geometry, Graphics, and Vision
  //
  // ISBN: 1-58450-427-7
  //
  // Charles River Media, Inc.
  //
  //
  // All programs are available at www.charlesriver.com/visualcomputing/
  //
  // You may use this program for ACADEMIC and PERSONAL purposes ONLY. 
  //
  //
  // The use of this program in a commercial product requires EXPLICITLY
  // written permission from the author. The author is NOT responsible or 
  // liable for damage or loss that may be caused by the use of this program. 
  //
  // Copyright (c) 2005. Frank Nielsen. All rights reserved.
  // ------------------------------------------------------------------------
   
  // ------------------------------------------------------------------------
  // File: lineconics.cpp
  // 
  // Description: Rasterize conics, line conis and dual conics
  // ------------------------------------------------------------------------
  
  include <stdafx.h>
  include <fstream>
  include <math.h>
  
  using namespace std;
  
  void SaveImagePPM(unsigned char * data, int w, int h, char * file);
  
  class Vector3D{
  public: double x,y,w;
  
                  Vector3D::Vector3D()
                  {x=y=0; w=1.0;}
  
                  Vector3D::Vector3D(double px, double py, double pw)
                  {
                  x=px;
                  y=py;
                  w=pw;
                  }
  
                  inline PerspectiveDivision()
                  {
                          if (w!=0) {x/=w; y/=w; w=1.0;}
                  }
  };
  
  class Vector6D{
  public: double a,b,c,d,e,f;
  
                  Vector6D::Vector6D(double pa, double pb, double pc, double pd,  double pe, double pf)
                  {
                  a=pa;
                  b=pb;
                  c=pc;
                  d=pd;
                  e=pe;
                  f=pf;
                  }
  };
  
  Vector6D conic(1,0.8,2,-0.5,-0.3,-0.5);
  
  typedef double matrix3x3[3][3];
  
  void InverseMatrix(matrix3x3 m,matrix3x3& minv)
  {
    double t4  = m[0][0] * m[1][1];
    double t6  = m[0][0] * m[1][2];
    double t8  = m[0][1] * m[1][0];
    double t10 = m[0][2] * m[1][0];
    double t12 = m[0][1] * m[2][0];
    double t14 = m[0][2] * m[2][0];
    double t17 = 1.0 / ( t4 * m[2][2] - t6  * m[2][1] - t8  * m[2][2] + 
                        t10 * m[2][1] + t12 * m[1][2] - t14 * m[1][1]);
  
    minv[0][0] =  (m[1][1] * m[2][2] - m[1][2] * m[2][1]) * t17;
    minv[0][1] = -(m[0][1] * m[2][2] - m[0][2] * m[2][1]) * t17;
    minv[0][2] =  (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * t17;
    minv[1][0] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]) * t17;
    minv[1][1] =  (m[0][0] * m[2][2] - t14) * t17;
    minv[1][2] = -(t6 - t10) * t17;
    minv[2][0] =  (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * t17;
    minv[2][1] = -(m[0][0] * m[2][1] - t12) * t17;
    minv[2][2] =  (t4 - t8) * t17;
  }
  
  void ConicToMatrix(Vector6D C,matrix3x3 &m)
  {
  m[0][0]=C.a;m[0][1]=0.5*C.b;m[0][2]=0.5*C.d;
  m[1][0]=0.5*C.b;m[1][1]=C.c;m[1][2]=0.5*C.e;
  m[2][0]=0.5*C.d;m[2][1]=0.5*C.e;m[2][2]=C.f;
  }
  
  void MatrixToConic(matrix3x3 m, Vector6D& C)
  {
  C.a=m[0][0];
  C.b=2*m[0][1];
  C.c=m[1][1];
  C.d=2*m[0][2];
  C.e=2*m[1][2];
  C.f=m[2][2];
  }
  
  define W 1024        
  define H 1024
  
  double thick=4.0/(double)W;
  
  double minx=-1.0;
  double maxx=1.3;
  
  double miny=-1.0;
  double maxy=1.3;
  
  inline double ToX(double x)
  {
  return minx+(maxx-minx)*x/(double)W;
  }
  
  inline double  ToY(double y)
  {
  return miny+(maxy-miny)*y/(double)H;
  }
  
  inline double Circle(Vector3D p)
  {
  return p.x*p.x+p.y*p.y-0.5*0.5;
  }
  
  inline double ConicFunction(Vector6D C, Vector3D p)
  {double res;
  
  res= C.a*p.x*p.x+C.b*p.x*p.y+C.c*p.y*p.y+C.d*p.x*p.w+C.e*p.y*p.w+C.f*p.w*p.w;
  
  return res;
  }
  
  // dot product
  inline double LineFunction(Vector3D l, Vector3D p)
  {
  return l.x*p.x+l.y*p.y+l.w*p.w;
  }
  
  char filename[256]="draw.ppm";
  unsigned char * img;
  
  // Draw a line
  void DrawLine(Vector3D l, double th)
  {
  int i,j,index;
  
  for(i=0;i<H;i++)
          for(j=0;j<W;j++)
          {
          Vector3D point(ToX(j),ToY(i),1);
          index=3*(i*W+j);
  
          if (fabs(LineFunction(l,point))<th) 
                  {        
                          img[index]=img[index+1]=img[index+2]=0;
                  }
          }
  }
  
  int _tmain(int argc, _TCHAR* argv[])
  {
  int i,j,index;
  Vector3D p;
  
  cout<<"Visual Computing: Geometry, Graphics, and Vision (ISBN:1-58450-427-7)"<<endl;
  cout<<"Demo program\n\n"<<endl;
  
  img=new unsigned char [3*W*H];
  
  for(i=0;i<H;i++)
          for(j=0;j<W;j++)
          {
                  index=3*(i*W+j);img[index]=img[index+1]=img[index+2]=255;
          }
  
          static first=false;
          matrix3x3 m,minv;
  
          
          //inverse conic
  
          ConicToMatrix(conic, m);
          InverseMatrix(m,minv);
          MatrixToConic(minv,conic);
  
          cout<<"Conics coefficients:"<<endl;
          cout<<conic.a<<" "<<conic.b<<" "<<conic.c<<" "<<conic.d<<" "<<conic.e<<" "<<conic.f<<endl;
  
  minx=3*minx;maxx=3*maxx;miny=3*miny;maxy=3*maxy;
  thick=3*thick;
  
  cout<<"Be patient this takes a while..."<<endl;
  
  for(i=0;i<H;i++)
  {
          if ((i%100)==0) {cout<<100.0*i/(double)H<<"% done..."<<endl;}
          for(j=0;j<W;j++)
          {
          Vector3D point(ToX(j),ToY(i),1);
          index=3*(i*W+j);
  
          
          
  if (fabs(ConicFunction(conic,point))<3*thick) 
                  {
                          // Point on the conic
                          img[index]=img[index+1]=img[index+2]=0;
  
                          point.PerspectiveDivision();
  
                  // p=Cx
                  p.x=conic.a*point.x+0.5*conic.b*point.y+0.5*conic.d*point.w;
                  p.y=0.5*conic.b*point.x+conic.c*point.y+0.5*conic.e*point.w;
                  p.w=0.5*conic.d*point.x+0.5*conic.e*point.y+conic.f*point.w;
  
                  //if (!first){first=true;
                  if (rand()%50==0)
                          DrawLine(p, thick/2.0);
                  //}                
                  }
                  
          }
          }
  
  SaveImagePPM(img,W,H,filename);
  
  char line[256];
  cout<<"Press Return key"<<endl;
  gets(line);
  
          return 0;
  }
  
  // Save a PPM Image
  void SaveImagePPM(unsigned char * data, int w, int h, char * file)
  {
          ofstream OUT(file, ios::binary);
          if (OUT){
      OUT << "P6" << endl << w << ' ' << h << endl << 255 << endl;
          OUT.write((char *)data, 3*w*h);
          OUT.close();}
  }
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.