#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 #include #include #include #include namespace meow { /*! * @brief 底片 * * 基本上就是一個 \c Bitmap 加上 \c focal * * @author cat_leopard */ template class Photo: public ObjBase { private: struct Myself { Bitmap bmp_; Vector2D c_; PhotoProjection proj_; Myself(): proj_(3) { } Myself(Myself const& b): bmp_(b.bmp_), c_(b.c_), proj_(b.proj_) { } ~Myself() { } }; Self const self; /*! * @brief 取得bitmap座標 */ Vector2D bitmapCoord(Vector2D const& yx) const { return Vector2D(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::COPY_FROM) { } /*! * @brief constructor * * 直接給定圖片, 焦距用猜的 * * @param [in] bmp 給定的圖片 */ Photo(Bitmap const& bmp): self() { reset(bmp); } /*! * @brief constructor * * 直接給定圖片與焦距 * * @param [in] bmp 給定的圖片 * @param [in] f 給定的焦距 */ Photo(Bitmap const& bmp, double f): self() { reset(bmp, f); } /*! * @brief constructor * * 直接給定圖片, 焦距與中心點位置 * * @param [in] bmp 給定的圖片 * @param [in] f 給定的焦距 * @param [in] c 中心點作標 */ Photo(Bitmap const& bmp, double f, Vector2D 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 const& bmp) { bitmap(bmp); focal(sqrt(squ(width()) + squ(height()))); center(Vector2D(bmp.width() / 2, bmp.height() / 2)); } /*! * @brief 重設bitmap, focal * * center代bitmap中心點 * * @param [in] bmp 新的 \c bitmap * @param [in] f 新的 \c focal */ void reset(Bitmap const& bmp, double f) { bitmap(bmp); focal(f); center(Vector2D(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 const& bmp, double f, Vector2D const& c) { bitmap(bmp); focal(f); center(c); } /*! * @brief 回傳\c bitmap */ Bitmap const& bitmap() const { return self->bmp_; } /*! * @brief 回傳\c bitmap 的參照(非constant) */ Bitmap& bitmapGet() { return self()->bmp_; } /*! * @brief 設定bitmap * * @param [in] bmp 新的 bitmap * @return 新的 \c bitmap */ Bitmap const& bitmap(Bitmap 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 projection() const { return self->proj_; } /*! * @brief 設定 photo projection */ PhotoProjection projection(PhotoProjection const& p) { if (p.dimension() == 3) { self()->proj_ = p; } return projection(); } /*! * @brief 取得照片中心點底片座標 * * @return 一個二維vector */ Vector2D const& center() const { return self->c_; } /*! * @brief 取得照片中心點底片座標 (non-constant reference) * * @return 一個二維vector */ Vector2D& centerGet() { return self()->c_; } /*! * @brief 設定照片中心點底片座標 * * @param [in] c 新的座標 * * @return 新的座標 */ Vector2D const& center(Vector2D 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 const& yx) const { Vector2D 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 const& p) const { if (p.z() > 0) return false; return inside(Vector2D(self->proj_.transformate(p.matrix()))); } /*! * @brief 取得給照片座標中某點的色彩 * * 用浮點數vector傳入, 所以色彩是經過渲染過的 * * @param [in] yx 底片座標(原點為center) * * @return pixel */ Pixel color(Vector2D const& yx) const { if (!inside(yx)) return Pixel(0); Vector2D 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 const& p) const { return color(Vector2D(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 */ 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__