Geometrie/Promítání

Z Wikiknih
Skočit na navigaci Skočit na vyhledává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.

Promitani rovnobezne.png

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.

Promitani axonometrie.png

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ě.

Promitani stredove.png

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í.

Promitani perspektiva 1bodova.png

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

Promitani perspektiva 2bodova.png

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

Promitani perspektiva 3bodova.png

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]

Popis[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]

Popis[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.