polygon.c++ 7.3 KB
#include "polygon.h"

void polygon::_init_normal_(void) {
    if(vl && count>0) {
        for(unsigned i=0; i<count; i++) {
            center[O_X]+=(*vl)[content[i]][O_X];
            center[O_Y]+=(*vl)[content[i]][O_Y];
            center[O_Z]+=(*vl)[content[i]][O_Z];
        }
    
        center[X]=center[O_X]/=count;
        center[Y]=center[O_Y]/=count;
        center[Z]=center[O_Z]/=count;
        center[W]=center[O_W]=1;
    
        normal=center+
               (((*vl)[content[1]]-(*vl)[content[0]])|
               ((*vl)[content[count-1]]-(*vl)[content[0]])).norm();
    }
    else {
        center=vertex();
        normal=vertex();
    }
}

void polygon::transform(const Mmn<double>& tm, int p) {
    for(unsigned i=0; i<count; i++) {
        (*vl)[content[i]].transform(tm, p);
    }

    transform_normal(tm, p);
}

void polygon::transform_normal(const Mmn<double>& tm, int p) {
    center.transform(tm, p);
    normal.transform(tm, p);
}

void polygon::reset(void) {
/*    for(unsigned i=0; i<count; i++) {
        (*vl)[content[i]].reset();
    }*/

    center.reset();
    normal.reset();
}

/**
 * \brief Clipping gegen eine vordere Z-Ebene
 *
 * Dieser Algorithmus clippt das polygon gegen eine vordere Z-Ebene
 *
 * \param this Das ungeclippte unprojezierte Polygon.
 * \return ein geclipptes Polygon.
 */
polygon polygon::clip_front_z(double min_Z) const {
   container<unsigned> clip;
   polygon ret;

   for(unsigned j=0; j<(*this).card(); j++) {
      double x0=(*vl)[container<unsigned>::operator[](j)][X],
             y0=(*vl)[container<unsigned>::operator[](j)][Y],
             z0=(*vl)[container<unsigned>::operator[](j)][Z],
             x1=(*vl)[container<unsigned>::operator[]((j+1)%(*this).card())][X],
             y1=(*vl)[container<unsigned>::operator[]((j+1)%(*this).card())][Y],
             z1=(*vl)[container<unsigned>::operator[]((j+1)%(*this).card())][Z];

      // Wenn beide drin sind den zweiten übernehmen.
      if(z0>min_Z && z1>min_Z)
         // Nur P2 nach clip übernehmen
         clip[clip.card()]=
            container<unsigned>::operator[]((j+1)%(*this).card());

      // Wenn nur P2 drin ist 
      if(z0<=min_Z && z1>min_Z) {
         // Schnittpunkt berechnen und nach temp übernehmen
         unsigned idx=(*vl).card();
         double t=(min_Z-z0)/(z1-z0);
         double x=x0+t*(x1-x0);
         double y=y0+t*(y1-y0);

         // neuen Vertex zur Vertexliste.
         (*vl)[idx]=vertex(x, y, min_Z, COORD);

         // und ins geclippte polygon
         clip[clip.card()]=idx;
         // und P2 ins geclippte polygon
         clip[clip.card()]=
            container<unsigned>::operator[]((j+1)%(*this).card());
      }

      // Wenn nur P1 drin ist 
      if(z0>min_Z && z1<=min_Z) {
         // Schnittpunkt berechnen und nach temp übernehmen
         unsigned idx=(*vl).card();
         double t=(min_Z-z1)/(z0-z1);
         double x=x1+t*(x0-x1);
         double y=y1+t*(y0-y1);

         // neuen Vertex zur Vertexliste.
         (*vl)[idx]=vertex(x, y, min_Z, COORD);

         // und ins geclippte polygon
         clip[clip.card()]=idx;
      }
   }

   // Das geclippte Polygon zurückliefern.
   ret=polygon(clip, vl);
   ret.set_id(id);
   return ret;
}

/** 
* \brief Clippings nach Sutherland-Hodgman
*
* Cliped das Polygon an dem Polygon p. Es wird ein neues Polygon
* erzeugt, das diesem Polygon innerhalb des Polygons p entspricht.
* Dieses neue Polygon nutzt die selbe Vertexliste.
*
* \param p Das Polygon an dem geclipped werden soll.
* \returns Ein in p passendes Polygon.
*/
polygon polygon::clip_2d(const polygon& p) const {
  //! enth&auml;lt w&auml;hrend des clippings die aktuellen
  //! Vertex_listen indizies.
  container<unsigned> clip;

  // Zuerst Origialdaten sichern.
  clip=(container<unsigned>)*this;

  // Solange unbearbeitete Kanten im Clippolygon sind...
  for(unsigned i=0; i<p.card(); i++) {
     //! enth&auml;lt immer die neuen geclippten VL-Indizies
     container<unsigned> temp;

     //! Hole nächste Kante des Clippolygons und sichere sie als 
     //! Vektor. Diese ist definiert über die beiden Punkte 
     //! p[i] und p[(i+1)%p.card()]
     double x0=p[i][X],
            y0=p[i][Y],
            x1=p[(i+1)%p.card()][X],
            y1=p[(i+1)%p.card()][Y];

     // Jetzt muss zunaechst ein Vektor erzeugt werden der senkrecht
     // von der Kante ins Poligon zeigt 
     // chk=(X=P1.Y-P2.Y, Y=P2.X-P1.X, 0)
     vertex chk(y0-y1, x1-x0, 0, VEKTOR);

     // Solange Kanten nicht bearbeitet wurden
     for(unsigned j=0; j<clip.card(); j++) {
        //! hole nächste Kante aus clipped Prüfe ob Punkt1 und/oder 
        //! Punkt2 immerhalb des Clippolygons sind.
        //! Kante ist (*vl)[clip[j]] und (*vl)[clip[(j+1)%clip.count]]
        double x0s=(*vl)[clip[j]][X],
               y0s=(*vl)[clip[j]][Y],
               x1s=(*vl)[clip[(j+1)%clip.card()]][X],
               y1s=(*vl)[clip[(j+1)%clip.card()]][Y];

        //! Liegt der erste Punkt innerhalb des Clippolygons
        //! chk%(P1 - clipP1) > 0.05 und/oder
        double chk_p1=chk%((*vl)[clip[j]] - (*p.vl)[i]);
        //! liegt der zweite Punkt innerhalb des Clippolygons
        //! chk%(P2 - clipP1) > 0.05
        double chk_p2=chk%((*vl)[clip[(j+1)%clip.card()]] - 
                           (*p.vl)[i]);

        // 0.05 ist ein Epsilon um Ungenauigkeiten auszugleichen und
        // ganz sicher zu gehen das der Punkt wirklich innerhalb liegt.

        // Wenn beide drin sind
        if(chk_p1>0.05 && chk_p2>0.05)
            // Nur P2 nach temp übernehmen
            temp[temp.card()]=clip[(j+1)%clip.card()];

        // Wenn nur P1 drin ist 
        if(chk_p1>0.05 && chk_p2<=0.05) {
            // Schnittpunkt berechnen und nach temp übernehmen
            unsigned idx=(*vl).card();
            double x,y;

            x=x0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
              (((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(x1-x0);

            y=y0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
              (((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(y1-y0);

            // neuen Vertex zur Vertexliste.
            (*vl)[idx]=vertex(x, y, 0, COORD);

            temp[temp.card()]=idx;
        }

        // Wenn nur P2 drin ist
        if(chk_p1<=0.05 && chk_p2>0.05) {
            // Schnittpunkt berechnen und nach temp übernehmen
            unsigned idx=(*vl).card();
            double x,y;

            x=x0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
              (((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(x1-x0);

            y=y0+((((x1s-x0s)*(y0-y0s))+((y1s-y0s)*(x0s-x0)))/
              (((x1-x0)*(y1s-y0s))-((y1-y0)*(x1s-x0s))))*(y1-y0);

            // neuen Vertex zur Vertexliste.
            (*vl)[idx]=vertex(x, y, 0, COORD);

            temp[temp.card()]=idx;

            // P2 nach temp übernehmen
            temp[temp.card()]=clip[(j+1)%clip.card()];
        }

        // Wenn keiner drin ist
        // Nichts nach temp
     }

     // temp enth&auml;lt jetzt die aktuellen Vertexindizies,
     // f&uuml;r den n&auml;chsten durchlauf mu&szlig; clip
     // darauf gesetzt werden.
     clip=temp;
  }

  // Das geclippte Polygon zurückliefern.
  return polygon(clip, vl);
}

void polygon::project_2d(double lcx, double sw, double sh, 
                          double ph_ar, double sy, int p) {
    for(unsigned i=0; i<count; i++) {
        (*vl)[content[i]].project_2d(lcx, sw, sh, ph_ar, sy, p);
    }
}