So, the bounds of Paths are stored with Gmprat
The Bezier's are all stored relative to the Path, as floats
The transformations are only applied to the Path Gmprat bounds.
This seems to work rather well.
In other news, the DeCasteljau algorithm in the CPU
renderer had no upper limit, which is why it was slowing down so much.
The CPU renderer tends to suffer from SIGFPE-itis when using floats,
because when you do a cast there is a SIGFPE if the resultant type can't represent the operand.
This occurs in a few places that don't actually affect the rendering...
12 files changed:
QT_DEF := -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB
QT_LIB := -L/usr/lib/x86_64-linux-gnu -lQtGui -lQtCore -lpthread
QT_DEF := -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB
QT_LIB := -L/usr/lib/x86_64-linux-gnu -lQtGui -lQtCore -lpthread
-LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL
-LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL
+LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL -lgmp
+LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL -lgmp
LIB_i686 = $(LIB_i386)
MAINRPATH_x86_64 = -Wl,-rpath,'$$ORIGIN/../contrib/lib'
LIB_i686 = $(LIB_i386)
MAINRPATH_x86_64 = -Wl,-rpath,'$$ORIGIN/../contrib/lib'
#include <cmath>
#include <algorithm>
#include <cmath>
#include <algorithm>
using namespace std;
namespace IPDF
using namespace std;
namespace IPDF
namespace IPDF
{
extern int Factorial(int n);
namespace IPDF
{
extern int Factorial(int n);
void Document::TranslateObjects(const Real & dx, const Real & dy, ObjectType type)
{
void Document::TranslateObjects(const Real & dx, const Real & dy, ObjectType type)
{
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ for (unsigned i = 0; i < m_objects.paths.size(); ++i)
+ {
+ Path & p = m_objects.paths[i];
+ p.x += dx;
+ p.y += dy;
+ }
+ return;
+ #endif
+
for (unsigned i = 0; i < m_count; ++i)
{
if (type == NUMBER_OF_OBJECT_TYPES || m_objects.types[i] == type)
for (unsigned i = 0; i < m_count; ++i)
{
if (type == NUMBER_OF_OBJECT_TYPES || m_objects.types[i] == type)
void Document::ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount, ObjectType type)
{
void Document::ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount, ObjectType type)
{
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ for (unsigned i = 0; i < m_objects.paths.size(); ++i)
+ {
+ Path & p = m_objects.paths[i];
+ p.w /= scale_amount;
+ p.h /= scale_amount;
+ p.x -= x;
+ p.x /= scale_amount;
+ p.x += x;
+ p.y -= y;
+ p.y /= scale_amount;
+ p.y += y;
+ }
+ return;
+ #endif
+
for (unsigned i = 0; i < m_count; ++i)
{
if (type != NUMBER_OF_OBJECT_TYPES && m_objects.types[i] != type)
for (unsigned i = 0; i < m_count; ++i)
{
if (type != NUMBER_OF_OBJECT_TYPES && m_objects.types[i] != type)
m_objects.bounds[i].y /= scale_amount;
m_objects.bounds[i].y += y;
}
m_objects.bounds[i].y /= scale_amount;
m_objects.bounds[i].y += y;
}
# Test how well document scales back to original...
# Test how well document scales back to original...
lazy
label start
debug Add rabbit 1
loadsvg svg-tests/rabbit_simple.svg
lazy
label start
debug Add rabbit 1
loadsvg svg-tests/rabbit_simple.svg
-loop 200 pxzoom 508 305 1
+loop 250 pxzoom 508 305 1
debug Add rabbit 2
loadsvg svg-tests/rabbit_simple.svg
debug Add rabbit 2
loadsvg svg-tests/rabbit_simple.svg
-loop 200 pxzoom 508 305 1
+loop 250 pxzoom 508 305 1
debug Add rabbit 3
loadsvg svg-tests/rabbit_simple.svg
debug Add rabbit 3
loadsvg svg-tests/rabbit_simple.svg
-loop 400 pxzoom 508 305 -1
-loop 200 pxzoom 508 305 1
+loop 500 pxzoom 508 305 -1
+loop 250 pxzoom 508 305 1
-loop 200 pxzoom 508 305 1
+loop 250 pxzoom 508 305 1
debug Repeat
#goto start
wait
debug Repeat
#goto start
wait
}
Gmprat & operator=(const Gmprat & equ) {mpq_set(m_op, equ.m_op); return *this;}
}
Gmprat & operator=(const Gmprat & equ) {mpq_set(m_op, equ.m_op); return *this;}
+ Gmprat & operator=(const double & equ) {mpq_set_d(m_op, equ); return *this;}
Gmprat & operator+=(const Gmprat & add) {mpq_add(m_op, m_op, add.m_op); return *this;}
Gmprat & operator-=(const Gmprat & sub) {mpq_sub(m_op, m_op, sub.m_op); return *this;}
Gmprat & operator*=(const Gmprat & mul) {mpq_mul(m_op, m_op, mul.m_op); return *this;}
Gmprat & operator+=(const Gmprat & add) {mpq_add(m_op, m_op, add.m_op); return *this;}
Gmprat & operator-=(const Gmprat & sub) {mpq_sub(m_op, m_op, sub.m_op); return *this;}
Gmprat & operator*=(const Gmprat & mul) {mpq_mul(m_op, m_op, mul.m_op); return *this;}
ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,255,0,0));
}
ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,255,0,0));
}
- unsigned blen = pix_bounds.w;//min(max(2U, (unsigned)Int64(Real(target.w)/view.GetBounds().w)),
+ int64_t blen = min(50L,pix_bounds.w);//min(max(2U, (unsigned)Int64(Real(target.w)/view.GetBounds().w)),
//min((unsigned)(pix_bounds.w+pix_bounds.h)/4 + 1, 100U));
// DeCasteljau Divide the Bezier
#ifdef BEZIER_CPU_DECASTELJAU
queue<Bezier> divisions;
divisions.push(control);
//min((unsigned)(pix_bounds.w+pix_bounds.h)/4 + 1, 100U));
// DeCasteljau Divide the Bezier
#ifdef BEZIER_CPU_DECASTELJAU
queue<Bezier> divisions;
divisions.push(control);
- while(divisions.size() < blen)
+ while(divisions.size() < (uint64_t)(blen))
{
Bezier & current = divisions.front();
//if (current.GetType() == Bezier::LINE)
{
Bezier & current = divisions.front();
//if (current.GetType() == Bezier::LINE)
- Rect & bounds = objects.bounds[m_indexes[i]];
+ Rect bounds = view.TransformToViewCoords(objects.bounds[m_indexes[i]]);
Bezier & bez = objects.beziers[objects.data_indices[m_indexes[i]]];
RenderBezierOnCPU(bez, bounds, view, target, c);
}
Bezier & bez = objects.beziers[objects.data_indices[m_indexes[i]]];
RenderBezierOnCPU(bez, bounds, view, target, c);
}
if (m_indexes[i] >= last_obj_id) continue;
if (m_indexes[i] >= last_obj_id) continue;
- Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target));
- PixelBounds pix_bounds(bounds);
Path & path = objects.paths[objects.data_indices[m_indexes[i]]];
Path & path = objects.paths[objects.data_indices[m_indexes[i]]];
+ Rect bounds(CPURenderBounds(path.GetBounds(objects), view, target));
+ PixelBounds pix_bounds(bounds);
if (view.ShowingFillPoints())
{
if (view.ShowingFillPoints())
{
+ObjectRenderer::PixelBounds::PixelBounds(const Rect & bounds)
+{
+ x = Int64(Double(bounds.x));
+ y = Int64(Double(bounds.y));
+ w = Int64(Double(bounds.w));
+ h = Int64(Double(bounds.h));
+}
+
#include "graphicsbuffer.h"
#include "shaderprogram.h"
#include "bufferbuilder.h"
#include "graphicsbuffer.h"
#include "shaderprogram.h"
#include "bufferbuilder.h"
#define BEZIER_CPU_DECASTELJAU
#define BEZIER_CPU_DECASTELJAU
struct PixelBounds
{
int64_t x; int64_t y; int64_t w; int64_t h;
struct PixelBounds
{
int64_t x; int64_t y; int64_t w; int64_t h;
- PixelBounds(const Rect & bounds) : x(Double(bounds.x)), y(Double(bounds.y)), w(Double(bounds.w)), h(Double(bounds.h)) {}
+ PixelBounds(const Rect & bounds);
};
typedef std::pair<int64_t, int64_t> PixelPoint;
};
typedef std::pair<int64_t, int64_t> PixelPoint;
m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight();
#ifdef TRANSFORM_BEZIERS_TO_PATH
m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight();
#ifdef TRANSFORM_BEZIERS_TO_PATH
+ x = m_left.x;
+ y = m_top.y;
+ w = m_right.x - m_left.x;
+ h = m_bottom.y - m_top.y;
+
Rect bounds = SolveBounds(objects);
for (unsigned i = m_start; i <= m_end; ++i)
{
Rect bounds = SolveBounds(objects);
for (unsigned i = m_start; i <= m_end; ++i)
{
-Rect Path::SolveBounds(const Objects & objects) const
+Rect Path::SolveBounds(const Objects & objects)
- return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y);
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ return Rect(Real(x.ToDouble()), Real(y.ToDouble()), Real(w.ToDouble()), Real(h.ToDouble()));
+ #else
+ return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y);
+ #endif
}
Rect & Path::GetBounds(Objects & objects)
{
}
Rect & Path::GetBounds(Objects & objects)
{
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ objects.bounds[m_index] = Rect(Real(x.ToDouble()), Real(y.ToDouble()), Real(w.ToDouble()), Real(h.ToDouble()));
+ #endif
return objects.bounds[m_index];
}
return objects.bounds[m_index];
}
#ifdef QUADTREE_DISABLED
#define TRANSFORM_BEZIERS_TO_PATH
#ifdef QUADTREE_DISABLED
#define TRANSFORM_BEZIERS_TO_PATH
+#ifdef TRANSFORM_BEZIERS_TO_PATH
+#include "gmprat.h"
+#endif
{
Path(Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(128,128,128,255), const Colour & _stroke = Colour(0,0,0,0));
{
Path(Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(128,128,128,255), const Colour & _stroke = Colour(0,0,0,0));
- Rect SolveBounds(const Objects & objects) const;
+ Rect SolveBounds(const Objects & objects);
Rect & GetBounds(Objects & objects);
std::vector<Vec2> & FillPoints(const Objects & objects, const View & view);
Rect & GetBounds(Objects & objects);
std::vector<Vec2> & FillPoints(const Objects & objects, const View & view);
std::vector<Vec2> m_fill_points;
std::vector<Vec2> m_fill_points;
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ Gmprat x;
+ Gmprat y;
+ Gmprat w;
+ Gmprat h;
+ #endif
+
Colour m_fill; // colour to fill with
Colour m_stroke; // colour to outline with
};
Colour m_fill; // colour to fill with
Colour m_stroke; // colour to outline with
};
inline double Double(long double f) {return (double)(f);}
inline double Sqrt(double f) {return sqrt(f);}
inline double Abs(double a) {return fabs(a);}
inline double Double(long double f) {return (double)(f);}
inline double Sqrt(double f) {return sqrt(f);}
inline double Abs(double a) {return fabs(a);}
- inline int64_t Int64(double a){return (int64_t)a;}
+ inline int64_t Int64(double a)
+ {
+ if (a < INT64_MIN)
+ return INT64_MIN;
+ if (a > INT64_MAX)
+ return INT64_MAX;
+ return (int64_t)(a);
+ }
inline Real Power(const Real & a, int n)
{
inline Real Power(const Real & a, int n)
{
-//#define TRANSFORM_OBJECTS_NOT_VIEW
+#define TRANSFORM_OBJECTS_NOT_VIEW