Blame libdjvu/GRect.cpp

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