From dfba002efc3b5f126ddb69e63b9a7dafdd9eacda Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Wed, 10 Sep 2014 12:45:00 +0800 Subject: [PATCH] Add MPFRC++ mpreal type It's slow but less slow than Rationals. Project complete. Haha I wish. --- src/Makefile | 2 +- src/bezier.h | 2 +- src/document.cpp | 3 +- src/main.h | 5 +- src/objectrenderer.cpp | 7 +- src/paranoidnumber.cpp | 425 +++++++++++++++++-------------- src/paranoidnumber.h | 91 ++++++- src/path.cpp | 125 +++++---- src/path.h | 2 + src/real.cpp | 3 +- src/real.h | 13 +- src/tests/calculator.cpp | 2 +- src/tests/fecalculator.cpp | 2 +- src/tests/paranoidcalculator.cpp | 22 +- src/tests/paranoidtester.cpp | 99 +++++++ src/view.cpp | 1 + 16 files changed, 524 insertions(+), 280 deletions(-) create mode 100644 src/tests/paranoidtester.cpp diff --git a/src/Makefile b/src/Makefile index 630f979..1e4d83f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ QT_INCLUDE := -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/qt4/QtCor 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 -lgmp $(QT_LIB) +LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL -lmpfr -lgmp $(QT_LIB) LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL -lgmp LIB_i686 = $(LIB_i386) diff --git a/src/bezier.h b/src/bezier.h index cfe5808..2b0c1e1 100644 --- a/src/bezier.h +++ b/src/bezier.h @@ -279,7 +279,7 @@ namespace IPDF { Real ptx, pty; Evaluate(ptx, pty, t); - Debug("Root: t = %f, (%f,%f)", t, ptx, pty); + Debug("Root: t = %f, (%f,%f)", Double(t), Double(ptx), Double(pty)); } std::vector all_beziers; diff --git a/src/document.cpp b/src/document.cpp index d097600..d825914 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -301,6 +301,7 @@ unsigned Document::AddPath(unsigned start_index, unsigned end_index, const Colou unsigned data_index = AddPathData(path); Rect bounds = path.SolveBounds(m_objects); unsigned result = Add(PATH, bounds,data_index); + //Debug("Added path %u -> %u (%u objects) colour {%u,%u,%u,%u}, stroke {%u,%u,%u,%u}", start_index, end_index, (end_index - start_index), fill.r, fill.g, fill.b, fill.a, stroke.r, stroke.g, stroke.b, stroke.a); return result; } @@ -1008,7 +1009,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca { AddPath(start_index, end_index); } - Debug("Added Glyph \"%c\" at %f %f, scale %f", (char)character, Float(x), Float(y), Float(scale)); + //Debug("Added Glyph \"%c\" at %f %f, scale %f", (char)character, Float(x), Float(y), Float(scale)); stbtt_FreeShape(font, instructions); } diff --git a/src/main.h b/src/main.h index 88aebfe..3de819c 100644 --- a/src/main.h +++ b/src/main.h @@ -23,6 +23,7 @@ inline void OverlayBMP(Document & doc, const char * input, const char * output, } // It is the only way. +// Dear god what have I done void RatCatcher(int x, int y, int buttons, int wheel, Screen * scr, View * view) { static bool oldButtonDown = false; @@ -52,7 +53,7 @@ void RatCatcher(int x, int y, int buttons, int wheel, Screen * scr, View * view) } if (buttons) { - #if REAL >= REAL_RATIONAL + #if REAL == REAL_RATIONAL view->Translate(Real(oldx, scr->ViewportWidth()) -Real(x,scr->ViewportWidth()), Real(oldy, scr->ViewportHeight()) - Real(y,scr->ViewportHeight())); #else view->Translate(Real(oldx-x)/Real(scr->ViewportWidth()), Real(oldy-y)/Real(scr->ViewportHeight())); @@ -68,7 +69,7 @@ void RatCatcher(int x, int y, int buttons, int wheel, Screen * scr, View * view) if (wheel) { - #if REAL >= REAL_RATIONAL + #if REAL == REAL_RATIONAL view->ScaleAroundPoint(Real(x,scr->ViewportWidth()), Real(y,scr->ViewportHeight()), Real(20-wheel, 20)); #else view->ScaleAroundPoint(Real(x)/Real(scr->ViewportWidth()),Real(y)/Real(scr->ViewportHeight()), Real(expf(-wheel/20.f))); diff --git a/src/objectrenderer.cpp b/src/objectrenderer.cpp index a6bb77d..8f4c55f 100644 --- a/src/objectrenderer.cpp +++ b/src/objectrenderer.cpp @@ -384,7 +384,7 @@ void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CP Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target)); PixelBounds pix_bounds(bounds); - const Path & path = objects.paths[objects.data_indices[m_indexes[i]]]; + Path & path = objects.paths[objects.data_indices[m_indexes[i]]]; if (view.ShowingFillPoints()) { @@ -407,10 +407,11 @@ void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CP if (pix_bounds.w*pix_bounds.h > 100) { + vector & fill_points = path.FillPoints(objects, view); Debug("High resolution; use fill points %u,%u", pix_bounds.w, pix_bounds.h); - for (unsigned f = 0; f < path.m_fill_points.size(); ++f) + for (unsigned f = 0; f < fill_points.size(); ++f) { - PixelPoint fill_point(CPUPointLocation(path.m_fill_points[f], view, target)); + PixelPoint fill_point(CPUPointLocation(fill_points[f], view, target)); FloodFillOnCPU(fill_point.first, fill_point.second, pix_bounds, target, path.m_fill, path.m_stroke); } diff --git a/src/paranoidnumber.cpp b/src/paranoidnumber.cpp index 2510f66..2bb44da 100644 --- a/src/paranoidnumber.cpp +++ b/src/paranoidnumber.cpp @@ -3,13 +3,14 @@ #include #include #include "log.h" +#include using namespace std; namespace IPDF { -ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next(NULL) +ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next_term(NULL), m_next_factor(NULL) { int dp = 0; int end = 0; @@ -26,7 +27,10 @@ ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next { ParanoidNumber b(str[i]-'0'); b*=m; + //Debug("m is %s", m.Str().c_str()); + //Debug("Add %s", b.Str().c_str()); this->operator+=(b); + //Debug("Now at %s", Str().c_str()); m*=10; } ParanoidNumber n(1); @@ -34,142 +38,131 @@ ParanoidNumber::ParanoidNumber(const char * str) : m_value(0), m_op(ADD), m_next { n/=10; ParanoidNumber b(str[i]-'0'); + //Debug("%s * %s", b.Str().c_str(), n.Str().c_str()); b*=n; + //Debug("b -> %s", b.Str().c_str()); + //Debug("Add %s", b.Str().c_str()); this->operator+=(b); - } - -} + //Debug("Now at %s", Str().c_str()); -ParanoidNumber * ParanoidNumber::InsertAfter(float value, Optype op) -{ - return InsertAfter(new ParanoidNumber(value, op)); -} - -ParanoidNumber * ParanoidNumber::InsertAfter(ParanoidNumber * insert) -{ - //Debug("Insert {%s} after {%f, %s}",insert->Str().c_str(), - // m_value, g_opstr[m_op]); - ParanoidNumber * n = m_next; - m_next = insert; - - ParanoidNumber * p = m_next; - while (p->m_next != NULL) - p = p->m_next; - p->m_next = n; - - return m_next; + } + Debug("Constructed {%s} from %s (%f)", Str().c_str(), str, ToDouble()); } - ParanoidNumber & ParanoidNumber::operator=(const ParanoidNumber & a) { - const ParanoidNumber * na = &a; - ParanoidNumber * nb = this; - ParanoidNumber * p = NULL; - while (na != NULL && nb != NULL) + //TODO: Optimise + delete m_next_term; + delete m_next_factor; + m_op = a.m_op; + if (a.m_next_term != NULL) { - nb->m_value = na->m_value; - nb->m_op = na->m_op; - na = na->m_next; - p = nb; - nb = nb->m_next; - - } - - while (na != NULL) // => nb == NULL - { - InsertAfter(na->m_value, na->m_op); - na = na->m_next; + m_next_term = new ParanoidNumber(*(a.m_next_term)); } - - if (nb != NULL) + if (a.m_next_factor != NULL) { - if (p != NULL) - p->m_next = NULL; - delete nb; + m_next_factor = new ParanoidNumber(*(a.m_next_factor)); } return *this; } ParanoidNumber & ParanoidNumber::operator+=(const ParanoidNumber & a) { - ParanoidNumber * insert = new ParanoidNumber(a, ADD); - if (m_next == NULL || m_next->m_op == ADD || m_next->m_op == SUBTRACT) - { - InsertAfter(insert); - Simplify(); - return *this; - } + // this = v + t + (a) + // -> v + (a) + t - if (m_next->m_op == MULTIPLY) // (a*b) + c == (a+[c/b]) * b - insert->operator/=(*m_next); - else - insert->operator*=(*m_next); // (a/b) + c == (a+[c*b])/b + ParanoidNumber * nt = m_next_term; + ParanoidNumber * nf = m_next_factor; - if (insert->m_next != NULL) // neither of the above simplified - { - //Debug("{%s} did not simplify, change back to {%s}", insert->Str().c_str(), a.Str().c_str()); - insert->operator=(a); // Just add as is - insert->m_op = ADD; - ParanoidNumber * n = this; - while (n->m_next != NULL) - n = n->m_next; - n->InsertAfter(insert); - } - else + ParanoidNumber ca(a); + if (m_next_factor != NULL) { - InsertAfter(insert); + if (m_next_factor->m_op == MULTIPLY) + ca /= (*m_next_factor); + else + ca *= (*m_next_factor); + + if (ca.Floating()) + { + m_next_factor = NULL; + m_next_term = NULL; + operator+=(ca); + m_next_factor = nf; + m_next_term = nt; + Simplify(); + return *this; + } + } + + m_next_term = new ParanoidNumber(a, ADD); + ParanoidNumber * t = m_next_term; + while (t->m_next_term != NULL) + t = t->m_next_term; + t->m_next_term = nt; + //Debug("Simplify {%s} after add", Str().c_str()); Simplify(); return *this; } + ParanoidNumber & ParanoidNumber::operator-=(const ParanoidNumber & a) { - ParanoidNumber * insert = new ParanoidNumber(a, SUBTRACT); - if (m_next == NULL || m_next->m_op == ADD || m_next->m_op == SUBTRACT) - { - InsertAfter(insert); - Simplify(); - return *this; - } + // this = v + t + (a) + // -> v + (a) + t - if (m_next->m_op == MULTIPLY) // (a*b) - c == (a-[c/b]) * b - insert->operator/=(*m_next); - else - insert->operator*=(*m_next); // (a/b) - c == (a-[c*b])/b + ParanoidNumber * nt = m_next_term; + ParanoidNumber * nf = m_next_factor; - if (insert->m_next != NULL) // neither of the above simplified + ParanoidNumber ca(a, SUBTRACT); + if (m_next_factor != NULL) { - //Debug("{%s} did not simplify, change back to {%s}", insert->Str().c_str(), a.Str().c_str()); - insert->operator=(a); // Just add as is - insert->m_op = SUBTRACT; - ParanoidNumber * n = this; - while (n->m_next != NULL) - n = n->m_next; - n->InsertAfter(insert); - } - else + if (m_next_factor->m_op == MULTIPLY) + ca /= (*m_next_factor); + else + ca *= (*m_next_factor); + + if (ca.Floating()) + { + m_next_factor = NULL; + m_next_term = NULL; + operator-=(ca); + m_next_factor = nf; + m_next_term = nt; + Simplify(); + return *this; + } + + } + + m_next_term = new ParanoidNumber(a,SUBTRACT); + ParanoidNumber * t = m_next_term; + while (t->m_next_term != NULL) { - InsertAfter(insert); + t->m_op = SUBTRACT; + t = t->m_next_term; } + t->m_op = SUBTRACT; + //Debug("next term {%s}", m_next_term->Str().c_str()); + t->m_next_term = nt; + //Debug("Simplify {%s} after sub", Str().c_str()); Simplify(); return *this; } ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a) { - ParanoidNumber * n = m_next; - while (n != NULL) - { - if (n->m_op == ADD || n->m_op == SUBTRACT) - { - n->operator*=(a); - break; - } - n = n->m_next; - } - - InsertAfter(new ParanoidNumber(a, MULTIPLY)); + Debug("{%s} *= {%s}", Str().c_str(), a.Str().c_str()); + // this = (vf + t) * (a) + ParanoidNumber * nf = m_next_factor; + m_next_factor = new ParanoidNumber(a, MULTIPLY); + ParanoidNumber * t = m_next_factor; + while (t->m_next_factor != NULL) + t = t->m_next_factor; + t->m_next_factor = nf; + if (m_next_term != NULL) + m_next_term->operator*=(a); + //Debug("Simplify after mul"); + Debug("Simplify {%s}", Str().c_str()); Simplify(); return *this; } @@ -177,122 +170,164 @@ ParanoidNumber & ParanoidNumber::operator*=(const ParanoidNumber & a) ParanoidNumber & ParanoidNumber::operator/=(const ParanoidNumber & a) { - ParanoidNumber * n = m_next; - while (n != NULL) - { - if (n->m_op == ADD || n->m_op == SUBTRACT) - { - n->operator/=(a); - break; - } - n = n->m_next; - } - - InsertAfter(new ParanoidNumber(a, DIVIDE)); + //Debug("Called %s /= %s", Str().c_str(), a.Str().c_str()); + // this = (vf + t) * (a) + ParanoidNumber * nf = m_next_factor; + m_next_factor = new ParanoidNumber(a, DIVIDE); + ParanoidNumber * t = m_next_factor; + while (t->m_next_factor != NULL) + t = t->m_next_factor; + t->m_next_factor = nf; + if (m_next_term != NULL) + m_next_term->operator/=(a); Simplify(); return *this; } -double ParanoidNumber::ToDouble() const -{ - double value = (m_op == SUBTRACT) ? -m_value : m_value; - const ParanoidNumber * n = m_next; - while (n != NULL) + + +void ParanoidNumber::SimplifyTerms() +{ + //Debug("Simplify {%s}", Str().c_str()); + if (m_next_term == NULL) { - switch (n->m_op) + //Debug("No terms!"); + return; + } + + for (ParanoidNumber * a = this; a != NULL; a = a->m_next_term) + { + ParanoidNumber * bprev = a; + ParanoidNumber * b = a->m_next_term; + while (b != NULL) { - case ADD: - case SUBTRACT: - return value + n->ToDouble(); - break; - case MULTIPLY: - value *= n->m_value; - break; - case DIVIDE: - value /= n->m_value; - break; + //Debug("Simplify factors of %s", b->Str().c_str()); + b->SimplifyFactors(); + if (b->m_next_factor != NULL) + { + bprev = b; + b = b->m_next_term; + continue; + } + float f = a->m_value; + feclearexcept(FE_ALL_EXCEPT); + switch (b->m_op) + { + case ADD: + f += b->m_value; + break; + case SUBTRACT: + f -= b->m_value; + break; + default: + Fatal("Unexpected %c in term list...", OpChar(b->m_op)); + break; + } + if (!fetestexcept(FE_ALL_EXCEPT)) + { + a->m_value = f; + bprev->m_next_term = b->m_next_term; + b->m_next_term = NULL; + delete b; + b = bprev; + } + bprev = b; + b = b->m_next_term; } - n = n->m_next; } - return value; } -void ParanoidNumber::Simplify() -{ - ParanoidNumber * n = m_next; - ParanoidNumber * p = this; - - while (n != NULL) +void ParanoidNumber::SimplifyFactors() +{ + //Debug("Simplify {%s}", Str().c_str()); + if (m_next_factor == NULL) { - - float a = p->m_value; - switch (n->m_op) + //Debug("No factors!"); + return; + } + + for (ParanoidNumber * a = this; a != NULL; a = a->m_next_factor) + { + ParanoidNumber * bprev = a; + ParanoidNumber * b = a->m_next_factor; + while (b != NULL) { - case ADD: - n->Simplify(); - feclearexcept(FE_ALL_EXCEPT); - a += n->m_value; - break; - case SUBTRACT: - n->Simplify(); - feclearexcept(FE_ALL_EXCEPT); - a -= n->m_value; - break; - case MULTIPLY: - feclearexcept(FE_ALL_EXCEPT); - a *= n->m_value; - break; - case DIVIDE: - feclearexcept(FE_ALL_EXCEPT); - a /= n->m_value; - break; + b->SimplifyTerms(); + if (b->m_next_term != NULL) + { + bprev = b; + b = b->m_next_factor; + continue; + } + float f = a->m_value; + feclearexcept(FE_ALL_EXCEPT); + switch (b->m_op) + { + case MULTIPLY: + if (a->m_op != DIVIDE) + f *= b->m_value; + else + f /= b->m_value; + break; + case DIVIDE: + if (a->m_op != DIVIDE) + f /= b->m_value; + else + f *= b->m_value; + break; + default: + Fatal("Unexpected %c in factor list...",OpChar(b->m_op)); + break; + } + if (!fetestexcept(FE_ALL_EXCEPT)) + { + a->m_value = f; + bprev->m_next_factor = b->m_next_factor; + b->m_next_factor = NULL; + delete b; + b = bprev; + } + //else + //Debug("Failed to simplify %f %c %f", a->m_value, OpChar(b->m_op), b->m_value); + bprev = b; + b = b->m_next_factor; } - // can't merge p and n - if (fetestexcept(FE_ALL_EXCEPT)) - { - while (n != NULL && n->m_op != ADD && n->m_op != SUBTRACT) - n = n->m_next; - if (n != NULL) - n->Simplify(); - return; - } - else - { - // merge n into p - p->m_value = a; - p->m_next = n->m_next; - n->m_next = NULL; - delete n; - n = p->m_next; - } - //Debug(" -> {%s}", Str().c_str()); } } +void ParanoidNumber::Simplify() +{ + SimplifyFactors(); + SimplifyTerms(); +} + string ParanoidNumber::Str() const { string result(""); - switch (m_op) + stringstream s; + + s << m_value; + + if (m_next_factor != NULL) { - case ADD: - result += " +"; - break; - case SUBTRACT: - result += " -"; - break; - case MULTIPLY: - result += " *"; - break; - case DIVIDE: - result += " /"; - break; + result += OpChar(m_op); + result += "("; + result += s.str(); + result += m_next_factor->Str(); + result += ")"; + } + else + { + result += OpChar(m_op); + result += s.str(); + } + + if (m_next_term != NULL) + { + result += " "; + result += m_next_term->Str(); } - stringstream s(""); - s << m_value; - result += s.str(); - if (m_next != NULL) - result += m_next->Str(); return result; } diff --git a/src/paranoidnumber.h b/src/paranoidnumber.h index 4c481bd..a2e8542 100644 --- a/src/paranoidnumber.h +++ b/src/paranoidnumber.h @@ -5,6 +5,9 @@ #include #include #include +#include "log.h" + + namespace IPDF { @@ -13,34 +16,52 @@ namespace IPDF public: typedef enum {ADD, SUBTRACT, MULTIPLY, DIVIDE} Optype; - ParanoidNumber(float value=0, Optype type = ADD) : m_value(value), m_op(type), m_next(NULL) + ParanoidNumber(float value=0, Optype type = ADD) : m_value(value), m_op(type), m_next_term(NULL), m_next_factor(NULL) { } - ParanoidNumber(const ParanoidNumber & cpy) : m_value(cpy.m_value), m_op(cpy.m_op), m_next(NULL) + ParanoidNumber(const ParanoidNumber & cpy) : m_value(cpy.m_value), m_op(cpy.m_op), m_next_term(NULL), m_next_factor(NULL) { - if (cpy.m_next != NULL) + if (cpy.m_next_term != NULL) { - m_next = new ParanoidNumber(*(cpy.m_next)); + m_next_term = new ParanoidNumber(*(cpy.m_next_term)); + } + if (cpy.m_next_factor != NULL) + { + m_next_factor = new ParanoidNumber(*(cpy.m_next_factor)); } } - ParanoidNumber(const ParanoidNumber & cpy, Optype type) : ParanoidNumber(cpy) + ParanoidNumber(const ParanoidNumber & cpy, Optype type) : m_value(cpy.m_value), m_op(type), m_next_term(NULL), m_next_factor(NULL) { - m_op = type; + if (cpy.m_next_term != NULL) + { + m_next_term = new ParanoidNumber(*(cpy.m_next_term)); + } + if (cpy.m_next_factor != NULL) + { + m_next_factor = new ParanoidNumber(*(cpy.m_next_factor)); + } } ParanoidNumber(const char * str); + ParanoidNumber(const std::string & str) : ParanoidNumber(str.c_str()) {} virtual ~ParanoidNumber() { - if (m_next != NULL) - delete m_next; + if (m_next_term != NULL) + delete m_next_term; + if (m_next_factor != NULL) + delete m_next_factor; } + template T Convert() const; + double ToDouble() const {return Convert();} + float ToFloat() const {return Convert();} - double ToDouble() const; + bool Floating() const {return (m_next_term == NULL && m_next_factor == NULL);} + bool Sunken() const {return !Floating();} // I could not resist... ParanoidNumber & operator+=(const ParanoidNumber & a); ParanoidNumber & operator-=(const ParanoidNumber & a); @@ -82,15 +103,24 @@ namespace IPDF } std::string Str() const; + static char OpChar(Optype op) + { + static char opch[] = {'+','-','*','/'}; + return opch[(int)op]; + } private: void Simplify(); - ParanoidNumber * InsertAfter(ParanoidNumber * insert); - ParanoidNumber * InsertAfter(float value, Optype op); + void SimplifyTerms(); + void SimplifyFactors(); + float m_value; Optype m_op; - ParanoidNumber * m_next; + ParanoidNumber * m_next_term; + ParanoidNumber * m_next_factor; + + @@ -98,6 +128,43 @@ namespace IPDF }; +template +T ParanoidNumber::Convert() const +{ + T value = (m_op == SUBTRACT) ? -m_value : m_value; + const ParanoidNumber * n = m_next_factor; + if (n != NULL) + { + switch (n->m_op) + { + case MULTIPLY: + value *= n->Convert(); + break; + case DIVIDE: + value /= n->Convert(); + break; + default: + Fatal("Shouldn't happen"); + break; + } + } + n = m_next_term; + if (n != NULL) + { + switch (n->m_op) + { + case ADD: + case SUBTRACT: + value += n->Convert(); + break; + default: + Fatal("Shouldn't happen"); + } + } + return value; +} + + } #endif //_PARANOIDNUMBER_H diff --git a/src/path.cpp b/src/path.cpp index c58d3df..589c509 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -43,68 +43,14 @@ Path::Path(const Objects & objects, unsigned start, unsigned end, const Colour & { ymax = (objb.y+objb.h); bottom = i; - } - - // find fill points - Vec2 pt; - // left - pt = Vec2(objb.x, objb.y+objb.h/Real(2)); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - // right - pt = Vec2(objb.x+objb.w, objb.y+objb.h/Real(2)); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - // bottom - pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - // top - pt = Vec2(objb.x+objb.w/Real(2), objb.y); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - - // topleft - pt = Vec2(objb.x, objb.y); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - // topright - pt = Vec2(objb.x+objb.w, objb.y); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - // bottom left - pt = Vec2(objb.x, objb.y+objb.h); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - // bottom right - pt = Vec2(objb.x+objb.w, objb.y); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - - // mid - pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h/Real(2)); - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - - + } } // Get actual turning point coords of the 4 edge case beziers m_top = objects.beziers[objects.data_indices[top]].ToAbsolute(objects.bounds[top]).GetTop(); m_bottom = objects.beziers[objects.data_indices[bottom]].ToAbsolute(objects.bounds[bottom]).GetBottom(); m_left = objects.beziers[objects.data_indices[left]].ToAbsolute(objects.bounds[left]).GetLeft(); - m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight(); - - Vec2 pt = (m_top + m_bottom)/2; - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - pt = (m_left + m_right)/2; - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - pt = (m_left + m_right + m_top + m_bottom)/4; - if (PointInside(objects, pt)) - m_fill_points.push_back(pt); - + m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight(); } @@ -166,6 +112,73 @@ bool Path::PointInside(const Objects & objects, const Vec2 & pt, bool debug) con return true; } +vector & Path::FillPoints(const Objects & objects, const View & view) +{ + if (m_fill_points.size() != 0) + return m_fill_points; + + + for (unsigned i = m_start; i <= m_end; ++i) + { + const Rect & objb = objects.bounds[i]; + // find fill points + Vec2 pt; + // left + pt = Vec2(objb.x, objb.y+objb.h/Real(2)); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + // right + pt = Vec2(objb.x+objb.w, objb.y+objb.h/Real(2)); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + // bottom + pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + // top + pt = Vec2(objb.x+objb.w/Real(2), objb.y); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + + // topleft + pt = Vec2(objb.x, objb.y); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + // topright + pt = Vec2(objb.x+objb.w, objb.y); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + // bottom left + pt = Vec2(objb.x, objb.y+objb.h); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + // bottom right + pt = Vec2(objb.x+objb.w, objb.y); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + + // mid + pt = Vec2(objb.x+objb.w/Real(2), objb.y+objb.h/Real(2)); + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + + + } + + // 4 extrema + Vec2 pt = (m_top + m_bottom)/2; + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + pt = (m_left + m_right)/2; + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + pt = (m_left + m_right + m_top + m_bottom)/4; + if (PointInside(objects, pt)) + m_fill_points.push_back(pt); + + return m_fill_points; +} + Rect Path::SolveBounds(const Objects & objects) const { return Rect(m_left.x, m_top.y, m_right.x-m_left.x, m_bottom.y-m_top.y); diff --git a/src/path.h b/src/path.h index 1a0ed53..fa63cb4 100644 --- a/src/path.h +++ b/src/path.h @@ -22,12 +22,14 @@ namespace IPDF }; class Objects; + class View; struct Path { Path(const 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; + std::vector & FillPoints(const Objects & objects, const View & view); // Is point inside shape? bool PointInside(const Objects & objects, const Vec2 & pt, bool debug=false) const; diff --git a/src/real.cpp b/src/real.cpp index 0f104e5..aa0cfc8 100644 --- a/src/real.cpp +++ b/src/real.cpp @@ -9,7 +9,8 @@ namespace IPDF "long double", "VFPU", "Rational", - "Rational" + "Rational", + "mpfrc++ real" }; #if REAL == REAL_RATIONAL_ARBINT diff --git a/src/real.h b/src/real.h index 0cbc05d..b107649 100644 --- a/src/real.h +++ b/src/real.h @@ -11,6 +11,7 @@ #define REAL_VFPU 3 #define REAL_RATIONAL 4 #define REAL_RATIONAL_ARBINT 5 +#define REAL_MPFRCPP 6 #ifndef REAL #error "REAL was not defined!" @@ -30,6 +31,10 @@ #include "gmpint.h" #endif //REAL +#if REAL == REAL_MPFRCPP + #include +#endif //REAL + namespace IPDF { extern const char * g_real_name[]; @@ -56,7 +61,13 @@ namespace IPDF inline double Double(const Real & r) {return r.ToDouble();} inline int64_t Int64(const Real & r) {return r.ToInt64();} inline Rational Sqrt(const Rational & r) {return r.Sqrt();} - +#elif REAL == REAL_MPFRCPP + typedef mpfr::mpreal Real; + inline double Double(const Real & r) {return r.toDouble();} + inline float Float(const Real & r) {return r.toDouble();} + inline int64_t Int64(const Real & r) {return r.toLong();} + inline Real Sqrt(const Real & r) {return mpfr::sqrt(r, mpfr::mpreal::get_default_rnd());} + inline Real Abs(const Real & r) {return mpfr::abs(r, mpfr::mpreal::get_default_rnd());} #else #error "Type of Real unspecified." #endif //REAL diff --git a/src/tests/calculator.cpp b/src/tests/calculator.cpp index 89009f1..ab100b9 100644 --- a/src/tests/calculator.cpp +++ b/src/tests/calculator.cpp @@ -11,7 +11,7 @@ using namespace IPDF; int main(int argc, char ** argv) { - while (true) + while (cin.good()) { double da; double db; char op; diff --git a/src/tests/fecalculator.cpp b/src/tests/fecalculator.cpp index 2ae39d9..c16265c 100644 --- a/src/tests/fecalculator.cpp +++ b/src/tests/fecalculator.cpp @@ -17,7 +17,7 @@ int main(int argc, char ** argv) Debug("FLT_MIN = %.40f", FLT_MIN); Debug("FLT_EPSILON = %.40f", FLT_EPSILON); - while (true) + while (cin.good()) { float a; float b; char op; diff --git a/src/tests/paranoidcalculator.cpp b/src/tests/paranoidcalculator.cpp index 171eaf0..9c5a88a 100644 --- a/src/tests/paranoidcalculator.cpp +++ b/src/tests/paranoidcalculator.cpp @@ -19,17 +19,29 @@ int main(int argc, char ** argv) Debug("FLT_EPSILON = %.40f", FLT_EPSILON); ParanoidNumber a("0.3"); - Debug("start at %s", a.Str().c_str()); + Debug("start at {%s} = %lf", a.Str().c_str(), a.ToDouble()); cout << "0.3 "; float fa = 0.3; double da = 0.3; while (cin.good()) { char op; - double db; - cin >> op >> db; - float fb(db); - ParanoidNumber b(fb); + cin >> op; + string token(""); + for (char c = cin.peek(); cin.good() && !iswspace(c); c = cin.peek()) + { + if (c == '+' || c == '-' || c == '*' || c == '/') + { + break; + } + token += c; + c = cin.get(); + } + Debug("String is %s", token.c_str()); + float fb = strtof(token.c_str(), NULL); + double db = strtod(token.c_str(), NULL); + ParanoidNumber b(token.c_str()); + Debug("b is {%s} %lf", b.Str().c_str(), b.ToDouble()); switch (op) { case '+': diff --git a/src/tests/paranoidtester.cpp b/src/tests/paranoidtester.cpp new file mode 100644 index 0000000..bf1dc0b --- /dev/null +++ b/src/tests/paranoidtester.cpp @@ -0,0 +1,99 @@ +#include "main.h" +#include "real.h" +#include +#include +#include +#include +#include +#include +#include +#include "paranoidnumber.h" + +using namespace std; +using namespace IPDF; + +string RandomNumberAsString(int digits = 6) +{ + string result(""); + int dp = 1+(rand() % 3); + for (int i = 0; i < digits; ++i) + { + if (i == dp) + { + result += "."; + continue; + } + result += ('0'+rand() % 10); + } + return result; +} + +#define TEST_CASES 10000 + +int main(int argc, char ** argv) +{ + + string number(RandomNumberAsString()); + ParanoidNumber a(number); + float fa = strtof(number.c_str(), NULL); + double da = strtod(number.c_str(), NULL); + long double lda = strtold(number.c_str(), NULL); + + if (fabs(a.ToDouble() - da) > 1e-6) + { + Error("double %lf, pn %lf {%s}", da, a.ToDouble(), a.Str().c_str()); + Fatal("Didn't construct correctly off %s", number.c_str()); + } + + char opch[] = {'+','-','*','/'}; + + for (int i = 0; i < TEST_CASES; ++i) + { + number = RandomNumberAsString(); + ParanoidNumber b(number); + float fb = strtof(number.c_str(), NULL); + double db = strtod(number.c_str(), NULL); + long double ldb = strtold(number.c_str(), NULL); + int op = (rand() % 4); + ParanoidNumber olda(a); + double oldda(da); + switch (op) + { + case 0: + a += b; + fa += fb; + da += db; + lda += ldb; + break; + case 1: + a -= b; + fa -= fb; + da -= db; + lda -= ldb; + break; + case 2: + a *= b; + fa *= fb; + da *= db; + lda *= ldb; + break; + case 3: + a /= b; + fa /= fb; + da /= db; + lda /= ldb; + break; + } + if (fabs(a.ToDouble() - da) > 1.0 ) + { + Error("Op %i: ParanoidNumber probably doesn't work", i); + Error("Operation: %lf %c %lf", oldda, opch[op], db); + Error("As PN: %lf %c %lf", olda.ToDouble(), opch[op], b.ToDouble()); + Fatal("%lf, expected aboout %lf", a.ToDouble(), da); + } + } + printf("ParanoidNumber: {%s} = %.40lf\n", a.Str().c_str(), a.ToDouble()); + printf("float: %.40f\n", fa); + printf("double: %.40lf\n", da); + printf("long double: %.40Lf\n", lda); +} diff --git a/src/view.cpp b/src/view.cpp index 925fa47..60f2976 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -264,6 +264,7 @@ void View::Render(int width, int height) #ifndef CONTROLPANEL_DISABLED ControlPanel::Update(); #endif //CONTROLPANEL_DISABLED + //Debug("Completed Render"); } -- 2.20.1