Geometrie/Promítání

Základní promítání

editovat

Promítání je transformace, která charakterizuje převod trojrozměrného objektu do dvojrozměrné reprezentace. Při promítání dochází ke ztrátě prostorové informace a tím i k možnému zkreslení názoru pozorovatele na skutečný tvar objektu. Proto jsou pro určité obory vybírány různé způsoby promítání a jsou doplňovány dalšími pravidly a postupy pro zvýšení reálného vjemu promítnutého objektu.

Obecně je promítání určeno středem (směrem) promítání a průmětnou. Pro oba druhy promítání lze volit umístění (obvykle) rovinné průmětny v prostoru. Rovinné projekce dělíme na dvě základní třídy - rovnoběžné(paralelní) a perspektivní.

Rovnoběžné promítání

editovat

Pokud je střed promítání nevlastní, mluvíme o rovnoběžném promítání a promítací přímky jsou určeny směrem promítání (všechny promítací paprsky mají stejný směr). Rovnoběžné promítání zachovává relativní velikost modelu.

 

Axonometrie

editovat

Patří mezi rovnoběžné promítání. Axonometrické promítání používá projekční roviny, které nejsou rovnoběžné s hlavními osami.

 

Perspektivní promítání

editovat

Pokud je střed promítání vlastní, mluvíme o perspektivním promítání a promítací přímky procházejí tímto středem promítání (promítací paprsky vycházejí z jediného bodu). Perspektivní promítání respektuje optický model, který vyjadřuje lidské vidění reálného světa. Modeluje proporcionální změnu předmětů při vzrůstající vzdálenosti od pozorovatele. Poskytuje dobrý prostorový vjem na rovinné průmětně.

 

Rozlišujeme tři základní druhy perspektivního promítání:

Jednoúběžníková perspektiva – je určena jedním středem promítání.

 

Dvouúběžníková perspektiva – je určena dvěma středy promítání.

 

Tříúběžníková perspektiva – je určena třemi středy promítání.

 

Algoritmizace

editovat

Každý druh rovinného promítání charakterizuje určitá transformační matice 4 x 4 pro transformaci bodů   ve scéně na body   v projekční rovině (v homogenních souřadnicích).

Vlastní rovnoběžné a perspektivní promítání lze jednotně popsat dále uvedeným postupem: - posunutí počátku soustavy souřadnic do bodu scény - projekce bodu scény do projekční roviny - zpětné posunutí soustavy souřadnic do původní pozice

Příslušné transformační matice:

- matice posunutí soustavy souřadnic

 

- matice středového promítání

 

- matice axonometrie

 

- matice jednoúběžníkové, dvouúběžníkové, tříúběžníkové projekce vzniknou vynásobením příslušné úbežníkové matice s promítací maticí (v programu použita matice středového promítání). Jednoúběžníková, dvouúběžníková a tříúběžníková matice

 
 
 

Kód v jazyce C#

editovat

Pomocné objekty a metody

editovat

Výpisy metod a objektů, které byly detailně popsány výše.

 public class Bod3D
 {
   private float[] souradnice; //pole pro uložení souřadnic
   public Bod3D()
      {   souradnice=new float[3]{0,0,0};   }
   public Bod3D(float x,float y, float z)
      {   souradnice=new float[3]{x,y,z};   }
   public float x {
      get {   return this.souradnice[0];   }
   }
   public float y {
      get {   return this.souradnice[1];   }
   }
   public float z {
      get {   return this.souradnice[2];   }
   }
   public float[] Souradnice {
      get {   return this.souradnice;   }
   }
   public Bod3D NasobeniSkalarem (float f) {
      return new Bod3D(this.x*f,this.y*f,this.z*f); 
   }
   public void Pricti(Bod3D b) {
      this.souradnice[0]+=b.x;this.souradnice[1]+=b.y;this.souradnice[2]+=b.z;
   }
   public float SkalarniSoucin(Bod3D vektor) {
      return souradnice[0]*vektor.souradnice[0]+
             souradnice[1]*vektor.souradnice[1]+
             souradnice[2]*vektor.souradnice[2]; 
   }
   public Bod3D VektorovySoucin(Bod3D v) {
      return new Bod3D(souradnice[1]*v.souradnice[2]-souradnice[2]*v.souradnice[1],
            souradnice[2]*v.souradnice[0]-souradnice[0]*v.souradnice[2],
            souradnice[0]*v.souradnice[1]-souradnice[1]*v.souradnice[0]);
   }
   public Bod3D Normalizovany() {
      float len=(float)Math.Sqrt(this.SkalarniSoucin(this));
      return new Bod3D(souradnice[0]/len,souradnice[1]/len,souradnice[2]/len);
   }
   public static Bod3D operator + (Bod3D a,Bod3D b) {
      return new Bod3D(a.souradnice[0]+b.souradnice[0],
         a.souradnice[1]+b.souradnice[1],a.souradnice[2]+b.souradnice[2]);
   }
   public static Bod3D operator - (Bod3D a,Bod3D b) {
      return new Bod3D(a.souradnice[0]-b.souradnice[0],
            a.souradnice[1]-b.souradnice[1],a.souradnice[2]-b.souradnice[2]);
   }
 }
 public class Hrana
 {
   private int ibod1;private int ibod2;
   private bool orientace;
   public Hrana()   {
      ibod1=0;ibod2=0;orientace=true;
   }
   public Hrana(int indexbodu1,int indexbodu2) {
      ibod1=indexbodu1;ibod2=indexbodu2;orientace=true;
   }
   public Hrana(int indexbodu1,int indexbodu2,bool klasickaorientace) {
      ibod1=indexbodu1;ibod2=indexbodu2;orientace=klasickaorientace;
   }
   public int indexbod1 {
      get {   return ibod1;   }
      set {   ibod1=value;   }
   }
   public int indexbod2 {
      get {   return ibod2;   }
      set {   ibod2=value;   }
   }
   public bool klasickaorientace {
      get {   return orientace;   }
      set {   orientace=value;   }
   }
 }
 public class Stena
 {
    public ArrayList hrany;
    public Stena(){
        hrany=new ArrayList(); 
    }
 }
 public class Matice
 {
   private float [,] hodnoty;
   private int radku;private int sloupcu;
   public Matice(int pocetRadku,int pocetSloupcu){
      hodnoty=new float [pocetRadku,pocetSloupcu];
      radku=pocetRadku;
      sloupcu=pocetSloupcu;
      for(int i=1;i<=radku;i++)
         for(int j=1;j<=sloupcu;j++)
            hodnoty[i-1,j-1]=0f;
   }
   public void NastavRS(int radek,int sloupec,float hodnota){
          hodnoty[radek-1,sloupec-1]=hodnota;   }
   public float VratRS(int radek,int sloupec){   
          return hodnoty[radek-1,sloupec-1];   }
   public int PocetRadku(){
          return radku;   }
   public int PocetSloupcu(){
          return sloupcu;   }
   public static Matice operator *(Matice m1, Matice m2)
      {   if(m1.PocetSloupcu()==m2.PocetRadku())
         {
            Matice ret;
            ret=new Matice(m1.PocetRadku(),m2.PocetSloupcu());
            for (int i=1;i<=m1.PocetRadku();i++)
            for(int j=1;j<=m2.PocetSloupcu();j++){
               float x;x=0;
               for (int k=1;k<=m1.PocetSloupcu();k++)
                  x+=m1.VratRS(i,k)*m2.VratRS(k,j);
               ret.NastavRS(i,j,x); 
            }
            return ret;
         }else return null;
      }
   public static Bod3D operator *(Bod3D bod, Matice m2){
      Matice m1=new Matice(1,4);
      m1.NastavRS(1,1,(float)(bod.x));m1.NastavRS(1,2,(float)(bod.y));
      m1.NastavRS(1,3,(float)(bod.z));m1.NastavRS(1,4,1f);
      Matice x=m1*m2;
      return new Bod3D(x.VratRS(1,1)/x.VratRS(1,4),
         x.VratRS(1,2)/x.VratRS(1,4),x.VratRS(1,3)/x.VratRS(1,4)); 
      }
 }

Matice promítání

editovat

Promítací matice pro popsané typy promítání.

 public class MaticePromitani
 {
      public MaticePromitani(){
      }
      private double StupenNaRadian(int stupen){
         return (double)(stupen*Math.PI/180);
      }
      public Matice Axonometrie(int azimut,int zenit){
         Matice pom;
         pom=new Matice(4,4);
         pom.NastavRS(1,1,(float)(-1f*(float)(Math.Sin(StupenNaRadian(azimut)))));  
         pom.NastavRS(2,1,(float)((float)(Math.Cos(StupenNaRadian(azimut)))));  
         pom.NastavRS(1,2,(-1f*(float)(Math.Cos(StupenNaRadian(azimut))) *
                   (float)(Math.Cos(StupenNaRadian(zenit))) ));  
         pom.NastavRS(2,2,(float)(-1f*(float)(Math.Sin(StupenNaRadian(azimut)))*
                     (float)(Math.Cos(StupenNaRadian(zenit)))));  
         pom.NastavRS(3,2,(float)((float)(Math.Sin(StupenNaRadian(zenit)))));  
         pom.NastavRS(1,3,(float)((float)(Math.Cos(StupenNaRadian(azimut)))*
                     (float)(Math.Sin(StupenNaRadian(zenit))))); 
         pom.NastavRS(2,3,(float)((float)(Math.Sin(StupenNaRadian(azimut)))*
                     (float)(Math.Sin(StupenNaRadian(zenit)))));  
         pom.NastavRS(3,3,(float)((float) Math.Cos(StupenNaRadian(zenit))));
         pom.NastavRS(4,4,(float)(1f));  
         return pom;   //puvodni
      /*   Matice pom; pom=new Matice(4,4);//zjednodušená verze
         pom.NastavRS(1,1,(float)(-(Math.Cos(StupenNaRadian(azimut)))));  
         pom.NastavRS(2,1,(float)(Math.Sin(StupenNaRadian(azimut))));  
         pom.NastavRS(1,2,(float)(-(Math.Sin(StupenNaRadian(azimut))))*
                    (float)(Math.Sin(StupenNaRadian(zenit))));
         pom.NastavRS(2,2,(float)(-(Math.Cos(StupenNaRadian(azimut))))*
                     (float)(Math.Sin(StupenNaRadian(zenit))));
         pom.NastavRS(3,2,(float)(Math.Cos(StupenNaRadian(zenit))));
         pom.NastavRS(4,4,(float)(1f));  
         return pom; */
      }
      public Matice Posunuti(Bod3D vektor){
         Matice pom;pom=new Matice(4,4);
         pom.NastavRS(1,1,1f);pom.NastavRS(2,2,1f);
         pom.NastavRS(3,3,1f);pom.NastavRS(4,4,1f);
         pom.NastavRS(4,1,-1f*vektor.x);
         pom.NastavRS(4,2,-1f*vektor.y);
         pom.NastavRS(4,3,-1f*vektor.z);
         return pom;
      }
     public Matice Stredove(float distance){
         Matice pom;pom=new Matice(4,4);
         pom.NastavRS(1,1,distance);pom.NastavRS(2,2,distance);
         pom.NastavRS(3,4,1f);pom.NastavRS(4,4,distance);
         return pom;
      }
      public Matice Pespektiva1(float distancez){
         Matice pom;pom=new Matice(4,4);
         pom.NastavRS(1,1,1f);pom.NastavRS(2,2,1f); 
         pom.NastavRS(3,3,1f);pom.NastavRS(4,4,1f); 
         pom.NastavRS(3,4,1/distancez); 
         return pom;
      }
      public Matice Pespektiva2(float distancey,float distancez){
         Matice pom;pom=new Matice(4,4);
         pom.NastavRS(1,1,1f);pom.NastavRS(2,2,1f); 
         pom.NastavRS(3,3,1f);pom.NastavRS(4,4,1f); 
         pom.NastavRS(2,4,1/distancey); 
         pom.NastavRS(3,4,1/distancez);
         return pom;
      }
      public Matice Pespektiva3(float distancex,float distancey,float distancez){
         Matice pom;pom=new Matice(4,4);
         pom.NastavRS(1,1,1f);pom.NastavRS(2,2,1f); 
         pom.NastavRS(3,3,1f);pom.NastavRS(4,4,1f); 
         pom.NastavRS(1,4,1/distancex); 
         pom.NastavRS(2,4,1/distancey); 
         pom.NastavRS(3,4,1/distancez); 
         return pom;
         
      } 
 }

Středové promítání na válcovou plochu

editovat

Jde vlastně o středové promítání na válcovou plochu se středem v počátku soustavy souřadnic. Bodem je proložena přímka procházející počátkem soustavy souřadnic a její průsečík s válcovou plochou je hledaným obrazem.

místo pro obr. projekce_na_valec

Pro vzor v o souřadnicích ( ) platí tedy následující rovnice

Z částečných rovnic přímky procházející počátkem soustavy souřadnic:

 

 

  (1)

a rovnice válcové plochy se středem v počátku soustavy souřadnic:

 

spočítáme parametr  

 

a po dosazení za parametr   do (1) dostáváme výsledný bod na válcové ploše.

Algoritmizace

editovat

Pro každý bod zobrazovaného objektu najdeme jeho průsečík s válcovou plochou. Nově nalezený bod (obraz) nahradí svůj vzor a vazby mezi body, hranami a stěnami zůstávají zachovány. Takto získaný model poté můžeme libovolnou metodou promítnout na zobrazovací plochu.

Bod3D
Třída popisující bod
Cylinder
Třída popisující Válec a poskytující metody nutné k promítnutí modelu na plochu válce.
Model
Třída reprezentující stěnový model geometrického objektu

Kód v jazyce C#

editovat

Příklad řešení v jazyce C#.

Pomocné objekty a metody

editovat

Ukázka možné implementace třídy Bod3D (pro naše potřeby postačí následující torzo)

 public class Bod3D
 {
  private float[] souradnice; //pole pro uložení souřadnic
  public Bod3D(float x,float y, float z)
  {
   this.souradnice= new float[3]{x,y,z};
  }
  ...
 }

Ukázka možné implementace třídy Cylinder (pro naše potřeby postačí následující torzo)

 public class Cylinder
 {
  private float radius;
  public Cylinder(float initRadius)
  {
   this.radius = initRadius;
  }
  ...
 }

Ukázka možné implementace metody Recording

  public Bod3D Recording(Bod3D mapped)
  {
   float x,y,z;
   x = this.radius*mapped.x/(float)(Math.Sqrt(Math.Pow(mapped.x,2)+Math.Pow(mapped.z,2)));
   y = this.radius*mapped.y/(float)(Math.Sqrt(Math.Pow(mapped.x,2)+Math.Pow(mapped.z,2)));
   z = this.radius*mapped.z/(float)(Math.Sqrt(Math.Pow(mapped.x,2)+Math.Pow(mapped.z,2)));
   return new Bod3D(x,y,z);
  }

Vlastní algoritmus

editovat

Ukázka možné implementace metody CylindricalProjection

 public static Model CylindricalProjection(Cylinder c, Model model)
  {
   Model ret = new Model();
   for(int i=1;i<=model.body.Count;i++)
   {
    Bod3D vzor = (Bod3D)model.body[i];
    Bod3D obraz;
    obraz = c.Recording(vzor);
    ret.body.Add(i,obraz); 
   }
   ret.hrany = model.hrany;
   ret.steny = model.steny;
   return ret;
  }

Panoramatické zobrazení

editovat

Při zobrazení do roviny můžeme rozvinutím válce získat panoramatický obraz. Z-tová souřadnice předpokládejme, že osou válce je osa z) bodu na válci může určovat y-ovou rozvinutého válce, x-ové souřadnice určíme pomocí úhlů polárních souřadnic bodů válce.

Ukázka možné implementace metody RollOpen

 public static Model RollOpen(Cylinder c, Model model)
 {
  Model ret = new Model();
  for(int i=1;i<=model.body.Count;i++)
  {
   Bod3D vzor = (Bod3D)model.body[i];
   vzor = Coord.CartesianToPolar(vzor);
   Bod3D obraz;
   float x,y,z;
   float radius = c.radius;
   float aux = (float)Math.PI*radius;
   y = vzor.z;
   x = radius*vzor.y-aux;
   z = vzor.z;
   obraz = new Bod3D(x,y,z);
   ret.body.Add(i,obraz);
  }
  ret.hrany = model.hrany;
  ret.steny = model.steny;
  return ret;
 }

Středové promítání na kulovou plochu

editovat

Jde vlastně o středové promítání na kulovou plochu se středem v počátku soustavy souřadnic. Bodem je proložena přímka procházející počátkem soustavy souřadnic a její průsečík s kulovou plochou je hledaným obrazem.

místo pro obr. projekce_na_kouli

Pro vzor v o souřadnicích ( ) platí tedy následující rovnice

Z částečných rovnic přímky procházející počátkem soustavy souřadnic:

 

 

  (1)

a rovnice kulové plochy se středem v počátku soustavy souřadnic:

 

spočítáme parametr  

 

a po dosazení za parametr   do (1) dostáváme výsledný bod na kulové ploše.

Algoritmizace

editovat

Pro každý bod zobrazovaného objektu najdeme pomocí jeho průsečík s kulovou plochou. Nově nalezený bod (obraz) nahradí svůj vzor a vazby mezi body, hranami a stěnami zůstávají zachovány. Takto získaný model poté můžeme libovolnou metodou promítnout na zobrazovací plochu.

Bod3D
Třída popisující bod
Sphere
Třída popisující kouli a poskytující metody nutné k promítnutí modelu na kulovou plochu.
Model
Třída reprezentující stěnový model geometrického objektu

Kód v jazyce C#

editovat

Příklad řešení v jazyce C#.

Pomocné objekty a metody

editovat

Ukázka možné implementace třídy Bod3D (pro naše potřeby postačí následující torzo)

 public class Bod3D
 {
  private float[] souradnice; //pole pro uložení souřadnic
  public Bod3D(float x,float y, float z)
  {
   this.souradnice= new float[3]{x,y,z};
  }
  ...
 }

Ukázka možné implementace třídy Sphere (pro naše potřeby postačí následující torzo)

 public class Sphere
 {
  private float radius;
  public Sphere(float initRadius)
  {
   this.radius = initRadius;
  }
  ...
 }

Ukázka možné implementace metody Recording

  public Bod3D Recording(Bod3D mapped)
  {
   float aux = this.radius/(float)(Math.Sqrt(Math.Pow(mapped.x,2)+Math.Pow(mapped.y,2)+
                Math.Pow(mapped.z,2))); 
   float x,y,z;
   x = mapped.x*aux;
   y = mapped.y*aux;
   z = mapped.z*aux;
   return new Bod3D(x,y,z);
  }

Vlastní algoritmus

editovat

Ukázka možné implementace metody SphericalProjection

 public static Model SphericalProjection(Sphere s, Model model)
 {
  Model ret = new Model();
  for(int i=1;i<=model.body.Count;i++)
  {
   Bod3D vzor = (Bod3D)model.body[i];
   Bod3D obraz;
   obraz = s.Recording(vzor);
   ret.body.Add(i,obraz); 
  }
  ret.hrany = model.hrany;
  ret.steny = model.steny;
  return ret;
 }

Autoři

editovat

Tento text vypracovali studenti Univerzity Palackého v Olomouci katedry Matematické informatiky jako součást zápočtového úkolu do předmětu Počítačová geometrie.