aboutsummaryrefslogblamecommitdiffstats
path: root/meowpp/gra/Photo.h
blob: 18377272362008ba510c9e5b6c9ae1b9b9d7c3e4 (plain) (tree)
1
2
3
4
5
6
7
8


                       

                   

                    
                           
















                                    
                                                  











                                  
                                                                     
     
               
















                                                                           
                   









                               
                                                                








                                        
                                           










                                    
                                                     











                                                 
                                                                                

























































































                                                                             
                               





















                                      
















                                                                        















































































                                                                          
                                




















































                                                                          











                                                                              






                                                 











                                                                                



                            
                                            






















                                                                               
                                










                                              
         

                       
#ifndef   gra_Photo_H__
#define   gra_Photo_H__

#include "Bitmap.h"

#include "../Self.h"

#include "../geo/Vectors.h"
#include "../math/utility.h"
#include "../math/Matrix.h"
#include "../math/Transformations.h"

#include "../oo/ObjBase.h"

#include <vector>
#include <cmath>
#include <string>
#include <typeinfo>
#include <cstdlib>

namespace meow {

/*!
 * @brief 底片 
 * 
 * 基本上就是一個 \c Bitmap 加上 \c focal
 * 
 * @author cat_leopard
 */
template<class Pixel>
class Photo: public ObjBase {
private:
  struct Myself {
    Bitmap<Pixel>            bmp_;
    Vector2D<double>           c_;
    PhotoProjection<double> proj_;
    Myself(): proj_(3) {
    }
    Myself(Myself const& b): bmp_(b.bmp_), c_(b.c_), proj_(b.proj_) {
    }
    ~Myself() {
    }
  };
  
  Self<Myself> const self;
  
  /*!
   * @brief 取得bitmap座標
   */
  Vector2D<double> bitmapCoord(Vector2D<double> const& yx) const {
    return Vector2D<double>(yx.x() + center().x(), -yx.y() + center().y());
  }
public:
  /*!
   * @brief constructor
   * 
   * focal 預設為 1
   */
  Photo(): self() {
    self()->proj_.focal(1.0);
  }
  
  /*!
   * @brief constructor
   * 
   * 複製資料
   * 
   * @param [in] b 資料來源
   */
  Photo(Photo const& b): self(b.self, Self<Myself>::COPY_FROM) {
  }
  
  /*!
   * @brief constructor
   * 
   * 直接給定圖片, 焦距用猜的
   * 
   * @param [in] bmp 給定的圖片
   */
  Photo(Bitmap<Pixel> const& bmp): self() {
    reset(bmp);
  }
  
  /*!
   * @brief constructor
   * 
   * 直接給定圖片與焦距
   * 
   * @param [in] bmp 給定的圖片
   * @param [in] f   給定的焦距
   */
  Photo(Bitmap<Pixel> const& bmp, double f): self() {
    reset(bmp, f);
  }
  
  /*!
   * @brief constructor
   * 
   * 直接給定圖片, 焦距與中心點位置
   * 
   * @param [in] bmp 給定的圖片
   * @param [in] f   給定的焦距
   * @param [in] c   中心點作標
   */
  Photo(Bitmap<Pixel> const& bmp, double f, Vector2D<double> const& c): self() {
    reset(bmp, f, c);
  }
  
  /*!
   * @brief destructor
   */
  ~Photo() {
  }
  
  /*!
   * @brief 複製資料
   * 
   * @param [in] b 資料來源
   */
  Photo& copyFrom(Photo const& b) {
    self().copyFrom(b.self);
    return *this;
  }
  
  /*!
   * @brief 參照
   * 
   * @param [in] b 參照來源
   */
  Photo& referneceFrom(Photo const& b) {
    self().referenceFrom(b.self);
    return *this;
  }
  
  /*!
   * @brief 重設bitmap, focal 用猜的
   * 
   * focal直接代對角線, center代bitmap中心點
   * 
   * @param [in] bmp 新的 \c bitmap
   */
  void reset(Bitmap<Pixel> const& bmp) {
    bitmap(bmp);
    focal(sqrt(squ(width()) + squ(height())));
    center(Vector2D<double>(bmp.width() / 2, bmp.height() / 2));
  }
  
  /*!
   * @brief 重設bitmap, focal
   *
   * center代bitmap中心點
   *
   * @param [in] bmp 新的 \c bitmap
   * @param [in] f   新的 \c focal
   */
  void reset(Bitmap<Pixel> const& bmp, double f) {
    bitmap(bmp);
    focal(f);
    center(Vector2D<double>(bmp.width() / 2, bmp.height() / 2));
  }
  
  /*!
   * @brief 重設bitmap, focal, center
   * 
   * @param [in] bmp 新的 \c bitmap
   * @param [in] f   新的 \c focal
   * @param [in] c   新的中心點作標
   */
  void reset(Bitmap<Pixel> const& bmp, double f, Vector2D<double> const& c) {
    bitmap(bmp);
    focal(f);
    center(c);
  }
  
  /*!
   * @brief 回傳\c bitmap
   */
  Bitmap<Pixel> const& bitmap() const {
    return self->bmp_;
  }
  
  /*!
   * @brief 回傳\c bitmap 的參照(非constant)
   */
  Bitmap<Pixel>& bitmapGet() {
    return self()->bmp_;
  }
  
  /*!
   * @brief 設定bitmap
   * 
   * @param [in] bmp 新的 bitmap
   * @return 新的 \c bitmap
   */
  Bitmap<Pixel> const& bitmap(Bitmap<Pixel> const& bmp) {
    self()->bmp_.copyFrom(bmp);
    return bitmap();
  }
  
  /*!
   * @brief 回傳focal length
   */
  double focal() const {
    return self->proj_.focal();
  }
  
  /*!
   * @brief 設定 focal length
   * 
   * @param [in] f 新的 focal length
   * @return 新的 \c focal length
   */
  double focal(double f) {
    self()->proj_.focal(f);
    return focal();
  }
  
  /*!
   * @brief 回傳相應的 photo projection
   */
  PhotoProjection<double> projection() const {
    return self->proj_;
  }
  
  /*!
   * @brief 設定 photo projection
   */
  PhotoProjection<double> projection(PhotoProjection<double> const& p) {
    if (p.dimension() == 3) {
      self()->proj_ = p;
    }
    return projection();
  }
  
  /*!
   * @brief 取得照片中心點底片座標
   *
   * @return 一個二維vector
   */
  Vector2D<double> const& center() const {
    return self->c_;
  }
  
  /*!
   * @brief 取得照片中心點底片座標 (non-constant reference)
   *
   * @return 一個二維vector
   */
  Vector2D<double>& centerGet() {
    return self()->c_;
  }
  
  /*!
   * @brief 設定照片中心點底片座標
   *
   * @param [in] c 新的座標
   *
   * @return 新的座標
   */
  Vector2D<double> const& center(Vector2D<double> const& c) {
    self()->c_ = c;
    return center();
  }
  
  /*!
   * @brief 回傳bitmap寬
   */
  size_t width() const {
    return self->bmp_.width();
  }
  
  /*!
   * @brief 回傳bitmap高
   */
  size_t height() const {
    return self->bmp_.height();
  }
  
  /*!
   * @brief 回傳bitmap的某pixel
   */
  Pixel pixel(size_t y, size_t x) const {
    return self->bmp_.pixel(y, x);
  }
  
  /*!
   * @brief 設定某pixel
   */
  Pixel pixel(size_t y, size_t x, Pixel const& p) {
    self()->bmp_.pixel(y, x, p);
    return pixel(y, x);
  }
  
  /*!
   * @brief 檢查某點是否在底片範圍內
   *
   * @param [in] yx 底片座標
   * 
   * @return \c true/false
   */
  bool inside(Vector2D<double> const& yx) const {
    Vector2D<double> c = bitmapCoord(yx);
    ssize_t h_max = (ssize_t)height() - 1;
    ssize_t w_max = (ssize_t)width () - 1;
    return (0 <= c.y() && c.y() <= h_max && 0 <= c.x() && c.x() <= w_max);
  }
  
  /*!
   * @brief 檢查某點是否在底片範圍內
   *
   * @param [in] p 大地座標
   * 
   * @return \c true/false
   */
  bool inside(Vector3D<double> const& p) const {
    if (p.z() > 0) return false;
    return inside(Vector2D<double>(self->proj_.transformate(p.matrix())));
  }
  
  /*!
   * @brief 取得給照片座標中某點的色彩
   *
   * 用浮點數vector傳入, 所以色彩是經過渲染過的
   *
   * @param [in] yx 底片座標(原點為center)
   *
   * @return pixel
   */
  Pixel color(Vector2D<double> const& yx) const {
    if (!inside(yx)) return Pixel(0);
    Vector2D<double> c(bitmapCoord(yx));
    int y0 = (int)c.y();
    int x0 = (int)c.x();
    double h[2] = {1 - (c.y() - y0), c.y() - y0};
    double w[2] = {1 - (c.x() - x0), c.x() - x0};
    Pixel sum(0);
    for (int dy = 0; dy < 2; dy++)
      for (int dx = 0; dx < 2; dx++) {
        sum = sum + bitmap().pixel(
          std::min(y0 + dy, (int)height() - 1),
          std::min(x0 + dx, (int)width () - 1)) * (w[dy] * h[dx]);
      }
    return sum;
  }
  
  /*!
   * @brief 取得給照片座標中某點的色彩
   *
   * 這次是輸入大地座標
   *
   * @param [in] p 大地座標p
   * @return pixel
   */
  Pixel color(Vector3D<double> const& p) const {
    return color(Vector2D<double>(self->proj_.transformate(p.matrix())));
  }
  
  /*!
   * @brief same as \c .copyFrom(b)
   */
  Photo& operator=(Photo const& b) {
    return copyFrom(b);
  }
  
  /*! @brief 將資料寫入檔案
   *
   *  @note 未完成
   */
  bool write(FILE* f, bool bin, unsigned int fg) const {
    if (bitmap().write(f, bin, fg) == false) return false;
    if (bin) {
      double tmp;
      if (fwrite(&(tmp = center().x()), sizeof(tmp), 1, f) < 1) return false;
      if (fwrite(&(tmp = center().y()), sizeof(tmp), 1, f) < 1) return false;
      if (fwrite(&(tmp = focal()), sizeof(tmp), 1, f) < 1) return false;
    }
    else {
      if (fprintf(f, "%f %f\n", center().x(), center().y()) < 2) return false;
      if (fprintf(f, "%f\n", focal()) < 1) return false;
    }
    return true;
  }
  
  /*! @brief 將資料讀入
   *
   *  @note 未完成
   */
  bool read(FILE* f, bool bin, unsigned int fg) {
    if (bitmapGet().read(f, bin, fg) == false) return false;
    double tmp[3];
    if (bin) {
      if (fread(tmp, sizeof(double), 3, f) < 3) return false;
    }
    else {
      if (fscanf(f, "%lf %lf %lf", tmp + 0, tmp + 1, tmp + 2) < 3) return false;
    }
    centerGet().x(tmp[0]);
    centerGet().y(tmp[1]);
    focal(tmp[2]);
    return true;
  }

  /*! @brief new一個自己
   *
   *  @return 一個new出來的Photo<Pixel>
   */
  ObjBase* create() const {
    return new Photo();
  }
  
  /*! @brief 複製資料
   *
   * 輸入型別是 \c ObjBase \c const*
   * 這裡假設實體其實是 \c Bitmap.
   * 事實上這個method就只是幫忙轉型然後呼叫原本的\c copyFrom
   *
   *  @param [in] b 資料來源
   *  @return this
   */
  ObjBase* copyFrom(ObjBase const* b) {
    return &(copyFrom(*(Photo*)b));
  }
  
  /*! @brief 回傳class的type
   *
   *  @return \c char \c const\c * 形式的typename
   */
  char const* ctype() const{
    return typeid(*this).name();
  }
  
  /*! @brief 回傳class的type
   *
   *  @return \c std::string 形式的typename
   */
  std::string type() const {
    return std::string(ctype());
  }
};
  
} // meow

#endif // gra_Photo_H__