462 lines
15 KiB
C++
462 lines
15 KiB
C++
//----------------------------------------------------------------------------
|
|
// Anti-Grain Geometry - Version 2.4
|
|
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
|
//
|
|
// Permission to copy, use, modify, sell and distribute this software
|
|
// is granted provided this copyright notice appears in all copies.
|
|
// This software is provided "as is" without express or implied
|
|
// warranty, and with no claim as to its suitability for any purpose.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// Contact: mcseem@antigrain.com
|
|
// mcseemagg@yahoo.com
|
|
// http://www.antigrain.com
|
|
//----------------------------------------------------------------------------
|
|
#ifndef AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED
|
|
#define AGG_SPAN_INTERPOLATOR_PERSP_INCLUDED
|
|
|
|
#include "agg_trans_perspective.h"
|
|
#include "agg_dda_line.h"
|
|
|
|
namespace agg
|
|
{
|
|
|
|
|
|
|
|
//===========================================span_interpolator_persp_exact
|
|
template<unsigned SubpixelShift = 8>
|
|
class span_interpolator_persp_exact
|
|
{
|
|
public:
|
|
typedef trans_perspective trans_type;
|
|
typedef trans_perspective::iterator_x iterator_type;
|
|
enum subpixel_scale_e
|
|
{
|
|
subpixel_shift = SubpixelShift,
|
|
subpixel_scale = 1 << subpixel_shift
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
span_interpolator_persp_exact() {}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Arbitrary quadrangle transformations
|
|
span_interpolator_persp_exact(const double* src, const double* dst)
|
|
{
|
|
quad_to_quad(src, dst);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Direct transformations
|
|
span_interpolator_persp_exact(double x1, double y1,
|
|
double x2, double y2,
|
|
const double* quad)
|
|
{
|
|
rect_to_quad(x1, y1, x2, y2, quad);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Reverse transformations
|
|
span_interpolator_persp_exact(const double* quad,
|
|
double x1, double y1,
|
|
double x2, double y2)
|
|
{
|
|
quad_to_rect(quad, x1, y1, x2, y2);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Set the transformations using two arbitrary quadrangles.
|
|
void quad_to_quad(const double* src, const double* dst)
|
|
{
|
|
m_trans_dir.quad_to_quad(src, dst);
|
|
m_trans_inv.quad_to_quad(dst, src);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Set the direct transformations, i.e., rectangle -> quadrangle
|
|
void rect_to_quad(double x1, double y1, double x2, double y2,
|
|
const double* quad)
|
|
{
|
|
double src[8];
|
|
src[0] = src[6] = x1;
|
|
src[2] = src[4] = x2;
|
|
src[1] = src[3] = y1;
|
|
src[5] = src[7] = y2;
|
|
quad_to_quad(src, quad);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Set the reverse transformations, i.e., quadrangle -> rectangle
|
|
void quad_to_rect(const double* quad,
|
|
double x1, double y1, double x2, double y2)
|
|
{
|
|
double dst[8];
|
|
dst[0] = dst[6] = x1;
|
|
dst[2] = dst[4] = x2;
|
|
dst[1] = dst[3] = y1;
|
|
dst[5] = dst[7] = y2;
|
|
quad_to_quad(quad, dst);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Check if the equations were solved successfully
|
|
bool is_valid() const { return m_trans_dir.is_valid(); }
|
|
|
|
//----------------------------------------------------------------
|
|
void begin(double x, double y, unsigned len)
|
|
{
|
|
m_iterator = m_trans_dir.begin(x, y, 1.0);
|
|
double xt = m_iterator.x;
|
|
double yt = m_iterator.y;
|
|
|
|
double dx;
|
|
double dy;
|
|
const double delta = 1/double(subpixel_scale);
|
|
dx = xt + delta;
|
|
dy = yt;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sx1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
dx = xt;
|
|
dy = yt + delta;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sy1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
x += len;
|
|
xt = x;
|
|
yt = y;
|
|
m_trans_dir.transform(&xt, &yt);
|
|
|
|
dx = xt + delta;
|
|
dy = yt;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
dx = xt;
|
|
dy = yt + delta;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
m_scale_x = dda2_line_interpolator(sx1, sx2, len);
|
|
m_scale_y = dda2_line_interpolator(sy1, sy2, len);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
void resynchronize(double xe, double ye, unsigned len)
|
|
{
|
|
// Assume x1,y1 are equal to the ones at the previous end point
|
|
int sx1 = m_scale_x.y();
|
|
int sy1 = m_scale_y.y();
|
|
|
|
// Calculate transformed coordinates at x2,y2
|
|
double xt = xe;
|
|
double yt = ye;
|
|
m_trans_dir.transform(&xt, &yt);
|
|
|
|
const double delta = 1/double(subpixel_scale);
|
|
double dx;
|
|
double dy;
|
|
|
|
// Calculate scale by X at x2,y2
|
|
dx = xt + delta;
|
|
dy = yt;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= xe;
|
|
dy -= ye;
|
|
int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Calculate scale by Y at x2,y2
|
|
dx = xt;
|
|
dy = yt + delta;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= xe;
|
|
dy -= ye;
|
|
int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Initialize the interpolators
|
|
m_scale_x = dda2_line_interpolator(sx1, sx2, len);
|
|
m_scale_y = dda2_line_interpolator(sy1, sy2, len);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
void operator++()
|
|
{
|
|
++m_iterator;
|
|
++m_scale_x;
|
|
++m_scale_y;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void coordinates(int* x, int* y) const
|
|
{
|
|
*x = iround(m_iterator.x * subpixel_scale);
|
|
*y = iround(m_iterator.y * subpixel_scale);
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void local_scale(int* x, int* y)
|
|
{
|
|
*x = m_scale_x.y();
|
|
*y = m_scale_y.y();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void transform(double* x, double* y) const
|
|
{
|
|
m_trans_dir.transform(x, y);
|
|
}
|
|
|
|
private:
|
|
trans_type m_trans_dir;
|
|
trans_type m_trans_inv;
|
|
iterator_type m_iterator;
|
|
dda2_line_interpolator m_scale_x;
|
|
dda2_line_interpolator m_scale_y;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//============================================span_interpolator_persp_lerp
|
|
template<unsigned SubpixelShift = 8>
|
|
class span_interpolator_persp_lerp
|
|
{
|
|
public:
|
|
typedef trans_perspective trans_type;
|
|
enum subpixel_scale_e
|
|
{
|
|
subpixel_shift = SubpixelShift,
|
|
subpixel_scale = 1 << subpixel_shift
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
span_interpolator_persp_lerp() {}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Arbitrary quadrangle transformations
|
|
span_interpolator_persp_lerp(const double* src, const double* dst)
|
|
{
|
|
quad_to_quad(src, dst);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Direct transformations
|
|
span_interpolator_persp_lerp(double x1, double y1,
|
|
double x2, double y2,
|
|
const double* quad)
|
|
{
|
|
rect_to_quad(x1, y1, x2, y2, quad);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Reverse transformations
|
|
span_interpolator_persp_lerp(const double* quad,
|
|
double x1, double y1,
|
|
double x2, double y2)
|
|
{
|
|
quad_to_rect(quad, x1, y1, x2, y2);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Set the transformations using two arbitrary quadrangles.
|
|
void quad_to_quad(const double* src, const double* dst)
|
|
{
|
|
m_trans_dir.quad_to_quad(src, dst);
|
|
m_trans_inv.quad_to_quad(dst, src);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Set the direct transformations, i.e., rectangle -> quadrangle
|
|
void rect_to_quad(double x1, double y1, double x2, double y2,
|
|
const double* quad)
|
|
{
|
|
double src[8];
|
|
src[0] = src[6] = x1;
|
|
src[2] = src[4] = x2;
|
|
src[1] = src[3] = y1;
|
|
src[5] = src[7] = y2;
|
|
quad_to_quad(src, quad);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
// Set the reverse transformations, i.e., quadrangle -> rectangle
|
|
void quad_to_rect(const double* quad,
|
|
double x1, double y1, double x2, double y2)
|
|
{
|
|
double dst[8];
|
|
dst[0] = dst[6] = x1;
|
|
dst[2] = dst[4] = x2;
|
|
dst[1] = dst[3] = y1;
|
|
dst[5] = dst[7] = y2;
|
|
quad_to_quad(quad, dst);
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
// Check if the equations were solved successfully
|
|
bool is_valid() const { return m_trans_dir.is_valid(); }
|
|
|
|
//----------------------------------------------------------------
|
|
void begin(double x, double y, unsigned len)
|
|
{
|
|
// Calculate transformed coordinates at x1,y1
|
|
double xt = x;
|
|
double yt = y;
|
|
m_trans_dir.transform(&xt, &yt);
|
|
int x1 = iround(xt * subpixel_scale);
|
|
int y1 = iround(yt * subpixel_scale);
|
|
|
|
double dx;
|
|
double dy;
|
|
const double delta = 1/double(subpixel_scale);
|
|
|
|
// Calculate scale by X at x1,y1
|
|
dx = xt + delta;
|
|
dy = yt;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sx1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Calculate scale by Y at x1,y1
|
|
dx = xt;
|
|
dy = yt + delta;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sy1 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Calculate transformed coordinates at x2,y2
|
|
x += len;
|
|
xt = x;
|
|
yt = y;
|
|
m_trans_dir.transform(&xt, &yt);
|
|
int x2 = iround(xt * subpixel_scale);
|
|
int y2 = iround(yt * subpixel_scale);
|
|
|
|
// Calculate scale by X at x2,y2
|
|
dx = xt + delta;
|
|
dy = yt;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Calculate scale by Y at x2,y2
|
|
dx = xt;
|
|
dy = yt + delta;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= x;
|
|
dy -= y;
|
|
int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Initialize the interpolators
|
|
m_coord_x = dda2_line_interpolator(x1, x2, len);
|
|
m_coord_y = dda2_line_interpolator(y1, y2, len);
|
|
m_scale_x = dda2_line_interpolator(sx1, sx2, len);
|
|
m_scale_y = dda2_line_interpolator(sy1, sy2, len);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
void resynchronize(double xe, double ye, unsigned len)
|
|
{
|
|
// Assume x1,y1 are equal to the ones at the previous end point
|
|
int x1 = m_coord_x.y();
|
|
int y1 = m_coord_y.y();
|
|
int sx1 = m_scale_x.y();
|
|
int sy1 = m_scale_y.y();
|
|
|
|
// Calculate transformed coordinates at x2,y2
|
|
double xt = xe;
|
|
double yt = ye;
|
|
m_trans_dir.transform(&xt, &yt);
|
|
int x2 = iround(xt * subpixel_scale);
|
|
int y2 = iround(yt * subpixel_scale);
|
|
|
|
const double delta = 1/double(subpixel_scale);
|
|
double dx;
|
|
double dy;
|
|
|
|
// Calculate scale by X at x2,y2
|
|
dx = xt + delta;
|
|
dy = yt;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= xe;
|
|
dy -= ye;
|
|
int sx2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Calculate scale by Y at x2,y2
|
|
dx = xt;
|
|
dy = yt + delta;
|
|
m_trans_inv.transform(&dx, &dy);
|
|
dx -= xe;
|
|
dy -= ye;
|
|
int sy2 = uround(subpixel_scale/sqrt(dx*dx + dy*dy)) >> subpixel_shift;
|
|
|
|
// Initialize the interpolators
|
|
m_coord_x = dda2_line_interpolator(x1, x2, len);
|
|
m_coord_y = dda2_line_interpolator(y1, y2, len);
|
|
m_scale_x = dda2_line_interpolator(sx1, sx2, len);
|
|
m_scale_y = dda2_line_interpolator(sy1, sy2, len);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------
|
|
void operator++()
|
|
{
|
|
++m_coord_x;
|
|
++m_coord_y;
|
|
++m_scale_x;
|
|
++m_scale_y;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void coordinates(int* x, int* y) const
|
|
{
|
|
*x = m_coord_x.y();
|
|
*y = m_coord_y.y();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void local_scale(int* x, int* y)
|
|
{
|
|
*x = m_scale_x.y();
|
|
*y = m_scale_y.y();
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
void transform(double* x, double* y) const
|
|
{
|
|
m_trans_dir.transform(x, y);
|
|
}
|
|
|
|
private:
|
|
trans_type m_trans_dir;
|
|
trans_type m_trans_inv;
|
|
dda2_line_interpolator m_coord_x;
|
|
dda2_line_interpolator m_coord_y;
|
|
dda2_line_interpolator m_scale_x;
|
|
dda2_line_interpolator m_scale_y;
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|