mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-05 23:49:20 +00:00
Now (Qt 4.3.1) that QPainter::CompositionMode_Multiply works remove agg2 based code
Actually i think it's even a bit faster now svn path=/trunk/KDE/kdegraphics/okular/; revision=708877
This commit is contained in:
parent
805b0f3386
commit
3f80eceaae
|
@ -13,7 +13,6 @@ else(NOT WIN32)
|
|||
endif(NOT WIN32)
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/painter_agg2/
|
||||
)
|
||||
|
||||
|
||||
|
@ -132,11 +131,6 @@ set(okularpart_SRCS
|
|||
ui/side_reviews.cpp
|
||||
ui/thumbnaillist.cpp
|
||||
ui/toc.cpp
|
||||
ui/painter_agg2/agg_bezier_arc.cpp
|
||||
ui/painter_agg2/agg_path_storage.cpp
|
||||
ui/painter_agg2/agg_rasterizer_scanline_aa.cpp
|
||||
ui/painter_agg2/agg_trans_affine.cpp
|
||||
ui/painter_agg2/agg_vcgen_stroke.cpp
|
||||
)
|
||||
|
||||
kde4_add_ui_files(okularpart_SRCS
|
||||
|
|
|
@ -292,10 +292,12 @@ void PagePainter::paintPageOnPainter( QPainter * destPainter, const Okular::Page
|
|||
// 4B.4. paint annotations [COMPOSITED ONES]
|
||||
if ( bufferedAnnotations )
|
||||
{
|
||||
// This is cheap
|
||||
// TODO Enable again once we switch to Arthur instead Agg for drawShapeOnImage
|
||||
// backImage = backImage.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
// Albert: This is quite "heavy" but all the backImage that reach here are QImage::Format_ARGB32_Premultiplied
|
||||
// and have to be so that the QPainter::CompositionMode_Multiply works
|
||||
// we could also put a
|
||||
// backImage = backImage.convertToFormat(QImage::Format_ARGB32_Premultiplied)
|
||||
// that would be almost a noop, but we'll leave the assert for now
|
||||
Q_ASSERT(backImage.format() == QImage::Format_ARGB32_Premultiplied);
|
||||
// precalc costants for normalizing the quads to the image
|
||||
double pageScale = (double)scaledWidth / page->width();
|
||||
double xOffset = (double)limits.left() / (double)scaledWidth,
|
||||
|
@ -699,10 +701,10 @@ void PagePainter::cropPixmapOnImage( QImage & dest, const QPixmap * src, const Q
|
|||
// else copy a portion of the src to an internal pixmap (smaller) and convert it
|
||||
else
|
||||
{
|
||||
QPixmap croppedPixmap( r.width(), r.height() );
|
||||
QPainter p( &croppedPixmap );
|
||||
QImage croppedImage( r.width(), r.height(), QImage::Format_ARGB32_Premultiplied );
|
||||
QPainter p( &croppedImage );
|
||||
p.drawPixmap( 0, 0, *src, r.left(), r.top(), r.width(), r.height() );
|
||||
dest = croppedPixmap.toImage();
|
||||
dest = croppedImage;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -801,115 +803,6 @@ void PagePainter::colorizeImage( QImage & grayImage, const QColor & color,
|
|||
}
|
||||
}
|
||||
|
||||
//BEGIN of Anti-Grain dependant code
|
||||
/** Shape Drawing using Anti-Grain Geometry library **/
|
||||
// The following code uses the AGG2.3 lib imported into the "painter_agg2"
|
||||
// directory. This is to be replaced by Arthur calls for drawing antialiased
|
||||
// primitives, but until that AGG2 does its job very fast and good-looking.
|
||||
|
||||
#include "okular_pixfmt_rgba.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_renderer_base.h"
|
||||
#include "agg_scanline_u.h"
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
#include "agg_renderer_scanline.h"
|
||||
#include "agg_conv_stroke.h"
|
||||
#include "agg_path_storage.h"
|
||||
|
||||
void PagePainter::drawShapeOnImage(
|
||||
QImage & image,
|
||||
const NormalizedPath & normPath,
|
||||
bool closeShape,
|
||||
const QPen & pen,
|
||||
const QBrush & brush,
|
||||
double penWidthMultiplier,
|
||||
RasterOperation op
|
||||
//float antiAliasRadius
|
||||
)
|
||||
{
|
||||
// safety checks
|
||||
int pointsNumber = normPath.size();
|
||||
if ( pointsNumber < 2 )
|
||||
return;
|
||||
|
||||
int imageWidth = image.width();
|
||||
int imageHeight = image.height();
|
||||
double fImageWidth = (double)imageWidth;
|
||||
double fImageHeight = (double)imageHeight;
|
||||
|
||||
// create a 'path'
|
||||
agg::path_storage path;
|
||||
path.move_to( normPath[ 0 ].x * fImageWidth, normPath[ 0 ].y * fImageHeight );
|
||||
for ( int i = 1; i < pointsNumber; i++ )
|
||||
path.line_to( normPath[ i ].x * fImageWidth, normPath[ i ].y * fImageHeight );
|
||||
//path.curve4( normPath[ i ].x * fImageWidth + 2, normPath[ i ].y * fImageHeight - 2,
|
||||
// normPath[ i ].x * fImageWidth, normPath[ i ].y * fImageHeight );
|
||||
if ( closeShape )
|
||||
path.close_polygon();
|
||||
|
||||
// create the 'rendering buffer' over qimage memory
|
||||
agg::rendering_buffer buffer( image.bits(), imageWidth, imageHeight, imageWidth << 2 );
|
||||
// create 'pixel buffer', 'clipped renderer', 'scanline renderer' on bgra32 format
|
||||
typedef agg::pixfmt_bgra32 bgra32;
|
||||
typedef agg::renderer_base< bgra32 > rb_bgra32;
|
||||
bgra32 pixels( buffer, op == Multiply ? 1 : 0 );
|
||||
rb_bgra32 rb( pixels );
|
||||
agg::renderer_scanline_aa_solid< rb_bgra32 > render( rb );
|
||||
// create rasterizer and scaline
|
||||
agg::rasterizer_scanline_aa<> rasterizer;
|
||||
agg::scanline_u8 scanline;
|
||||
|
||||
#if 0
|
||||
//draw RAINBOW
|
||||
agg::rgba8 span[ imageWidth ];
|
||||
for( int x = 0; x < imageWidth; x++ )
|
||||
{
|
||||
agg::rgba c( 380.0 + 400.0 * x / imageWidth, 0.8 );
|
||||
span[ x ] = agg::rgba8(c);
|
||||
}
|
||||
for( int y = 0; y < imageHeight; y++ )
|
||||
pixels.blend_color_hspan( 0, y, imageWidth, span, 0, (123*y)/imageHeight );
|
||||
#endif
|
||||
|
||||
// fill rect
|
||||
if ( brush.style() != Qt::NoBrush )
|
||||
{
|
||||
const QColor & brushColor = brush.color();
|
||||
render.color( agg::rgba8( brushColor.red(), brushColor.green(), brushColor.blue(), (int)( agg::rgba8::base_mask * brushColor.alphaF() ) ) );
|
||||
rasterizer.add_path( path );
|
||||
agg::render_scanlines( rasterizer, scanline, render );
|
||||
rasterizer.reset();
|
||||
}
|
||||
|
||||
// stroke outline
|
||||
double penWidth = (double)pen.width() * penWidthMultiplier;
|
||||
if ( penWidth > 0.1 )
|
||||
{
|
||||
const QColor & penColor = pen.color();
|
||||
render.color( agg::rgba8( penColor.red(), penColor.green(), penColor.blue(), (int)( agg::rgba8::base_mask * penColor.alphaF() ) ) );
|
||||
#if 0
|
||||
// BSPLINE curve over path
|
||||
typedef agg::conv_bspline< agg::path_storage > conv_bspline_type;
|
||||
conv_bspline_type bspline( path );
|
||||
bspline.interpolation_step( 0.2 );
|
||||
agg::conv_stroke< conv_bspline_type > strokedPath( bspline );
|
||||
#else
|
||||
agg::conv_stroke< agg::path_storage > strokedPath( path );
|
||||
#endif
|
||||
strokedPath.width( penWidth );
|
||||
rasterizer.add_path( strokedPath );
|
||||
agg::render_scanlines( rasterizer, scanline, render );
|
||||
}
|
||||
}
|
||||
|
||||
//END of Anti-Grain dependant code
|
||||
|
||||
// TODO Enable this and remove AGG code when
|
||||
// http://www.trolltech.com/developer/task-tracker/index_html?id=158815&method=entry
|
||||
// gets fixed
|
||||
// remember to uncomment
|
||||
// backImage = backImage.convertToFormat(QImage::Format_ARGB32);
|
||||
#if 0
|
||||
void PagePainter::drawShapeOnImage(
|
||||
QImage & image,
|
||||
const NormalizedPath & normPath,
|
||||
|
@ -955,4 +848,3 @@ void PagePainter::drawShapeOnImage(
|
|||
|
||||
painter.drawPath(path);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -47,7 +47,7 @@ class PagePainter
|
|||
// to 'scaledWidth' by 'scaledHeight' pixels. cropRect must be inside
|
||||
// the QRect(0,0, scaledWidth,scaledHeight)
|
||||
static void scalePixmapOnImage( QImage & dest, const QPixmap *src,
|
||||
int scaledWidth, int scaledHeight, const QRect & cropRect, QImage::Format format = QImage::Format_RGB32 );
|
||||
int scaledWidth, int scaledHeight, const QRect & cropRect, QImage::Format format = QImage::Format_ARGB32_Premultiplied );
|
||||
|
||||
// set the alpha component of the image to a given value
|
||||
static void changeImageAlpha( QImage & image, unsigned int alpha );
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
File: okular/ui/painter_agg2/README.okular
|
||||
Created by: Enrico Ros @ KPDF project 2005
|
||||
Renamed to README.okular by: Tobias Koenig @ okular project 2006
|
||||
|
||||
>> Anti-Grain Geometry 2.3
|
||||
The files contained in this directory are from the Anti-Grain Geometry library,
|
||||
that provides many loosely copuled algorithms and classes for performing fine
|
||||
rendering. All files in there are using a good bsd-like licence compatible with
|
||||
okular development.
|
||||
No external dependancies required other than a standard C++ compiler suite.
|
||||
|
||||
>> File Naming
|
||||
- "agg_" prefixed files are from the Anti-Grain Geometry distribution. Those
|
||||
files are updated to the 2.3 release of that library
|
||||
- "okular_" prefixed files are made by okular developers to extend library
|
||||
capabilities and fit the needs of that project.
|
||||
- README.okular must be updated to reflect changes happening in that directory.
|
||||
|
||||
>> Directory contents
|
||||
As AGG is a template based collection of tools, there is no need for the full
|
||||
library, we need only a small subset of it. In fact in that directory there
|
||||
are mixed Headers (.h) and Implementations (.cpp) files taken respectively
|
||||
from:
|
||||
.h: agg23/include
|
||||
.cpp: agg23/src
|
||||
Note that directories "agg23/src/platform" (crossplatform GUI support),
|
||||
"agg23/src/ctrl" (GUI widgets), "agg23/gpc" (generic polygon clipper),
|
||||
"agg23/svg" (SVG viewer tool) are NOT USED AT ALL in the okular project.
|
||||
|
||||
>> File inclusion by scope
|
||||
< Memory Buffer, RGBA color buffer, ScanLine, ScanLine Renderer,
|
||||
Path Storage, Path Stroker, Rendering >
|
||||
agg_array.h, agg_basics.h, agg_bezier_arc.h, agg_clip_liang_barsky.h,
|
||||
agg_color_rgba.h, agg_conv_adaptor_vcgen.h, agg_conv_stroke.h,
|
||||
agg_conv_transform.h, agg_gamma_functions.h, agg_math.h, agg_math_stroke.h,
|
||||
agg_path_storage.h, agg_pixfmt_rgba.h, agg_rasterizer_scanline_aa.h,
|
||||
agg_render_scanlines.h, agg_renderer_base.h, agg_renderer_scanline.h,
|
||||
agg_rendering_buffer.h, agg_scanline_u.h, agg_shorten_path.h,
|
||||
agg_trans_affine.h, agg_vcgen_stroke.h, agg_vertex_iterator.h,
|
||||
agg_vertex_sequence.h
|
||||
agg_bezier_arc.cpp, agg_path_storage.cpp, agg_rasterizer_scanline_aa.cpp,
|
||||
agg_trans_affine.cpp, agg_vcgen_stroke.cpp
|
||||
|
||||
< Raster Ops on RGBA color buffer >
|
||||
okular_pixfmt_rgba.h (removed: agg_pixfmt_rgba.h)
|
||||
|
||||
< ..for every new algo added.. >
|
||||
..append added files here..
|
||||
|
||||
>> For Maxim Shemanarev
|
||||
Thanks for your work - the okular team
|
|
@ -1,887 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_ARRAY_INCLUDED
|
||||
#define AGG_ARRAY_INCLUDED
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------pod_array_adaptor
|
||||
template<class T> class pod_array_adaptor
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
pod_array_adaptor(T* array, unsigned size) :
|
||||
m_array(array), m_size(size) {}
|
||||
|
||||
unsigned size() const { return m_size; }
|
||||
const T& operator [] (unsigned idx) const { return m_array[idx]; }
|
||||
T& operator [] (unsigned idx) { return m_array[idx]; }
|
||||
private:
|
||||
T* m_array;
|
||||
unsigned m_size;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------pod_auto_array
|
||||
template<class T, unsigned Size> class pod_auto_array
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef pod_auto_array<T, Size> self_type;
|
||||
|
||||
pod_auto_array() {}
|
||||
explicit pod_auto_array(const T* c)
|
||||
{
|
||||
memcpy(m_array, c, sizeof(T) * Size);
|
||||
}
|
||||
|
||||
const self_type& operator = (const T* c)
|
||||
{
|
||||
memcpy(m_array, c, sizeof(T) * Size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static unsigned size() { return Size; }
|
||||
const T& operator [] (unsigned i) const { return m_array[i]; }
|
||||
T& operator [] (unsigned i) { return m_array[i]; }
|
||||
private:
|
||||
T m_array[Size];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------pod_array
|
||||
// A simple class template to store Plain Old Data, a vector
|
||||
// of a fixed size. The data is continuous in memory
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> class pod_array
|
||||
{
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
~pod_array() { delete [] m_array; }
|
||||
pod_array() : m_size(0), m_capacity(0), m_array(0) {}
|
||||
pod_array(unsigned cap, unsigned extra_tail=0);
|
||||
|
||||
// Copying
|
||||
pod_array(const pod_array<T>&);
|
||||
const pod_array<T>& operator = (const pod_array<T>&);
|
||||
|
||||
unsigned capacity() const { return m_capacity; }
|
||||
void capacity(unsigned cap, unsigned extra_tail=0);
|
||||
|
||||
void resize(unsigned new_size);
|
||||
|
||||
void add(const T& v) { m_array[m_size++] = v; }
|
||||
void inc_size(unsigned size) { m_size += size; }
|
||||
unsigned size() const { return m_size; }
|
||||
unsigned byte_size() const { return m_size * sizeof(T); }
|
||||
void serialize(int8u* ptr) const;
|
||||
void deserialize(const int8u* data, unsigned byte_size);
|
||||
const T& operator [] (unsigned idx) const { return m_array[idx]; }
|
||||
T& operator [] (unsigned idx) { return m_array[idx]; }
|
||||
|
||||
void remove_all() { m_size = 0; }
|
||||
void cut_at(unsigned num) { if(num < m_size) m_size = num; }
|
||||
|
||||
private:
|
||||
unsigned m_size;
|
||||
unsigned m_capacity;
|
||||
T* m_array;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void pod_array<T>::capacity(unsigned cap, unsigned extra_tail)
|
||||
{
|
||||
m_size = 0;
|
||||
if(cap > m_capacity)
|
||||
{
|
||||
delete [] m_array;
|
||||
m_capacity = cap + extra_tail;
|
||||
m_array = m_capacity ? new T [m_capacity] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void pod_array<T>::resize(unsigned new_size)
|
||||
{
|
||||
if(new_size > m_size)
|
||||
{
|
||||
if(new_size > m_capacity)
|
||||
{
|
||||
T* data = new T[new_size];
|
||||
memcpy(data, m_array, m_size * sizeof(T));
|
||||
delete [] m_array;
|
||||
m_array = data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_size = new_size;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> pod_array<T>::pod_array(unsigned cap, unsigned extra_tail) :
|
||||
m_size(cap), m_capacity(cap + extra_tail), m_array(new T[m_capacity]) {}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> pod_array<T>::pod_array(const pod_array<T>& v) :
|
||||
m_size(v.m_size),
|
||||
m_capacity(v.m_capacity),
|
||||
m_array(v.m_capacity ? new T [v.m_capacity] : 0)
|
||||
{
|
||||
memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> const pod_array<T>&
|
||||
pod_array<T>::operator = (const pod_array<T>&v)
|
||||
{
|
||||
capacity(v.m_capacity);
|
||||
if(v.m_size) memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> void pod_array<T>::serialize(int8u* ptr) const
|
||||
{
|
||||
if(m_size) memcpy(ptr, m_array, m_size * sizeof(T));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T>
|
||||
void pod_array<T>::deserialize(const int8u* data, unsigned byte_size)
|
||||
{
|
||||
byte_size /= sizeof(T);
|
||||
capacity(byte_size);
|
||||
if(byte_size) memcpy(m_array, data, byte_size * sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------pod_deque
|
||||
// A simple class template to store Plain Old Data, similar to std::deque
|
||||
// It doesn't reallocate memory but instead, uses blocks of data of size
|
||||
// of (1 << S), that is, power of two. The data is NOT continuous in memory,
|
||||
// so the only valid access method is operator [] or curr(), prev(), next()
|
||||
//
|
||||
// There reallocs occur only when the pool of pointers to blocks needs
|
||||
// to be extended (it happens very rear). You can control the value
|
||||
// of increment to reallocate the pointer buffer. See the second constructor.
|
||||
// By default, the incremeent value equals (1 << S), i.e., the block size.
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S=6> class pod_deque
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
block_shift = S,
|
||||
block_size = 1 << block_shift,
|
||||
block_mask = block_size - 1
|
||||
};
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
~pod_deque();
|
||||
pod_deque();
|
||||
pod_deque(unsigned block_ptr_inc);
|
||||
|
||||
// Copying
|
||||
pod_deque(const pod_deque<T, S>& v);
|
||||
const pod_deque<T, S>& operator = (const pod_deque<T, S>& v);
|
||||
|
||||
void remove_all() { m_size = 0; }
|
||||
void free_all() { free_tail(0); }
|
||||
void free_tail(unsigned size);
|
||||
void add(const T& val);
|
||||
void modify_last(const T& val);
|
||||
void remove_last();
|
||||
|
||||
int allocate_continuous_block(unsigned num_elements);
|
||||
|
||||
void add_array(const T* ptr, unsigned num_elem)
|
||||
{
|
||||
while(num_elem--)
|
||||
{
|
||||
add(*ptr++);
|
||||
}
|
||||
}
|
||||
|
||||
template<class DataAccessor> void add_data(DataAccessor& data)
|
||||
{
|
||||
while(data.size())
|
||||
{
|
||||
add(*data);
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
||||
void cut_at(unsigned size)
|
||||
{
|
||||
if(size < m_size) m_size = size;
|
||||
}
|
||||
|
||||
unsigned size() const { return m_size; }
|
||||
|
||||
const T& operator [] (unsigned idx) const
|
||||
{
|
||||
return m_blocks[idx >> block_shift][idx & block_mask];
|
||||
}
|
||||
|
||||
T& operator [] (unsigned idx)
|
||||
{
|
||||
return m_blocks[idx >> block_shift][idx & block_mask];
|
||||
}
|
||||
|
||||
const T& curr(unsigned idx) const
|
||||
{
|
||||
return (*this)[idx];
|
||||
}
|
||||
|
||||
T& curr(unsigned idx)
|
||||
{
|
||||
return (*this)[idx];
|
||||
}
|
||||
|
||||
const T& prev(unsigned idx) const
|
||||
{
|
||||
return (*this)[(idx + m_size - 1) % m_size];
|
||||
}
|
||||
|
||||
T& prev(unsigned idx)
|
||||
{
|
||||
return (*this)[(idx + m_size - 1) % m_size];
|
||||
}
|
||||
|
||||
const T& next(unsigned idx) const
|
||||
{
|
||||
return (*this)[(idx + 1) % m_size];
|
||||
}
|
||||
|
||||
T& next(unsigned idx)
|
||||
{
|
||||
return (*this)[(idx + 1) % m_size];
|
||||
}
|
||||
|
||||
const T& last() const
|
||||
{
|
||||
return (*this)[m_size - 1];
|
||||
}
|
||||
|
||||
T& last()
|
||||
{
|
||||
return (*this)[m_size - 1];
|
||||
}
|
||||
|
||||
unsigned byte_size() const;
|
||||
void serialize(int8u* ptr) const;
|
||||
void deserialize(const int8u* data, unsigned byte_size);
|
||||
void deserialize(unsigned start, const T& empty_val,
|
||||
const int8u* data, unsigned byte_size);
|
||||
|
||||
template<class ByteAccessor>
|
||||
void deserialize(ByteAccessor data)
|
||||
{
|
||||
remove_all();
|
||||
unsigned elem_size = data.size() / sizeof(T);
|
||||
|
||||
for(unsigned i = 0; i < elem_size; ++i)
|
||||
{
|
||||
int8u* ptr = (int8u*)data_ptr();
|
||||
for(unsigned j = 0; j < sizeof(T); ++j)
|
||||
{
|
||||
*ptr++ = *data;
|
||||
++data;
|
||||
}
|
||||
++m_size;
|
||||
}
|
||||
}
|
||||
|
||||
template<class ByteAccessor>
|
||||
void deserialize(unsigned start, const T& empty_val, ByteAccessor data)
|
||||
{
|
||||
while(m_size < start)
|
||||
{
|
||||
add(empty_val);
|
||||
}
|
||||
|
||||
unsigned elem_size = data.size() / sizeof(T);
|
||||
for(unsigned i = 0; i < elem_size; ++i)
|
||||
{
|
||||
int8u* ptr;
|
||||
if(start + i < m_size)
|
||||
{
|
||||
ptr = (int8u*)(&((*this)[start + i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = (int8u*)data_ptr();
|
||||
++m_size;
|
||||
}
|
||||
for(unsigned j = 0; j < sizeof(T); ++j)
|
||||
{
|
||||
*ptr++ = *data;
|
||||
++data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const T* block(unsigned nb) const { return m_blocks[nb]; }
|
||||
|
||||
private:
|
||||
void allocate_block(unsigned nb);
|
||||
T* data_ptr();
|
||||
|
||||
unsigned m_size;
|
||||
unsigned m_num_blocks;
|
||||
unsigned m_max_blocks;
|
||||
T** m_blocks;
|
||||
unsigned m_block_ptr_inc;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S> pod_deque<T, S>::~pod_deque()
|
||||
{
|
||||
if(m_num_blocks)
|
||||
{
|
||||
T** blk = m_blocks + m_num_blocks - 1;
|
||||
while(m_num_blocks--)
|
||||
{
|
||||
delete [] *blk;
|
||||
--blk;
|
||||
}
|
||||
delete [] m_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void pod_deque<T, S>::free_tail(unsigned size)
|
||||
{
|
||||
if(size < m_size)
|
||||
{
|
||||
unsigned nb = (size + block_mask) >> block_shift;
|
||||
while(m_num_blocks > nb)
|
||||
{
|
||||
delete [] m_blocks[--m_num_blocks];
|
||||
}
|
||||
m_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S> pod_deque<T, S>::pod_deque() :
|
||||
m_size(0),
|
||||
m_num_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_blocks(0),
|
||||
m_block_ptr_inc(block_size)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
pod_deque<T, S>::pod_deque(unsigned block_ptr_inc) :
|
||||
m_size(0),
|
||||
m_num_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_blocks(0),
|
||||
m_block_ptr_inc(block_ptr_inc)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
pod_deque<T, S>::pod_deque(const pod_deque<T, S>& v) :
|
||||
m_size(v.m_size),
|
||||
m_num_blocks(v.m_num_blocks),
|
||||
m_max_blocks(v.m_max_blocks),
|
||||
m_blocks(v.m_max_blocks ? new T* [v.m_max_blocks] : 0),
|
||||
m_block_ptr_inc(v.m_block_ptr_inc)
|
||||
{
|
||||
unsigned i;
|
||||
for(i = 0; i < v.m_num_blocks; ++i)
|
||||
{
|
||||
m_blocks[i] = new T [block_size];
|
||||
memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
const pod_deque<T, S>& pod_deque<T, S>::operator = (const pod_deque<T, S>& v)
|
||||
{
|
||||
unsigned i;
|
||||
for(i = m_num_blocks; i < v.m_num_blocks; ++i)
|
||||
{
|
||||
allocate_block(i);
|
||||
}
|
||||
for(i = 0; i < v.m_num_blocks; ++i)
|
||||
{
|
||||
memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
|
||||
}
|
||||
m_size = v.m_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void pod_deque<T, S>::allocate_block(unsigned nb)
|
||||
{
|
||||
if(nb >= m_max_blocks)
|
||||
{
|
||||
T** new_blocks = new T* [m_max_blocks + m_block_ptr_inc];
|
||||
|
||||
if(m_blocks)
|
||||
{
|
||||
memcpy(new_blocks,
|
||||
m_blocks,
|
||||
m_num_blocks * sizeof(T*));
|
||||
|
||||
delete [] m_blocks;
|
||||
}
|
||||
m_blocks = new_blocks;
|
||||
m_max_blocks += m_block_ptr_inc;
|
||||
}
|
||||
m_blocks[nb] = new T [block_size];
|
||||
m_num_blocks++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
inline T* pod_deque<T, S>::data_ptr()
|
||||
{
|
||||
unsigned nb = m_size >> block_shift;
|
||||
if(nb >= m_num_blocks)
|
||||
{
|
||||
allocate_block(nb);
|
||||
}
|
||||
return m_blocks[nb] + (m_size & block_mask);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
inline void pod_deque<T, S>::add(const T& val)
|
||||
{
|
||||
*data_ptr() = val;
|
||||
++m_size;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
inline void pod_deque<T, S>::remove_last()
|
||||
{
|
||||
if(m_size) --m_size;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void pod_deque<T, S>::modify_last(const T& val)
|
||||
{
|
||||
remove_last();
|
||||
add(val);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
int pod_deque<T, S>::allocate_continuous_block(unsigned num_elements)
|
||||
{
|
||||
if(num_elements < block_size)
|
||||
{
|
||||
data_ptr(); // Allocate initial block if necessary
|
||||
unsigned rest = block_size - (m_size & block_mask);
|
||||
unsigned index;
|
||||
if(num_elements <= rest)
|
||||
{
|
||||
// The rest of the block is good, we can use it
|
||||
//-----------------
|
||||
index = m_size;
|
||||
m_size += num_elements;
|
||||
return index;
|
||||
}
|
||||
|
||||
// New block
|
||||
//---------------
|
||||
m_size += rest;
|
||||
data_ptr();
|
||||
index = m_size;
|
||||
m_size += num_elements;
|
||||
return index;
|
||||
}
|
||||
return -1; // Impossible to allocate
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
unsigned pod_deque<T, S>::byte_size() const
|
||||
{
|
||||
return m_size * sizeof(T);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void pod_deque<T, S>::serialize(int8u* ptr) const
|
||||
{
|
||||
unsigned i;
|
||||
for(i = 0; i < m_size; i++)
|
||||
{
|
||||
memcpy(ptr, &(*this)[i], sizeof(T));
|
||||
ptr += sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void pod_deque<T, S>::deserialize(const int8u* data, unsigned byte_size)
|
||||
{
|
||||
remove_all();
|
||||
byte_size /= sizeof(T);
|
||||
for(unsigned i = 0; i < byte_size; ++i)
|
||||
{
|
||||
T* ptr = data_ptr();
|
||||
memcpy(ptr, data, sizeof(T));
|
||||
++m_size;
|
||||
data += sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Replace or add a number of elements starting from "start" position
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void pod_deque<T, S>::deserialize(unsigned start, const T& empty_val,
|
||||
const int8u* data, unsigned byte_size)
|
||||
{
|
||||
while(m_size < start)
|
||||
{
|
||||
add(empty_val);
|
||||
}
|
||||
|
||||
byte_size /= sizeof(T);
|
||||
for(unsigned i = 0; i < byte_size; ++i)
|
||||
{
|
||||
if(start + i < m_size)
|
||||
{
|
||||
memcpy(&((*this)[start + i]), data, sizeof(T));
|
||||
}
|
||||
else
|
||||
{
|
||||
T* ptr = data_ptr();
|
||||
memcpy(ptr, data, sizeof(T));
|
||||
++m_size;
|
||||
}
|
||||
data += sizeof(T);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------pod_allocator
|
||||
// Allocator for arbitrary POD data. Most usable in different cache
|
||||
// systems for efficient memory allocations.
|
||||
// Memory is allocated with blocks of fixed size ("block_size" in
|
||||
// the constructor). If required size exceeds the block size the allocator
|
||||
// creates a new block of the required size. However, the most efficient
|
||||
// use is when the average reqired size is much less than the block size.
|
||||
//------------------------------------------------------------------------
|
||||
class pod_allocator
|
||||
{
|
||||
public:
|
||||
void remove_all()
|
||||
{
|
||||
if(m_num_blocks)
|
||||
{
|
||||
int8u** blk = m_blocks + m_num_blocks - 1;
|
||||
while(m_num_blocks--)
|
||||
{
|
||||
delete [] *blk;
|
||||
--blk;
|
||||
}
|
||||
delete [] m_blocks;
|
||||
}
|
||||
m_num_blocks = 0;
|
||||
m_max_blocks = 0;
|
||||
m_blocks = 0;
|
||||
m_buf_ptr = 0;
|
||||
m_rest = 0;
|
||||
}
|
||||
|
||||
~pod_allocator()
|
||||
{
|
||||
remove_all();
|
||||
}
|
||||
|
||||
pod_allocator(unsigned block_size, unsigned block_ptr_inc=256-8) :
|
||||
m_block_size(block_size),
|
||||
m_block_ptr_inc(block_ptr_inc),
|
||||
m_num_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_blocks(0),
|
||||
m_buf_ptr(0),
|
||||
m_rest(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int8u* allocate(unsigned size, unsigned alignment=1)
|
||||
{
|
||||
if(size == 0) return 0;
|
||||
if(size <= m_rest)
|
||||
{
|
||||
int8u* ptr = m_buf_ptr;
|
||||
if(alignment > 1)
|
||||
{
|
||||
unsigned align = (alignment - unsigned((size_t)ptr) % alignment) % alignment;
|
||||
size += align;
|
||||
ptr += align;
|
||||
if(size <= m_rest)
|
||||
{
|
||||
m_rest -= size;
|
||||
m_buf_ptr += size;
|
||||
return ptr;
|
||||
}
|
||||
allocate_block(size);
|
||||
return allocate(size - align, alignment);
|
||||
}
|
||||
m_rest -= size;
|
||||
m_buf_ptr += size;
|
||||
return ptr;
|
||||
}
|
||||
allocate_block(size + alignment - 1);
|
||||
return allocate(size, alignment);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void allocate_block(unsigned size)
|
||||
{
|
||||
if(size < m_block_size) size = m_block_size;
|
||||
if(m_num_blocks >= m_max_blocks)
|
||||
{
|
||||
int8u** new_blocks = new int8u* [m_max_blocks + m_block_ptr_inc];
|
||||
|
||||
if(m_blocks)
|
||||
{
|
||||
memcpy(new_blocks,
|
||||
m_blocks,
|
||||
m_num_blocks * sizeof(int8u*));
|
||||
|
||||
delete [] m_blocks;
|
||||
}
|
||||
m_blocks = new_blocks;
|
||||
m_max_blocks += m_block_ptr_inc;
|
||||
}
|
||||
m_blocks[m_num_blocks] = m_buf_ptr = new int8u [size];
|
||||
m_num_blocks++;
|
||||
m_rest = size;
|
||||
}
|
||||
|
||||
unsigned m_block_size;
|
||||
unsigned m_block_ptr_inc;
|
||||
unsigned m_num_blocks;
|
||||
unsigned m_max_blocks;
|
||||
int8u** m_blocks;
|
||||
int8u* m_buf_ptr;
|
||||
unsigned m_rest;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum
|
||||
{
|
||||
quick_sort_threshold = 9
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------swap_elements
|
||||
template<class T> inline void swap_elements(T& a, T& b)
|
||||
{
|
||||
T temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------quick_sort
|
||||
template<class Array, class Less>
|
||||
void quick_sort(Array& arr, Less less)
|
||||
{
|
||||
if(arr.size() < 2) return;
|
||||
|
||||
typename Array::value_type* e1;
|
||||
typename Array::value_type* e2;
|
||||
|
||||
int stack[80];
|
||||
int* top = stack;
|
||||
int limit = arr.size();
|
||||
int base = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int len = limit - base;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int pivot;
|
||||
|
||||
if(len > quick_sort_threshold)
|
||||
{
|
||||
// we use base + len/2 as the pivot
|
||||
pivot = base + len / 2;
|
||||
swap_elements(arr[base], arr[pivot]);
|
||||
|
||||
i = base + 1;
|
||||
j = limit - 1;
|
||||
|
||||
// now ensure that *i <= *base <= *j
|
||||
e1 = &(arr[j]);
|
||||
e2 = &(arr[i]);
|
||||
if(less(*e1, *e2)) swap_elements(*e1, *e2);
|
||||
|
||||
e1 = &(arr[base]);
|
||||
e2 = &(arr[i]);
|
||||
if(less(*e1, *e2)) swap_elements(*e1, *e2);
|
||||
|
||||
e1 = &(arr[j]);
|
||||
e2 = &(arr[base]);
|
||||
if(less(*e1, *e2)) swap_elements(*e1, *e2);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
do i++; while( less(arr[i], arr[base]) );
|
||||
do j--; while( less(arr[base], arr[j]) );
|
||||
|
||||
if( i > j )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
swap_elements(arr[i], arr[j]);
|
||||
}
|
||||
|
||||
swap_elements(arr[base], arr[j]);
|
||||
|
||||
// now, push the largest sub-array
|
||||
if(j - base > limit - i)
|
||||
{
|
||||
top[0] = base;
|
||||
top[1] = j;
|
||||
base = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
top[0] = i;
|
||||
top[1] = limit;
|
||||
limit = j;
|
||||
}
|
||||
top += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the sub-array is small, perform insertion sort
|
||||
j = base;
|
||||
i = j + 1;
|
||||
|
||||
for(; i < limit; j = i, i++)
|
||||
{
|
||||
for(; less(*(e1 = &(arr[j + 1])), *(e2 = &(arr[j]))); j--)
|
||||
{
|
||||
swap_elements(*e1, *e2);
|
||||
if(j == base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(top > stack)
|
||||
{
|
||||
top -= 2;
|
||||
base = top[0];
|
||||
limit = top[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------remove_duplicates
|
||||
// Remove duplicates from a sorted array. It doesn't cut the the
|
||||
// tail of the array, it just returns the number of remaining elements.
|
||||
//-----------------------------------------------------------------------
|
||||
template<class Array, class Equal>
|
||||
unsigned remove_duplicates(Array& arr, Equal equal)
|
||||
{
|
||||
if(arr.size() < 2) return arr.size();
|
||||
|
||||
unsigned i, j;
|
||||
for(i = 1, j = 1; i < arr.size(); i++)
|
||||
{
|
||||
typename Array::value_type& e = arr[i];
|
||||
if(!equal(e, arr[i - 1]))
|
||||
{
|
||||
arr[j++] = e;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,299 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_BASICS_INCLUDED
|
||||
#define AGG_BASICS_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable:4786) // Identifier was truncated...
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define AGG_INLINE __forceinline
|
||||
#else
|
||||
#define AGG_INLINE inline
|
||||
#endif
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
typedef signed char int8; //----int8
|
||||
typedef unsigned char int8u; //----int8u
|
||||
typedef signed short int16; //----int16
|
||||
typedef unsigned short int16u; //----int16u
|
||||
typedef signed int int32; //----int32
|
||||
typedef unsigned int int32u; //----int32u
|
||||
#if defined(_MSC_VER)
|
||||
typedef signed __int64 int64; //---- int64
|
||||
typedef unsigned __int64 int64u; //---- int64u
|
||||
#else
|
||||
typedef signed long long int64; // not sure about the compatibility
|
||||
typedef unsigned long long int64u;
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
typedef unsigned char cover_type; //----cover_type
|
||||
enum
|
||||
{
|
||||
cover_shift = 8, //----cover_shift
|
||||
cover_size = 1 << cover_shift, //----cover_size
|
||||
cover_mask = cover_size - 1, //----cover_mask
|
||||
cover_none = 0, //----cover_none
|
||||
cover_full = cover_mask //----cover_full
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------pi
|
||||
const double pi = 3.14159265358979323846;
|
||||
|
||||
//------------------------------------------------------------------deg2rad
|
||||
inline double deg2rad(double deg)
|
||||
{
|
||||
return deg * pi / 180.0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------rad2deg
|
||||
inline double rad2deg(double rad)
|
||||
{
|
||||
return rad * 180.0 / pi;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------rect_base
|
||||
template<class T> struct rect_base
|
||||
{
|
||||
typedef rect_base<T> self_type;
|
||||
T x1;
|
||||
T y1;
|
||||
T x2;
|
||||
T y2;
|
||||
|
||||
rect_base() {}
|
||||
rect_base(T x1_, T y1_, T x2_, T y2_) :
|
||||
x1(x1_), y1(y1_), x2(x2_), y2(y2_) {}
|
||||
|
||||
const self_type& normalize()
|
||||
{
|
||||
T t;
|
||||
if(x1 > x2) { t = x1; x1 = x2; x2 = t; }
|
||||
if(y1 > y2) { t = y1; y1 = y2; y2 = t; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool clip(const self_type& r)
|
||||
{
|
||||
if(x2 > r.x2) x2 = r.x2;
|
||||
if(y2 > r.y2) y2 = r.y2;
|
||||
if(x1 < r.x1) x1 = r.x1;
|
||||
if(y1 < r.y1) y1 = r.y1;
|
||||
return x1 <= x2 && y1 <= y2;
|
||||
}
|
||||
|
||||
bool is_valid() const
|
||||
{
|
||||
return x1 <= x2 && y1 <= y2;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------intersect_rectangles
|
||||
template<class Rect>
|
||||
inline Rect intersect_rectangles(const Rect& r1, const Rect& r2)
|
||||
{
|
||||
Rect r = r1;
|
||||
|
||||
// First process x2,y2 because the other order
|
||||
// results in Internal Compiler Error under
|
||||
// Microsoft Visual C++ .NET 2003 69462-335-0000007-18038 in
|
||||
// case of "Maximize Speed" optimization option.
|
||||
//-----------------
|
||||
if(r.x2 > r2.x2) r.x2 = r2.x2;
|
||||
if(r.y2 > r2.y2) r.y2 = r2.y2;
|
||||
if(r.x1 < r2.x1) r.x1 = r2.x1;
|
||||
if(r.y1 < r2.y1) r.y1 = r2.y1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------unite_rectangles
|
||||
template<class Rect>
|
||||
inline Rect unite_rectangles(const Rect& r1, const Rect& r2)
|
||||
{
|
||||
Rect r = r1;
|
||||
if(r.x2 < r2.x2) r.x2 = r2.x2;
|
||||
if(r.y2 < r2.y2) r.y2 = r2.y2;
|
||||
if(r.x1 > r2.x1) r.x1 = r2.x1;
|
||||
if(r.y1 > r2.y1) r.y1 = r2.y1;
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef rect_base<int> rect; //----rect
|
||||
typedef rect_base<double> rect_d; //----rect_d
|
||||
|
||||
//---------------------------------------------------------path_commands_e
|
||||
enum path_commands_e
|
||||
{
|
||||
path_cmd_stop = 0, //----path_cmd_stop
|
||||
path_cmd_move_to = 1, //----path_cmd_move_to
|
||||
path_cmd_line_to = 2, //----path_cmd_line_to
|
||||
path_cmd_curve3 = 3, //----path_cmd_curve3
|
||||
path_cmd_curve4 = 4, //----path_cmd_curve4
|
||||
path_cmd_end_poly = 6, //----path_cmd_end_poly
|
||||
path_cmd_mask = 0x0F //----path_cmd_mask
|
||||
};
|
||||
|
||||
//------------------------------------------------------------path_flags_e
|
||||
enum path_flags_e
|
||||
{
|
||||
path_flags_none = 0, //----path_flags_none
|
||||
path_flags_ccw = 0x10, //----path_flags_ccw
|
||||
path_flags_cw = 0x20, //----path_flags_cw
|
||||
path_flags_close = 0x40, //----path_flags_close
|
||||
path_flags_mask = 0xF0 //----path_flags_mask
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------is_vertex
|
||||
inline bool is_vertex(unsigned c)
|
||||
{
|
||||
return c >= path_cmd_move_to && c < path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------is_stop
|
||||
inline bool is_stop(unsigned c)
|
||||
{
|
||||
return c == path_cmd_stop;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_move_to
|
||||
inline bool is_move_to(unsigned c)
|
||||
{
|
||||
return c == path_cmd_move_to;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_line_to
|
||||
inline bool is_line_to(unsigned c)
|
||||
{
|
||||
return c == path_cmd_line_to;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------is_curve
|
||||
inline bool is_curve(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve3 || c == path_cmd_curve4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_curve3
|
||||
inline bool is_curve3(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve3;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_curve4
|
||||
inline bool is_curve4(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve4;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------is_end_poly
|
||||
inline bool is_end_poly(unsigned c)
|
||||
{
|
||||
return (c & path_cmd_mask) == path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------is_close
|
||||
inline bool is_close(unsigned c)
|
||||
{
|
||||
return (c & ~(path_flags_cw | path_flags_ccw)) ==
|
||||
(path_cmd_end_poly | path_flags_close);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------is_next_poly
|
||||
inline bool is_next_poly(unsigned c)
|
||||
{
|
||||
return is_stop(c) || is_move_to(c) || is_end_poly(c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------is_cw
|
||||
inline bool is_cw(unsigned c)
|
||||
{
|
||||
return (c & path_flags_cw) != 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------is_ccw
|
||||
inline bool is_ccw(unsigned c)
|
||||
{
|
||||
return (c & path_flags_ccw) != 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------is_oriented
|
||||
inline bool is_oriented(unsigned c)
|
||||
{
|
||||
return (c & (path_flags_cw | path_flags_ccw)) != 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_closed
|
||||
inline bool is_closed(unsigned c)
|
||||
{
|
||||
return (c & path_flags_close) != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------get_close_flag
|
||||
inline unsigned get_close_flag(unsigned c)
|
||||
{
|
||||
return c & path_flags_close;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------clear_orientation
|
||||
inline unsigned clear_orientation(unsigned c)
|
||||
{
|
||||
return c & ~(path_flags_cw | path_flags_ccw);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------get_orientation
|
||||
inline unsigned get_orientation(unsigned c)
|
||||
{
|
||||
return c & (path_flags_cw | path_flags_ccw);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------set_orientation
|
||||
inline unsigned set_orientation(unsigned c, unsigned o)
|
||||
{
|
||||
return clear_orientation(c) | o;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------point_type
|
||||
struct point_type
|
||||
{
|
||||
double x, y;
|
||||
|
||||
point_type() {}
|
||||
point_type(double x_, double y_) : x(x_), y(y_) {}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------vertex_type
|
||||
struct vertex_type
|
||||
{
|
||||
double x, y;
|
||||
unsigned cmd;
|
||||
|
||||
vertex_type() {}
|
||||
vertex_type(double x_, double y_, unsigned cmd_) :
|
||||
x(x_), y(y_), cmd(cmd_) {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e.,
|
||||
// 4, 7, 10, or 13 vertices.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_bezier_arc.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------arc_to_bezier
|
||||
void arc_to_bezier(double cx, double cy, double rx, double ry,
|
||||
double start_angle, double sweep_angle,
|
||||
double* curve)
|
||||
{
|
||||
double x0 = cos(sweep_angle / 2.0);
|
||||
double y0 = sin(sweep_angle / 2.0);
|
||||
double tx = (1.0 - x0) * 4.0 / 3.0;
|
||||
double ty = y0 - tx * x0 / y0;
|
||||
double px[4];
|
||||
double py[4];
|
||||
px[0] = x0;
|
||||
py[0] = -y0;
|
||||
px[1] = x0 + tx;
|
||||
py[1] = -ty;
|
||||
px[2] = x0 + tx;
|
||||
py[2] = ty;
|
||||
px[3] = x0;
|
||||
py[3] = y0;
|
||||
|
||||
double sn = sin(start_angle + sweep_angle / 2.0);
|
||||
double cs = cos(start_angle + sweep_angle / 2.0);
|
||||
|
||||
unsigned i;
|
||||
for(i = 0; i < 4; i++)
|
||||
{
|
||||
curve[i * 2] = cx + rx * (px[i] * cs - py[i] * sn);
|
||||
curve[i * 2 + 1] = cy + ry * (px[i] * sn + py[i] * cs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void bezier_arc::init(double x, double y,
|
||||
double rx, double ry,
|
||||
double start_angle,
|
||||
double sweep_angle)
|
||||
{
|
||||
start_angle = fmod(start_angle, 2.0 * pi);
|
||||
if(sweep_angle >= 2.0 * pi) sweep_angle = 2.0 * pi;
|
||||
if(sweep_angle <= -2.0 * pi) sweep_angle = -2.0 * pi;
|
||||
|
||||
double total_sweep = 0.0;
|
||||
double local_sweep = 0.0;
|
||||
m_num_vertices = 2;
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
if(sweep_angle < 0.0)
|
||||
{
|
||||
local_sweep = -pi * 0.5;
|
||||
total_sweep -= pi * 0.5;
|
||||
if(total_sweep <= sweep_angle)
|
||||
{
|
||||
local_sweep = sweep_angle - (total_sweep + pi * 0.5);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
local_sweep = pi * 0.5;
|
||||
total_sweep += pi * 0.5;
|
||||
if(total_sweep >= sweep_angle)
|
||||
{
|
||||
local_sweep = sweep_angle - (total_sweep - pi * 0.5);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
arc_to_bezier(x, y, rx, ry,
|
||||
start_angle,
|
||||
local_sweep,
|
||||
m_vertices + m_num_vertices - 2);
|
||||
|
||||
m_num_vertices += 6;
|
||||
start_angle += local_sweep;
|
||||
}
|
||||
while(!done && m_num_vertices < 26);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void bezier_arc_svg::init(double x0, double y0,
|
||||
double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double x2, double y2)
|
||||
{
|
||||
m_radii_ok = true;
|
||||
|
||||
if(rx < 0.0) rx = -rx;
|
||||
if(ry < 0.0) ry = -rx;
|
||||
|
||||
// Calculate the middle point between
|
||||
// the current and the final points
|
||||
//------------------------
|
||||
double dx2 = (x0 - x2) / 2.0;
|
||||
double dy2 = (y0 - y2) / 2.0;
|
||||
|
||||
// Convert angle from degrees to radians
|
||||
//------------------------
|
||||
double cos_a = cos(angle);
|
||||
double sin_a = sin(angle);
|
||||
|
||||
// Calculate (x1, y1)
|
||||
//------------------------
|
||||
double x1 = cos_a * dx2 + sin_a * dy2;
|
||||
double y1 = -sin_a * dx2 + cos_a * dy2;
|
||||
|
||||
// Ensure radii are large enough
|
||||
//------------------------
|
||||
double prx = rx * rx;
|
||||
double pry = ry * ry;
|
||||
double px1 = x1 * x1;
|
||||
double py1 = y1 * y1;
|
||||
|
||||
// Check that radii are large enough
|
||||
//------------------------
|
||||
double radii_check = px1/prx + py1/pry;
|
||||
if(radii_check > 1.0)
|
||||
{
|
||||
rx = sqrt(radii_check) * rx;
|
||||
ry = sqrt(radii_check) * ry;
|
||||
prx = rx * rx;
|
||||
pry = ry * ry;
|
||||
if(radii_check > 10.0) m_radii_ok = false;
|
||||
}
|
||||
|
||||
// Calculate (cx1, cy1)
|
||||
//------------------------
|
||||
double sign = (large_arc_flag == sweep_flag) ? -1.0 : 1.0;
|
||||
double sq = (prx*pry - prx*py1 - pry*px1) / (prx*py1 + pry*px1);
|
||||
double coef = sign * sqrt((sq < 0) ? 0 : sq);
|
||||
double cx1 = coef * ((rx * y1) / ry);
|
||||
double cy1 = coef * -((ry * x1) / rx);
|
||||
|
||||
//
|
||||
// Calculate (cx, cy) from (cx1, cy1)
|
||||
//------------------------
|
||||
double sx2 = (x0 + x2) / 2.0;
|
||||
double sy2 = (y0 + y2) / 2.0;
|
||||
double cx = sx2 + (cos_a * cx1 - sin_a * cy1);
|
||||
double cy = sy2 + (sin_a * cx1 + cos_a * cy1);
|
||||
|
||||
// Calculate the start_angle (angle1) and the sweep_angle (dangle)
|
||||
//------------------------
|
||||
double ux = (x1 - cx1) / rx;
|
||||
double uy = (y1 - cy1) / ry;
|
||||
double vx = (-x1 - cx1) / rx;
|
||||
double vy = (-y1 - cy1) / ry;
|
||||
double p, n;
|
||||
|
||||
// Calculate the angle start
|
||||
//------------------------
|
||||
n = sqrt(ux*ux + uy*uy);
|
||||
p = ux; // (1 * ux) + (0 * uy)
|
||||
sign = (uy < 0) ? -1.0 : 1.0;
|
||||
double v = p / n;
|
||||
if(v < -1.0) v = -1.0;
|
||||
if(v > 1.0) v = 1.0;
|
||||
double start_angle = sign * acos(v);
|
||||
|
||||
// Calculate the sweep angle
|
||||
//------------------------
|
||||
n = sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy));
|
||||
p = ux * vx + uy * vy;
|
||||
sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0;
|
||||
v = p / n;
|
||||
if(v < -1.0) v = -1.0;
|
||||
if(v > 1.0) v = 1.0;
|
||||
double sweep_angle = sign * acos(v);
|
||||
if(!sweep_flag && sweep_angle > 0)
|
||||
{
|
||||
sweep_angle -= pi * 2.0;
|
||||
}
|
||||
else
|
||||
if (sweep_flag && sweep_angle < 0)
|
||||
{
|
||||
sweep_angle += pi * 2.0;
|
||||
}
|
||||
|
||||
// We can now build and transform the resulting arc
|
||||
//------------------------
|
||||
m_arc.init(0.0, 0.0, rx, ry, start_angle, sweep_angle);
|
||||
trans_affine mtx = trans_affine_rotation(angle);
|
||||
mtx *= trans_affine_translation(cx, cy);
|
||||
|
||||
for(unsigned i = 2; i < m_arc.num_vertices()-2; i += 2)
|
||||
{
|
||||
mtx.transform(m_arc.vertices() + i, m_arc.vertices() + i + 1);
|
||||
}
|
||||
|
||||
// We must make sure that the starting and ending points
|
||||
// exactly coincide with the initial (x0,y0) and (x2,y2)
|
||||
m_arc.vertices()[0] = x0;
|
||||
m_arc.vertices()[1] = y0;
|
||||
if(m_arc.num_vertices() > 2)
|
||||
{
|
||||
m_arc.vertices()[m_arc.num_vertices() - 2] = x2;
|
||||
m_arc.vertices()[m_arc.num_vertices() - 1] = y2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e.,
|
||||
// 4, 7, 10, or 13 vertices.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_BEZIER_ARC_INCLUDED
|
||||
#define AGG_BEZIER_ARC_INCLUDED
|
||||
|
||||
#include "agg_conv_transform.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void arc_to_bezier(double cx, double cy, double rx, double ry,
|
||||
double start_angle, double sweep_angle,
|
||||
double* curve);
|
||||
|
||||
|
||||
//==============================================================bezier_arc
|
||||
//
|
||||
// See implemantaion agg_bezier_arc.cpp
|
||||
//
|
||||
class bezier_arc
|
||||
{
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
bezier_arc() : m_vertex(26) {}
|
||||
bezier_arc(double x, double y,
|
||||
double rx, double ry,
|
||||
double start_angle,
|
||||
double sweep_angle)
|
||||
{
|
||||
init(x, y, rx, ry, start_angle, sweep_angle);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void init(double x, double y,
|
||||
double rx, double ry,
|
||||
double start_angle,
|
||||
double sweep_angle);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void rewind(unsigned)
|
||||
{
|
||||
m_vertex = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
if(m_vertex >= m_num_vertices) return path_cmd_stop;
|
||||
*x = m_vertices[m_vertex];
|
||||
*y = m_vertices[m_vertex + 1];
|
||||
m_vertex += 2;
|
||||
return (m_vertex == 2) ? path_cmd_move_to : path_cmd_curve4;
|
||||
}
|
||||
|
||||
// Supplemantary functions. num_vertices() actually returns doubled
|
||||
// number of vertices. That is, for 1 vertex it returns 2.
|
||||
//--------------------------------------------------------------------
|
||||
unsigned num_vertices() const { return m_num_vertices; }
|
||||
const double* vertices() const { return m_vertices; }
|
||||
double* vertices() { return m_vertices; }
|
||||
|
||||
private:
|
||||
unsigned m_vertex;
|
||||
unsigned m_num_vertices;
|
||||
double m_vertices[26];
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==========================================================bezier_arc_svg
|
||||
// Compute an SVG-style bezier arc.
|
||||
//
|
||||
// Computes an elliptical arc from (x1, y1) to (x2, y2). The size and
|
||||
// orientation of the ellipse are defined by two radii (rx, ry)
|
||||
// and an x-axis-rotation, which indicates how the ellipse as a whole
|
||||
// is rotated relative to the current coordinate system. The center
|
||||
// (cx, cy) of the ellipse is calculated automatically to satisfy the
|
||||
// constraints imposed by the other parameters.
|
||||
// large-arc-flag and sweep-flag contribute to the automatic calculations
|
||||
// and help determine how the arc is drawn.
|
||||
class bezier_arc_svg
|
||||
{
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
bezier_arc_svg() : m_arc(), m_radii_ok(false) {}
|
||||
|
||||
bezier_arc_svg(double x1, double y1,
|
||||
double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double x2, double y2) :
|
||||
m_arc(), m_radii_ok(false)
|
||||
{
|
||||
init(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void init(double x1, double y1,
|
||||
double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double x2, double y2);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool radii_ok() const { return m_radii_ok; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void rewind(unsigned)
|
||||
{
|
||||
m_arc.rewind(0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
return m_arc.vertex(x, y);
|
||||
}
|
||||
|
||||
// Supplemantary functions. num_vertices() actually returns doubled
|
||||
// number of vertices. That is, for 1 vertex it returns 2.
|
||||
//--------------------------------------------------------------------
|
||||
unsigned num_vertices() const { return m_arc.num_vertices(); }
|
||||
const double* vertices() const { return m_arc.vertices(); }
|
||||
double* vertices() { return m_arc.vertices(); }
|
||||
|
||||
private:
|
||||
bezier_arc m_arc;
|
||||
bool m_radii_ok;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,209 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Liang-Barsky clipping
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED
|
||||
#define AGG_CLIP_LIANG_BARSKY_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//----------------------------------------------------------clipping_flags
|
||||
// Determine the clipping code of the vertex according to the
|
||||
// Cyrus-Beck line clipping algorithm
|
||||
//
|
||||
// | |
|
||||
// 0110 | 0010 | 0011
|
||||
// | |
|
||||
// -------+--------+-------- clip_box.y2
|
||||
// | |
|
||||
// 0100 | 0000 | 0001
|
||||
// | |
|
||||
// -------+--------+-------- clip_box.y1
|
||||
// | |
|
||||
// 1100 | 1000 | 1001
|
||||
// | |
|
||||
// clip_box.x1 clip_box.x2
|
||||
//
|
||||
//
|
||||
template<class T>
|
||||
inline unsigned clipping_flags(T x, T y, const rect_base<T>& clip_box)
|
||||
{
|
||||
return (x > clip_box.x2) |
|
||||
((y > clip_box.y2) << 1) |
|
||||
((x < clip_box.x1) << 2) |
|
||||
((y < clip_box.y1) << 3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------clip_liang_barsky
|
||||
template<class T>
|
||||
inline unsigned clip_liang_barsky(T x1, T y1, T x2, T y2,
|
||||
const rect_base<T>& clip_box,
|
||||
T* x, T* y)
|
||||
{
|
||||
const double nearzero = 1e-30;
|
||||
|
||||
double deltax = x2 - x1;
|
||||
double deltay = y2 - y1;
|
||||
double xin;
|
||||
double xout;
|
||||
double yin;
|
||||
double yout;
|
||||
double tinx;
|
||||
double tiny;
|
||||
double toutx;
|
||||
double touty;
|
||||
double tin1;
|
||||
double tin2;
|
||||
double tout1;
|
||||
unsigned np = 0;
|
||||
|
||||
if(deltax == 0.0)
|
||||
{
|
||||
// bump off of the vertical
|
||||
deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
|
||||
}
|
||||
|
||||
if(deltay == 0.0)
|
||||
{
|
||||
// bump off of the horizontal
|
||||
deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
|
||||
}
|
||||
|
||||
if(deltax > 0.0)
|
||||
{
|
||||
// points to right
|
||||
xin = clip_box.x1;
|
||||
xout = clip_box.x2;
|
||||
}
|
||||
else
|
||||
{
|
||||
xin = clip_box.x2;
|
||||
xout = clip_box.x1;
|
||||
}
|
||||
|
||||
if(deltay > 0.0)
|
||||
{
|
||||
// points up
|
||||
yin = clip_box.y1;
|
||||
yout = clip_box.y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
yin = clip_box.y2;
|
||||
yout = clip_box.y1;
|
||||
}
|
||||
|
||||
tinx = (xin - x1) / deltax;
|
||||
tiny = (yin - y1) / deltay;
|
||||
|
||||
if (tinx < tiny)
|
||||
{
|
||||
// hits x first
|
||||
tin1 = tinx;
|
||||
tin2 = tiny;
|
||||
}
|
||||
else
|
||||
{
|
||||
// hits y first
|
||||
tin1 = tiny;
|
||||
tin2 = tinx;
|
||||
}
|
||||
|
||||
if(tin1 <= 1.0)
|
||||
{
|
||||
if(0.0 < tin1)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)yin;
|
||||
++np;
|
||||
}
|
||||
|
||||
if(tin2 <= 1.0)
|
||||
{
|
||||
toutx = (xout - x1) / deltax;
|
||||
touty = (yout - y1) / deltay;
|
||||
|
||||
tout1 = (toutx < touty) ? toutx : touty;
|
||||
|
||||
if(tin2 > 0.0 || tout1 > 0.0)
|
||||
{
|
||||
if(tin2 <= tout1)
|
||||
{
|
||||
if(tin2 > 0.0)
|
||||
{
|
||||
if(tinx > tiny)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)(y1 + tinx * deltay);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)(x1 + tiny * deltax);
|
||||
*y++ = (T)yin;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
|
||||
if(tout1 < 1.0)
|
||||
{
|
||||
if(toutx < touty)
|
||||
{
|
||||
*x++ = (T)xout;
|
||||
*y++ = (T)(y1 + toutx * deltay);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)(x1 + touty * deltax);
|
||||
*y++ = (T)yout;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = x2;
|
||||
*y++ = y2;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tinx > tiny)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)yout;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)xout;
|
||||
*y++ = (T)yin;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return np;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,618 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for high precision colors has been sponsored by
|
||||
// Liberty Technology Systems, Inc., visit http://lib-sys.com
|
||||
//
|
||||
// Liberty Technology Systems, Inc. is the provider of
|
||||
// PostScript and PDF technology for software developers.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_COLOR_RGBA_INCLUDED
|
||||
#define AGG_COLOR_RGBA_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
// Supported byte orders for RGB and RGBA pixel formats
|
||||
//=======================================================================
|
||||
struct order_rgb { enum { R=0, G=1, B=2, rgb_tag }; }; //----order_rgb
|
||||
struct order_bgr { enum { B=0, G=1, R=2, rgb_tag }; }; //----order_bgr
|
||||
struct order_rgba { enum { R=0, G=1, B=2, A=3, rgba_tag }; }; //----order_rgba
|
||||
struct order_argb { enum { A=0, R=1, G=2, B=3, rgba_tag }; }; //----order_argb
|
||||
struct order_abgr { enum { A=0, B=1, G=2, R=3, rgba_tag }; }; //----order_abgr
|
||||
struct order_bgra { enum { B=0, G=1, R=2, A=3, rgba_tag }; }; //----order_bgra
|
||||
|
||||
//====================================================================rgba
|
||||
struct rgba
|
||||
{
|
||||
typedef double value_type;
|
||||
|
||||
double r;
|
||||
double g;
|
||||
double b;
|
||||
double a;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba(double r_, double g_, double b_, double a_=1.0) :
|
||||
r(r_), g(g_), b(b_), a(a_) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba(const rgba& c, double a_) : r(c.r), g(c.g), b(c.b), a(a_) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear()
|
||||
{
|
||||
r = g = b = a = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rgba& transparent()
|
||||
{
|
||||
a = 0.0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rgba& opacity(double a_)
|
||||
{
|
||||
if(a_ < 0.0) a_ = 0.0;
|
||||
if(a_ > 1.0) a_ = 1.0;
|
||||
a = a_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
double opacity() const
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rgba& premultiply()
|
||||
{
|
||||
r *= a;
|
||||
g *= a;
|
||||
b *= a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rgba& premultiply(double a_)
|
||||
{
|
||||
if(a == 0.0 || a_ == 0.0)
|
||||
{
|
||||
r = g = b = a = 0.0;
|
||||
return *this;
|
||||
}
|
||||
a_ /= a;
|
||||
r *= a_;
|
||||
g *= a_;
|
||||
b *= a_;
|
||||
a = a_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rgba& demultiply()
|
||||
{
|
||||
if(a == 0)
|
||||
{
|
||||
r = g = b = 0;
|
||||
return *this;
|
||||
}
|
||||
double a_ = 1.0 / a;
|
||||
r *= a_;
|
||||
g *= a_;
|
||||
b *= a_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba gradient(rgba c, double k) const
|
||||
{
|
||||
rgba ret;
|
||||
ret.r = r + (c.r - r) * k;
|
||||
ret.g = g + (c.g - g) * k;
|
||||
ret.b = b + (c.b - b) * k;
|
||||
ret.a = a + (c.a - a) * k;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static rgba no_color() { return rgba(0,0,0,0); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static rgba from_wavelength(double wl, double gamma = 1.0);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba(double wavelen, double gamma=1.0)
|
||||
{
|
||||
*this = from_wavelength(wavelen, gamma);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------rgba_pre
|
||||
inline rgba rgba_pre(double r, double g, double b, double a=1.0)
|
||||
{
|
||||
return rgba(r, g, b, a).premultiply();
|
||||
}
|
||||
inline rgba rgba_pre(const rgba& c)
|
||||
{
|
||||
return rgba(c).premultiply();
|
||||
}
|
||||
inline rgba rgba_pre(const rgba& c, double a)
|
||||
{
|
||||
return rgba(c, a).premultiply();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline rgba rgba::from_wavelength(double wl, double gamma)
|
||||
{
|
||||
rgba t(0.0, 0.0, 0.0);
|
||||
|
||||
if(wl >= 380.0 && wl <= 440.0)
|
||||
{
|
||||
t.r = -1.0 * (wl - 440.0) / (440.0 - 380.0);
|
||||
t.b = 1.0;
|
||||
}
|
||||
else
|
||||
if(wl >= 440.0 && wl <= 490.0)
|
||||
{
|
||||
t.g = (wl - 440.0) / (490.0 - 440.0);
|
||||
t.b = 1.0;
|
||||
}
|
||||
else
|
||||
if(wl >= 490.0 && wl <= 510.0)
|
||||
{
|
||||
t.g = 1.0;
|
||||
t.b = -1.0 * (wl - 510.0) / (510.0 - 490.0);
|
||||
}
|
||||
else
|
||||
if(wl >= 510.0 && wl <= 580.0)
|
||||
{
|
||||
t.r = (wl - 510.0) / (580.0 - 510.0);
|
||||
t.g = 1.0;
|
||||
}
|
||||
else
|
||||
if(wl >= 580.0 && wl <= 645.0)
|
||||
{
|
||||
t.r = 1.0;
|
||||
t.g = -1.0 * (wl - 645.0) / (645.0 - 580.0);
|
||||
}
|
||||
else
|
||||
if(wl >= 645.0 && wl <= 780.0)
|
||||
{
|
||||
t.r = 1.0;
|
||||
}
|
||||
|
||||
double s = 1.0;
|
||||
if(wl > 700.0) s = 0.3 + 0.7 * (780.0 - wl) / (780.0 - 700.0);
|
||||
else if(wl < 420.0) s = 0.3 + 0.7 * (wl - 380.0) / (420.0 - 380.0);
|
||||
|
||||
t.r = pow(t.r * s, gamma);
|
||||
t.g = pow(t.g * s, gamma);
|
||||
t.b = pow(t.b * s, gamma);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//===================================================================rgba8
|
||||
struct rgba8
|
||||
{
|
||||
typedef int8u value_type;
|
||||
typedef int32u calc_type;
|
||||
typedef int32 long_type;
|
||||
enum
|
||||
{
|
||||
base_shift = 8,
|
||||
base_size = 1 << base_shift,
|
||||
base_mask = base_size - 1
|
||||
};
|
||||
typedef rgba8 self_type;
|
||||
|
||||
|
||||
value_type r;
|
||||
value_type g;
|
||||
value_type b;
|
||||
value_type a;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba8() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba8(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) :
|
||||
r(value_type(r_)),
|
||||
g(value_type(g_)),
|
||||
b(value_type(b_)),
|
||||
a(value_type(a_)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba8(const rgba& c, double a_) :
|
||||
r(value_type(c.r * double(base_mask) + 0.5)),
|
||||
g(value_type(c.g * double(base_mask) + 0.5)),
|
||||
b(value_type(c.b * double(base_mask) + 0.5)),
|
||||
a(value_type(a_ * double(base_mask) + 0.5)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba8(const self_type& c, unsigned a_) :
|
||||
r(c.r), g(c.g), b(c.b), a(value_type(a_)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba8(const rgba& c) :
|
||||
r(value_type(c.r * double(base_mask) + 0.5)),
|
||||
g(value_type(c.g * double(base_mask) + 0.5)),
|
||||
b(value_type(c.b * double(base_mask) + 0.5)),
|
||||
a(value_type(c.a * double(base_mask) + 0.5)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear()
|
||||
{
|
||||
r = g = b = a = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& transparent()
|
||||
{
|
||||
a = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& opacity(double a_)
|
||||
{
|
||||
if(a_ < 0.0) a_ = 0.0;
|
||||
if(a_ > 1.0) a_ = 1.0;
|
||||
a = value_type(a_ * double(base_mask) + 0.5);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
double opacity() const
|
||||
{
|
||||
return double(a) / double(base_mask);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& premultiply()
|
||||
{
|
||||
if(a == base_mask) return *this;
|
||||
if(a == 0)
|
||||
{
|
||||
r = g = b = 0;
|
||||
return *this;
|
||||
}
|
||||
r = value_type((calc_type(r) * a) >> base_shift);
|
||||
g = value_type((calc_type(g) * a) >> base_shift);
|
||||
b = value_type((calc_type(b) * a) >> base_shift);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& premultiply(unsigned a_)
|
||||
{
|
||||
if(a == base_mask && a_ >= base_mask) return *this;
|
||||
if(a == 0 || a_ == 0)
|
||||
{
|
||||
r = g = b = a = 0;
|
||||
return *this;
|
||||
}
|
||||
calc_type r_ = (calc_type(r) * a_) / a;
|
||||
calc_type g_ = (calc_type(g) * a_) / a;
|
||||
calc_type b_ = (calc_type(b) * a_) / a;
|
||||
r = value_type((r_ > a_) ? a_ : r_);
|
||||
g = value_type((g_ > a_) ? a_ : g_);
|
||||
b = value_type((b_ > a_) ? a_ : b_);
|
||||
a = value_type(a_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& demultiply()
|
||||
{
|
||||
if(a == base_mask) return *this;
|
||||
if(a == 0)
|
||||
{
|
||||
r = g = b = 0;
|
||||
return *this;
|
||||
}
|
||||
calc_type r_ = (calc_type(r) * base_mask) / a;
|
||||
calc_type g_ = (calc_type(g) * base_mask) / a;
|
||||
calc_type b_ = (calc_type(b) * base_mask) / a;
|
||||
r = value_type((r_ > base_mask) ? calc_type(base_mask) : r_);
|
||||
g = value_type((g_ > base_mask) ? calc_type(base_mask) : g_);
|
||||
b = value_type((b_ > base_mask) ? calc_type(base_mask) : b_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
self_type gradient(const self_type& c, double k) const
|
||||
{
|
||||
self_type ret;
|
||||
calc_type ik = calc_type(k * base_size);
|
||||
ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift));
|
||||
ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift));
|
||||
ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift));
|
||||
ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift));
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static self_type no_color() { return self_type(0,0,0,0); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static self_type from_wavelength(double wl, double gamma = 1.0)
|
||||
{
|
||||
return self_type(rgba::from_wavelength(wl, gamma));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------rgba8_pre
|
||||
inline rgba8 rgba8_pre(unsigned r, unsigned g, unsigned b,
|
||||
unsigned a = rgba8::base_mask)
|
||||
{
|
||||
return rgba8(r,g,b,a).premultiply();
|
||||
}
|
||||
inline rgba8 rgba8_pre(const rgba8& c)
|
||||
{
|
||||
return rgba8(c).premultiply();
|
||||
}
|
||||
inline rgba8 rgba8_pre(const rgba8& c, unsigned a)
|
||||
{
|
||||
return rgba8(c,a).premultiply();
|
||||
}
|
||||
inline rgba8 rgba8_pre(const rgba& c)
|
||||
{
|
||||
return rgba8(c).premultiply();
|
||||
}
|
||||
inline rgba8 rgba8_pre(const rgba& c, double a)
|
||||
{
|
||||
return rgba8(c,a).premultiply();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------rgb8_packed
|
||||
inline rgba8 rgb8_packed(unsigned v)
|
||||
{
|
||||
return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------bgr8_packed
|
||||
inline rgba8 bgr8_packed(unsigned v)
|
||||
{
|
||||
return rgba8(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------argb8_packed
|
||||
inline rgba8 argb8_packed(unsigned v)
|
||||
{
|
||||
return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF, v >> 24);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=================================================================rgba16
|
||||
struct rgba16
|
||||
{
|
||||
typedef int16u value_type;
|
||||
typedef int32u calc_type;
|
||||
typedef int64 long_type;
|
||||
enum
|
||||
{
|
||||
base_shift = 16,
|
||||
base_size = 1 << base_shift,
|
||||
base_mask = base_size - 1
|
||||
};
|
||||
typedef rgba16 self_type;
|
||||
|
||||
value_type r;
|
||||
value_type g;
|
||||
value_type b;
|
||||
value_type a;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba16() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba16(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) :
|
||||
r(value_type(r_)),
|
||||
g(value_type(g_)),
|
||||
b(value_type(b_)),
|
||||
a(value_type(a_)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba16(const self_type& c, unsigned a_) :
|
||||
r(c.r), g(c.g), b(c.b), a(value_type(a_)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba16(const rgba& c) :
|
||||
r(value_type(c.r * double(base_mask) + 0.5)),
|
||||
g(value_type(c.g * double(base_mask) + 0.5)),
|
||||
b(value_type(c.b * double(base_mask) + 0.5)),
|
||||
a(value_type(c.a * double(base_mask) + 0.5)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba16(const rgba& c, double a_) :
|
||||
r(value_type(c.r * double(base_mask) + 0.5)),
|
||||
g(value_type(c.g * double(base_mask) + 0.5)),
|
||||
b(value_type(c.b * double(base_mask) + 0.5)),
|
||||
a(value_type(a_ * double(base_mask) + 0.5)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba16(const rgba8& c) :
|
||||
r(value_type((value_type(c.r) << 8) | c.r)),
|
||||
g(value_type((value_type(c.g) << 8) | c.g)),
|
||||
b(value_type((value_type(c.b) << 8) | c.b)),
|
||||
a(value_type((value_type(c.a) << 8) | c.a)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rgba16(const rgba8& c, unsigned a_) :
|
||||
r(value_type((value_type(c.r) << 8) | c.r)),
|
||||
g(value_type((value_type(c.g) << 8) | c.g)),
|
||||
b(value_type((value_type(c.b) << 8) | c.b)),
|
||||
a(value_type(( a_ << 8) | c.a)) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear()
|
||||
{
|
||||
r = g = b = a = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& transparent()
|
||||
{
|
||||
a = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& opacity(double a_)
|
||||
{
|
||||
if(a_ < 0.0) a_ = 0.0;
|
||||
if(a_ > 1.0) a_ = 1.0;
|
||||
a = value_type(a_ * double(base_mask) + 0.5);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
double opacity() const
|
||||
{
|
||||
return double(a) / double(base_mask);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& premultiply()
|
||||
{
|
||||
if(a == base_mask) return *this;
|
||||
if(a == 0)
|
||||
{
|
||||
r = g = b = 0;
|
||||
return *this;
|
||||
}
|
||||
r = value_type((calc_type(r) * a) >> base_shift);
|
||||
g = value_type((calc_type(g) * a) >> base_shift);
|
||||
b = value_type((calc_type(b) * a) >> base_shift);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& premultiply(unsigned a_)
|
||||
{
|
||||
if(a == base_mask && a_ >= base_mask) return *this;
|
||||
if(a == 0 || a_ == 0)
|
||||
{
|
||||
r = g = b = a = 0;
|
||||
return *this;
|
||||
}
|
||||
calc_type r_ = (calc_type(r) * a_) / a;
|
||||
calc_type g_ = (calc_type(g) * a_) / a;
|
||||
calc_type b_ = (calc_type(b) * a_) / a;
|
||||
r = value_type((r_ > a_) ? a_ : r_);
|
||||
g = value_type((g_ > a_) ? a_ : g_);
|
||||
b = value_type((b_ > a_) ? a_ : b_);
|
||||
a = value_type(a_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const self_type& demultiply()
|
||||
{
|
||||
if(a == base_mask) return *this;
|
||||
if(a == 0)
|
||||
{
|
||||
r = g = b = 0;
|
||||
return *this;
|
||||
}
|
||||
calc_type r_ = (calc_type(r) * base_mask) / a;
|
||||
calc_type g_ = (calc_type(g) * base_mask) / a;
|
||||
calc_type b_ = (calc_type(b) * base_mask) / a;
|
||||
r = value_type((r_ > base_mask) ? calc_type(base_mask) : r_);
|
||||
g = value_type((g_ > base_mask) ? calc_type(base_mask) : g_);
|
||||
b = value_type((b_ > base_mask) ? calc_type(base_mask) : b_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
self_type gradient(const self_type& c, double k) const
|
||||
{
|
||||
self_type ret;
|
||||
calc_type ik = calc_type(k * base_size);
|
||||
ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift));
|
||||
ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift));
|
||||
ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift));
|
||||
ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift));
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static self_type no_color() { return self_type(0,0,0,0); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static self_type from_wavelength(double wl, double gamma = 1.0)
|
||||
{
|
||||
return self_type(rgba::from_wavelength(wl, gamma));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------rgba16_pre
|
||||
inline rgba16 rgba16_pre(unsigned r, unsigned g, unsigned b,
|
||||
unsigned a = rgba16::base_mask)
|
||||
{
|
||||
return rgba16(r,g,b,a).premultiply();
|
||||
}
|
||||
inline rgba16 rgba16_pre(const rgba16& c, unsigned a)
|
||||
{
|
||||
return rgba16(c,a).premultiply();
|
||||
}
|
||||
inline rgba16 rgba16_pre(const rgba& c)
|
||||
{
|
||||
return rgba16(c).premultiply();
|
||||
}
|
||||
inline rgba16 rgba16_pre(const rgba& c, double a)
|
||||
{
|
||||
return rgba16(c,a).premultiply();
|
||||
}
|
||||
inline rgba16 rgba16_pre(const rgba8& c)
|
||||
{
|
||||
return rgba16(c).premultiply();
|
||||
}
|
||||
inline rgba16 rgba16_pre(const rgba8& c, unsigned a)
|
||||
{
|
||||
return rgba16(c,a).premultiply();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,169 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_CONV_ADAPTOR_VCGEN_INCLUDED
|
||||
#define AGG_CONV_ADAPTOR_VCGEN_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vertex_iterator.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//------------------------------------------------------------null_markers
|
||||
struct null_markers
|
||||
{
|
||||
void remove_all() {}
|
||||
void add_vertex(double, double, unsigned) {}
|
||||
void prepare_src() {}
|
||||
|
||||
void rewind(unsigned) {}
|
||||
unsigned vertex(double*, double*) { return path_cmd_stop; }
|
||||
|
||||
typedef null_markers source_type;
|
||||
typedef vertex_iterator<source_type> iterator;
|
||||
iterator begin(unsigned id) { return iterator(*this, id); }
|
||||
iterator end() { return iterator(path_cmd_stop); }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------conv_adaptor_vcgen
|
||||
template<class VertexSource,
|
||||
class Generator,
|
||||
class Markers=null_markers> class conv_adaptor_vcgen
|
||||
{
|
||||
enum status
|
||||
{
|
||||
initial,
|
||||
accumulate,
|
||||
generate
|
||||
};
|
||||
|
||||
public:
|
||||
conv_adaptor_vcgen(VertexSource& source) :
|
||||
m_source(&source),
|
||||
m_status(initial)
|
||||
{}
|
||||
|
||||
void set_source(VertexSource& source) { m_source = &source; }
|
||||
|
||||
Generator& generator() { return m_generator; }
|
||||
const Generator& generator() const { return m_generator; }
|
||||
|
||||
Markers& markers() { return m_markers; }
|
||||
const Markers& markers() const { return m_markers; }
|
||||
|
||||
void rewind(unsigned id)
|
||||
{
|
||||
m_source->rewind(id);
|
||||
m_status = initial;
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
typedef conv_adaptor_vcgen<VertexSource, Generator, Markers> source_type;
|
||||
typedef vertex_iterator<source_type> iterator;
|
||||
iterator begin(unsigned id) { return iterator(*this, id); }
|
||||
iterator end() { return iterator(path_cmd_stop); }
|
||||
|
||||
private:
|
||||
// Prohibit copying
|
||||
conv_adaptor_vcgen(const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
|
||||
const conv_adaptor_vcgen<VertexSource, Generator, Markers>&
|
||||
operator = (const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
|
||||
|
||||
VertexSource* m_source;
|
||||
Generator m_generator;
|
||||
Markers m_markers;
|
||||
status m_status;
|
||||
unsigned m_last_cmd;
|
||||
double m_start_x;
|
||||
double m_start_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class VertexSource, class Generator, class Markers>
|
||||
unsigned conv_adaptor_vcgen<VertexSource, Generator, Markers>::vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_stop;
|
||||
bool done = false;
|
||||
while(!done)
|
||||
{
|
||||
switch(m_status)
|
||||
{
|
||||
case initial:
|
||||
m_markers.remove_all();
|
||||
m_last_cmd = m_source->vertex(&m_start_x, &m_start_y);
|
||||
m_status = accumulate;
|
||||
|
||||
case accumulate:
|
||||
if(is_stop(m_last_cmd)) return path_cmd_stop;
|
||||
|
||||
m_generator.remove_all();
|
||||
m_generator.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
|
||||
m_markers.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
cmd = m_source->vertex(x, y);
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_last_cmd = cmd;
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
m_start_x = *x;
|
||||
m_start_y = *y;
|
||||
break;
|
||||
}
|
||||
m_generator.add_vertex(*x, *y, cmd);
|
||||
m_markers.add_vertex(*x, *y, path_cmd_line_to);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_stop(cmd))
|
||||
{
|
||||
m_last_cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
if(is_end_poly(cmd))
|
||||
{
|
||||
m_generator.add_vertex(*x, *y, cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_generator.rewind(0);
|
||||
m_status = generate;
|
||||
|
||||
case generate:
|
||||
cmd = m_generator.vertex(x, y);
|
||||
if(is_stop(cmd))
|
||||
{
|
||||
m_status = accumulate;
|
||||
break;
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// conv_stroke
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CONV_STROKE_INCLUDED
|
||||
#define AGG_CONV_STROKE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vcgen_stroke.h"
|
||||
#include "agg_conv_adaptor_vcgen.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------conv_stroke
|
||||
template<class VertexSource, class Markers=null_markers>
|
||||
struct conv_stroke :
|
||||
public conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers>
|
||||
{
|
||||
typedef Markers marker_type;
|
||||
typedef conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers> base_type;
|
||||
|
||||
conv_stroke(VertexSource& vs) :
|
||||
conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers>(vs)
|
||||
{
|
||||
}
|
||||
|
||||
void line_cap(line_cap_e lc) { base_type::generator().line_cap(lc); }
|
||||
void line_join(line_join_e lj) { base_type::generator().line_join(lj); }
|
||||
void inner_line_join(line_join_e lj) { base_type::generator().inner_line_join(lj); }
|
||||
|
||||
line_cap_e line_cap() const { return base_type::generator().line_cap(); }
|
||||
line_join_e line_join() const { return base_type::generator().line_join(); }
|
||||
line_join_e inner_line_join() const { return base_type::generator().inner_line_join(); }
|
||||
|
||||
void width(double w) { base_type::generator().width(w); }
|
||||
void miter_limit(double ml) { base_type::generator().miter_limit(ml); }
|
||||
void miter_limit_theta(double t) { base_type::generator().miter_limit_theta(t); }
|
||||
void inner_miter_limit(double ml) { base_type::generator().inner_miter_limit(ml); }
|
||||
void approximation_scale(double as) { base_type::generator().approximation_scale(as); }
|
||||
|
||||
double width() const { return base_type::generator().width(); }
|
||||
double miter_limit() const { return base_type::generator().miter_limit(); }
|
||||
double inner_miter_limit() const { return base_type::generator().inner_miter_limit(); }
|
||||
double approximation_scale() const { return base_type::generator().approximation_scale(); }
|
||||
|
||||
void shorten(double s) { base_type::generator().shorten(s); }
|
||||
double shorten() const { return base_type::generator().shorten(); }
|
||||
|
||||
private:
|
||||
conv_stroke(const conv_stroke<VertexSource, Markers>&);
|
||||
const conv_stroke<VertexSource, Markers>&
|
||||
operator = (const conv_stroke<VertexSource, Markers>&);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class conv_transform
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CONV_TRANSFORM_INCLUDED
|
||||
#define AGG_CONV_TRANSFORM_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_trans_affine.h"
|
||||
#include "agg_vertex_iterator.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//----------------------------------------------------------conv_transform
|
||||
template<class VertexSource, class Transformer=trans_affine> class conv_transform
|
||||
{
|
||||
public:
|
||||
conv_transform(VertexSource& source, const Transformer& tr) :
|
||||
m_source(&source), m_trans(&tr) {}
|
||||
|
||||
void set_source(VertexSource& source) { m_source = &source; }
|
||||
|
||||
void rewind(unsigned id)
|
||||
{
|
||||
m_source->rewind(id);
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = m_source->vertex(x, y);
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_trans->transform(x, y);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void transformer(const Transformer& tr)
|
||||
{
|
||||
m_trans = &tr;
|
||||
}
|
||||
|
||||
typedef conv_transform<VertexSource, Transformer> source_type;
|
||||
typedef vertex_iterator<source_type> iterator;
|
||||
iterator begin(unsigned id) { return iterator(*this, id); }
|
||||
iterator end() { return iterator(path_cmd_stop); }
|
||||
|
||||
private:
|
||||
conv_transform(const conv_transform<VertexSource>&);
|
||||
const conv_transform<VertexSource>&
|
||||
operator = (const conv_transform<VertexSource>&);
|
||||
|
||||
VertexSource* m_source;
|
||||
const Transformer* m_trans;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,123 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_GAMMA_FUNCTIONS_INCLUDED
|
||||
#define AGG_GAMMA_FUNCTIONS_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//===============================================================gamma_none
|
||||
struct gamma_none
|
||||
{
|
||||
double operator()(double x) const { return x; }
|
||||
};
|
||||
|
||||
|
||||
//==============================================================gamma_power
|
||||
class gamma_power
|
||||
{
|
||||
public:
|
||||
gamma_power() : m_gamma(1.0) {}
|
||||
gamma_power(double g) : m_gamma(g) {}
|
||||
|
||||
void gamma(double g) { m_gamma = g; }
|
||||
double gamma() const { return m_gamma; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
return pow(x, m_gamma);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_gamma;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================gamma_threshold
|
||||
class gamma_threshold
|
||||
{
|
||||
public:
|
||||
gamma_threshold() : m_threshold(0.5) {}
|
||||
gamma_threshold(double t) : m_threshold(t) {}
|
||||
|
||||
void threshold(double t) { m_threshold = t; }
|
||||
double threshold() const { return m_threshold; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
return (x < m_threshold) ? 0.0 : 1.0;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_threshold;
|
||||
};
|
||||
|
||||
|
||||
//============================================================gamma_linear
|
||||
class gamma_linear
|
||||
{
|
||||
public:
|
||||
gamma_linear() : m_start(0.0), m_end(1.0) {}
|
||||
gamma_linear(double s, double e) : m_start(s), m_end(e) {}
|
||||
|
||||
void set(double s, double e) { m_start = s; m_end = e; }
|
||||
void start(double s) { m_start = s; }
|
||||
void end(double e) { m_end = e; }
|
||||
double start() const { return m_start; }
|
||||
double end() const { return m_end; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
if(x < m_start) return 0.0;
|
||||
if(x > m_end) return 1.0;
|
||||
return (x - m_start) / (m_end - m_start);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_start;
|
||||
double m_end;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================gamma_multiply
|
||||
class gamma_multiply
|
||||
{
|
||||
public:
|
||||
gamma_multiply() : m_mul(1.0) {}
|
||||
gamma_multiply(double v) : m_mul(v) {}
|
||||
|
||||
void value(double v) { m_mul = v; }
|
||||
double value() const { return m_mul; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
double y = x * m_mul;
|
||||
if(y > 1.0) y = 1.0;
|
||||
return y;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_mul;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_MATH_INCLUDED
|
||||
#define AGG_MATH_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
const double intersection_epsilon = 1.0e-8;
|
||||
|
||||
//------------------------------------------------------calc_point_location
|
||||
AGG_INLINE double calc_point_location(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
return (x - x2) * (y2 - y1) - (y - y2) * (x2 - x1);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------point_in_triangle
|
||||
AGG_INLINE bool point_in_triangle(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x, double y)
|
||||
{
|
||||
bool cp1 = calc_point_location(x1, y1, x2, y2, x, y) < 0.0;
|
||||
bool cp2 = calc_point_location(x2, y2, x3, y3, x, y) < 0.0;
|
||||
bool cp3 = calc_point_location(x3, y3, x1, y1, x, y) < 0.0;
|
||||
return cp1 == cp2 && cp2 == cp3 && cp3 == cp1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------calc_distance
|
||||
AGG_INLINE double calc_distance(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------calc_point_line_distance
|
||||
AGG_INLINE double calc_point_line_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
return ((x - x2) * dy - (y - y2) * dx) / sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------calc_intersection
|
||||
AGG_INLINE bool calc_intersection(double ax, double ay, double bx, double by,
|
||||
double cx, double cy, double dx, double dy,
|
||||
double* x, double* y)
|
||||
{
|
||||
double num = (ay-cy) * (dx-cx) - (ax-cx) * (dy-cy);
|
||||
double den = (bx-ax) * (dy-cy) - (by-ay) * (dx-cx);
|
||||
if(fabs(den) < intersection_epsilon) return false;
|
||||
double r = num / den;
|
||||
*x = ax + r * (bx-ax);
|
||||
*y = ay + r * (by-ay);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------calc_orthogonal
|
||||
AGG_INLINE void calc_orthogonal(double thickness,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double* x, double* y)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double d = sqrt(dx*dx + dy*dy);
|
||||
*x = thickness * dy / d;
|
||||
*y = thickness * dx / d;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------dilate_triangle
|
||||
AGG_INLINE void dilate_triangle(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double *x, double* y,
|
||||
double d)
|
||||
{
|
||||
double dx1=0.0;
|
||||
double dy1=0.0;
|
||||
double dx2=0.0;
|
||||
double dy2=0.0;
|
||||
double dx3=0.0;
|
||||
double dy3=0.0;
|
||||
double loc = calc_point_location(x1, y1, x2, y2, x3, y3);
|
||||
if(fabs(loc) > intersection_epsilon)
|
||||
{
|
||||
if(calc_point_location(x1, y1, x2, y2, x3, y3) > 0.0)
|
||||
{
|
||||
d = -d;
|
||||
}
|
||||
calc_orthogonal(d, x1, y1, x2, y2, &dx1, &dy1);
|
||||
calc_orthogonal(d, x2, y2, x3, y3, &dx2, &dy2);
|
||||
calc_orthogonal(d, x3, y3, x1, y1, &dx3, &dy3);
|
||||
}
|
||||
*x++ = x1 + dx1; *y++ = y1 - dy1;
|
||||
*x++ = x2 + dx1; *y++ = y2 - dy1;
|
||||
*x++ = x2 + dx2; *y++ = y2 - dy2;
|
||||
*x++ = x3 + dx2; *y++ = y3 - dy2;
|
||||
*x++ = x3 + dx3; *y++ = y3 - dy3;
|
||||
*x++ = x1 + dx3; *y++ = y1 - dy3;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------calc_polygon_area
|
||||
template<class Storage> double calc_polygon_area(const Storage& st)
|
||||
{
|
||||
unsigned i;
|
||||
double sum = 0.0;
|
||||
double x = st[0].x;
|
||||
double y = st[0].y;
|
||||
double xs = x;
|
||||
double ys = y;
|
||||
|
||||
for(i = 1; i < st.size(); i++)
|
||||
{
|
||||
const typename Storage::value_type& v = st[i];
|
||||
sum += x * v.y - y * v.x;
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
}
|
||||
return (sum + x * ys - y * xs) * 0.5;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Tables for fast sqrt
|
||||
extern int16u g_sqrt_table[1024];
|
||||
extern int8 g_elder_bit_table[256];
|
||||
|
||||
|
||||
//---------------------------------------------------------------fast_sqrt
|
||||
//Fast integer Sqrt - really fast: no cycles, divisions or multiplications
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4035) //Disable warning "no return value"
|
||||
#endif
|
||||
AGG_INLINE unsigned fast_sqrt(unsigned val)
|
||||
{
|
||||
#if defined(_M_IX86) && defined(_MSC_VER) && !defined(AGG_NO_ASM)
|
||||
//For Ix86 family processors this assembler code is used.
|
||||
//The key command here is bsr - determination the number of the most
|
||||
//significant bit of the value. For other processors
|
||||
//(and maybe compilers) the pure C "#else" section is used.
|
||||
__asm
|
||||
{
|
||||
mov ebx, val
|
||||
mov edx, 11
|
||||
bsr ecx, ebx
|
||||
sub ecx, 9
|
||||
jle less_than_9_bits
|
||||
shr ecx, 1
|
||||
adc ecx, 0
|
||||
sub edx, ecx
|
||||
shl ecx, 1
|
||||
shr ebx, cl
|
||||
less_than_9_bits:
|
||||
xor eax, eax
|
||||
mov ax, g_sqrt_table[ebx*2]
|
||||
mov ecx, edx
|
||||
shr eax, cl
|
||||
}
|
||||
#else
|
||||
|
||||
//This code is actually pure C and portable to most
|
||||
//arcitectures including 64bit ones.
|
||||
unsigned t = val;
|
||||
int bit=0;
|
||||
unsigned shift = 11;
|
||||
|
||||
//The following piece of code is just an emulation of the
|
||||
//Ix86 assembler command "bsr" (see above). However on old
|
||||
//Intels (like Intel MMX 233MHz) this code is about twice
|
||||
//faster (sic!) then just one "bsr". On PIII and PIV the
|
||||
//bsr is optimized quite well.
|
||||
bit = t >> 24;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = (t >> 16) & 0xFF;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = (t >> 8) & 0xFF;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = g_elder_bit_table[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This is calculation sqrt itself.
|
||||
bit -= 9;
|
||||
if(bit > 0)
|
||||
{
|
||||
bit = (bit >> 1) + (bit & 1);
|
||||
shift -= bit;
|
||||
val >>= (bit << 1);
|
||||
}
|
||||
return g_sqrt_table[val] >> shift;
|
||||
#endif
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,340 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Stroke math
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_STROKE_MATH_INCLUDED
|
||||
#define AGG_STROKE_MATH_INCLUDED
|
||||
|
||||
#include "agg_math.h"
|
||||
#include "agg_vertex_sequence.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//-------------------------------------------------------------line_cap_e
|
||||
enum line_cap_e
|
||||
{
|
||||
butt_cap,
|
||||
square_cap,
|
||||
round_cap
|
||||
};
|
||||
|
||||
//------------------------------------------------------------line_join_e
|
||||
enum line_join_e
|
||||
{
|
||||
miter_join,
|
||||
miter_join_revert,
|
||||
round_join,
|
||||
bevel_join
|
||||
};
|
||||
|
||||
// Minimal angle to calculate round joins, less than 0.1 degree.
|
||||
const double stroke_theta = 0.001; //----stroke_theta
|
||||
|
||||
|
||||
//--------------------------------------------------------stroke_calc_arc
|
||||
template<class VertexConsumer>
|
||||
void stroke_calc_arc(VertexConsumer& out_vertices,
|
||||
double x, double y,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
double width,
|
||||
double approximation_scale)
|
||||
{
|
||||
typedef typename VertexConsumer::value_type coord_type;
|
||||
|
||||
//// Check if we actually need the arc (this optimization works bad)
|
||||
////-----------------
|
||||
//double dd = calc_distance(dx1, dy1, dx2, dy2);
|
||||
//if(dd < 1.0/approximation_scale)
|
||||
//{
|
||||
// out_vertices.add(coord_type(x + dx1, y + dy1));
|
||||
// if(dd > 0.25/approximation_scale)
|
||||
// {
|
||||
// out_vertices.add(coord_type(x + dx2, y + dy2));
|
||||
// }
|
||||
// return;
|
||||
//}
|
||||
|
||||
double a1 = atan2(dy1, dx1);
|
||||
double a2 = atan2(dy2, dx2);
|
||||
double da = a1 - a2;
|
||||
|
||||
if(fabs(da) < stroke_theta)
|
||||
{
|
||||
out_vertices.add(coord_type((x + x + dx1 + dx2) * 0.5,
|
||||
(y + y + dy1 + dy2) * 0.5));
|
||||
return;
|
||||
}
|
||||
|
||||
bool ccw = da > 0.0 && da < pi;
|
||||
|
||||
if(width < 0) width = -width;
|
||||
da = fabs(1.0 / (width * approximation_scale));
|
||||
if(!ccw)
|
||||
{
|
||||
if(a1 > a2) a2 += 2 * pi;
|
||||
while(a1 < a2)
|
||||
{
|
||||
out_vertices.add(coord_type(x + cos(a1) * width, y + sin(a1) * width));
|
||||
a1 += da;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(a1 < a2) a2 -= 2 * pi;
|
||||
while(a1 > a2)
|
||||
{
|
||||
out_vertices.add(coord_type(x + cos(a1) * width, y + sin(a1) * width));
|
||||
a1 -= da;
|
||||
}
|
||||
}
|
||||
out_vertices.add(coord_type(x + dx2, y + dy2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------stroke_calc_miter
|
||||
template<class VertexConsumer>
|
||||
void stroke_calc_miter(VertexConsumer& out_vertices,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
double width,
|
||||
bool revert_flag,
|
||||
double miter_limit)
|
||||
{
|
||||
typedef typename VertexConsumer::value_type coord_type;
|
||||
|
||||
double xi = v1.x;
|
||||
double yi = v1.y;
|
||||
|
||||
if(!calc_intersection(v0.x + dx1, v0.y - dy1,
|
||||
v1.x + dx1, v1.y - dy1,
|
||||
v1.x + dx2, v1.y - dy2,
|
||||
v2.x + dx2, v2.y - dy2,
|
||||
&xi, &yi))
|
||||
{
|
||||
// The calculation didn't succeed, most probaly
|
||||
// the three points lie one straight line
|
||||
//----------------
|
||||
if(calc_distance(dx1, -dy1, dx2, -dy2) < width * 0.025)
|
||||
{
|
||||
// This case means that the next segment continues
|
||||
// the previous one (straight line)
|
||||
//-----------------
|
||||
out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// This case means that the next segment goes back
|
||||
//-----------------
|
||||
if(revert_flag)
|
||||
{
|
||||
out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
|
||||
out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no miter-revert, calcuate new dx1, dy1, dx2, dy2
|
||||
out_vertices.add(coord_type(v1.x + dx1 + dy1 * miter_limit,
|
||||
v1.y - dy1 + dx1 * miter_limit));
|
||||
out_vertices.add(coord_type(v1.x + dx2 - dy2 * miter_limit,
|
||||
v1.y - dy2 - dx2 * miter_limit));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double d1 = calc_distance(v1.x, v1.y, xi, yi);
|
||||
double lim = width * miter_limit;
|
||||
if(d1 > lim)
|
||||
{
|
||||
// Miter limit exceeded
|
||||
//------------------------
|
||||
if(revert_flag)
|
||||
{
|
||||
// For the compatibility with SVG, PDF, etc,
|
||||
// we use a simple bevel join instead of
|
||||
// "smart" bevel
|
||||
//-------------------
|
||||
out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
|
||||
out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Smart bevel that cuts the miter at the limit point
|
||||
//-------------------
|
||||
d1 = lim / d1;
|
||||
double x1 = v1.x + dx1;
|
||||
double y1 = v1.y - dy1;
|
||||
double x2 = v1.x + dx2;
|
||||
double y2 = v1.y - dy2;
|
||||
|
||||
x1 += (xi - x1) * d1;
|
||||
y1 += (yi - y1) * d1;
|
||||
x2 += (xi - x2) * d1;
|
||||
y2 += (yi - y2) * d1;
|
||||
out_vertices.add(coord_type(x1, y1));
|
||||
out_vertices.add(coord_type(x2, y2));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inside the miter limit
|
||||
//---------------------
|
||||
out_vertices.add(coord_type(xi, yi));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------stroke_calc_cap
|
||||
template<class VertexConsumer>
|
||||
void stroke_calc_cap(VertexConsumer& out_vertices,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
double len,
|
||||
line_cap_e line_cap,
|
||||
double width,
|
||||
double approximation_scale)
|
||||
{
|
||||
typedef typename VertexConsumer::value_type coord_type;
|
||||
|
||||
out_vertices.remove_all();
|
||||
|
||||
double dx1 = width * (v1.y - v0.y) / len;
|
||||
double dy1 = width * (v1.x - v0.x) / len;
|
||||
double dx2 = 0;
|
||||
double dy2 = 0;
|
||||
|
||||
if(line_cap == square_cap)
|
||||
{
|
||||
dx2 = dy1;
|
||||
dy2 = dx1;
|
||||
}
|
||||
|
||||
if(line_cap == round_cap)
|
||||
{
|
||||
double a1 = atan2(dy1, -dx1);
|
||||
double a2 = a1 + pi;
|
||||
double da = fabs(1.0 / (width * approximation_scale));
|
||||
while(a1 < a2)
|
||||
{
|
||||
out_vertices.add(coord_type(v0.x + cos(a1) * width,
|
||||
v0.y + sin(a1) * width));
|
||||
a1 += da;
|
||||
}
|
||||
out_vertices.add(coord_type(v0.x + dx1, v0.y - dy1));
|
||||
}
|
||||
else
|
||||
{
|
||||
out_vertices.add(coord_type(v0.x - dx1 - dx2, v0.y + dy1 - dy2));
|
||||
out_vertices.add(coord_type(v0.x + dx1 - dx2, v0.y - dy1 - dy2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------stroke_calc_join
|
||||
template<class VertexConsumer>
|
||||
void stroke_calc_join(VertexConsumer& out_vertices,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double len1,
|
||||
double len2,
|
||||
double width,
|
||||
line_join_e line_join,
|
||||
line_join_e inner_line_join,
|
||||
double miter_limit,
|
||||
double inner_miter_limit,
|
||||
double approximation_scale)
|
||||
{
|
||||
typedef typename VertexConsumer::value_type coord_type;
|
||||
|
||||
double dx1, dy1, dx2, dy2;
|
||||
|
||||
dx1 = width * (v1.y - v0.y) / len1;
|
||||
dy1 = width * (v1.x - v0.x) / len1;
|
||||
|
||||
dx2 = width * (v2.y - v1.y) / len2;
|
||||
dy2 = width * (v2.x - v1.x) / len2;
|
||||
|
||||
out_vertices.remove_all();
|
||||
|
||||
if(calc_point_location(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y) > 0.0)
|
||||
{
|
||||
// Inner join
|
||||
//---------------
|
||||
stroke_calc_miter(out_vertices,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
width,
|
||||
inner_line_join == miter_join_revert,
|
||||
inner_miter_limit);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Outer join
|
||||
//---------------
|
||||
switch(line_join)
|
||||
{
|
||||
case miter_join:
|
||||
stroke_calc_miter(out_vertices,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
width,
|
||||
false,
|
||||
miter_limit);
|
||||
break;
|
||||
|
||||
case miter_join_revert:
|
||||
stroke_calc_miter(out_vertices,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
width,
|
||||
true,
|
||||
miter_limit);
|
||||
break;
|
||||
|
||||
case round_join:
|
||||
stroke_calc_arc(out_vertices,
|
||||
v1.x, v1.y, dx1, -dy1, dx2, -dy2,
|
||||
width, approximation_scale);
|
||||
break;
|
||||
|
||||
default: // Bevel join
|
||||
out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1));
|
||||
if(calc_distance(dx1, dy1, dx2, dy2) > approximation_scale * 0.25)
|
||||
{
|
||||
out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,525 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Class path_storage
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "agg_path_storage.h"
|
||||
#include "agg_math.h"
|
||||
#include "agg_bezier_arc.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
path_storage::~path_storage()
|
||||
{
|
||||
if(m_total_blocks)
|
||||
{
|
||||
double** coord_blk = m_coord_blocks + m_total_blocks - 1;
|
||||
while(m_total_blocks--)
|
||||
{
|
||||
delete [] *coord_blk;
|
||||
--coord_blk;
|
||||
}
|
||||
delete [] m_coord_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
path_storage::path_storage() :
|
||||
m_total_vertices(0),
|
||||
m_total_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_coord_blocks(0),
|
||||
m_cmd_blocks(0),
|
||||
m_iterator(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
path_storage::path_storage(const path_storage& ps) :
|
||||
m_total_vertices(0),
|
||||
m_total_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_coord_blocks(0),
|
||||
m_cmd_blocks(0),
|
||||
m_iterator(0)
|
||||
{
|
||||
copy_from(ps);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::remove_all()
|
||||
{
|
||||
m_total_vertices = 0;
|
||||
m_iterator = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::copy_from(const path_storage& ps)
|
||||
{
|
||||
remove_all();
|
||||
unsigned i;
|
||||
for(i = 0; i < ps.total_vertices(); i++)
|
||||
{
|
||||
double x, y;
|
||||
unsigned cmd = ps.vertex(i, &x, &y);
|
||||
add_vertex(x, y, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::allocate_block(unsigned nb)
|
||||
{
|
||||
if(nb >= m_max_blocks)
|
||||
{
|
||||
double** new_coords =
|
||||
new double* [(m_max_blocks + block_pool) * 2];
|
||||
|
||||
unsigned char** new_cmds =
|
||||
(unsigned char**)(new_coords + m_max_blocks + block_pool);
|
||||
|
||||
if(m_coord_blocks)
|
||||
{
|
||||
memcpy(new_coords,
|
||||
m_coord_blocks,
|
||||
m_max_blocks * sizeof(double*));
|
||||
|
||||
memcpy(new_cmds,
|
||||
m_cmd_blocks,
|
||||
m_max_blocks * sizeof(unsigned char*));
|
||||
|
||||
delete [] m_coord_blocks;
|
||||
}
|
||||
m_coord_blocks = new_coords;
|
||||
m_cmd_blocks = new_cmds;
|
||||
m_max_blocks += block_pool;
|
||||
}
|
||||
m_coord_blocks[nb] =
|
||||
new double [block_size * 2 +
|
||||
block_size /
|
||||
(sizeof(double) / sizeof(unsigned char))];
|
||||
|
||||
m_cmd_blocks[nb] =
|
||||
(unsigned char*)(m_coord_blocks[nb] + block_size * 2);
|
||||
|
||||
m_total_blocks++;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::rewind(unsigned path_id)
|
||||
{
|
||||
m_iterator = path_id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::arc_to(double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double x, double y)
|
||||
{
|
||||
if(m_total_vertices && is_vertex(command(m_total_vertices - 1)))
|
||||
{
|
||||
const double epsilon = 1e-30;
|
||||
double x0 = 0.0;
|
||||
double y0 = 0.0;
|
||||
last_vertex(&x0, &y0);
|
||||
|
||||
rx = fabs(rx);
|
||||
ry = fabs(ry);
|
||||
|
||||
// Ensure radii are valid
|
||||
//-------------------------
|
||||
if(rx < epsilon || ry < epsilon)
|
||||
{
|
||||
line_to(x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
if(calc_distance(x0, y0, x, y) < epsilon)
|
||||
{
|
||||
// If the endpoints (x, y) and (x0, y0) are identical, then this
|
||||
// is equivalent to omitting the elliptical arc segment entirely.
|
||||
return;
|
||||
}
|
||||
bezier_arc_svg a(x0, y0, rx, ry, angle, large_arc_flag, sweep_flag, x, y);
|
||||
if(a.radii_ok())
|
||||
{
|
||||
add_path(a, 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
line_to(x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
move_to(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::arc_rel(double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double dx, double dy)
|
||||
{
|
||||
rel_to_abs(&dx, &dy);
|
||||
arc_to(rx, ry, angle, large_arc_flag, sweep_flag, dx, dy);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve3(double x_ctrl, double y_ctrl,
|
||||
double x_to, double y_to)
|
||||
{
|
||||
add_vertex(x_ctrl, y_ctrl, path_cmd_curve3);
|
||||
add_vertex(x_to, y_to, path_cmd_curve3);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve3_rel(double dx_ctrl, double dy_ctrl,
|
||||
double dx_to, double dy_to)
|
||||
{
|
||||
rel_to_abs(&dx_ctrl, &dy_ctrl);
|
||||
rel_to_abs(&dx_to, &dy_to);
|
||||
add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3);
|
||||
add_vertex(dx_to, dy_to, path_cmd_curve3);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve3(double x_to, double y_to)
|
||||
{
|
||||
double x0;
|
||||
double y0;
|
||||
if(is_vertex(last_vertex(&x0, &y0)))
|
||||
{
|
||||
double x_ctrl;
|
||||
double y_ctrl;
|
||||
unsigned cmd = prev_vertex(&x_ctrl, &y_ctrl);
|
||||
if(is_curve(cmd))
|
||||
{
|
||||
x_ctrl = x0 + x0 - x_ctrl;
|
||||
y_ctrl = y0 + y0 - y_ctrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
x_ctrl = x0;
|
||||
y_ctrl = y0;
|
||||
}
|
||||
curve3(x_ctrl, y_ctrl, x_to, y_to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve3_rel(double dx_to, double dy_to)
|
||||
{
|
||||
rel_to_abs(&dx_to, &dy_to);
|
||||
curve3(dx_to, dy_to);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve4(double x_ctrl1, double y_ctrl1,
|
||||
double x_ctrl2, double y_ctrl2,
|
||||
double x_to, double y_to)
|
||||
{
|
||||
add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4);
|
||||
add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4);
|
||||
add_vertex(x_to, y_to, path_cmd_curve4);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve4_rel(double dx_ctrl1, double dy_ctrl1,
|
||||
double dx_ctrl2, double dy_ctrl2,
|
||||
double dx_to, double dy_to)
|
||||
{
|
||||
rel_to_abs(&dx_ctrl1, &dy_ctrl1);
|
||||
rel_to_abs(&dx_ctrl2, &dy_ctrl2);
|
||||
rel_to_abs(&dx_to, &dy_to);
|
||||
add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4);
|
||||
add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4);
|
||||
add_vertex(dx_to, dy_to, path_cmd_curve4);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve4(double x_ctrl2, double y_ctrl2,
|
||||
double x_to, double y_to)
|
||||
{
|
||||
double x0;
|
||||
double y0;
|
||||
if(is_vertex(last_vertex(&x0, &y0)))
|
||||
{
|
||||
double x_ctrl1;
|
||||
double y_ctrl1;
|
||||
unsigned cmd = prev_vertex(&x_ctrl1, &y_ctrl1);
|
||||
if(is_curve(cmd))
|
||||
{
|
||||
x_ctrl1 = x0 + x0 - x_ctrl1;
|
||||
y_ctrl1 = y0 + y0 - y_ctrl1;
|
||||
}
|
||||
else
|
||||
{
|
||||
x_ctrl1 = x0;
|
||||
y_ctrl1 = y0;
|
||||
}
|
||||
curve4(x_ctrl1, y_ctrl1, x_ctrl2, y_ctrl2, x_to, y_to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::curve4_rel(double dx_ctrl2, double dy_ctrl2,
|
||||
double dx_to, double dy_to)
|
||||
{
|
||||
rel_to_abs(&dx_ctrl2, &dy_ctrl2);
|
||||
rel_to_abs(&dx_to, &dy_to);
|
||||
curve4(dx_ctrl2, dy_ctrl2, dx_to, dy_to);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::end_poly(unsigned flags)
|
||||
{
|
||||
if(m_total_vertices)
|
||||
{
|
||||
if(is_vertex(command(m_total_vertices - 1)))
|
||||
{
|
||||
add_vertex(0.0, 0.0, path_cmd_end_poly | flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned path_storage::start_new_path()
|
||||
{
|
||||
if(m_total_vertices)
|
||||
{
|
||||
if(!is_stop(command(m_total_vertices - 1)))
|
||||
{
|
||||
add_vertex(0.0, 0.0, path_cmd_stop);
|
||||
}
|
||||
}
|
||||
return m_total_vertices;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::add_poly(const double* vertices, unsigned num,
|
||||
bool solid_path, unsigned end_flags)
|
||||
{
|
||||
if(num)
|
||||
{
|
||||
if(!solid_path)
|
||||
{
|
||||
move_to(vertices[0], vertices[1]);
|
||||
vertices += 2;
|
||||
--num;
|
||||
}
|
||||
while(num--)
|
||||
{
|
||||
line_to(vertices[0], vertices[1]);
|
||||
vertices += 2;
|
||||
}
|
||||
if(end_flags) end_poly(end_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned path_storage::perceive_polygon_orientation(unsigned idx,
|
||||
double xs, double ys,
|
||||
unsigned* orientation)
|
||||
{
|
||||
unsigned i;
|
||||
double sum = 0.0;
|
||||
double x, y, xn, yn;
|
||||
|
||||
x = xs;
|
||||
y = ys;
|
||||
for(i = idx; i < m_total_vertices; ++i)
|
||||
{
|
||||
if(is_next_poly(vertex(i, &xn, &yn))) break;
|
||||
sum += x * yn - y * xn;
|
||||
x = xn;
|
||||
y = yn;
|
||||
}
|
||||
if(i > idx) sum += x * ys - y * xs;
|
||||
*orientation = path_flags_none;
|
||||
if(sum != 0.0)
|
||||
{
|
||||
*orientation = (sum < 0.0) ? path_flags_cw : path_flags_ccw;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::reverse_polygon(unsigned start, unsigned end)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned tmp_cmd = command(start);
|
||||
|
||||
// Shift all commands to one position
|
||||
for(i = start; i < end; i++)
|
||||
{
|
||||
modify_command(i, command(i + 1));
|
||||
}
|
||||
|
||||
// Assign starting command to the ending command
|
||||
modify_command(end, tmp_cmd);
|
||||
|
||||
// Reverse the polygon
|
||||
while(end > start)
|
||||
{
|
||||
unsigned start_nb = start >> block_shift;
|
||||
unsigned end_nb = end >> block_shift;
|
||||
double* start_ptr = m_coord_blocks[start_nb] + ((start & block_mask) << 1);
|
||||
double* end_ptr = m_coord_blocks[end_nb] + ((end & block_mask) << 1);
|
||||
double tmp_xy;
|
||||
|
||||
tmp_xy = *start_ptr;
|
||||
*start_ptr++ = *end_ptr;
|
||||
*end_ptr++ = tmp_xy;
|
||||
|
||||
tmp_xy = *start_ptr;
|
||||
*start_ptr = *end_ptr;
|
||||
*end_ptr = tmp_xy;
|
||||
|
||||
tmp_cmd = m_cmd_blocks[start_nb][start & block_mask];
|
||||
m_cmd_blocks[start_nb][start & block_mask] = m_cmd_blocks[end_nb][end & block_mask];
|
||||
m_cmd_blocks[end_nb][end & block_mask] = (unsigned char)tmp_cmd;
|
||||
|
||||
++start;
|
||||
--end;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned path_storage::arrange_orientations(unsigned path_id,
|
||||
path_flags_e new_orientation)
|
||||
{
|
||||
unsigned end = m_total_vertices;
|
||||
if(m_total_vertices && new_orientation != path_flags_none)
|
||||
{
|
||||
unsigned start = path_id;
|
||||
|
||||
double xs, ys;
|
||||
unsigned cmd = vertex(start, &xs, &ys);
|
||||
unsigned inc = 0;
|
||||
for(;;)
|
||||
{
|
||||
unsigned orientation;
|
||||
end = perceive_polygon_orientation(start + 1, xs, ys,
|
||||
&orientation);
|
||||
if(end > start + 2 &&
|
||||
orientation &&
|
||||
orientation != unsigned(new_orientation))
|
||||
{
|
||||
reverse_polygon(start + inc, end - 1);
|
||||
}
|
||||
if(end >= m_total_vertices) break;
|
||||
cmd = command(end);
|
||||
if(is_stop(cmd))
|
||||
{
|
||||
++end;
|
||||
break;
|
||||
}
|
||||
if(is_end_poly(cmd))
|
||||
{
|
||||
inc = 1;
|
||||
modify_command(end, set_orientation(cmd, new_orientation));
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd = vertex(++end, &xs, &ys);
|
||||
inc = 0;
|
||||
}
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::arrange_orientations_all_paths(path_flags_e new_orientation)
|
||||
{
|
||||
if(new_orientation != path_flags_none)
|
||||
{
|
||||
unsigned start = 0;
|
||||
while(start < m_total_vertices)
|
||||
{
|
||||
start = arrange_orientations(start, new_orientation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::flip_x(double x1, double x2)
|
||||
{
|
||||
unsigned i;
|
||||
double x, y;
|
||||
for(i = 0; i < m_total_vertices; i++)
|
||||
{
|
||||
unsigned cmd = vertex(i, &x, &y);
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
modify_vertex(i, x2 - x + x1, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void path_storage::flip_y(double y1, double y2)
|
||||
{
|
||||
unsigned i;
|
||||
double x, y;
|
||||
for(i = 0; i < m_total_vertices; i++)
|
||||
{
|
||||
unsigned cmd = vertex(i, &x, &y);
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
modify_vertex(i, x, y2 - y + y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,368 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_PATH_STORAGE_INCLUDED
|
||||
#define AGG_PATH_STORAGE_INCLUDED
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------path_storage
|
||||
// A container to store vertices with their flags.
|
||||
// A path consists of a number of contours separated with "move_to"
|
||||
// commands. The path storage can keep and maintain more than one
|
||||
// path.
|
||||
// To navigate to the beginning of a particular path, use rewind(path_id);
|
||||
// Where path_id is what start_new_path() returns. So, when you call
|
||||
// start_new_path() you need to store its return value somewhere else
|
||||
// to navigate to the path afterwards.
|
||||
//
|
||||
// See Implementation: agg_path_storage.cpp
|
||||
// See also: vertex_source concept
|
||||
//------------------------------------------------------------------------
|
||||
class path_storage
|
||||
{
|
||||
// Allocation parameters
|
||||
enum
|
||||
{
|
||||
block_shift = 8,
|
||||
block_size = 1 << block_shift,
|
||||
block_mask = block_size - 1,
|
||||
block_pool = 256
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
class const_iterator
|
||||
{
|
||||
void vertex()
|
||||
{
|
||||
if(m_vertex_idx < m_path->total_vertices())
|
||||
{
|
||||
m_vertex.cmd = m_path->vertex(m_vertex_idx, &m_vertex.x, &m_vertex.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vertex.cmd = path_cmd_stop;
|
||||
m_vertex.x = m_vertex.y = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
const_iterator() {}
|
||||
const_iterator(unsigned cmd) { m_vertex.cmd = cmd; }
|
||||
const_iterator(const const_iterator& i) :
|
||||
m_path(i.m_path),
|
||||
m_vertex_idx(i.m_vertex_idx),
|
||||
m_vertex(i.m_vertex)
|
||||
{
|
||||
}
|
||||
|
||||
const_iterator(const path_storage& p, unsigned id) :
|
||||
m_path(&p),
|
||||
m_vertex_idx(id)
|
||||
{
|
||||
vertex();
|
||||
}
|
||||
|
||||
const_iterator& operator++()
|
||||
{
|
||||
++m_vertex_idx;
|
||||
vertex();
|
||||
return *this;
|
||||
}
|
||||
|
||||
const vertex_type& operator*() const { return m_vertex; }
|
||||
const vertex_type* operator->() const { return &m_vertex; }
|
||||
|
||||
bool operator != (const const_iterator& i)
|
||||
{
|
||||
return m_vertex.cmd != i.m_vertex.cmd;
|
||||
}
|
||||
|
||||
private:
|
||||
const path_storage* m_path;
|
||||
unsigned m_vertex_idx;
|
||||
vertex_type m_vertex;
|
||||
};
|
||||
|
||||
~path_storage();
|
||||
path_storage();
|
||||
path_storage(const path_storage& ps);
|
||||
|
||||
void remove_all();
|
||||
|
||||
unsigned last_vertex(double* x, double* y) const;
|
||||
unsigned prev_vertex(double* x, double* y) const;
|
||||
|
||||
void rel_to_abs(double* x, double* y) const;
|
||||
|
||||
void move_to(double x, double y);
|
||||
void move_rel(double dx, double dy);
|
||||
|
||||
void line_to(double x, double y);
|
||||
void line_rel(double dx, double dy);
|
||||
|
||||
void arc_to(double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double x, double y);
|
||||
|
||||
void arc_rel(double rx, double ry,
|
||||
double angle,
|
||||
bool large_arc_flag,
|
||||
bool sweep_flag,
|
||||
double dx, double dy);
|
||||
|
||||
void curve3(double x_ctrl, double y_ctrl,
|
||||
double x_to, double y_to);
|
||||
|
||||
void curve3_rel(double dx_ctrl, double dy_ctrl,
|
||||
double dx_to, double dy_to);
|
||||
|
||||
void curve3(double x_to, double y_to);
|
||||
|
||||
void curve3_rel(double dx_to, double dy_to);
|
||||
|
||||
void curve4(double x_ctrl1, double y_ctrl1,
|
||||
double x_ctrl2, double y_ctrl2,
|
||||
double x_to, double y_to);
|
||||
|
||||
void curve4_rel(double dx_ctrl1, double dy_ctrl1,
|
||||
double dx_ctrl2, double dy_ctrl2,
|
||||
double dx_to, double dy_to);
|
||||
|
||||
void curve4(double x_ctrl2, double y_ctrl2,
|
||||
double x_to, double y_to);
|
||||
|
||||
void curve4_rel(double x_ctrl2, double y_ctrl2,
|
||||
double x_to, double y_to);
|
||||
|
||||
|
||||
void end_poly(unsigned flags = path_flags_close);
|
||||
|
||||
void close_polygon(unsigned flags = path_flags_none)
|
||||
{
|
||||
end_poly(path_flags_close | flags);
|
||||
}
|
||||
|
||||
void add_poly(const double* vertices, unsigned num,
|
||||
bool solid_path = false,
|
||||
unsigned end_flags = path_flags_none);
|
||||
|
||||
template<class VertexSource>
|
||||
void add_path(VertexSource& vs,
|
||||
unsigned path_id = 0,
|
||||
bool solid_path = true)
|
||||
{
|
||||
double x, y;
|
||||
unsigned cmd;
|
||||
vs.rewind(path_id);
|
||||
while(!is_stop(cmd = vs.vertex(&x, &y)))
|
||||
{
|
||||
if(is_move_to(cmd) && solid_path && m_total_vertices)
|
||||
{
|
||||
cmd = path_cmd_line_to;
|
||||
}
|
||||
add_vertex(x, y, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned start_new_path();
|
||||
|
||||
void copy_from(const path_storage& ps);
|
||||
const path_storage& operator = (const path_storage& ps)
|
||||
{
|
||||
copy_from(ps);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
unsigned total_vertices() const { return m_total_vertices; }
|
||||
unsigned vertex(unsigned idx, double* x, double* y) const
|
||||
{
|
||||
unsigned nb = idx >> block_shift;
|
||||
const double* pv = m_coord_blocks[nb] + ((idx & block_mask) << 1);
|
||||
*x = *pv++;
|
||||
*y = *pv;
|
||||
return m_cmd_blocks[nb][idx & block_mask];
|
||||
}
|
||||
unsigned command(unsigned idx) const
|
||||
{
|
||||
return m_cmd_blocks[idx >> block_shift][idx & block_mask];
|
||||
}
|
||||
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
const_iterator begin(unsigned id) const { return const_iterator(*this, id); }
|
||||
const_iterator begin() const { return const_iterator(*this, 0); }
|
||||
const_iterator end() const { return const_iterator(path_cmd_stop); }
|
||||
|
||||
// Arrange the orientation of all the polygons. After calling this
|
||||
// method all the polygons will have the same orientation
|
||||
// determined by the new_orientation flag, i.e.,
|
||||
// path_flags_cw or path_flags_ccw
|
||||
unsigned arrange_orientations(unsigned path_id, path_flags_e new_orientation);
|
||||
void arrange_orientations_all_paths(path_flags_e new_orientation);
|
||||
|
||||
// Flip all the vertices horizontally or vertically
|
||||
void flip_x(double x1, double x2);
|
||||
void flip_y(double y1, double y2);
|
||||
|
||||
// This function adds a vertex with its flags directly. Since there's no
|
||||
// checking for errors, keeping proper path integrity is the responsibility
|
||||
// of the caller. It can be said the function is "not very public".
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
|
||||
// Allows you to modify vertex coordinates. The caller must know
|
||||
// the index of the vertex.
|
||||
void modify_vertex(unsigned idx, double x, double y)
|
||||
{
|
||||
double* pv = m_coord_blocks[idx >> block_shift] + ((idx & block_mask) << 1);
|
||||
*pv++ = x;
|
||||
*pv = y;
|
||||
}
|
||||
|
||||
// Allows you to modify vertex command. The caller must know
|
||||
// the index of the vertex.
|
||||
void modify_command(unsigned idx, unsigned cmd)
|
||||
{
|
||||
m_cmd_blocks[idx >> block_shift][idx & block_mask] = (unsigned char)cmd;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void allocate_block(unsigned nb);
|
||||
unsigned char* storage_ptrs(double** xy_ptr);
|
||||
unsigned perceive_polygon_orientation(unsigned idx,
|
||||
double xs, double ys,
|
||||
unsigned* orientation);
|
||||
void reverse_polygon(unsigned start, unsigned end);
|
||||
|
||||
private:
|
||||
unsigned m_total_vertices;
|
||||
unsigned m_total_blocks;
|
||||
unsigned m_max_blocks;
|
||||
double** m_coord_blocks;
|
||||
unsigned char** m_cmd_blocks;
|
||||
unsigned m_iterator;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline unsigned path_storage::vertex(double* x, double* y)
|
||||
{
|
||||
if(m_iterator >= m_total_vertices) return path_cmd_stop;
|
||||
return vertex(m_iterator++, x, y);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline unsigned path_storage::prev_vertex(double* x, double* y) const
|
||||
{
|
||||
if(m_total_vertices > 1)
|
||||
{
|
||||
return vertex(m_total_vertices - 2, x, y);
|
||||
}
|
||||
return path_cmd_stop;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline unsigned path_storage::last_vertex(double* x, double* y) const
|
||||
{
|
||||
if(m_total_vertices)
|
||||
{
|
||||
return vertex(m_total_vertices - 1, x, y);
|
||||
}
|
||||
return path_cmd_stop;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void path_storage::rel_to_abs(double* x, double* y) const
|
||||
{
|
||||
if(m_total_vertices)
|
||||
{
|
||||
double x2;
|
||||
double y2;
|
||||
if(is_vertex(vertex(m_total_vertices - 1, &x2, &y2)))
|
||||
{
|
||||
*x += x2;
|
||||
*y += y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline unsigned char* path_storage::storage_ptrs(double** xy_ptr)
|
||||
{
|
||||
unsigned nb = m_total_vertices >> block_shift;
|
||||
if(nb >= m_total_blocks)
|
||||
{
|
||||
allocate_block(nb);
|
||||
}
|
||||
|
||||
assert(m_coord_blocks);
|
||||
*xy_ptr = m_coord_blocks[nb] + ((m_total_vertices & block_mask) << 1);
|
||||
return m_cmd_blocks[nb] + (m_total_vertices & block_mask);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void path_storage::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
double* coord_ptr = 0;
|
||||
unsigned char* cmd_ptr = storage_ptrs(&coord_ptr);
|
||||
*cmd_ptr = (unsigned char)cmd;
|
||||
*coord_ptr++ = x;
|
||||
*coord_ptr = y;
|
||||
m_total_vertices++;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void path_storage::move_to(double x, double y)
|
||||
{
|
||||
add_vertex(x, y, path_cmd_move_to);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void path_storage::move_rel(double dx, double dy)
|
||||
{
|
||||
rel_to_abs(&dx, &dy);
|
||||
add_vertex(dx, dy, path_cmd_move_to);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void path_storage::line_to(double x, double y)
|
||||
{
|
||||
add_vertex(x, y, path_cmd_line_to);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void path_storage::line_rel(double dx, double dy)
|
||||
{
|
||||
rel_to_abs(&dx, &dy);
|
||||
add_vertex(dx, dy, path_cmd_line_to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,621 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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.
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Class outline_aa - implementation.
|
||||
//
|
||||
// Initially the rendering algorithm was designed by David Turner and the
|
||||
// other authors of the FreeType library - see the above notice. I nearly
|
||||
// created a similar renderer, but still I was far from David's work.
|
||||
// I completely redesigned the original code and adapted it for Anti-Grain
|
||||
// ideas. Two functions - render_line and render_hline are the core of
|
||||
// the algorithm - they calculate the exact coverage of each pixel cell
|
||||
// of the polygon. I left these functions almost as is, because there's
|
||||
// no way to improve the perfection - hats off to David and his group!
|
||||
//
|
||||
// All other code is very different from the original.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
AGG_INLINE void cell_aa::set_cover(int c, int a)
|
||||
{
|
||||
cover = c;
|
||||
area = a;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
AGG_INLINE void cell_aa::add_cover(int c, int a)
|
||||
{
|
||||
cover += c;
|
||||
area += a;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
AGG_INLINE void cell_aa::set_coord(int cx, int cy)
|
||||
{
|
||||
x = int16(cx);
|
||||
y = int16(cy);
|
||||
packed_coord = (cy << 16) + cx;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
AGG_INLINE void cell_aa::set(int cx, int cy, int c, int a)
|
||||
{
|
||||
x = int16(cx);
|
||||
y = int16(cy);
|
||||
packed_coord = (cy << 16) + cx;
|
||||
cover = c;
|
||||
area = a;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
outline_aa::~outline_aa()
|
||||
{
|
||||
delete [] m_sorted_cells;
|
||||
if(m_num_blocks)
|
||||
{
|
||||
cell_aa** ptr = m_cells + m_num_blocks - 1;
|
||||
while(m_num_blocks--)
|
||||
{
|
||||
delete [] *ptr;
|
||||
ptr--;
|
||||
}
|
||||
delete [] m_cells;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
outline_aa::outline_aa() :
|
||||
m_num_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_cur_block(0),
|
||||
m_num_cells(0),
|
||||
m_cells(0),
|
||||
m_cur_cell_ptr(0),
|
||||
m_sorted_cells(0),
|
||||
m_sorted_size(0),
|
||||
m_cur_x(0),
|
||||
m_cur_y(0),
|
||||
m_min_x(0x7FFFFFFF),
|
||||
m_min_y(0x7FFFFFFF),
|
||||
m_max_x(-0x7FFFFFFF),
|
||||
m_max_y(-0x7FFFFFFF),
|
||||
m_sorted(false)
|
||||
{
|
||||
m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void outline_aa::reset()
|
||||
{
|
||||
m_num_cells = 0;
|
||||
m_cur_block = 0;
|
||||
m_cur_cell.set(0x7FFF, 0x7FFF, 0, 0);
|
||||
m_sorted = false;
|
||||
m_min_x = 0x7FFFFFFF;
|
||||
m_min_y = 0x7FFFFFFF;
|
||||
m_max_x = -0x7FFFFFFF;
|
||||
m_max_y = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void outline_aa::allocate_block()
|
||||
{
|
||||
if(m_cur_block >= m_num_blocks)
|
||||
{
|
||||
if(m_num_blocks >= m_max_blocks)
|
||||
{
|
||||
cell_aa** new_cells = new cell_aa* [m_max_blocks + cell_block_pool];
|
||||
if(m_cells)
|
||||
{
|
||||
memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_aa*));
|
||||
delete [] m_cells;
|
||||
}
|
||||
m_cells = new_cells;
|
||||
m_max_blocks += cell_block_pool;
|
||||
}
|
||||
m_cells[m_num_blocks++] = new cell_aa [unsigned(cell_block_size)];
|
||||
}
|
||||
m_cur_cell_ptr = m_cells[m_cur_block++];
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
AGG_INLINE void outline_aa::add_cur_cell()
|
||||
{
|
||||
if(m_cur_cell.area | m_cur_cell.cover)
|
||||
{
|
||||
if((m_num_cells & cell_block_mask) == 0)
|
||||
{
|
||||
if(m_num_blocks >= cell_block_limit) return;
|
||||
allocate_block();
|
||||
}
|
||||
*m_cur_cell_ptr++ = m_cur_cell;
|
||||
++m_num_cells;
|
||||
if(m_cur_cell.x < m_min_x) m_min_x = m_cur_cell.x;
|
||||
if(m_cur_cell.x > m_max_x) m_max_x = m_cur_cell.x;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
AGG_INLINE void outline_aa::set_cur_cell(int x, int y)
|
||||
{
|
||||
if(m_cur_cell.packed_coord != (y << 16) + x)
|
||||
{
|
||||
add_cur_cell();
|
||||
m_cur_cell.set(x, y, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
AGG_INLINE void outline_aa::render_hline(int ey, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int ex1 = x1 >> poly_base_shift;
|
||||
int ex2 = x2 >> poly_base_shift;
|
||||
int fx1 = x1 & poly_base_mask;
|
||||
int fx2 = x2 & poly_base_mask;
|
||||
|
||||
int delta, p, first, dx;
|
||||
int incr, lift, mod, rem;
|
||||
|
||||
//trivial case. Happens often
|
||||
if(y1 == y2)
|
||||
{
|
||||
set_cur_cell(ex2, ey);
|
||||
return;
|
||||
}
|
||||
|
||||
//everything is located in a single cell. That is easy!
|
||||
if(ex1 == ex2)
|
||||
{
|
||||
delta = y2 - y1;
|
||||
m_cur_cell.add_cover(delta, (fx1 + fx2) * delta);
|
||||
return;
|
||||
}
|
||||
|
||||
//ok, we'll have to render a run of adjacent cells on the same
|
||||
//hline...
|
||||
p = (poly_base_size - fx1) * (y2 - y1);
|
||||
first = poly_base_size;
|
||||
incr = 1;
|
||||
|
||||
dx = x2 - x1;
|
||||
|
||||
if(dx < 0)
|
||||
{
|
||||
p = fx1 * (y2 - y1);
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dx = -dx;
|
||||
}
|
||||
|
||||
delta = p / dx;
|
||||
mod = p % dx;
|
||||
|
||||
if(mod < 0)
|
||||
{
|
||||
delta--;
|
||||
mod += dx;
|
||||
}
|
||||
|
||||
m_cur_cell.add_cover(delta, (fx1 + first) * delta);
|
||||
|
||||
ex1 += incr;
|
||||
set_cur_cell(ex1, ey);
|
||||
y1 += delta;
|
||||
|
||||
if(ex1 != ex2)
|
||||
{
|
||||
p = poly_base_size * (y2 - y1 + delta);
|
||||
lift = p / dx;
|
||||
rem = p % dx;
|
||||
|
||||
if (rem < 0)
|
||||
{
|
||||
lift--;
|
||||
rem += dx;
|
||||
}
|
||||
|
||||
mod -= dx;
|
||||
|
||||
while (ex1 != ex2)
|
||||
{
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0)
|
||||
{
|
||||
mod -= dx;
|
||||
delta++;
|
||||
}
|
||||
|
||||
m_cur_cell.add_cover(delta, (poly_base_size) * delta);
|
||||
y1 += delta;
|
||||
ex1 += incr;
|
||||
set_cur_cell(ex1, ey);
|
||||
}
|
||||
}
|
||||
delta = y2 - y1;
|
||||
m_cur_cell.add_cover(delta, (fx2 + poly_base_size - first) * delta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void outline_aa::render_line(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int ey1 = y1 >> poly_base_shift;
|
||||
int ey2 = y2 >> poly_base_shift;
|
||||
int fy1 = y1 & poly_base_mask;
|
||||
int fy2 = y2 & poly_base_mask;
|
||||
|
||||
int dx, dy, x_from, x_to;
|
||||
int p, rem, mod, lift, delta, first, incr;
|
||||
|
||||
dx = x2 - x1;
|
||||
dy = y2 - y1;
|
||||
|
||||
//everything is on a single hline
|
||||
if(ey1 == ey2)
|
||||
{
|
||||
render_hline(ey1, x1, fy1, x2, fy2);
|
||||
return;
|
||||
}
|
||||
|
||||
//Vertical line - we have to calculate start and end cells,
|
||||
//and then - the common values of the area and coverage for
|
||||
//all cells of the line. We know exactly there's only one
|
||||
//cell, so, we don't have to call render_hline().
|
||||
incr = 1;
|
||||
if(dx == 0)
|
||||
{
|
||||
int ex = x1 >> poly_base_shift;
|
||||
int two_fx = (x1 - (ex << poly_base_shift)) << 1;
|
||||
int area;
|
||||
|
||||
first = poly_base_size;
|
||||
if(dy < 0)
|
||||
{
|
||||
first = 0;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
x_from = x1;
|
||||
|
||||
//render_hline(ey1, x_from, fy1, x_from, first);
|
||||
delta = first - fy1;
|
||||
m_cur_cell.add_cover(delta, two_fx * delta);
|
||||
|
||||
ey1 += incr;
|
||||
set_cur_cell(ex, ey1);
|
||||
|
||||
delta = first + first - poly_base_size;
|
||||
area = two_fx * delta;
|
||||
while(ey1 != ey2)
|
||||
{
|
||||
//render_hline(ey1, x_from, poly_base_size - first, x_from, first);
|
||||
m_cur_cell.set_cover(delta, area);
|
||||
ey1 += incr;
|
||||
set_cur_cell(ex, ey1);
|
||||
}
|
||||
//render_hline(ey1, x_from, poly_base_size - first, x_from, fy2);
|
||||
delta = fy2 - poly_base_size + first;
|
||||
m_cur_cell.add_cover(delta, two_fx * delta);
|
||||
return;
|
||||
}
|
||||
|
||||
//ok, we have to render several hlines
|
||||
p = (poly_base_size - fy1) * dx;
|
||||
first = poly_base_size;
|
||||
|
||||
if(dy < 0)
|
||||
{
|
||||
p = fy1 * dx;
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
delta = p / dy;
|
||||
mod = p % dy;
|
||||
|
||||
if(mod < 0)
|
||||
{
|
||||
delta--;
|
||||
mod += dy;
|
||||
}
|
||||
|
||||
x_from = x1 + delta;
|
||||
render_hline(ey1, x1, fy1, x_from, first);
|
||||
|
||||
ey1 += incr;
|
||||
set_cur_cell(x_from >> poly_base_shift, ey1);
|
||||
|
||||
if(ey1 != ey2)
|
||||
{
|
||||
p = poly_base_size * dx;
|
||||
lift = p / dy;
|
||||
rem = p % dy;
|
||||
|
||||
if(rem < 0)
|
||||
{
|
||||
lift--;
|
||||
rem += dy;
|
||||
}
|
||||
mod -= dy;
|
||||
|
||||
while(ey1 != ey2)
|
||||
{
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if (mod >= 0)
|
||||
{
|
||||
mod -= dy;
|
||||
delta++;
|
||||
}
|
||||
|
||||
x_to = x_from + delta;
|
||||
render_hline(ey1, x_from, poly_base_size - first, x_to, first);
|
||||
x_from = x_to;
|
||||
|
||||
ey1 += incr;
|
||||
set_cur_cell(x_from >> poly_base_shift, ey1);
|
||||
}
|
||||
}
|
||||
render_hline(ey1, x_from, poly_base_size - first, x2, fy2);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void outline_aa::move_to(int x, int y)
|
||||
{
|
||||
if(m_sorted) reset();
|
||||
set_cur_cell(x >> poly_base_shift, y >> poly_base_shift);
|
||||
m_cur_x = x;
|
||||
m_cur_y = y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void outline_aa::line_to(int x, int y)
|
||||
{
|
||||
render_line(m_cur_x, m_cur_y, x, y);
|
||||
m_cur_x = x;
|
||||
m_cur_y = y;
|
||||
m_sorted = false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum
|
||||
{
|
||||
qsort_threshold = 9
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <class T> static AGG_INLINE void swap_cells(T* a, T* b)
|
||||
{
|
||||
T temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <class T> static AGG_INLINE bool less_than(T* a, T* b)
|
||||
{
|
||||
return (*a)->packed_coord < (*b)->packed_coord;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void outline_aa::qsort_cells(cell_aa** start, unsigned num)
|
||||
{
|
||||
cell_aa** stack[80];
|
||||
cell_aa*** top;
|
||||
cell_aa** limit;
|
||||
cell_aa** base;
|
||||
|
||||
limit = start + num;
|
||||
base = start;
|
||||
top = stack;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int len = int(limit - base);
|
||||
|
||||
cell_aa** i;
|
||||
cell_aa** j;
|
||||
cell_aa** pivot;
|
||||
|
||||
if(len > qsort_threshold)
|
||||
{
|
||||
// we use base + len/2 as the pivot
|
||||
pivot = base + len / 2;
|
||||
swap_cells(base, pivot);
|
||||
|
||||
i = base + 1;
|
||||
j = limit - 1;
|
||||
|
||||
// now ensure that *i <= *base <= *j
|
||||
if(less_than(j, i))
|
||||
{
|
||||
swap_cells(i, j);
|
||||
}
|
||||
|
||||
if(less_than(base, i))
|
||||
{
|
||||
swap_cells(base, i);
|
||||
}
|
||||
|
||||
if(less_than(j, base))
|
||||
{
|
||||
swap_cells(base, j);
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
do i++; while( less_than(i, base) );
|
||||
do j--; while( less_than(base, j) );
|
||||
|
||||
if ( i > j )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
swap_cells(i, j);
|
||||
}
|
||||
|
||||
swap_cells(base, j);
|
||||
|
||||
// now, push the largest sub-array
|
||||
if(j - base > limit - i)
|
||||
{
|
||||
top[0] = base;
|
||||
top[1] = j;
|
||||
base = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
top[0] = i;
|
||||
top[1] = limit;
|
||||
limit = j;
|
||||
}
|
||||
top += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the sub-array is small, perform insertion sort
|
||||
j = base;
|
||||
i = j + 1;
|
||||
|
||||
for(; i < limit; j = i, i++)
|
||||
{
|
||||
for(; less_than(j + 1, j); j--)
|
||||
{
|
||||
swap_cells(j + 1, j);
|
||||
if (j == base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(top > stack)
|
||||
{
|
||||
top -= 2;
|
||||
base = top[0];
|
||||
limit = top[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void outline_aa::sort_cells()
|
||||
{
|
||||
if(m_num_cells == 0) return;
|
||||
if(m_num_cells > m_sorted_size)
|
||||
{
|
||||
delete [] m_sorted_cells;
|
||||
m_sorted_size = m_num_cells;
|
||||
m_sorted_cells = new cell_aa* [m_num_cells + 1];
|
||||
}
|
||||
|
||||
cell_aa** sorted_ptr = m_sorted_cells;
|
||||
cell_aa** block_ptr = m_cells;
|
||||
cell_aa* cell_ptr;
|
||||
|
||||
unsigned nb = m_num_cells >> cell_block_shift;
|
||||
unsigned i;
|
||||
|
||||
while(nb--)
|
||||
{
|
||||
cell_ptr = *block_ptr++;
|
||||
i = cell_block_size;
|
||||
while(i--)
|
||||
{
|
||||
*sorted_ptr++ = cell_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
cell_ptr = *block_ptr++;
|
||||
i = m_num_cells & cell_block_mask;
|
||||
while(i--)
|
||||
{
|
||||
*sorted_ptr++ = cell_ptr++;
|
||||
}
|
||||
m_sorted_cells[m_num_cells] = 0;
|
||||
qsort_cells(m_sorted_cells, m_num_cells);
|
||||
m_min_y = m_sorted_cells[0]->y;
|
||||
m_max_y = m_sorted_cells[m_num_cells - 1]->y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const cell_aa* const* outline_aa::cells()
|
||||
{
|
||||
//Perform sort only the first time.
|
||||
if(!m_sorted)
|
||||
{
|
||||
add_cur_cell();
|
||||
sort_cells();
|
||||
m_sorted = true;
|
||||
}
|
||||
return m_sorted_cells;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,743 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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.
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Class rasterizer_scanline_aa
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
|
||||
#define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
#include "agg_math.h"
|
||||
#include "agg_gamma_functions.h"
|
||||
#include "agg_clip_liang_barsky.h"
|
||||
#include "agg_render_scanlines.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// These constants determine the subpixel accuracy, to be more precise,
|
||||
// the number of bits of the fractional part of the coordinates.
|
||||
// The possible coordinate capacity in bits can be calculated by formula:
|
||||
// sizeof(int) * 8 - poly_base_shift * 2, i.e, for 32-bit integers and
|
||||
// 8-bits fractional part the capacity is 16 bits or [-32768...32767].
|
||||
enum
|
||||
{
|
||||
poly_base_shift = 8, //----poly_base_shift
|
||||
poly_base_size = 1 << poly_base_shift, //----poly_base_size
|
||||
poly_base_mask = poly_base_size - 1 //----poly_base_mask
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------poly_coord
|
||||
inline int poly_coord(double c)
|
||||
{
|
||||
return int(c * poly_base_size);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------cell_aa
|
||||
// A pixel cell. There're no constructors defined and it was done
|
||||
// intentionally in order to avoid extra overhead when allocating an
|
||||
// array of cells.
|
||||
struct cell_aa
|
||||
{
|
||||
int16 x;
|
||||
int16 y;
|
||||
int packed_coord;
|
||||
int cover;
|
||||
int area;
|
||||
|
||||
void set(int x, int y, int c, int a);
|
||||
void set_coord(int x, int y);
|
||||
void set_cover(int c, int a);
|
||||
void add_cover(int c, int a);
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------outline_aa
|
||||
// An internal class that implements the main rasterization algorithm.
|
||||
// Used in the rasterizer. Should not be used direcly.
|
||||
class outline_aa
|
||||
{
|
||||
enum
|
||||
{
|
||||
cell_block_shift = 12,
|
||||
cell_block_size = 1 << cell_block_shift,
|
||||
cell_block_mask = cell_block_size - 1,
|
||||
cell_block_pool = 256,
|
||||
cell_block_limit = 1024
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
~outline_aa();
|
||||
outline_aa();
|
||||
|
||||
void reset();
|
||||
|
||||
void move_to(int x, int y);
|
||||
void line_to(int x, int y);
|
||||
|
||||
int min_x() const { return m_min_x; }
|
||||
int min_y() const { return m_min_y; }
|
||||
int max_x() const { return m_max_x; }
|
||||
int max_y() const { return m_max_y; }
|
||||
|
||||
const cell_aa* const* cells();
|
||||
unsigned num_cells() { cells(); return m_num_cells; }
|
||||
bool sorted() const { return m_sorted; }
|
||||
|
||||
private:
|
||||
outline_aa(const outline_aa&);
|
||||
const outline_aa& operator = (const outline_aa&);
|
||||
|
||||
void set_cur_cell(int x, int y);
|
||||
void add_cur_cell();
|
||||
void sort_cells();
|
||||
void render_hline(int ey, int x1, int y1, int x2, int y2);
|
||||
void render_line(int x1, int y1, int x2, int y2);
|
||||
void allocate_block();
|
||||
|
||||
static void qsort_cells(cell_aa** start, unsigned num);
|
||||
|
||||
private:
|
||||
unsigned m_num_blocks;
|
||||
unsigned m_max_blocks;
|
||||
unsigned m_cur_block;
|
||||
unsigned m_num_cells;
|
||||
cell_aa** m_cells;
|
||||
cell_aa* m_cur_cell_ptr;
|
||||
cell_aa** m_sorted_cells;
|
||||
unsigned m_sorted_size;
|
||||
cell_aa m_cur_cell;
|
||||
int m_cur_x;
|
||||
int m_cur_y;
|
||||
int m_min_x;
|
||||
int m_min_y;
|
||||
int m_max_x;
|
||||
int m_max_y;
|
||||
bool m_sorted;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------filling_rule_e
|
||||
enum filling_rule_e
|
||||
{
|
||||
fill_non_zero,
|
||||
fill_even_odd
|
||||
};
|
||||
|
||||
|
||||
//==================================================rasterizer_scanline_aa
|
||||
// Polygon rasterizer that is used to render filled polygons with
|
||||
// high-quality Anti-Aliasing. Internally, by default, the class uses
|
||||
// integer coordinates in format 24.8, i.e. 24 bits for integer part
|
||||
// and 8 bits for fractional - see poly_base_shift. This class can be
|
||||
// used in the following way:
|
||||
//
|
||||
// 1. filling_rule(filling_rule_e ft) - optional.
|
||||
//
|
||||
// 2. gamma() - optional.
|
||||
//
|
||||
// 3. reset()
|
||||
//
|
||||
// 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create
|
||||
// more than one contour, but each contour must consist of at least 3
|
||||
// vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
|
||||
// is the absolute minimum of vertices that define a triangle.
|
||||
// The algorithm does not check either the number of vertices nor
|
||||
// coincidence of their coordinates, but in the worst case it just
|
||||
// won't draw anything.
|
||||
// The orger of the vertices (clockwise or counterclockwise)
|
||||
// is important when using the non-zero filling rule (fill_non_zero).
|
||||
// In this case the vertex order of all the contours must be the same
|
||||
// if you want your intersecting polygons to be without "holes".
|
||||
// You actually can use different vertices order. If the contours do not
|
||||
// intersect each other the order is not important anyway. If they do,
|
||||
// contours with the same vertex order will be rendered without "holes"
|
||||
// while the intersecting contours with different orders will have "holes".
|
||||
//
|
||||
// filling_rule() and gamma() can be called anytime before "sweeping".
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale=1, unsigned AA_Shift=8> class rasterizer_scanline_aa
|
||||
{
|
||||
enum status
|
||||
{
|
||||
status_initial,
|
||||
status_line_to,
|
||||
status_closed
|
||||
};
|
||||
|
||||
struct iterator
|
||||
{
|
||||
const cell_aa* const* cells;
|
||||
int cover;
|
||||
int last_y;
|
||||
};
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
aa_shift = AA_Shift,
|
||||
aa_num = 1 << aa_shift,
|
||||
aa_mask = aa_num - 1,
|
||||
aa_2num = aa_num * 2,
|
||||
aa_2mask = aa_2num - 1
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rasterizer_scanline_aa() :
|
||||
m_filling_rule(fill_non_zero),
|
||||
m_clipped_start_x(0),
|
||||
m_clipped_start_y(0),
|
||||
m_start_x(0),
|
||||
m_start_y(0),
|
||||
m_prev_x(0),
|
||||
m_prev_y(0),
|
||||
m_prev_flags(0),
|
||||
m_status(status_initial),
|
||||
m_clipping(false)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < aa_num; i++) m_gamma[i] = i;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class GammaF>
|
||||
rasterizer_scanline_aa(const GammaF& gamma_function) :
|
||||
m_filling_rule(fill_non_zero),
|
||||
m_clipped_start_x(0),
|
||||
m_clipped_start_y(0),
|
||||
m_start_x(0),
|
||||
m_start_y(0),
|
||||
m_prev_x(0),
|
||||
m_prev_y(0),
|
||||
m_prev_flags(0),
|
||||
m_status(status_initial),
|
||||
m_clipping(false)
|
||||
{
|
||||
gamma(gamma_function);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset();
|
||||
void filling_rule(filling_rule_e filling_rule);
|
||||
void clip_box(double x1, double y1, double x2, double y2);
|
||||
void reset_clipping();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class GammaF> void gamma(const GammaF& gamma_function)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < aa_num; i++)
|
||||
{
|
||||
m_gamma[i] = int(floor(gamma_function(double(i) / aa_mask) * aa_mask + 0.5));
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned apply_gamma(unsigned cover) const
|
||||
{
|
||||
return m_gamma[cover];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
void move_to(int x, int y);
|
||||
void line_to(int x, int y);
|
||||
void close_polygon();
|
||||
void move_to_d(double x, double y);
|
||||
void line_to_d(double x, double y);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int min_x() const { return m_outline.min_x(); }
|
||||
int min_y() const { return m_outline.min_y(); }
|
||||
int max_x() const { return m_outline.max_x(); }
|
||||
int max_y() const { return m_outline.max_y(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE unsigned calculate_alpha(int area) const
|
||||
{
|
||||
int cover = area >> (poly_base_shift*2 + 1 - aa_shift);
|
||||
|
||||
if(cover < 0) cover = -cover;
|
||||
if(m_filling_rule == fill_even_odd)
|
||||
{
|
||||
cover &= aa_2mask;
|
||||
if(cover > aa_num)
|
||||
{
|
||||
cover = aa_2num - cover;
|
||||
}
|
||||
}
|
||||
if(cover > aa_mask) cover = aa_mask;
|
||||
return m_gamma[cover];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void sort()
|
||||
{
|
||||
m_outline.cells();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool rewind_scanlines()
|
||||
{
|
||||
close_polygon();
|
||||
m_iterator.cells = m_outline.cells();
|
||||
if(m_outline.num_cells() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_iterator.cover = 0;
|
||||
m_iterator.last_y = (*m_iterator.cells)->y;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> bool sweep_scanline(Scanline& sl)
|
||||
{
|
||||
sl.reset_spans();
|
||||
for(;;)
|
||||
{
|
||||
const cell_aa* cur_cell = *m_iterator.cells;
|
||||
if(cur_cell == 0) return false;
|
||||
++m_iterator.cells;
|
||||
m_iterator.last_y = cur_cell->y;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int coord = cur_cell->packed_coord;
|
||||
int area = cur_cell->area;
|
||||
int last_x = cur_cell->x;
|
||||
|
||||
m_iterator.cover += cur_cell->cover;
|
||||
|
||||
//accumulate all cells with the same coordinates
|
||||
for(; (cur_cell = *m_iterator.cells) != 0; ++m_iterator.cells)
|
||||
{
|
||||
if(cur_cell->packed_coord != coord) break;
|
||||
area += cur_cell->area;
|
||||
m_iterator.cover += cur_cell->cover;
|
||||
}
|
||||
|
||||
int alpha;
|
||||
if(cur_cell == 0 || cur_cell->y != m_iterator.last_y)
|
||||
{
|
||||
|
||||
if(area)
|
||||
{
|
||||
alpha = calculate_alpha((m_iterator.cover << (poly_base_shift + 1)) - area);
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_cell(last_x, alpha);
|
||||
}
|
||||
++last_x;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
++m_iterator.cells;
|
||||
|
||||
if(area)
|
||||
{
|
||||
alpha = calculate_alpha((m_iterator.cover << (poly_base_shift + 1)) - area);
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_cell(last_x, alpha);
|
||||
}
|
||||
++last_x;
|
||||
}
|
||||
|
||||
if(cur_cell->x > last_x)
|
||||
{
|
||||
alpha = calculate_alpha(m_iterator.cover << (poly_base_shift + 1));
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_span(last_x, cur_cell->x - last_x, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(sl.num_spans())
|
||||
{
|
||||
sl.finalize(m_iterator.last_y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool hit_test(int tx, int ty);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_xy(const double* x, const double* y, unsigned n)
|
||||
{
|
||||
if(n > 2)
|
||||
{
|
||||
move_to_d(*x++, *y++);
|
||||
--n;
|
||||
do
|
||||
{
|
||||
line_to_d(*x++, *y++);
|
||||
}
|
||||
while(--n);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
template<class VertexSource>
|
||||
void add_path(VertexSource& vs, unsigned id=0)
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
|
||||
unsigned cmd;
|
||||
vs.rewind(id);
|
||||
while(!is_stop(cmd = vs.vertex(&x, &y)))
|
||||
{
|
||||
add_vertex(x, y, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
// Disable copying
|
||||
rasterizer_scanline_aa(const rasterizer_scanline_aa<XScale, AA_Shift>&);
|
||||
const rasterizer_scanline_aa<XScale, AA_Shift>&
|
||||
operator = (const rasterizer_scanline_aa<XScale, AA_Shift>&);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void move_to_no_clip(int x, int y);
|
||||
void line_to_no_clip(int x, int y);
|
||||
void close_polygon_no_clip();
|
||||
void clip_segment(int x, int y);
|
||||
|
||||
private:
|
||||
outline_aa m_outline;
|
||||
int m_gamma[aa_num];
|
||||
filling_rule_e m_filling_rule;
|
||||
int m_clipped_start_x;
|
||||
int m_clipped_start_y;
|
||||
int m_start_x;
|
||||
int m_start_y;
|
||||
int m_prev_x;
|
||||
int m_prev_y;
|
||||
unsigned m_prev_flags;
|
||||
unsigned m_status;
|
||||
rect m_clip_box;
|
||||
bool m_clipping;
|
||||
iterator m_iterator;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::reset()
|
||||
{
|
||||
m_outline.reset();
|
||||
m_status = status_initial;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::filling_rule(filling_rule_e filling_rule)
|
||||
{
|
||||
m_filling_rule = filling_rule;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::clip_box(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
reset();
|
||||
m_clip_box = rect(poly_coord(x1), poly_coord(y1),
|
||||
poly_coord(x2), poly_coord(y2));
|
||||
m_clip_box.normalize();
|
||||
m_clipping = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::reset_clipping()
|
||||
{
|
||||
reset();
|
||||
m_clipping = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::move_to_no_clip(int x, int y)
|
||||
{
|
||||
if(m_status == status_line_to)
|
||||
{
|
||||
close_polygon_no_clip();
|
||||
}
|
||||
m_outline.move_to(x * XScale, y);
|
||||
m_clipped_start_x = x;
|
||||
m_clipped_start_y = y;
|
||||
m_status = status_line_to;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::line_to_no_clip(int x, int y)
|
||||
{
|
||||
if(m_status != status_initial)
|
||||
{
|
||||
m_outline.line_to(x * XScale, y);
|
||||
m_status = status_line_to;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::close_polygon_no_clip()
|
||||
{
|
||||
if(m_status == status_line_to)
|
||||
{
|
||||
m_outline.line_to(m_clipped_start_x * XScale, m_clipped_start_y);
|
||||
m_status = status_closed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::clip_segment(int x, int y)
|
||||
{
|
||||
unsigned flags = clipping_flags(x, y, m_clip_box);
|
||||
if(m_prev_flags == flags)
|
||||
{
|
||||
if(flags == 0)
|
||||
{
|
||||
if(m_status == status_initial)
|
||||
{
|
||||
move_to_no_clip(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
line_to_no_clip(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int cx[4];
|
||||
int cy[4];
|
||||
unsigned n = clip_liang_barsky(m_prev_x, m_prev_y,
|
||||
x, y,
|
||||
m_clip_box,
|
||||
cx, cy);
|
||||
const int* px = cx;
|
||||
const int* py = cy;
|
||||
while(n--)
|
||||
{
|
||||
if(m_status == status_initial)
|
||||
{
|
||||
move_to_no_clip(*px++, *py++);
|
||||
}
|
||||
else
|
||||
{
|
||||
line_to_no_clip(*px++, *py++);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_prev_flags = flags;
|
||||
m_prev_x = x;
|
||||
m_prev_y = y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
if(is_close(cmd))
|
||||
{
|
||||
close_polygon();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
move_to(poly_coord(x), poly_coord(y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
line_to(poly_coord(x), poly_coord(y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::move_to(int x, int y)
|
||||
{
|
||||
if(m_clipping)
|
||||
{
|
||||
if(m_outline.sorted())
|
||||
{
|
||||
reset();
|
||||
}
|
||||
if(m_status == status_line_to)
|
||||
{
|
||||
close_polygon();
|
||||
}
|
||||
m_prev_x = m_start_x = x;
|
||||
m_prev_y = m_start_y = y;
|
||||
m_status = status_initial;
|
||||
m_prev_flags = clipping_flags(x, y, m_clip_box);
|
||||
if(m_prev_flags == 0)
|
||||
{
|
||||
move_to_no_clip(x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
move_to_no_clip(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::line_to(int x, int y)
|
||||
{
|
||||
if(m_clipping)
|
||||
{
|
||||
clip_segment(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
line_to_no_clip(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::close_polygon()
|
||||
{
|
||||
if(m_clipping)
|
||||
{
|
||||
clip_segment(m_start_x, m_start_y);
|
||||
}
|
||||
close_polygon_no_clip();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::move_to_d(double x, double y)
|
||||
{
|
||||
move_to(poly_coord(x), poly_coord(y));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
void rasterizer_scanline_aa<XScale, AA_Shift>::line_to_d(double x, double y)
|
||||
{
|
||||
line_to(poly_coord(x), poly_coord(y));
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<unsigned XScale, unsigned AA_Shift>
|
||||
bool rasterizer_scanline_aa<XScale, AA_Shift>::hit_test(int tx, int ty)
|
||||
{
|
||||
close_polygon();
|
||||
const cell_aa* const* cells = m_outline.cells();
|
||||
if(m_outline.num_cells() == 0) return false;
|
||||
|
||||
int cover = 0;
|
||||
|
||||
const cell_aa* cur_cell = *cells++;
|
||||
for(;;)
|
||||
{
|
||||
int alpha;
|
||||
int coord = cur_cell->packed_coord;
|
||||
int x = cur_cell->x;
|
||||
int y = cur_cell->y;
|
||||
|
||||
if(y > ty) return false;
|
||||
|
||||
int area = cur_cell->area;
|
||||
cover += cur_cell->cover;
|
||||
|
||||
while((cur_cell = *cells++) != 0)
|
||||
{
|
||||
if(cur_cell->packed_coord != coord) break;
|
||||
area += cur_cell->area;
|
||||
cover += cur_cell->cover;
|
||||
}
|
||||
|
||||
if(area)
|
||||
{
|
||||
alpha = calculate_alpha((cover << (poly_base_shift + 1)) - area);
|
||||
if(alpha)
|
||||
{
|
||||
if(tx == x && ty == y) return true;
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
if(!cur_cell) break;
|
||||
|
||||
if(cur_cell->x > x)
|
||||
{
|
||||
alpha = calculate_alpha(cover << (poly_base_shift + 1));
|
||||
if(alpha)
|
||||
{
|
||||
if(ty == y && tx >= x && tx <= cur_cell->x) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_RENDER_SCANLINES_INCLUDED
|
||||
#define AGG_RENDER_SCANLINES_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//========================================================render_scanlines
|
||||
template<class Rasterizer, class Scanline, class Renderer>
|
||||
void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
ren.prepare(unsigned(ras.max_x() - ras.min_x() + 2));
|
||||
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
ren.render(sl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================render_all_paths
|
||||
template<class Rasterizer, class Scanline, class Renderer,
|
||||
class VertexSource, class ColorStorage, class PathId>
|
||||
void render_all_paths(Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& r,
|
||||
VertexSource& vs,
|
||||
const ColorStorage& as,
|
||||
const PathId& id,
|
||||
unsigned num_paths)
|
||||
{
|
||||
for(unsigned i = 0; i < num_paths; i++)
|
||||
{
|
||||
ras.reset();
|
||||
ras.add_path(vs, id[i]);
|
||||
r.color(as[i]);
|
||||
render_scanlines(ras, sl, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1,618 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class renderer_base
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERER_BASE_INCLUDED
|
||||
#define AGG_RENDERER_BASE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------renderer_base
|
||||
template<class PixelFormat> class renderer_base
|
||||
{
|
||||
public:
|
||||
typedef PixelFormat pixfmt_type;
|
||||
typedef typename pixfmt_type::color_type color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_base(pixfmt_type& ren) :
|
||||
m_ren(&ren),
|
||||
m_clip_box(0, 0, ren.width() - 1, ren.height() - 1)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const pixfmt_type& ren() const { return *m_ren; }
|
||||
pixfmt_type& ren() { return *m_ren; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned width() const { return m_ren->width(); }
|
||||
unsigned height() const { return m_ren->height(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool clip_box(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
rect cb(x1, y1, x2, y2);
|
||||
cb.normalize();
|
||||
if(cb.clip(rect(0, 0, width() - 1, height() - 1)))
|
||||
{
|
||||
m_clip_box = cb;
|
||||
return true;
|
||||
}
|
||||
m_clip_box.x1 = 1;
|
||||
m_clip_box.y1 = 1;
|
||||
m_clip_box.x2 = 0;
|
||||
m_clip_box.y2 = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_clipping(bool visibility)
|
||||
{
|
||||
if(visibility)
|
||||
{
|
||||
m_clip_box.x1 = 0;
|
||||
m_clip_box.y1 = 0;
|
||||
m_clip_box.x2 = width() - 1;
|
||||
m_clip_box.y2 = height() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_clip_box.x1 = 1;
|
||||
m_clip_box.y1 = 1;
|
||||
m_clip_box.x2 = 0;
|
||||
m_clip_box.y2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clip_box_naked(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
m_clip_box.x1 = x1;
|
||||
m_clip_box.y1 = y1;
|
||||
m_clip_box.x2 = x2;
|
||||
m_clip_box.y2 = y2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool inbox(int x, int y) const
|
||||
{
|
||||
return x >= m_clip_box.x1 && y >= m_clip_box.y1 &&
|
||||
x <= m_clip_box.x2 && y <= m_clip_box.y2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void first_clip_box() {}
|
||||
bool next_clip_box() { return false; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rect& clip_box() const { return m_clip_box; }
|
||||
int xmin() const { return m_clip_box.x1; }
|
||||
int ymin() const { return m_clip_box.y1; }
|
||||
int xmax() const { return m_clip_box.x2; }
|
||||
int ymax() const { return m_clip_box.y2; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rect& bounding_clip_box() const { return m_clip_box; }
|
||||
int bounding_xmin() const { return m_clip_box.x1; }
|
||||
int bounding_ymin() const { return m_clip_box.y1; }
|
||||
int bounding_xmax() const { return m_clip_box.x2; }
|
||||
int bounding_ymax() const { return m_clip_box.y2; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(const color_type& c)
|
||||
{
|
||||
unsigned y;
|
||||
if(width())
|
||||
{
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
m_ren->copy_hline(0, y, width(), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_pixel(int x, int y, const color_type& c)
|
||||
{
|
||||
if(inbox(x, y))
|
||||
{
|
||||
m_ren->copy_pixel(x, y, c);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_pixel(int x, int y, const color_type& c, cover_type cover)
|
||||
{
|
||||
if(inbox(x, y))
|
||||
{
|
||||
m_ren->blend_pixel(x, y, c, cover);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
color_type pixel(int x, int y) const
|
||||
{
|
||||
return inbox(x, y) ?
|
||||
m_ren->pixel(x, y) :
|
||||
color_type::no_color();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_hline(int x1, int y, int x2, const color_type& c)
|
||||
{
|
||||
if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
if(x1 > xmax()) return;
|
||||
if(x2 < xmin()) return;
|
||||
|
||||
if(x1 < xmin()) x1 = xmin();
|
||||
if(x2 > xmax()) x2 = xmax();
|
||||
|
||||
m_ren->copy_hline(x1, y, x2 - x1 + 1, c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_vline(int x, int y1, int y2, const color_type& c)
|
||||
{
|
||||
if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
if(y1 > ymax()) return;
|
||||
if(y2 < ymin()) return;
|
||||
|
||||
if(y1 < ymin()) y1 = ymin();
|
||||
if(y2 > ymax()) y2 = ymax();
|
||||
|
||||
m_ren->copy_vline(x, y1, y2 - y1 + 1, c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_hline(int x1, int y, int x2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
if(x1 > xmax()) return;
|
||||
if(x2 < xmin()) return;
|
||||
|
||||
if(x1 < xmin()) x1 = xmin();
|
||||
if(x2 > xmax()) x2 = xmax();
|
||||
|
||||
m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_vline(int x, int y1, int y2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
if(y1 > ymax()) return;
|
||||
if(y2 < ymin()) return;
|
||||
|
||||
if(y1 < ymin()) y1 = ymin();
|
||||
if(y2 > ymax()) y2 = ymax();
|
||||
|
||||
m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
|
||||
{
|
||||
rect rc(x1, y1, x2, y2);
|
||||
rc.normalize();
|
||||
if(rc.clip(clip_box()))
|
||||
{
|
||||
int y;
|
||||
for(y = rc.y1; y <= rc.y2; y++)
|
||||
{
|
||||
m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_bar(int x1, int y1, int x2, int y2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
rect rc(x1, y1, x2, y2);
|
||||
rc.normalize();
|
||||
if(rc.clip(clip_box()))
|
||||
{
|
||||
int y;
|
||||
for(y = rc.y1; y <= rc.y2; y++)
|
||||
{
|
||||
m_ren->blend_hline(rc.x1,
|
||||
y,
|
||||
unsigned(rc.x2 - rc.x1 + 1),
|
||||
c,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_hspan(int x, int y, int len,
|
||||
const color_type& c,
|
||||
const cover_type* covers)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
len -= xmin() - x;
|
||||
if(len <= 0) return;
|
||||
covers += xmin() - x;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_solid_hspan(x, y, len, c, covers);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_vspan(int x, int y, int len,
|
||||
const color_type& c,
|
||||
const cover_type* covers)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
len -= ymin() - y;
|
||||
if(len <= 0) return;
|
||||
covers += ymin() - y;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_solid_vspan(x, y, len, c, covers);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_hspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
int d = xmin() - x;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_vspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
int d = ymin() - y;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_opaque_color_hspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
int d = xmin() - x;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_opaque_color_hspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_opaque_color_vspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
int d = ymin() - y;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_opaque_color_vspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_hspan_no_clip(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_vspan_no_clip(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_opaque_color_hspan_no_clip(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
m_ren->blend_opaque_color_hspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_opaque_color_vspan_no_clip(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = cover_full)
|
||||
{
|
||||
m_ren->blend_opaque_color_vspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rect clip_rect_area(rect& dst, rect& src, int wsrc, int hsrc) const
|
||||
{
|
||||
rect rc(0,0,0,0);
|
||||
rect cb = clip_box();
|
||||
++cb.x2;
|
||||
++cb.y2;
|
||||
|
||||
if(src.x1 < 0)
|
||||
{
|
||||
dst.x1 -= src.x1;
|
||||
src.x1 = 0;
|
||||
}
|
||||
if(src.y1 < 0)
|
||||
{
|
||||
dst.y1 -= src.y1;
|
||||
src.y1 = 0;
|
||||
}
|
||||
|
||||
if(src.x2 > wsrc) src.x2 = wsrc;
|
||||
if(src.y2 > hsrc) src.y2 = hsrc;
|
||||
|
||||
if(dst.x1 < cb.x1)
|
||||
{
|
||||
src.x1 += cb.x1 - dst.x1;
|
||||
dst.x1 = cb.x1;
|
||||
}
|
||||
if(dst.y1 < cb.y1)
|
||||
{
|
||||
src.y1 += cb.y1 - dst.y1;
|
||||
dst.y1 = cb.y1;
|
||||
}
|
||||
|
||||
if(dst.x2 > cb.x2) dst.x2 = cb.x2;
|
||||
if(dst.y2 > cb.y2) dst.y2 = cb.y2;
|
||||
|
||||
rc.x2 = dst.x2 - dst.x1;
|
||||
rc.y2 = dst.y2 - dst.y1;
|
||||
|
||||
if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1;
|
||||
if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_from(const rendering_buffer& src,
|
||||
const rect* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0)
|
||||
{
|
||||
rect rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
|
||||
rect rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
m_ren->copy_from(src,
|
||||
rdst.x1, rdst.y1,
|
||||
rsrc.x1, rsrc.y1,
|
||||
rc.x2);
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from(const SrcPixelFormatRenderer& src,
|
||||
const rect* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0)
|
||||
{
|
||||
rect rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
|
||||
rect rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
typename SrcPixelFormatRenderer::row_data span = src.span(rsrc.x1, rsrc.y1);
|
||||
if(span.ptr)
|
||||
{
|
||||
int x1src = rsrc.x1;
|
||||
int x1dst = rdst.x1;
|
||||
int len = rc.x2;
|
||||
if(span.x1 > x1src)
|
||||
{
|
||||
x1dst += span.x1 - x1src;
|
||||
len -= span.x1 - x1src;
|
||||
x1src = span.x1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x1src + len-1 > span.x2)
|
||||
{
|
||||
len -= x1src + len - span.x2 - 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_from(src, span.ptr,
|
||||
x1dst, rdst.y1,
|
||||
x1src, rsrc.y1,
|
||||
len);
|
||||
}
|
||||
}
|
||||
}
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
pixfmt_type* m_ren;
|
||||
rect m_clip_box;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,450 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_RENDERER_SCANLINE_INCLUDED
|
||||
#define AGG_RENDERER_SCANLINE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_renderer_base.h"
|
||||
#include "agg_render_scanlines.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//====================================================renderer_scanline_aa
|
||||
template<class BaseRenderer, class SpanGenerator> class renderer_scanline_aa
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_aa(base_ren_type& ren, SpanGenerator& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_span_gen(&span_gen)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare(unsigned max_span_len)
|
||||
{
|
||||
m_span_gen->prepare(max_span_len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
int y = sl.y();
|
||||
m_ren->first_clip_box();
|
||||
do
|
||||
{
|
||||
int xmin = m_ren->xmin();
|
||||
int xmax = m_ren->xmax();
|
||||
|
||||
if(y >= m_ren->ymin() && y <= m_ren->ymax())
|
||||
{
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
do
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
bool solid = false;
|
||||
const typename Scanline::cover_type* covers = span->covers;
|
||||
|
||||
if(len < 0)
|
||||
{
|
||||
solid = true;
|
||||
len = -len;
|
||||
}
|
||||
|
||||
if(x < xmin)
|
||||
{
|
||||
len -= xmin - x;
|
||||
if(!solid)
|
||||
{
|
||||
covers += xmin - x;
|
||||
}
|
||||
x = xmin;
|
||||
}
|
||||
|
||||
if(len > 0)
|
||||
{
|
||||
if(x + len > xmax)
|
||||
{
|
||||
len = xmax - x + 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_color_hspan_no_clip(
|
||||
x, y, len,
|
||||
m_span_gen->generate(x, y, len),
|
||||
solid ? 0 : covers,
|
||||
*covers);
|
||||
}
|
||||
}
|
||||
++span;
|
||||
}
|
||||
while(--num_spans);
|
||||
}
|
||||
}
|
||||
while(m_ren->next_clip_box());
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
SpanGenerator* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==============================================renderer_scanline_aa_opaque
|
||||
template<class BaseRenderer, class SpanGenerator> class renderer_scanline_aa_opaque
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_aa_opaque(base_ren_type& ren, SpanGenerator& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_span_gen(&span_gen)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare(unsigned max_span_len)
|
||||
{
|
||||
m_span_gen->prepare(max_span_len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
int y = sl.y();
|
||||
m_ren->first_clip_box();
|
||||
do
|
||||
{
|
||||
int xmin = m_ren->xmin();
|
||||
int xmax = m_ren->xmax();
|
||||
|
||||
if(y >= m_ren->ymin() && y <= m_ren->ymax())
|
||||
{
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
do
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
bool solid = false;
|
||||
const typename Scanline::cover_type* covers = span->covers;
|
||||
|
||||
if(len < 0)
|
||||
{
|
||||
solid = true;
|
||||
len = -len;
|
||||
}
|
||||
|
||||
if(x < xmin)
|
||||
{
|
||||
len -= xmin - x;
|
||||
if(!solid)
|
||||
{
|
||||
covers += xmin - x;
|
||||
}
|
||||
x = xmin;
|
||||
}
|
||||
|
||||
if(len > 0)
|
||||
{
|
||||
if(x + len > xmax)
|
||||
{
|
||||
len = xmax - x + 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_opaque_color_hspan_no_clip(
|
||||
x, y, len,
|
||||
m_span_gen->generate(x, y, len),
|
||||
solid ? 0 : covers,
|
||||
*covers);
|
||||
}
|
||||
}
|
||||
++span;
|
||||
}
|
||||
while(--num_spans);
|
||||
}
|
||||
}
|
||||
while(m_ren->next_clip_box());
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
SpanGenerator* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==============================================renderer_scanline_aa_solid
|
||||
template<class BaseRenderer> class renderer_scanline_aa_solid
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef typename base_ren_type::color_type color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_aa_solid(base_ren_type& ren) :
|
||||
m_ren(&ren)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void color(const color_type& c) { m_color = c; }
|
||||
const color_type& color() const { return m_color; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare(unsigned) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
int y = sl.y();
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
|
||||
do
|
||||
{
|
||||
int x = span->x;
|
||||
if(span->len > 0)
|
||||
{
|
||||
m_ren->blend_solid_hspan(x, y, (unsigned)span->len,
|
||||
m_color,
|
||||
span->covers);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ren->blend_hline(x, y, (unsigned)(x - span->len - 1),
|
||||
m_color,
|
||||
*(span->covers));
|
||||
}
|
||||
++span;
|
||||
}
|
||||
while(--num_spans);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
color_type m_color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===================================================renderer_scanline_bin
|
||||
template<class BaseRenderer, class SpanGenerator> class renderer_scanline_bin
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_bin(base_ren_type& ren, SpanGenerator& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_span_gen(&span_gen)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare(unsigned max_span_len)
|
||||
{
|
||||
m_span_gen->prepare(max_span_len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
int y = sl.y();
|
||||
m_ren->first_clip_box();
|
||||
do
|
||||
{
|
||||
int xmin = m_ren->xmin();
|
||||
int xmax = m_ren->xmax();
|
||||
|
||||
if(y >= m_ren->ymin() && y <= m_ren->ymax())
|
||||
{
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
do
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
|
||||
if(len < 0) len = -len;
|
||||
if(x < xmin)
|
||||
{
|
||||
len -= xmin - x;
|
||||
x = xmin;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x + len > xmax)
|
||||
{
|
||||
len = xmax - x + 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_color_hspan_no_clip(
|
||||
x, y, len,
|
||||
m_span_gen->generate(x, y, len),
|
||||
0);
|
||||
}
|
||||
}
|
||||
++span;
|
||||
}
|
||||
while(--num_spans);
|
||||
}
|
||||
}
|
||||
while(m_ren->next_clip_box());
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
SpanGenerator* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===============================================renderer_scanline_bin_opaque
|
||||
template<class BaseRenderer, class SpanGenerator> class renderer_scanline_bin_opaque
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_bin_opaque(base_ren_type& ren, SpanGenerator& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_span_gen(&span_gen)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare(unsigned max_span_len)
|
||||
{
|
||||
m_span_gen->prepare(max_span_len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
int y = sl.y();
|
||||
m_ren->first_clip_box();
|
||||
do
|
||||
{
|
||||
int xmin = m_ren->xmin();
|
||||
int xmax = m_ren->xmax();
|
||||
|
||||
if(y >= m_ren->ymin() && y <= m_ren->ymax())
|
||||
{
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
do
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
|
||||
if(len < 0) len = -len;
|
||||
if(x < xmin)
|
||||
{
|
||||
len -= xmin - x;
|
||||
x = xmin;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x + len > xmax)
|
||||
{
|
||||
len = xmax - x + 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_opaque_color_hspan_no_clip(
|
||||
x, y, len,
|
||||
m_span_gen->generate(x, y, len),
|
||||
0);
|
||||
}
|
||||
}
|
||||
++span;
|
||||
}
|
||||
while(--num_spans);
|
||||
}
|
||||
}
|
||||
while(m_ren->next_clip_box());
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
SpanGenerator* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//=============================================renderer_scanline_bin_solid
|
||||
template<class BaseRenderer> class renderer_scanline_bin_solid
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef typename base_ren_type::color_type color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_bin_solid(base_ren_type& ren) :
|
||||
m_ren(&ren)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void color(const color_type& c) { m_color = c; }
|
||||
const color_type& color() const { return m_color; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare(unsigned) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
do
|
||||
{
|
||||
m_ren->blend_hline(span->x,
|
||||
sl.y(),
|
||||
span->x - 1 + ((span->len < 0) ?
|
||||
-span->len :
|
||||
span->len),
|
||||
m_color,
|
||||
cover_full);
|
||||
++span;
|
||||
}
|
||||
while(--num_spans);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
color_type m_color;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,182 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class rendering_buffer
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERING_BUFFER_INCLUDED
|
||||
#define AGG_RENDERING_BUFFER_INCLUDED
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//==========================================================row_ptr_cache
|
||||
template<class T> class row_ptr_cache
|
||||
{
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
struct row_data
|
||||
{
|
||||
int x1, x2;
|
||||
const int8u* ptr;
|
||||
row_data() {}
|
||||
row_data(int x1_, int x2_, const int8u* ptr_) :
|
||||
x1(x1_), x2(x2_), ptr(ptr_) {}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
~row_ptr_cache()
|
||||
{
|
||||
delete [] m_rows;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
row_ptr_cache() :
|
||||
m_buf(0),
|
||||
m_rows(0),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0),
|
||||
m_max_height(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
row_ptr_cache(T* buf, unsigned width, unsigned height, int stride) :
|
||||
m_buf(0),
|
||||
m_rows(0),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0),
|
||||
m_max_height(0)
|
||||
{
|
||||
attach(buf, width, height, stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void attach(T* buf, unsigned width, unsigned height, int stride)
|
||||
{
|
||||
m_buf = buf;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_stride = stride;
|
||||
if(height > m_max_height)
|
||||
{
|
||||
delete [] m_rows;
|
||||
m_rows = new T* [m_max_height = height];
|
||||
}
|
||||
|
||||
T* row_ptr = m_buf;
|
||||
|
||||
if(stride < 0)
|
||||
{
|
||||
row_ptr = m_buf - int(height - 1) * stride;
|
||||
}
|
||||
|
||||
T** rows = m_rows;
|
||||
|
||||
assert(height == 0 || m_rows);
|
||||
while(height--)
|
||||
{
|
||||
*rows++ = row_ptr;
|
||||
row_ptr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const T* buf() const { return m_buf; }
|
||||
unsigned width() const { return m_width; }
|
||||
unsigned height() const { return m_height; }
|
||||
int stride() const { return m_stride; }
|
||||
unsigned stride_abs() const
|
||||
{
|
||||
return (m_stride < 0) ?
|
||||
unsigned(-m_stride) :
|
||||
unsigned(m_stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
T* row(unsigned y) { return m_rows[y]; }
|
||||
const T* row(unsigned y) const { return m_rows[y]; }
|
||||
|
||||
T* next_row(void* p) { return (T*)p + m_stride; }
|
||||
const T* next_row(const void* p) const { return (T*)p + m_stride; }
|
||||
|
||||
T const* const* rows() const { return m_rows; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_from(const row_ptr_cache<T>& mtx)
|
||||
{
|
||||
unsigned h = height();
|
||||
if(mtx.height() < h) h = mtx.height();
|
||||
|
||||
unsigned l = stride_abs();
|
||||
if(mtx.stride_abs() < l) l = mtx.stride_abs();
|
||||
|
||||
l *= sizeof(T);
|
||||
|
||||
unsigned y;
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(row(y), mtx.row(y), l);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(T value)
|
||||
{
|
||||
unsigned y;
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
T* p = row(y);
|
||||
unsigned x;
|
||||
for(x = 0; x < stride_abs(); x++)
|
||||
{
|
||||
*p++ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
// Prohibit copying
|
||||
row_ptr_cache(const row_ptr_cache<T>&);
|
||||
const row_ptr_cache<T>& operator = (const row_ptr_cache<T>&);
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
T* m_buf; // Pointer to renrdering buffer
|
||||
T** m_rows; // Pointers to each row of the buffer
|
||||
unsigned m_width; // Width in pixels
|
||||
unsigned m_height; // Height in pixels
|
||||
int m_stride; // Number of bytes per row. Can be < 0
|
||||
unsigned m_max_height; // The maximal height (currently allocated)
|
||||
};
|
||||
|
||||
|
||||
|
||||
//========================================================rendering_buffer
|
||||
typedef row_ptr_cache<int8u> rendering_buffer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,323 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_SCANLINE_U_INCLUDED
|
||||
#define AGG_SCANLINE_U_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//==============================================================scanline_u
|
||||
//
|
||||
// Unpacked scanline container class
|
||||
//
|
||||
// This class is used to transfer data from a scanline rastyerizer
|
||||
// to the rendering buffer. It's organized very simple. The class stores
|
||||
// information of horizontal spans to render it into a pixel-map buffer.
|
||||
// Each span has staring X, length, and an array of bytes that determine the
|
||||
// cover-values for each pixel.
|
||||
// Before using this class you should know the minimal and maximal pixel
|
||||
// coordinates of your scanline. The protocol of using is:
|
||||
// 1. reset(min_x, max_x)
|
||||
// 2. add_cell() / add_span() - accumulate scanline.
|
||||
// When forming one scanline the next X coordinate must be always greater
|
||||
// than the last stored one, i.e. it works only with ordered coordinates.
|
||||
// 3. Call finalize(y) and render the scanline.
|
||||
// 3. Call reset_spans() to prepare for the new scanline.
|
||||
//
|
||||
// 4. Rendering:
|
||||
//
|
||||
// Scanline provides an iterator class that allows you to extract
|
||||
// the spans and the cover values for each pixel. Be aware that clipping
|
||||
// has not been done yet, so you should perform it yourself.
|
||||
// Use scanline_u8::iterator to render spans:
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// int y = sl.y(); // Y-coordinate of the scanline
|
||||
//
|
||||
// ************************************
|
||||
// ...Perform vertical clipping here...
|
||||
// ************************************
|
||||
//
|
||||
// scanline_u8::const_iterator span = sl.begin();
|
||||
//
|
||||
// unsigned char* row = m_rbuf->row(y); // The the address of the beginning
|
||||
// // of the current row
|
||||
//
|
||||
// unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that
|
||||
// // num_spans is always greater than 0.
|
||||
//
|
||||
// do
|
||||
// {
|
||||
// const scanline_u8::cover_type* covers =
|
||||
// span->covers; // The array of the cover values
|
||||
//
|
||||
// int num_pix = span->len; // Number of pixels of the span.
|
||||
// // Always greater than 0, still it's
|
||||
// // better to use "int" instead of
|
||||
// // "unsigned" because it's more
|
||||
// // convenient for clipping
|
||||
// int x = span->x;
|
||||
//
|
||||
// **************************************
|
||||
// ...Perform horizontal clipping here...
|
||||
// ...you have x, covers, and pix_count..
|
||||
// **************************************
|
||||
//
|
||||
// unsigned char* dst = row + x; // Calculate the start address of the row.
|
||||
// // In this case we assume a simple
|
||||
// // grayscale image 1-byte per pixel.
|
||||
// do
|
||||
// {
|
||||
// *dst++ = *covers++; // Hypotetical rendering.
|
||||
// }
|
||||
// while(--num_pix);
|
||||
//
|
||||
// ++span;
|
||||
// }
|
||||
// while(--num_spans); // num_spans cannot be 0, so this loop is quite safe
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// The question is: why should we accumulate the whole scanline when we
|
||||
// could render just separate spans when they're ready?
|
||||
// That's because using the scaline is generally faster. When is consists
|
||||
// of more than one span the conditions for the processor cash system
|
||||
// are better, because switching between two different areas of memory
|
||||
// (that can be very large) occures less frequently.
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> class scanline_u
|
||||
{
|
||||
public:
|
||||
typedef T cover_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
struct span
|
||||
{
|
||||
int16 x;
|
||||
int16 len;
|
||||
cover_type* covers;
|
||||
};
|
||||
|
||||
typedef span* iterator;
|
||||
typedef const span* const_iterator;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
~scanline_u();
|
||||
scanline_u();
|
||||
|
||||
void reset(int min_x, int max_x);
|
||||
void add_cell(int x, unsigned cover);
|
||||
void add_cells(int x, unsigned len, const T* covers);
|
||||
void add_span(int x, unsigned len, unsigned cover);
|
||||
void finalize(int y) { m_y = y; }
|
||||
void reset_spans();
|
||||
|
||||
int y() const { return m_y; }
|
||||
unsigned num_spans() const { return unsigned(m_cur_span - m_spans); }
|
||||
const_iterator begin() const { return m_spans + 1; }
|
||||
iterator begin() { return m_spans + 1; }
|
||||
|
||||
private:
|
||||
scanline_u<T>(const scanline_u<T>&);
|
||||
const scanline_u<T>& operator = (const scanline_u<T>&);
|
||||
|
||||
private:
|
||||
int m_min_x;
|
||||
unsigned m_max_len;
|
||||
int m_last_x;
|
||||
int m_y;
|
||||
cover_type* m_covers;
|
||||
span* m_spans;
|
||||
span* m_cur_span;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> scanline_u<T>::~scanline_u()
|
||||
{
|
||||
delete [] m_spans;
|
||||
delete [] m_covers;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> scanline_u<T>::scanline_u() :
|
||||
m_min_x(0),
|
||||
m_max_len(0),
|
||||
m_last_x(0x7FFFFFF0),
|
||||
m_covers(0),
|
||||
m_spans(0),
|
||||
m_cur_span(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> void scanline_u<T>::reset(int min_x, int max_x)
|
||||
{
|
||||
unsigned max_len = max_x - min_x + 2;
|
||||
if(max_len > m_max_len)
|
||||
{
|
||||
delete [] m_spans;
|
||||
delete [] m_covers;
|
||||
m_covers = new cover_type [max_len];
|
||||
m_spans = new span [max_len];
|
||||
m_max_len = max_len;
|
||||
}
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_min_x = min_x;
|
||||
m_cur_span = m_spans;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> inline void scanline_u<T>::reset_spans()
|
||||
{
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_cur_span = m_spans;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> inline void scanline_u<T>::add_cell(int x, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
m_covers[x] = (unsigned char)cover;
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (int16)(x + m_min_x);
|
||||
m_cur_span->len = 1;
|
||||
m_cur_span->covers = m_covers + x;
|
||||
}
|
||||
m_last_x = x;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> void scanline_u<T>::add_cells(int x, unsigned len, const T* covers)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memcpy(m_covers + x, covers, len * sizeof(T));
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len += (int16)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (int16)(x + m_min_x);
|
||||
m_cur_span->len = (int16)len;
|
||||
m_cur_span->covers = m_covers + x;
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T> void scanline_u<T>::add_span(int x, unsigned len, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memset(m_covers + x, cover, len);
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len += (int16)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (int16)(x + m_min_x);
|
||||
m_cur_span->len = (int16)len;
|
||||
m_cur_span->covers = m_covers + x;
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================scanline_u8
|
||||
typedef scanline_u<int8u> scanline_u8;
|
||||
|
||||
//============================================================scanline_u16
|
||||
typedef scanline_u<int16u> scanline_u16;
|
||||
|
||||
//============================================================scanline_u32
|
||||
typedef scanline_u<int32u> scanline_u32;
|
||||
|
||||
|
||||
//=============================================================scanline_am
|
||||
//
|
||||
// The scanline container with alpha-masking
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
template<class AlphaMask, class CoverT>
|
||||
class scanline_am : public scanline_u<CoverT>
|
||||
{
|
||||
public:
|
||||
typedef AlphaMask alpha_mask_type;
|
||||
typedef CoverT cover_type;
|
||||
typedef scanline_u<CoverT> scanline_type;
|
||||
|
||||
scanline_am() : scanline_type(), m_alpha_mask(0) {}
|
||||
scanline_am(const AlphaMask& am) : scanline_type(), m_alpha_mask(&am) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int span_y)
|
||||
{
|
||||
scanline_u<CoverT>::finalize(span_y);
|
||||
if(m_alpha_mask)
|
||||
{
|
||||
typename scanline_type::iterator span = scanline_type::begin();
|
||||
unsigned count = scanline_type::num_spans();
|
||||
do
|
||||
{
|
||||
m_alpha_mask->combine_hspan(span->x,
|
||||
scanline_type::y(),
|
||||
span->covers,
|
||||
span->len);
|
||||
++span;
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const AlphaMask* m_alpha_mask;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================scanline_u8_am
|
||||
template<class AlphaMask>
|
||||
class scanline_u8_am : public scanline_am<AlphaMask, int8u>
|
||||
{
|
||||
public:
|
||||
typedef AlphaMask alpha_mask_type;
|
||||
typedef int8u cover_type;
|
||||
typedef scanline_am<alpha_mask_type, cover_type> self_type;
|
||||
|
||||
scanline_u8_am() : self_type() {}
|
||||
scanline_u8_am(const AlphaMask& am) : self_type(am) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_SHORTEN_PATH_INCLUDED
|
||||
#define AGG_SHORTEN_PATH_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vertex_sequence.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===========================================================shorten_path
|
||||
template<class VertexSequence>
|
||||
void shorten_path(VertexSequence& vs, double s, unsigned closed = 0)
|
||||
{
|
||||
typedef typename VertexSequence::value_type vertex_type;
|
||||
|
||||
if(s > 0.0 && vs.size() > 1)
|
||||
{
|
||||
double d;
|
||||
int n = int(vs.size() - 2);
|
||||
while(n)
|
||||
{
|
||||
d = vs[n].dist;
|
||||
if(d > s) break;
|
||||
vs.remove_last();
|
||||
s -= d;
|
||||
--n;
|
||||
}
|
||||
if(vs.size() < 2)
|
||||
{
|
||||
vs.remove_all();
|
||||
}
|
||||
else
|
||||
{
|
||||
n = vs.size() - 1;
|
||||
vertex_type& prev = vs[n-1];
|
||||
vertex_type& last = vs[n];
|
||||
d = (prev.dist - s) / prev.dist;
|
||||
double x = prev.x + (last.x - prev.x) * d;
|
||||
double y = prev.y + (last.y - prev.y) * d;
|
||||
last.x = x;
|
||||
last.y = y;
|
||||
if(!prev(last)) vs.remove_last();
|
||||
vs.close(closed != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,195 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Affine transformations
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::parl_to_parl(const double* src,
|
||||
const double* dst)
|
||||
{
|
||||
m0 = src[2] - src[0];
|
||||
m1 = src[3] - src[1];
|
||||
m2 = src[4] - src[0];
|
||||
m3 = src[5] - src[1];
|
||||
m4 = src[0];
|
||||
m5 = src[1];
|
||||
invert();
|
||||
multiply(trans_affine(dst[2] - dst[0], dst[3] - dst[1],
|
||||
dst[4] - dst[0], dst[5] - dst[1],
|
||||
dst[0], dst[1]));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const double* parl)
|
||||
{
|
||||
double src[6];
|
||||
src[0] = x1; src[1] = y1;
|
||||
src[2] = x2; src[3] = y1;
|
||||
src[4] = x2; src[5] = y2;
|
||||
parl_to_parl(src, parl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
double dst[6];
|
||||
dst[0] = x1; dst[1] = y1;
|
||||
dst[2] = x2; dst[3] = y1;
|
||||
dst[4] = x2; dst[5] = y2;
|
||||
parl_to_parl(parl, dst);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::multiply(const trans_affine& m)
|
||||
{
|
||||
double t0 = m0 * m.m0 + m1 * m.m2;
|
||||
double t2 = m2 * m.m0 + m3 * m.m2;
|
||||
double t4 = m4 * m.m0 + m5 * m.m2 + m.m4;
|
||||
m1 = m0 * m.m1 + m1 * m.m3;
|
||||
m3 = m2 * m.m1 + m3 * m.m3;
|
||||
m5 = m4 * m.m1 + m5 * m.m3 + m.m5;
|
||||
m0 = t0;
|
||||
m2 = t2;
|
||||
m4 = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::invert()
|
||||
{
|
||||
double d = determinant();
|
||||
|
||||
double t0 = m3 * d;
|
||||
m3 = m0 * d;
|
||||
m1 = -m1 * d;
|
||||
m2 = -m2 * d;
|
||||
|
||||
double t4 = -m4 * t0 - m5 * m2;
|
||||
m5 = -m4 * m1 - m5 * m3;
|
||||
|
||||
m0 = t0;
|
||||
m4 = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::flip_x()
|
||||
{
|
||||
m0 = -m0;
|
||||
m1 = -m1;
|
||||
m4 = -m4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::flip_y()
|
||||
{
|
||||
m2 = -m2;
|
||||
m3 = -m3;
|
||||
m5 = -m5;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::reset()
|
||||
{
|
||||
m0 = m3 = 1.0;
|
||||
m1 = m2 = m4 = m5 = 0.0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline bool is_equal_eps(double v1, double v2, double epsilon)
|
||||
{
|
||||
return fabs(v1 - v2) < epsilon;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_identity(double epsilon) const
|
||||
{
|
||||
return is_equal_eps(m0, 1.0, epsilon) &&
|
||||
is_equal_eps(m1, 0.0, epsilon) &&
|
||||
is_equal_eps(m2, 0.0, epsilon) &&
|
||||
is_equal_eps(m3, 1.0, epsilon) &&
|
||||
is_equal_eps(m4, 0.0, epsilon) &&
|
||||
is_equal_eps(m5, 0.0, epsilon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_equal(const trans_affine& m, double epsilon) const
|
||||
{
|
||||
return is_equal_eps(m0, m.m0, epsilon) &&
|
||||
is_equal_eps(m1, m.m1, epsilon) &&
|
||||
is_equal_eps(m2, m.m2, epsilon) &&
|
||||
is_equal_eps(m3, m.m3, epsilon) &&
|
||||
is_equal_eps(m4, m.m4, epsilon) &&
|
||||
is_equal_eps(m5, m.m5, epsilon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double trans_affine::rotation() const
|
||||
{
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double x2 = 1.0;
|
||||
double y2 = 0.0;
|
||||
transform(&x1, &y1);
|
||||
transform(&x2, &y2);
|
||||
return atan2(y2-y1, x2-x1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void trans_affine::translation(double* dx, double* dy) const
|
||||
{
|
||||
trans_affine t(*this);
|
||||
t *= trans_affine_rotation(-rotation());
|
||||
t.transform(dx, dy);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void trans_affine::scaling(double* sx, double* sy) const
|
||||
{
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double x2 = 1.0;
|
||||
double y2 = 1.0;
|
||||
trans_affine t(*this);
|
||||
t *= trans_affine_rotation(-rotation());
|
||||
t.transform(&x1, &y1);
|
||||
t.transform(&x2, &y2);
|
||||
*sx = x2 - x1;
|
||||
*sy = y2 - y1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,344 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Affine transformation classes.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_TRANS_AFFINE_INCLUDED
|
||||
#define AGG_TRANS_AFFINE_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
const double affine_epsilon = 1e-14; // About of precision of doubles
|
||||
|
||||
//============================================================trans_affine
|
||||
//
|
||||
// See Implementation agg_trans_affine.cpp
|
||||
//
|
||||
// Affine transformation are linear transformations in Cartesian coordinates
|
||||
// (strictly speaking not only in Cartesian, but for the beginning we will
|
||||
// think so). They are rotation, scaling, translation and skewing.
|
||||
// After any affine transformation a line segment remains a line segment
|
||||
// and it will never become a curve.
|
||||
//
|
||||
// There will be no math about matrix calculations, since it has been
|
||||
// described many times. Ask yourself a very simple question:
|
||||
// "why do we need to understand and use some matrix stuff instead of just
|
||||
// rotating, scaling and so on". The answers are:
|
||||
//
|
||||
// 1. Any combination of transformations can be done by only 4 multiplications
|
||||
// and 4 additions in floating point.
|
||||
// 2. One matrix transformation is equivalent to the number of consecutive
|
||||
// discrete transformations, i.e. the matrix "accumulates" all transformations
|
||||
// in the order of their settings. Suppose we have 4 transformations:
|
||||
// * rotate by 30 degrees,
|
||||
// * scale X to 2.0,
|
||||
// * scale Y to 1.5,
|
||||
// * move to (100, 100).
|
||||
// The result will depend on the order of these transformations,
|
||||
// and the advantage of matrix is that the sequence of discret calls:
|
||||
// rotate(30), scaleX(2.0), scaleY(1.5), move(100,100)
|
||||
// will have exactly the same result as the following matrix transformations:
|
||||
//
|
||||
// affine_matrix m;
|
||||
// m *= rotate_matrix(30);
|
||||
// m *= scaleX_matrix(2.0);
|
||||
// m *= scaleY_matrix(1.5);
|
||||
// m *= move_matrix(100,100);
|
||||
//
|
||||
// m.transform_my_point_at_last(x, y);
|
||||
//
|
||||
// What is the good of it? In real life we will set-up the matrix only once
|
||||
// and then transform many points, let alone the convenience to set any
|
||||
// combination of transformations.
|
||||
//
|
||||
// So, how to use it? Very easy - literally as it's shown above. Not quite,
|
||||
// let us write a correct example:
|
||||
//
|
||||
// agg::trans_affine m;
|
||||
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0);
|
||||
// m *= agg::trans_affine_scaling(2.0, 1.5);
|
||||
// m *= agg::trans_affine_translation(100.0, 100.0);
|
||||
// m.transform(&x, &y);
|
||||
//
|
||||
// The affine matrix is all you need to perform any linear transformation,
|
||||
// but all transformations have origin point (0,0). It means that we need to
|
||||
// use 2 translations if we want to rotate someting around (100,100):
|
||||
//
|
||||
// m *= agg::trans_affine_translation(-100.0, -100.0); // move to (0,0)
|
||||
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate
|
||||
// m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100)
|
||||
//----------------------------------------------------------------------
|
||||
class trans_affine
|
||||
{
|
||||
public:
|
||||
//------------------------------------------ Construction
|
||||
// Construct an identity matrix - it does not transform anything
|
||||
trans_affine() :
|
||||
m0(1.0), m1(0.0), m2(0.0), m3(1.0), m4(0.0), m5(0.0)
|
||||
{}
|
||||
|
||||
// Construct a custom matrix. Usually used in derived classes
|
||||
trans_affine(double v0, double v1, double v2, double v3, double v4, double v5) :
|
||||
m0(v0), m1(v1), m2(v2), m3(v3), m4(v4), m5(v5)
|
||||
{}
|
||||
|
||||
// Construct a matrix to transform a parallelogram to another one.
|
||||
trans_affine(const double* rect, const double* parl)
|
||||
{
|
||||
parl_to_parl(rect, parl);
|
||||
}
|
||||
|
||||
// Construct a matrix to transform a rectangle to a parallelogram.
|
||||
trans_affine(double x1, double y1, double x2, double y2,
|
||||
const double* parl)
|
||||
{
|
||||
rect_to_parl(x1, y1, x2, y2, parl);
|
||||
}
|
||||
|
||||
// Construct a matrix to transform a parallelogram to a rectangle.
|
||||
trans_affine(const double* parl,
|
||||
double x1, double y1, double x2, double y2)
|
||||
{
|
||||
parl_to_rect(parl, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------- Parellelogram transformations
|
||||
// Calculate a matrix to transform a parallelogram to another one.
|
||||
// src and dst are pointers to arrays of three points
|
||||
// (double[6], x,y,...) that identify three corners of the
|
||||
// parallelograms assuming implicit fourth points.
|
||||
// There are also transformations rectangtle to parallelogram and
|
||||
// parellelogram to rectangle
|
||||
const trans_affine& parl_to_parl(const double* src,
|
||||
const double* dst);
|
||||
|
||||
const trans_affine& rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const double* parl);
|
||||
|
||||
const trans_affine& parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
double x2, double y2);
|
||||
|
||||
|
||||
//------------------------------------------ Operations
|
||||
// Reset - actually load an identity matrix
|
||||
const trans_affine& reset();
|
||||
|
||||
// Multiply matrix to another one
|
||||
const trans_affine& multiply(const trans_affine& m);
|
||||
|
||||
// Multiply "m" to "this" and assign the result to "this"
|
||||
const trans_affine& premultiply(const trans_affine& m);
|
||||
|
||||
// Invert matrix. Do not try to invert degenerate matrices,
|
||||
// there's no check for validity. If you set scale to 0 and
|
||||
// then try to invert matrix, expect unpredictable result.
|
||||
const trans_affine& invert();
|
||||
|
||||
// Mirroring around X
|
||||
const trans_affine& flip_x();
|
||||
|
||||
// Mirroring around Y
|
||||
const trans_affine& flip_y();
|
||||
|
||||
//------------------------------------------- Load/Store
|
||||
// Store matrix to an array [6] of double
|
||||
void store_to(double* m) const
|
||||
{
|
||||
*m++ = m0; *m++ = m1; *m++ = m2; *m++ = m3; *m++ = m4; *m++ = m5;
|
||||
}
|
||||
|
||||
// Load matrix from an array [6] of double
|
||||
const trans_affine& load_from(const double* m)
|
||||
{
|
||||
m0 = *m++; m1 = *m++; m2 = *m++; m3 = *m++; m4 = *m++; m5 = *m++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------- Operators
|
||||
|
||||
// Multiply current matrix to another one
|
||||
const trans_affine& operator *= (const trans_affine& m)
|
||||
{
|
||||
return multiply(m);
|
||||
}
|
||||
|
||||
// Multiply current matrix to another one and return
|
||||
// the result in a separete matrix.
|
||||
trans_affine operator * (const trans_affine& m)
|
||||
{
|
||||
return trans_affine(*this).multiply(m);
|
||||
}
|
||||
|
||||
// Calculate and return the inverse matrix
|
||||
trans_affine operator ~ () const
|
||||
{
|
||||
trans_affine ret = *this;
|
||||
return ret.invert();
|
||||
}
|
||||
|
||||
// Equal operator with default epsilon
|
||||
bool operator == (const trans_affine& m) const
|
||||
{
|
||||
return is_equal(m, affine_epsilon);
|
||||
}
|
||||
|
||||
// Not Equal operator with default epsilon
|
||||
bool operator != (const trans_affine& m) const
|
||||
{
|
||||
return !is_equal(m, affine_epsilon);
|
||||
}
|
||||
|
||||
//-------------------------------------------- Transformations
|
||||
// Direct transformation x and y
|
||||
void transform(double* x, double* y) const;
|
||||
|
||||
// Inverse transformation x and y. It works slower than the
|
||||
// direct transformation, so if the performance is critical
|
||||
// it's better to invert() the matrix and then use transform()
|
||||
void inverse_transform(double* x, double* y) const;
|
||||
|
||||
//-------------------------------------------- Auxiliary
|
||||
// Calculate the determinant of matrix
|
||||
double determinant() const
|
||||
{
|
||||
return 1.0 / (m0 * m3 - m1 * m2);
|
||||
}
|
||||
|
||||
// Get the average scale (by X and Y).
|
||||
// Basically used to calculate the approximation_scale when
|
||||
// decomposinting curves into line segments.
|
||||
double scale() const;
|
||||
|
||||
// Check to see if it's an identity matrix
|
||||
bool is_identity(double epsilon = affine_epsilon) const;
|
||||
|
||||
// Check to see if two matrices are equal
|
||||
bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const;
|
||||
|
||||
// Determine the major parameters. Use carefully considering degenerate matrices
|
||||
double rotation() const;
|
||||
void translation(double* dx, double* dy) const;
|
||||
void scaling(double* sx, double* sy) const;
|
||||
void scaling_abs(double* sx, double* sy) const
|
||||
{
|
||||
*sx = sqrt(m0*m0 + m2*m2);
|
||||
*sy = sqrt(m1*m1 + m3*m3);
|
||||
}
|
||||
|
||||
private:
|
||||
double m0;
|
||||
double m1;
|
||||
double m2;
|
||||
double m3;
|
||||
double m4;
|
||||
double m5;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::transform(double* x, double* y) const
|
||||
{
|
||||
register double tx = *x;
|
||||
*x = tx * m0 + *y * m2 + m4;
|
||||
*y = tx * m1 + *y * m3 + m5;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::inverse_transform(double* x, double* y) const
|
||||
{
|
||||
register double d = determinant();
|
||||
register double a = (*x - m4) * d;
|
||||
register double b = (*y - m5) * d;
|
||||
*x = a * m3 - b * m2;
|
||||
*y = b * m0 - a * m1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline double trans_affine::scale() const
|
||||
{
|
||||
double x = 0.707106781 * m0 + 0.707106781 * m2;
|
||||
double y = 0.707106781 * m1 + 0.707106781 * m3;
|
||||
return sqrt(x*x + y*y);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::premultiply(const trans_affine& m)
|
||||
{
|
||||
trans_affine t = m;
|
||||
return *this = t.multiply(*this);
|
||||
}
|
||||
|
||||
|
||||
//====================================================trans_affine_rotation
|
||||
// Rotation matrix. sin() and cos() are calculated twice for the same angle.
|
||||
// There's no harm because the performance of sin()/cos() is very good on all
|
||||
// modern processors. Besides, this operation is not going to be invoked too
|
||||
// often.
|
||||
class trans_affine_rotation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_rotation(double a) :
|
||||
trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
//====================================================trans_affine_scaling
|
||||
// Scaling matrix. sx, sy - scale coefficients by X and Y respectively
|
||||
class trans_affine_scaling : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_scaling(double sx, double sy) :
|
||||
trans_affine(sx, 0.0, 0.0, sy, 0.0, 0.0)
|
||||
{}
|
||||
|
||||
trans_affine_scaling(double s) :
|
||||
trans_affine(s, 0.0, 0.0, s, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
//================================================trans_affine_translation
|
||||
// Translation matrix
|
||||
class trans_affine_translation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_translation(double tx, double ty) :
|
||||
trans_affine(1.0, 0.0, 0.0, 1.0, tx, ty)
|
||||
{}
|
||||
};
|
||||
|
||||
//====================================================trans_affine_skewing
|
||||
// Sckewing (shear) matrix
|
||||
class trans_affine_skewing : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_skewing(double sx, double sy) :
|
||||
trans_affine(1.0, tan(sy), tan(sx), 1.0, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Stroke generator
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#include <math.h>
|
||||
#include "agg_vcgen_stroke.h"
|
||||
#include "agg_shorten_path.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
vcgen_stroke::vcgen_stroke() :
|
||||
m_src_vertices(),
|
||||
m_out_vertices(),
|
||||
m_width(0.5),
|
||||
m_miter_limit(4.0),
|
||||
m_inner_miter_limit(1.0 + 1.0/64.0),
|
||||
m_approx_scale(1.0),
|
||||
m_shorten(0.0),
|
||||
m_line_cap(butt_cap),
|
||||
m_line_join(miter_join),
|
||||
m_inner_line_join(miter_join_revert),
|
||||
m_closed(0),
|
||||
m_status(initial),
|
||||
m_src_vertex(0),
|
||||
m_out_vertex(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::miter_limit_theta(double t)
|
||||
{
|
||||
m_miter_limit = 1.0 / sin(t * 0.5) ;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::remove_all()
|
||||
{
|
||||
m_src_vertices.remove_all();
|
||||
m_closed = 0;
|
||||
m_status = initial;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
m_status = initial;
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
m_src_vertices.modify_last(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_src_vertices.add(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_closed = get_close_flag(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::rewind(unsigned)
|
||||
{
|
||||
if(m_status == initial)
|
||||
{
|
||||
m_src_vertices.close(m_closed != 0);
|
||||
shorten_path(m_src_vertices, m_shorten, m_closed);
|
||||
if(m_src_vertices.size() < 3) m_closed = 0;
|
||||
}
|
||||
m_status = ready;
|
||||
m_src_vertex = 0;
|
||||
m_out_vertex = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned vcgen_stroke::vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_line_to;
|
||||
while(!is_stop(cmd))
|
||||
{
|
||||
switch(m_status)
|
||||
{
|
||||
case initial:
|
||||
rewind(0);
|
||||
|
||||
case ready:
|
||||
if(m_src_vertices.size() < 2 + unsigned(m_closed != 0))
|
||||
{
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
m_status = m_closed ? outline1 : cap1;
|
||||
cmd = path_cmd_move_to;
|
||||
m_src_vertex = 0;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case cap1:
|
||||
stroke_calc_cap(m_out_vertices,
|
||||
m_src_vertices[0],
|
||||
m_src_vertices[1],
|
||||
m_src_vertices[0].dist,
|
||||
m_line_cap,
|
||||
m_width,
|
||||
m_approx_scale);
|
||||
m_src_vertex = 1;
|
||||
m_prev_status = outline1;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case cap2:
|
||||
stroke_calc_cap(m_out_vertices,
|
||||
m_src_vertices[m_src_vertices.size() - 1],
|
||||
m_src_vertices[m_src_vertices.size() - 2],
|
||||
m_src_vertices[m_src_vertices.size() - 2].dist,
|
||||
m_line_cap,
|
||||
m_width,
|
||||
m_approx_scale);
|
||||
m_prev_status = outline2;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case outline1:
|
||||
if(m_closed)
|
||||
{
|
||||
if(m_src_vertex >= m_src_vertices.size())
|
||||
{
|
||||
m_prev_status = close_first;
|
||||
m_status = end_poly1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_src_vertex >= m_src_vertices.size() - 1)
|
||||
{
|
||||
m_status = cap2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
stroke_calc_join(m_out_vertices,
|
||||
m_src_vertices.prev(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex),
|
||||
m_src_vertices.next(m_src_vertex),
|
||||
m_src_vertices.prev(m_src_vertex).dist,
|
||||
m_src_vertices.curr(m_src_vertex).dist,
|
||||
m_width,
|
||||
m_line_join,
|
||||
m_inner_line_join,
|
||||
m_miter_limit,
|
||||
m_inner_miter_limit,
|
||||
m_approx_scale);
|
||||
++m_src_vertex;
|
||||
m_prev_status = m_status;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case close_first:
|
||||
m_status = outline2;
|
||||
cmd = path_cmd_move_to;
|
||||
|
||||
case outline2:
|
||||
if(m_src_vertex <= unsigned(m_closed == 0))
|
||||
{
|
||||
m_status = end_poly2;
|
||||
m_prev_status = stop;
|
||||
break;
|
||||
}
|
||||
|
||||
--m_src_vertex;
|
||||
stroke_calc_join(m_out_vertices,
|
||||
m_src_vertices.next(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex),
|
||||
m_src_vertices.prev(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex).dist,
|
||||
m_src_vertices.prev(m_src_vertex).dist,
|
||||
m_width,
|
||||
m_line_join,
|
||||
m_inner_line_join,
|
||||
m_miter_limit,
|
||||
m_inner_miter_limit,
|
||||
m_approx_scale);
|
||||
|
||||
m_prev_status = m_status;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case out_vertices:
|
||||
if(m_out_vertex >= m_out_vertices.size())
|
||||
{
|
||||
m_status = m_prev_status;
|
||||
}
|
||||
else
|
||||
{
|
||||
const point_type& c = m_out_vertices[m_out_vertex++];
|
||||
*x = c.x;
|
||||
*y = c.y;
|
||||
return cmd;
|
||||
}
|
||||
break;
|
||||
|
||||
case end_poly1:
|
||||
m_status = m_prev_status;
|
||||
return path_cmd_end_poly | path_flags_close | path_flags_ccw;
|
||||
|
||||
case end_poly2:
|
||||
m_status = m_prev_status;
|
||||
return path_cmd_end_poly | path_flags_close | path_flags_cw;
|
||||
|
||||
case stop:
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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_VCGEN_STROKE_INCLUDED
|
||||
#define AGG_VCGEN_STROKE_INCLUDED
|
||||
|
||||
#include "agg_math_stroke.h"
|
||||
#include "agg_vertex_iterator.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//============================================================vcgen_stroke
|
||||
//
|
||||
// See Implementation agg_vcgen_stroke.cpp
|
||||
// Stroke generator
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
class vcgen_stroke
|
||||
{
|
||||
enum status_e
|
||||
{
|
||||
initial,
|
||||
ready,
|
||||
cap1,
|
||||
cap2,
|
||||
outline1,
|
||||
close_first,
|
||||
outline2,
|
||||
out_vertices,
|
||||
end_poly1,
|
||||
end_poly2,
|
||||
stop
|
||||
};
|
||||
|
||||
public:
|
||||
typedef vertex_sequence<vertex_dist, 6> vertex_storage;
|
||||
typedef pod_deque<point_type, 6> coord_storage;
|
||||
|
||||
vcgen_stroke();
|
||||
|
||||
void line_cap(line_cap_e lc) { m_line_cap = lc; }
|
||||
void line_join(line_join_e lj) { m_line_join = lj; }
|
||||
void inner_line_join(line_join_e lj) { m_inner_line_join = lj; }
|
||||
|
||||
line_cap_e line_cap() const { return m_line_cap; }
|
||||
line_join_e line_join() const { return m_line_join; }
|
||||
line_join_e inner_line_join() const { return m_inner_line_join; }
|
||||
|
||||
void width(double w) { m_width = w * 0.5; }
|
||||
void miter_limit(double ml) { m_miter_limit = ml; }
|
||||
void miter_limit_theta(double t);
|
||||
void inner_miter_limit(double ml) { m_inner_miter_limit = ml; }
|
||||
void approximation_scale(double as) { m_approx_scale = as; }
|
||||
|
||||
double width() const { return m_width * 2.0; }
|
||||
double miter_limit() const { return m_miter_limit; }
|
||||
double inner_miter_limit() const { return m_inner_miter_limit; }
|
||||
double approximation_scale() const { return m_approx_scale; }
|
||||
|
||||
void shorten(double s) { m_shorten = s; }
|
||||
double shorten() const { return m_shorten; }
|
||||
|
||||
// Vertex Generator Interface
|
||||
void remove_all();
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
|
||||
// Vertex Source Interface
|
||||
void rewind(unsigned id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
typedef vcgen_stroke source_type;
|
||||
typedef vertex_iterator<source_type> iterator;
|
||||
iterator begin(unsigned id) { return iterator(*this, id); }
|
||||
iterator end() { return iterator(path_cmd_stop); }
|
||||
|
||||
private:
|
||||
vcgen_stroke(const vcgen_stroke&);
|
||||
const vcgen_stroke& operator = (const vcgen_stroke&);
|
||||
|
||||
vertex_storage m_src_vertices;
|
||||
coord_storage m_out_vertices;
|
||||
double m_width;
|
||||
double m_miter_limit;
|
||||
double m_inner_miter_limit;
|
||||
double m_approx_scale;
|
||||
double m_shorten;
|
||||
line_cap_e m_line_cap;
|
||||
line_join_e m_line_join;
|
||||
line_join_e m_inner_line_join;
|
||||
unsigned m_closed;
|
||||
status_e m_status;
|
||||
status_e m_prev_status;
|
||||
unsigned m_src_vertex;
|
||||
unsigned m_out_vertex;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,133 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// classes: vertex_iterator
|
||||
// vertex_source_adaptor
|
||||
// vertex_source_adaptor_with_id
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_VERTEX_ITERATOR_INCLUDED
|
||||
#define AGG_VERTEX_ITERATOR_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//---------------------------------------------------------vertex_iterator
|
||||
template<class VertexSource> class vertex_iterator
|
||||
{
|
||||
public:
|
||||
vertex_iterator() {}
|
||||
vertex_iterator(unsigned cmd) { m_vertex.cmd = cmd; }
|
||||
vertex_iterator(const vertex_iterator& i) : m_vs(i.m_vs), m_vertex(i.m_vertex) {}
|
||||
vertex_iterator(VertexSource& vs, unsigned id) : m_vs(&vs)
|
||||
{
|
||||
m_vs->rewind(id);
|
||||
m_vertex.cmd = m_vs->vertex(&m_vertex.x, &m_vertex.y);
|
||||
}
|
||||
vertex_iterator& operator++()
|
||||
{
|
||||
m_vertex.cmd = m_vs->vertex(&m_vertex.x, &m_vertex.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const vertex_type& operator*() const { return m_vertex; }
|
||||
const vertex_type* operator->() const { return &m_vertex; }
|
||||
|
||||
bool operator != (const vertex_iterator& i)
|
||||
{
|
||||
return m_vertex.cmd != i.m_vertex.cmd;
|
||||
}
|
||||
|
||||
private:
|
||||
VertexSource* m_vs;
|
||||
vertex_type m_vertex;
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------vertex_source_adaptor
|
||||
template<class VertexContainer> class vertex_source_adaptor
|
||||
{
|
||||
public:
|
||||
vertex_source_adaptor(const VertexContainer& container) :
|
||||
m_container(&container) {}
|
||||
|
||||
void rewind(unsigned)
|
||||
{
|
||||
m_iterator = m_container->begin();
|
||||
m_end = m_container->end();
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_stop;
|
||||
if(m_iterator != m_end)
|
||||
{
|
||||
*x = m_iterator->x;
|
||||
*y = m_iterator->y;
|
||||
cmd = m_iterator->cmd;
|
||||
++m_iterator;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private:
|
||||
const VertexContainer* m_container;
|
||||
typename VertexContainer::const_iterator m_iterator;
|
||||
typename VertexContainer::const_iterator m_end;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------vertex_source_adaptor_with_id
|
||||
template<class VertexContainer> class vertex_source_adaptor_with_id
|
||||
{
|
||||
public:
|
||||
vertex_source_adaptor_with_id(const VertexContainer& container) :
|
||||
m_container(&container) {}
|
||||
|
||||
void rewind(unsigned id)
|
||||
{
|
||||
m_iterator = m_container->begin(id);
|
||||
m_end = m_container->end();
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_stop;
|
||||
if(m_iterator != m_end)
|
||||
{
|
||||
*x = m_iterator->x;
|
||||
*y = m_iterator->y;
|
||||
cmd = m_iterator->cmd;
|
||||
++m_iterator;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
private:
|
||||
const VertexContainer* m_container;
|
||||
typename VertexContainer::const_iterator m_iterator;
|
||||
typename VertexContainer::const_iterator m_end;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,176 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// vertex_sequence container and vertex_dist struct
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_VERTEX_SEQUENCE_INCLUDED
|
||||
#define AGG_VERTEX_SEQUENCE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_array.h"
|
||||
#include "agg_math.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//----------------------------------------------------------vertex_sequence
|
||||
// Modified agg::pod_deque. The data is interpreted as a sequence of vertices.
|
||||
// It means that the type T must expose:
|
||||
//
|
||||
// bool operator() (const T& val)
|
||||
//
|
||||
// that is called every time new vertex is being added. The main purpose
|
||||
// of this operator is the possibility to calculate some values during
|
||||
// adding and to return true if the vertex fits some criteria or false if
|
||||
// it doesn't. In the last case the new vertex is not added.
|
||||
//
|
||||
// The simple example is filtering coinciding vertices with calculation
|
||||
// of the distance between the current and previous ones:
|
||||
//
|
||||
// struct vertex_dist
|
||||
// {
|
||||
// double x;
|
||||
// double y;
|
||||
// double dist;
|
||||
//
|
||||
// vertex_dist() {}
|
||||
// vertex_dist(double x_, double y_) :
|
||||
// x(x_),
|
||||
// y(y_),
|
||||
// dist(0.0)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// bool operator () (const vertex_dist& val)
|
||||
// {
|
||||
// return (dist = calc_distance(x, y, val.x, val.y)) > EPSILON;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// Function close() calls this operator and removes the last vertex if
|
||||
// necessary.
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S=6>
|
||||
class vertex_sequence : public pod_deque<T, S>
|
||||
{
|
||||
public:
|
||||
typedef pod_deque<T, S> base_type;
|
||||
|
||||
void add(const T& val);
|
||||
void modify_last(const T& val);
|
||||
void close(bool remove_flag);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::add(const T& val)
|
||||
{
|
||||
if(base_type::size() > 1)
|
||||
{
|
||||
if(!(*this)[base_type::size() - 2]((*this)[base_type::size() - 1]))
|
||||
{
|
||||
base_type::remove_last();
|
||||
}
|
||||
}
|
||||
base_type::add(val);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::modify_last(const T& val)
|
||||
{
|
||||
base_type::remove_last();
|
||||
add(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::close(bool closed)
|
||||
{
|
||||
while(base_type::size() > 1)
|
||||
{
|
||||
if((*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) break;
|
||||
T t = (*this)[base_type::size() - 1];
|
||||
base_type::remove_last();
|
||||
modify_last(t);
|
||||
}
|
||||
|
||||
if(closed)
|
||||
{
|
||||
while(base_type::size() > 1)
|
||||
{
|
||||
if((*this)[base_type::size() - 1]((*this)[0])) break;
|
||||
base_type::remove_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Coinciding points maximal distance (Epsilon)
|
||||
const double vertex_dist_epsilon = 1e-14;
|
||||
|
||||
//-------------------------------------------------------------vertex_dist
|
||||
// Vertex (x, y) with the distance to the next one. The last vertex has
|
||||
// distance between the last and the first points if the polygon is closed
|
||||
// and 0.0 if it's a polyline.
|
||||
struct vertex_dist
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double dist;
|
||||
|
||||
vertex_dist() {}
|
||||
vertex_dist(double x_, double y_) :
|
||||
x(x_),
|
||||
y(y_),
|
||||
dist(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator () (const vertex_dist& val)
|
||||
{
|
||||
bool ret = (dist = calc_distance(x, y, val.x, val.y)) > vertex_dist_epsilon;
|
||||
if(!ret) dist = 1.0 / vertex_dist_epsilon;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------vertex_dist_cmd
|
||||
// Save as the above but with additional "command" value
|
||||
struct vertex_dist_cmd : public vertex_dist
|
||||
{
|
||||
unsigned cmd;
|
||||
|
||||
vertex_dist_cmd() {}
|
||||
vertex_dist_cmd(double x_, double y_, unsigned cmd_) :
|
||||
vertex_dist(x_, y_),
|
||||
cmd(cmd_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,267 +0,0 @@
|
|||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.3
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for high precision colors has been sponsored by
|
||||
// Liberty Technology Systems, Inc., visit http://lib-sys.com
|
||||
//
|
||||
// Liberty Technology Systems, Inc. is the provider of
|
||||
// PostScript and PDF technology for software developers.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @short Okular modified rgba pixel format provider for rastering operations
|
||||
* This is the agg_pixfmt_rgba.h file with some added code. When syncing to
|
||||
* the latest agg counterpart, diff the mods and apply them again after
|
||||
* copying the legacy file over this.
|
||||
* - Enrico Ros @ KDPF Team - 2005
|
||||
*
|
||||
* Thanks to Rob Buis <rwlbuis@xs4all.nl> for providing the raster algorithms
|
||||
* he used when modifying agg for usage with KCanvas/KSvg2.
|
||||
*/
|
||||
|
||||
#ifndef AGG_PIXFMT_RGBA_INCLUDED
|
||||
#define AGG_PIXFMT_RGBA_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include "agg_basics.h"
|
||||
#include "agg_color_rgba.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
// Nice trick from Qt4's Arthur
|
||||
inline int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; }
|
||||
|
||||
//=============================================================normal_blend_rgba
|
||||
/** The standard blending algo */
|
||||
template<class ColorT, class Order, class PixelT> struct normal_blend_rgba
|
||||
{
|
||||
typedef ColorT color_type;
|
||||
typedef PixelT pixel_type;
|
||||
typedef Order order_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
enum
|
||||
{
|
||||
base_shift = color_type::base_shift,
|
||||
base_mask = color_type::base_mask
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
unsigned cr, unsigned cg, unsigned cb,
|
||||
unsigned alpha,
|
||||
unsigned)
|
||||
{
|
||||
calc_type r = p[Order::R];
|
||||
calc_type g = p[Order::G];
|
||||
calc_type b = p[Order::B];
|
||||
calc_type a = p[Order::A];
|
||||
p[Order::R] = (value_type)(((cr - r) * alpha + (r << base_shift)) >> base_shift);
|
||||
p[Order::G] = (value_type)(((cg - g) * alpha + (g << base_shift)) >> base_shift);
|
||||
p[Order::B] = (value_type)(((cb - b) * alpha + (b << base_shift)) >> base_shift);
|
||||
p[Order::A] = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift));
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================multiply_blend_rgba
|
||||
/** The Multiplier blending algo (for Highlighting pigmentation) */
|
||||
template<class ColorT, class Order, class PixelT> struct multiply_blend_rgba
|
||||
{
|
||||
typedef ColorT color_type;
|
||||
typedef PixelT pixel_type;
|
||||
typedef Order order_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
enum
|
||||
{
|
||||
base_shift = color_type::base_shift,
|
||||
base_mask = color_type::base_mask
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
unsigned cr, unsigned cg, unsigned cb,
|
||||
unsigned alpha,
|
||||
unsigned)
|
||||
{
|
||||
calc_type r = p[Order::R];
|
||||
calc_type g = p[Order::G];
|
||||
calc_type b = p[Order::B];
|
||||
calc_type a = p[Order::A];
|
||||
p[Order::R] = (value_type)(((qt_div_255(cr*r) - r) * alpha + (r << base_shift)) >> base_shift);
|
||||
p[Order::G] = (value_type)(((qt_div_255(cg*g) - g) * alpha + (g << base_shift)) >> base_shift);
|
||||
p[Order::B] = (value_type)(((qt_div_255(cb*b) - b) * alpha + (b << base_shift)) >> base_shift);
|
||||
p[Order::A] = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift));
|
||||
}
|
||||
};
|
||||
|
||||
//=======================================================pixel_formats_rgba
|
||||
/** The following functions have been modified for using different blenders:
|
||||
* blend_pixel, blend_hline, blend_solid_hspan
|
||||
* (the others are not used by okular and have been removed)
|
||||
*/
|
||||
template<class ColorT, class Order, class PixelT> class pixel_formats_rgba
|
||||
{
|
||||
public:
|
||||
typedef rendering_buffer::row_data row_data;
|
||||
typedef ColorT color_type;
|
||||
typedef Order order_type;
|
||||
typedef PixelT pixel_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
enum
|
||||
{
|
||||
base_shift = color_type::base_shift,
|
||||
base_size = color_type::base_size,
|
||||
base_mask = color_type::base_mask
|
||||
};
|
||||
typedef normal_blend_rgba<ColorT, Order, PixelT> normal_blender;
|
||||
typedef multiply_blend_rgba<ColorT, Order, PixelT> multiply_blender;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
pixel_formats_rgba( rendering_buffer& rb, int rasterMode ) :
|
||||
m_rbuf(&rb), m_mode( rasterMode )
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE unsigned width() const { return m_rbuf->width(); }
|
||||
AGG_INLINE unsigned height() const { return m_rbuf->height(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
|
||||
{
|
||||
if ( !c.a )
|
||||
return;
|
||||
|
||||
value_type* p = (value_type*)m_rbuf->row(y) + (x << 2);
|
||||
|
||||
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
|
||||
if ( !m_mode )
|
||||
{
|
||||
if(alpha == base_mask)
|
||||
{
|
||||
p[order_type::R] = c.r;
|
||||
p[order_type::G] = c.g;
|
||||
p[order_type::B] = c.b;
|
||||
p[order_type::A] = c.a;
|
||||
}
|
||||
else
|
||||
normal_blender::blend_pix(p, c.r, c.g, c.b, alpha, cover);
|
||||
}
|
||||
else if ( m_mode == 1 )
|
||||
multiply_blender::blend_pix(p, c.r, c.g, c.b, alpha, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_hline(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c,
|
||||
int8u cover)
|
||||
{
|
||||
if ( !c.a )
|
||||
return;
|
||||
|
||||
value_type* p = (value_type*)m_rbuf->row(y) + (x << 2);
|
||||
calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8;
|
||||
switch ( m_mode )
|
||||
{
|
||||
case 0:
|
||||
if ( alpha == base_mask )
|
||||
{
|
||||
pixel_type v;
|
||||
((value_type*)&v)[order_type::R] = c.r;
|
||||
((value_type*)&v)[order_type::G] = c.g;
|
||||
((value_type*)&v)[order_type::B] = c.b;
|
||||
((value_type*)&v)[order_type::A] = c.a;
|
||||
while( len-- )
|
||||
{
|
||||
*(pixel_type*)p = v;
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( len-- )
|
||||
{
|
||||
normal_blender::blend_pix(p, c.r, c.g, c.b, alpha, cover);
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
while( len-- )
|
||||
{
|
||||
multiply_blender::blend_pix(p, c.r, c.g, c.b, alpha, cover);
|
||||
p += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_hspan(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c,
|
||||
const int8u* covers)
|
||||
{
|
||||
if ( !c.a )
|
||||
return;
|
||||
|
||||
value_type* p = (value_type*)m_rbuf->row(y) + (x << 2);
|
||||
switch ( m_mode )
|
||||
{
|
||||
case 0:
|
||||
while( len-- )
|
||||
{
|
||||
calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
|
||||
if ( alpha == base_mask )
|
||||
{
|
||||
p[order_type::R] = c.r;
|
||||
p[order_type::G] = c.g;
|
||||
p[order_type::B] = c.b;
|
||||
p[order_type::A] = base_mask;
|
||||
}
|
||||
else
|
||||
normal_blender::blend_pix(p, c.r, c.g, c.b, alpha, *covers);
|
||||
p += 4;
|
||||
++covers;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
while( len-- )
|
||||
{
|
||||
calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8;
|
||||
multiply_blender::blend_pix(p, c.r, c.g, c.b, alpha, *covers);
|
||||
p += 4;
|
||||
++covers;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
rendering_buffer* m_rbuf;
|
||||
int m_mode;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Order Types: order_rgba, order_argb, order_abgr, [order_bgra]
|
||||
// the RBGA32 is used by okular/qimage ( 0xAARRGGBB in memory )
|
||||
typedef pixel_formats_rgba<rgba8, order_bgra, int32u> pixfmt_bgra32;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue