133 lines
5.7 KiB
C++
133 lines
5.7 KiB
C++
/*******************************************************************************
|
|
* *
|
|
* Author : Angus Johnson *
|
|
* Version : 1.1 *
|
|
* Date : 4 April 2011 *
|
|
* Copyright : Angus Johnson 2010-2011 *
|
|
* *
|
|
* License: *
|
|
* Use, modification & distribution is subject to Boost Software License Ver 1. *
|
|
* http://www.boost.org/LICENSE_1_0.txt *
|
|
* *
|
|
* Modified by Mike Owens to support coordinate transformation *
|
|
*******************************************************************************/
|
|
|
|
#include <stdexcept>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <cairo.h>
|
|
#include "clipper.hpp"
|
|
#include "cairo_clipper.hpp"
|
|
|
|
namespace ClipperLib {
|
|
namespace cairo {
|
|
|
|
namespace {
|
|
|
|
inline cInt Round(double val)
|
|
{
|
|
if ((val < 0)) return (cInt)(val - 0.5); else return (cInt)(val + 0.5);
|
|
}
|
|
|
|
void transform_point(cairo_t* pen, Transform transform, cInt* x, cInt* y)
|
|
{
|
|
double _x = (double)*x, _y = (double)*y;
|
|
switch (transform)
|
|
{
|
|
case tDeviceToUser:
|
|
cairo_device_to_user(pen, &_x, &_y);
|
|
break;
|
|
case tUserToDevice:
|
|
cairo_user_to_device(pen, &_x, &_y);
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
*x = Round(_x); *y = Round(_y);
|
|
}
|
|
}
|
|
|
|
void cairo_to_clipper(cairo_t* cr,
|
|
Paths &pg,
|
|
int scaling_factor,
|
|
Transform transform)
|
|
{
|
|
if (scaling_factor > 8 || scaling_factor < 0)
|
|
throw clipperCairoException("cairo_to_clipper: invalid scaling factor");
|
|
double scaling = std::pow((double)10, scaling_factor);
|
|
|
|
pg.clear();
|
|
cairo_path_t *path = cairo_copy_path_flat(cr);
|
|
|
|
int poly_count = 0;
|
|
for (int i = 0; i < path->num_data; i += path->data[i].header.length) {
|
|
if( path->data[i].header.type == CAIRO_PATH_CLOSE_PATH) poly_count++;
|
|
}
|
|
|
|
pg.resize(poly_count);
|
|
int i = 0, pc = 0;
|
|
while (pc < poly_count)
|
|
{
|
|
int vert_count = 1;
|
|
int j = i;
|
|
while(j < path->num_data && path->data[j].header.type != CAIRO_PATH_CLOSE_PATH)
|
|
{
|
|
if (path->data[j].header.type == CAIRO_PATH_LINE_TO)
|
|
vert_count++;
|
|
j += path->data[j].header.length;
|
|
}
|
|
pg[pc].resize(vert_count);
|
|
if (path->data[i].header.type != CAIRO_PATH_MOVE_TO) {
|
|
pg.resize(pc);
|
|
break;
|
|
}
|
|
pg[pc][0].X = Round(path->data[i+1].point.x *scaling);
|
|
pg[pc][0].Y = Round(path->data[i+1].point.y *scaling);
|
|
if (transform != tNone)
|
|
transform_point(cr, transform, &pg[pc][0].X, &pg[pc][0].Y);
|
|
|
|
i += path->data[i].header.length;
|
|
|
|
j = 1;
|
|
while (j < vert_count && i < path->num_data && path->data[i].header.type == CAIRO_PATH_LINE_TO) {
|
|
pg[pc][j].X = Round(path->data[i+1].point.x *scaling);
|
|
pg[pc][j].Y = Round(path->data[i+1].point.y *scaling);
|
|
if (transform != tNone)
|
|
transform_point(cr, transform, &pg[pc][j].X, &pg[pc][j].Y);
|
|
j++;
|
|
i += path->data[i].header.length;
|
|
}
|
|
pc++;
|
|
i += path->data[i].header.length;
|
|
}
|
|
cairo_path_destroy(path);
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
void clipper_to_cairo(const Paths &pg, cairo_t* cr, int scaling_factor, Transform transform)
|
|
{
|
|
if (scaling_factor > 8 || scaling_factor < 0)
|
|
throw clipperCairoException("clipper_to_cairo: invalid scaling factor");
|
|
double scaling = std::pow((double)10, scaling_factor);
|
|
for (size_t i = 0; i < pg.size(); ++i)
|
|
{
|
|
size_t sz = pg[i].size();
|
|
if (sz < 3)
|
|
continue;
|
|
cairo_new_sub_path(cr);
|
|
//std::cerr << "sub path";
|
|
for (size_t j = 0; j < sz; ++j) {
|
|
cInt x = pg[i][j].X, y = pg[i][j].Y;
|
|
if (transform != tNone)
|
|
transform_point(cr, transform, &x, &y);
|
|
//std::cerr << " (" << (double)x / scaling << "," << (double)y / scaling << ")";
|
|
cairo_line_to(cr, (double)x / scaling, (double)y / scaling);
|
|
}
|
|
//std::cerr << std::endl;
|
|
cairo_close_path(cr);
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
|
|
}
|
|
}
|