|
|
|
//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, Version 2. 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
|
|
|
|
//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech
|
|
|
|
//C- Software authorized us to replace the original DjVu(r) Reference
|
|
|
|
//C- Library notice by the following text (see doc/lizard2002.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, Version 2. 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- +------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// $Id: GRect.cpp,v 1.10 2003/11/07 22:08:21 leonb Exp $
|
|
|
|
// $Name: release_3_5_15 $
|
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
|
|
|
int isempty1 = r1.isempty();
|
|
|
|
int 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
|