gerbolyze/upstream/clipper-6.4.2/cpp/cpp_cairo/cairo_clipper.cpp
2021-01-24 18:44:56 +01:00

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);
}
}
//--------------------------------------------------------------------------
}
}