You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kviewshell/plugins/djvu/libdjvu/GRect.cpp

458 lines
9.9 KiB

//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