//C- -*- C++ -*- //C- ------------------------------------------------------------------- //C- DjVuLibre-3.5 //C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. //C- Copyright (c) 2001 AT&T //C- //C- This software is subject to, and may be distributed under, the //C- GNU General Public License, either Version 2 of the license, //C- or (at your option) any later version. The license should have //C- accompanied the software or you may obtain a copy of the license //C- from the Free Software Foundation at http://www.fsf.org . //C- //C- This program is distributed in the hope that it will be useful, //C- but WITHOUT ANY WARRANTY; without even the implied warranty of //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //C- GNU General Public License for more details. //C- //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from //C- Lizardtech Software. Lizardtech Software has authorized us to //C- replace the original DjVu(r) Reference Library notice by the following //C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu): //C- //C- ------------------------------------------------------------------ //C- | DjVu (r) Reference Library (v. 3.5) //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. //C- | The DjVu Reference Library is protected by U.S. Pat. No. //C- | 6,058,214 and patents pending. //C- | //C- | This software is subject to, and may be distributed under, the //C- | GNU General Public License, either Version 2 of the license, //C- | or (at your option) any later version. The license should have //C- | accompanied the software or you may obtain a copy of the license //C- | from the Free Software Foundation at http://www.fsf.org . //C- | //C- | The computer code originally released by LizardTech under this //C- | license and unmodified by other parties is deemed "the LIZARDTECH //C- | ORIGINAL CODE." Subject to any third party intellectual property //C- | claims, LizardTech grants recipient a worldwide, royalty-free, //C- | non-exclusive license to make, use, sell, or otherwise dispose of //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU //C- | General Public License. This grant only confers the right to //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to //C- | the extent such infringement is reasonably necessary to enable //C- | recipient to make, have made, practice, sell, or otherwise dispose //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to //C- | any greater extent that may be necessary to utilize further //C- | modifications or combinations. //C- | //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. //C- +------------------------------------------------------------------ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if NEED_GNUG_PRAGMAS # pragma implementation #endif // -- Implementation of class GRect and GRectMapper // - Author: Leon Bottou, 05/1997 #include "GRect.h" #include "GException.h" #ifdef HAVE_NAMESPACES namespace DJVU { # ifdef NOT_DEFINED // Just to fool emacs c++ mode } #endif #endif // -- Local utilities static inline int imin(int x, int y) { if (x < y) return x; else return y; } static inline int imax(int x, int y) { if (x > y) return x; else return y; } static inline void iswap(int &x, int &y) { int tmp = x; x = y; y = tmp; } // -- Class GRect int operator==(const GRect & r1, const GRect & r2) { bool isempty1 = r1.isempty(); bool isempty2 = r2.isempty(); if (isempty1 || isempty2) if (isempty1 && isempty2) return 1; if ( r1.xmin==r2.xmin && r1.xmax==r2.xmax && r1.ymin==r2.ymin && r1.ymax==r2.ymax ) return 1; return 0; } int GRect::inflate(int dx, int dy) { xmin -= dx; xmax += dx; ymin -= dy; ymax += dy; if (! isempty()) return 1; xmin = ymin = xmax = ymax = 0; return 0; } int GRect::translate(int dx, int dy) { xmin += dx; xmax += dx; ymin += dy; ymax += dy; if (! isempty()) return 1; xmin = ymin = xmax = ymax = 0; return 0; } int GRect::intersect(const GRect &rect1, const GRect &rect2) { xmin = imax(rect1.xmin, rect2.xmin); xmax = imin(rect1.xmax, rect2.xmax); ymin = imax(rect1.ymin, rect2.ymin); ymax = imin(rect1.ymax, rect2.ymax); if (! isempty()) return 1; xmin = ymin = xmax = ymax = 0; return 0; } int GRect::recthull(const GRect &rect1, const GRect &rect2) { if (rect1.isempty()) { xmin = rect2.xmin; xmax = rect2.xmax; ymin = rect2.ymin; ymax = rect2.ymax; return !isempty(); } if (rect2.isempty()) { xmin = rect1.xmin; xmax = rect1.xmax; ymin = rect1.ymin; ymax = rect1.ymax; return !isempty(); } xmin = imin(rect1.xmin, rect2.xmin); xmax = imax(rect1.xmax, rect2.xmax); ymin = imin(rect1.ymin, rect2.ymin); ymax = imax(rect1.ymax, rect2.ymax); return 1; } int GRect::contains(const GRect & rect) const { GRect tmp_rect; tmp_rect.intersect(*this, rect); return tmp_rect==rect; } void GRect::scale(float factor) { xmin = (int)(((float)xmin) * factor); ymin = (int)(((float)ymin) * factor); xmax = (int)(((float)xmax) * factor); ymax = (int)(((float)ymax) * factor); } void GRect::scale(float xfactor, float yfactor) { xmin = (int)(((float)xmin) * xfactor); ymin = (int)(((float)ymin) * yfactor); xmax = (int)(((float)xmax) * xfactor); ymax = (int)(((float)ymax) * yfactor); } // -- Class GRatio inline GRectMapper::GRatio::GRatio() : p(0), q(1) { } inline GRectMapper::GRatio::GRatio(int p, int q) : p(p), q(q) { if (q == 0) G_THROW( ERR_MSG("GRect.div_zero") ); if (p == 0) q = 1; if (q < 0) { p = -p; q = -q; } int gcd = 1; int g1 = p; int g2 = q; if (g1 > g2) { gcd = g1; g1 = g2; g2 = gcd; } while (g1 > 0) { gcd = g1; g1 = g2 % g1; g2 = gcd; } p /= gcd; q /= gcd; } #ifdef HAVE_LONG_LONG_INT #define llint_t long long int #else #define llint_t long int #endif inline int operator*(int n, GRectMapper::GRatio r ) { /* [LB] -- This computation is carried out with integers and rational numbers because it must be exact. Some lizard changed it to double and this is wrong. I suspect they did so because they encountered overflow issues. Let's use long long ints. */ llint_t x = (llint_t) n * (llint_t) r.p; if (x >= 0) return ((r.q/2 + x) / r.q); else return - ((r.q/2 - x) / r.q); } inline int operator/(int n, GRectMapper::GRatio r ) { /* [LB] -- See comment in operator*() above. */ llint_t x = (llint_t) n * (llint_t) r.q; if (x >= 0) return ((r.p/2 + x) / r.p); else return - ((r.p/2 - x) / r.p); } // -- Class GRectMapper #define MIRRORX 1 #define MIRRORY 2 #define SWAPXY 4 GRectMapper::GRectMapper() : rectFrom(0,0,1,1), rectTo(0,0,1,1), code(0) { } void GRectMapper::clear() { rectFrom = GRect(0,0,1,1); rectTo = GRect(0,0,1,1); code = 0; } void GRectMapper::set_input(const GRect &rect) { if (rect.isempty()) G_THROW( ERR_MSG("GRect.empty_rect1") ); rectFrom = rect; if (code & SWAPXY) { iswap(rectFrom.xmin, rectFrom.ymin); iswap(rectFrom.xmax, rectFrom.ymax); } rw = rh = GRatio(); } void GRectMapper::set_output(const GRect &rect) { if (rect.isempty()) G_THROW( ERR_MSG("GRect.empty_rect2") ); rectTo = rect; rw = rh = GRatio(); } void GRectMapper::rotate(int count) { int oldcode = code; switch (count & 0x3) { case 1: code ^= (code & SWAPXY) ? MIRRORY : MIRRORX; code ^= SWAPXY; break; case 2: code ^= (MIRRORX|MIRRORY); break; case 3: code ^= (code & SWAPXY) ? MIRRORX : MIRRORY; code ^= SWAPXY; break; } if ((oldcode ^ code) & SWAPXY) { iswap(rectFrom.xmin, rectFrom.ymin); iswap(rectFrom.xmax, rectFrom.ymax); rw = rh = GRatio(); } } void GRectMapper::mirrorx() { code ^= MIRRORX; } void GRectMapper::mirrory() { code ^= MIRRORY; } void GRectMapper::precalc() { if (rectTo.isempty() || rectFrom.isempty()) G_THROW( ERR_MSG("GRect.empty_rect3") ); rw = GRatio(rectTo.width(), rectFrom.width()); rh = GRatio(rectTo.height(), rectFrom.height()); } void GRectMapper::map(int &x, int &y) { int mx = x; int my = y; // precalc if (! (rw.p && rh.p)) precalc(); // swap and mirror if (code & SWAPXY) iswap(mx,my); if (code & MIRRORX) mx = rectFrom.xmin + rectFrom.xmax - mx; if (code & MIRRORY) my = rectFrom.ymin + rectFrom.ymax - my; // scale and translate x = rectTo.xmin + (mx - rectFrom.xmin) * rw; y = rectTo.ymin + (my - rectFrom.ymin) * rh; } void GRectMapper::unmap(int &x, int &y) { // precalc if (! (rw.p && rh.p)) precalc(); // scale and translate int mx = rectFrom.xmin + (x - rectTo.xmin) / rw; int my = rectFrom.ymin + (y - rectTo.ymin) / rh; // mirror and swap if (code & MIRRORX) mx = rectFrom.xmin + rectFrom.xmax - mx; if (code & MIRRORY) my = rectFrom.ymin + rectFrom.ymax - my; if (code & SWAPXY) iswap(mx,my); x = mx; y = my; } void GRectMapper::map(GRect &rect) { map(rect.xmin, rect.ymin); map(rect.xmax, rect.ymax); if (rect.xmin >= rect.xmax) iswap(rect.xmin, rect.xmax); if (rect.ymin >= rect.ymax) iswap(rect.ymin, rect.ymax); } void GRectMapper::unmap(GRect &rect) { unmap(rect.xmin, rect.ymin); unmap(rect.xmax, rect.ymax); if (rect.xmin >= rect.xmax) iswap(rect.xmin, rect.xmax); if (rect.ymin >= rect.ymax) iswap(rect.ymin, rect.ymax); } GRect GRectMapper::get_input() { return rectFrom; } GRect GRectMapper::get_output() { return rectTo; } #ifdef HAVE_NAMESPACES } # ifndef NOT_USING_DJVU_NAMESPACE using namespace DJVU; # endif #endif