From: Sam Moore Date: Wed, 8 Oct 2014 14:50:58 +0000 (+0800) Subject: Mostly features added to DebugScript X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=180d764223a3568f734434a15d56f18e9ddc012b;p=ipdf%2Fcode.git Mostly features added to DebugScript Also got MPFR C++ reals to work Should allow for a quantitative comparison between Rationals and Arbitrary Precision Floats Just... overwhelming amounts of results that it would be nice to get, so I don't know where to start... --- diff --git a/src/debugscript.cpp b/src/debugscript.cpp index d7ccad3..ff00f9e 100644 --- a/src/debugscript.cpp +++ b/src/debugscript.cpp @@ -4,7 +4,7 @@ using namespace IPDF; -void DebugScript::ParseAction() +void DebugScript::ParseAction(View * view, Screen * scr) { std::string actionType; inp >> actionType; @@ -118,6 +118,52 @@ void DebugScript::ParseAction() currentAction.type = AT_DebugFont; inp >> currentAction.textargs; } + else if (actionType == "approachz") // approach zenoistically + { + currentAction.type = AT_ApproachBoundsZeno; + std::string _x, _y, _w, _h, _z; + inp >> _x >> _y >> _w >> _h >> _z; + currentAction.x = RealFromStr(_x.c_str()); + currentAction.y = RealFromStr(_y.c_str()); + currentAction.w = RealFromStr(_w.c_str()); + currentAction.h = RealFromStr(_h.c_str()); + currentAction.z = RealFromStr(_z.c_str()); + } + else if (actionType == "approachl") // approach linearly + { + currentAction.type = AT_ApproachBoundsLinear; + std::string _x, _y, _w, _h, _z; + inp >> _x >> _y >> _w >> _h >> _z; + currentAction.x = RealFromStr(_x.c_str()); + currentAction.y = RealFromStr(_y.c_str()); + currentAction.w = RealFromStr(_w.c_str()); + currentAction.h = RealFromStr(_h.c_str()); + currentAction.z = RealFromStr(_z.c_str()); + currentAction.x = (currentAction.x - view->GetBounds().x)/currentAction.z; + currentAction.y = (currentAction.y - view->GetBounds().y)/currentAction.z; + currentAction.w = (currentAction.w - view->GetBounds().w)/currentAction.z; + currentAction.h = (currentAction.h - view->GetBounds().h)/currentAction.z; + } + else if (actionType == "setbounds") + { + currentAction.type = AT_SetBounds; + std::string _x, _y, _w, _h; + inp >> _x >> _y >> _w >> _h; + currentAction.x = RealFromStr(_x.c_str()); + currentAction.y = RealFromStr(_y.c_str()); + currentAction.w = RealFromStr(_w.c_str()); + currentAction.h = RealFromStr(_h.c_str()); + } + else if (actionType == "querygpubounds") + { + currentAction.type = AT_QueryGPUBounds; + inp >> currentAction.textargs; + } + else if (actionType == "screenshot") + { + currentAction.type = AT_ScreenShot; + inp >> currentAction.textargs; + } } @@ -127,7 +173,7 @@ bool DebugScript::Execute(View *view, Screen *scr) { if (m_index >= m_actions.size()) { - ParseAction(); + ParseAction(view, scr); if (m_labels.size() > 0) { m_actions.push_back(currentAction); @@ -217,6 +263,79 @@ bool DebugScript::Execute(View *view, Screen *scr) scr->ShowDebugFont(currentAction.textargs == "1" || currentAction.textargs == "on"); currentAction.loops = 1; break; + + case AT_ApproachBoundsZeno: + { + VRect target(currentAction.x, currentAction.y, currentAction.w, currentAction.h); + if (currentAction.z != VReal(1)) + { + target.x = view->GetBounds().x + (target.x-view->GetBounds().x)/VReal(currentAction.z); + target.y = view->GetBounds().y + (target.y-view->GetBounds().y)/VReal(currentAction.z); + target.w = view->GetBounds().w + (target.w-view->GetBounds().w)/VReal(currentAction.z); + target.h = view->GetBounds().h + (target.h-view->GetBounds().h)/VReal(currentAction.z); + } + + + VReal s = target.w/(view->GetBounds().w); + if (Real(s) != 1) + { + VReal x0; + VReal y0; + x0 = (view->GetBounds().x - target.x)/((s - VReal(1))*view->GetBounds().w); + y0 = (view->GetBounds().y - target.y)/((s - VReal(1))*view->GetBounds().h); + view->ScaleAroundPoint(x0, y0, s); + currentAction.loops++; + } + else + { + Debug("Already at target view; Waiting for remaining %d frames", currentAction.loops); + currentAction.type = AT_WaitFrame; + } + break; + } + case AT_ApproachBoundsLinear: + { + VRect target(currentAction.x, currentAction.y, currentAction.w, currentAction.h); + target.x += view->GetBounds().x; + target.y += view->GetBounds().y; + target.w += view->GetBounds().w; + target.h += view->GetBounds().h; + VReal s = target.w/(view->GetBounds().w); + if (Real(s) != 1) + { + VReal x0; + VReal y0; + x0 = (view->GetBounds().x - target.x)/((s - VReal(1))*view->GetBounds().w); + y0 = (view->GetBounds().y - target.y)/((s - VReal(1))*view->GetBounds().h); + view->ScaleAroundPoint(x0, y0, s); + currentAction.loops++; + } + else + { + Debug("Already at target view; Waiting for remaining %d frames", currentAction.loops); + currentAction.type = AT_WaitFrame; + } + break; + } + case AT_SetBounds: + { + VRect target(currentAction.x, currentAction.y, currentAction.w, currentAction.h); + view->SetBounds(target); + break; + } + + case AT_QueryGPUBounds: + { + view->QueryGPUBounds(currentAction.textargs.c_str(), "w"); + currentAction.loops = 1; + break; + } + case AT_ScreenShot: + { + view->SaveBMP(currentAction.textargs.c_str()); + currentAction.loops = 1; + break; + } default: Fatal("Unknown script command in queue."); } @@ -241,12 +360,12 @@ void DebugScript::PrintPerformance(View * view, Screen * scr) // object_count clock delta_clock x Log10(x) y Log10(y) w Log10(w) Size(w) #ifdef QUADTREE_DISABLED - printf("%d\t%llu\t%llu\t%s\t%f\t%s\t%f\t%s\t%f\t%u\n", + printf("%d\t%llu\t%llu\t%s\t%s\t%s\t%s\t%s\t%s\t%u\n", now.object_count, (long long unsigned)now.clock, (long long unsigned)(now.clock - m_perf_last.clock), - Str(now.view_bounds.x).c_str(), Log10(Abs(now.view_bounds.x)), - Str(now.view_bounds.y).c_str(), Log10(Abs(now.view_bounds.y)), - Str(now.view_bounds.w).c_str(), Log10(now.view_bounds.w), + Str(now.view_bounds.x).c_str(), Str(Log10(Abs(now.view_bounds.x))).c_str(), + Str(now.view_bounds.y).c_str(), Str(Log10(Abs(now.view_bounds.y))).c_str(), + Str(now.view_bounds.w).c_str(), Str(Log10(now.view_bounds.w)).c_str(), (unsigned)Size(now.view_bounds.w)); #endif m_perf_last = now; diff --git a/src/debugscript.h b/src/debugscript.h index fd1a195..9e85b51 100644 --- a/src/debugscript.h +++ b/src/debugscript.h @@ -41,6 +41,11 @@ private: AT_PrintPerformance, AT_RecordPerformance, AT_DebugFont, + AT_ApproachBoundsZeno, + AT_ApproachBoundsLinear, + AT_SetBounds, + AT_QueryGPUBounds, // query bounds of Beziers when transformed to GPU + AT_ScreenShot, // take screenshot AT_Quit }; @@ -52,6 +57,7 @@ private: Real z; int iz; int loops; + Real w, h; std::string textargs; Action() : type(AT_WaitFrame), x(0), y(0), ix(0), iy(0), z(0), loops(0), textargs("") {} }; @@ -76,7 +82,7 @@ private: void PrintPerformance(View * view, Screen * scr); void ClearPerformance(View * view, Screen * scr); - void ParseAction(); + void ParseAction(View * view, Screen * scr); }; } diff --git a/src/document.cpp b/src/document.cpp index f8a1796..d01e075 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1145,28 +1145,43 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca stbtt_FreeShape(font, instructions); } -void Document::TransformObjectBounds(const SVGMatrix & transform) +void Document::TransformObjectBounds(const SVGMatrix & transform, ObjectType type) { + #ifdef TRANSFORM_BEZIERS_TO_PATH + for (unsigned i = 0; i < m_objects.paths.size(); ++i) + { + Path & p = m_objects.paths[i]; + p.m_bounds.x = transform.a * p.m_bounds.x + transform.e; + p.m_bounds.y = transform.d * p.m_bounds.y + transform.f; + p.m_bounds.w *= transform.a; + p.m_bounds.h *= transform.d; + } + return; + #endif + for (unsigned i = 0; i < m_count; ++i) { - TransformXYPair(m_objects.bounds[i].x, m_objects.bounds[i].y, transform); - m_objects.bounds[i].w *= transform.a; - m_objects.bounds[i].h *= transform.d; + if (type == NUMBER_OF_OBJECT_TYPES || m_objects.types[i] == type) + { + TransformXYPair(m_objects.bounds[i].x, m_objects.bounds[i].y, transform); + m_objects.bounds[i].w *= transform.a; + m_objects.bounds[i].h *= transform.d; + } } } 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.m_bounds.x += dx; - p.m_bounds.y += dy; - } - return; - #endif - + for (unsigned i = 0; i < m_objects.paths.size(); ++i) + { + Path & p = m_objects.paths[i]; + p.m_bounds.x += dx; + p.m_bounds.y += dy; + } + return; + #endif + for (unsigned i = 0; i < m_count; ++i) { if (type == NUMBER_OF_OBJECT_TYPES || m_objects.types[i] == type) diff --git a/src/document.h b/src/document.h index 94be6cc..d6f41f3 100644 --- a/src/document.h +++ b/src/document.h @@ -82,7 +82,7 @@ namespace IPDF void AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real scale, Real x, Real y); - void TransformObjectBounds(const SVGMatrix & transform); + void TransformObjectBounds(const SVGMatrix & transform, ObjectType type = NUMBER_OF_OBJECT_TYPES); void TranslateObjects(const Real & x, const Real & y, ObjectType type = NUMBER_OF_OBJECT_TYPES); void ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount, ObjectType type = NUMBER_OF_OBJECT_TYPES); diff --git a/src/eye_of_the_rabbit.script b/src/eye_of_the_rabbit.script index 12e6af9..db76eeb 100644 --- a/src/eye_of_the_rabbit.script +++ b/src/eye_of_the_rabbit.script @@ -1,7 +1,7 @@ # Test how well document scales back to original... -gpu +cpu lazy -debugfont off +debugfont on clearperf label start printperf diff --git a/src/foxzoom.script b/src/foxzoom.script new file mode 100644 index 0000000..bf191e0 --- /dev/null +++ b/src/foxzoom.script @@ -0,0 +1,12 @@ +label start +setbounds 0 0 1 1 +loadsvg svg-tests/fox-vector.svg +querygpubounds original.dat +screenshot original.bmp +loop 1950 pxzoom 0 0 -1 +loop 200 wait +debug hi +loop 1950 pxzoom 0 0 1 +querygpubounds transformed.dat +screenshot transformed.bmp +wait diff --git a/src/grid.script b/src/grid.script new file mode 100644 index 0000000..a053e9c --- /dev/null +++ b/src/grid.script @@ -0,0 +1,9 @@ +gpu +lazy +setbounds 0.5 0.5 1e-6 1e-6 +loadsvg svg-tests/grid.svg +screenshot grid1.bmp +loop 10 translate 1e-6 0 +loadsvg svg-tests/grid.svg +screenshot grid2.bmp +wait diff --git a/src/gridtest.script b/src/gridtest.script new file mode 100644 index 0000000..fce1fac --- /dev/null +++ b/src/gridtest.script @@ -0,0 +1,6 @@ +setbounds 0 0 1 1 +loadsvg svg-tests/grid.svg +loop 1000 wait +setbounds 0.5 0.5 1e-5 1e-5 +loadsvg svg-tests/grid.svg +loop 1000 wait diff --git a/src/main.cpp b/src/main.cpp index 67e2076..22a1f6b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,6 +21,8 @@ void sigfpe_handler(int sig) int main(int argc, char ** argv) { + + //Debug("Main!"); signal(SIGFPE, sigfpe_handler); #if REALTYPE == REAL_IRRAM @@ -36,9 +38,13 @@ int main(int argc, char ** argv) #ifndef __MINGW32__ feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); #endif - + #if REALTYPE == REAL_MPFRCPP + mpfr_set_default_prec(6); + #endif DebugRealInfo(); + + Document doc("","fonts/ComicSans.ttf"); srand(time(NULL)); diff --git a/src/main.h b/src/main.h index 5015044..bd43c12 100644 --- a/src/main.h +++ b/src/main.h @@ -80,6 +80,7 @@ void MainLoop(Document & doc, Screen & scr, View & view, int max_frames = -1) DebugScript script; scr.DebugFontInit("fonts/DejaVuSansMono.ttf", 12); + //scr.DebugFontInit("fonts/DejaVuSansMono.ttf", 18); scr.SetMouseHandler(RatCatcher); if (script_filename) @@ -143,20 +144,26 @@ void MainLoop(Document & doc, Screen & scr, View & view, int max_frames = -1) data_points++; } - scr.DebugFontPrintF("View Width = %s m\n", Str(view.GetBounds().w * VReal(22e-3)).c_str()); - scr.DebugFontPrintF("Similar size: %s\n", HumanScale(view.GetBounds().w * VReal(22e-3))); + + + + scr.DebugFontPrintF("Top Left: (%s,%s)\n", Str(view.GetBounds().x).c_str(),Str(view.GetBounds().y).c_str()); + scr.DebugFontPrintF("Width: %s\n", Str(view.GetBounds().w).c_str()); + scr.DebugFontPrintF("Zoom: %s %%\n", Str(VReal(100)/VReal(view.GetBounds().w)).c_str()); + //scr.DebugFontPrintF("Similar size: %s\n", HumanScale(view.GetBounds().w * VReal(22e-3))); - #if 0 + #if 1 scr.DebugFontPrintF("Rendered frame %lu\n", (uint64_t)frames); scr.DebugFontPrintF("Lazy Rendering = %d\n", view.UsingLazyRendering()); - if (cpu_frame > 0 && total_cpu_time > 0) + /*if (cpu_frame > 0 && total_cpu_time > 0) scr.DebugFontPrintF("[CPU] Render took %lf ms (%lf FPS) (total %lf s, avg FPS %lf)\n", cpu_frame*1e3, 1.0/cpu_frame, total_cpu_time,frames/total_cpu_time); if (gpu_frame > 0 && total_gpu_time > 0) scr.DebugFontPrintF("[GPU] Render took %lf ms (%lf FPS) (total %lf s, avg FPS %lf)\n", gpu_frame*1e3, 1.0/gpu_frame, total_gpu_time, frames/total_gpu_time); + */ if (real_frame > 0 && total_real_time > 0) - scr.DebugFontPrintF("[REALTIME] Render+Present+Cruft took %lf ms (%lf FPS) (total %lf s, avg FPS %lf)\n", real_frame*1e3, 1.0/real_frame, total_real_time,frames/total_real_time); + scr.DebugFontPrintF("[REALTIME] Render took %lf ms (%lf FPS) (total %lf s, avg FPS %lf)\n", real_frame*1e3, 1.0/real_frame, total_real_time,frames/total_real_time); - scr.DebugFontPrintF("View bounds: %s\n", view.GetBounds().Str().c_str()); + //scr.DebugFontPrintF("View bounds: %s\n", view.GetBounds().Str().c_str()); scr.DebugFontPrintF("type of Real == %s\n", g_real_name[REALTYPE]); //#if REALTYPE == REAL_MPFRCPP // scr.DebugFontPrintf("Precision: %s\nRounding: %s\n"); diff --git a/src/objectrenderer.cpp b/src/objectrenderer.cpp index 886871c..3f1bc41 100644 --- a/src/objectrenderer.cpp +++ b/src/objectrenderer.cpp @@ -390,6 +390,12 @@ void BezierRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id) glUniform1i(m_shader_program.GetUniformLocation("bezier_buffer_texture"), 0); glUniform1i(m_shader_program.GetUniformLocation("bezier_id_buffer_texture"), 1); m_ibo.Bind(); + + // To antialias the line... causes SIGFPE because why would anything make sense + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glEnable(GL_LINE_SMOOTH); + //glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glDrawElements(GL_LINES, (last_index-first_index)*2, GL_UNSIGNED_INT, (GLvoid*)(2*first_index*sizeof(uint32_t))); } @@ -429,7 +435,7 @@ void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CP continue; for (unsigned b = path.m_start; b <= path.m_end; ++b) { - Rect & bbounds = objects.bounds[b]; + Rect bbounds = view.TransformToViewCoords(objects.bounds[b]); Bezier & bez = objects.beziers[objects.data_indices[b]]; BezierRenderer::RenderBezierOnCPU(bez,bbounds,view,target,path.m_stroke); } diff --git a/src/path.cpp b/src/path.cpp index 0516e5b..cae1e68 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -126,7 +126,7 @@ bool Path::PointInside(const Objects & objects, const Vec2 & pt, bool debug) con vector & Path::FillPoints(const Objects & objects, const View & view) { - if (m_fill_points.size() != 0) + //if (m_fill_points.size() != 0) return m_fill_points; diff --git a/src/real.h b/src/real.h index e72709b..13395fb 100644 --- a/src/real.h +++ b/src/real.h @@ -41,6 +41,7 @@ #if REALTYPE == REAL_MPFRCPP #include + #endif //REALTYPE #if REALTYPE == REAL_IRRAM @@ -98,6 +99,10 @@ namespace IPDF 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());} inline Real RealFromStr(const char * str) {return Real(strtod(str, NULL));} + inline std::string Str(const mpfr::mpreal & a) {std::stringstream s; s << a; return s.str();} + inline size_t Size(mpfr::mpreal & a) {return a.get_prec();} + inline mpfr::mpreal Log10(const mpfr::mpreal & a) {return mpfr::log10(a);} + #elif REALTYPE == REAL_IRRAM typedef iRRAM::REAL Real; inline double Double(const Real & r) {return r.as_double(53);} @@ -138,8 +143,9 @@ namespace IPDF inline double Sqrt(double f) {return sqrt(f);} inline double Abs(double a) {return fabs(a);} inline double Log10(double a) {return log(a)/log(10.0);} - inline size_t Size(double a) {return sizeof(a);} inline size_t Size(float a) {return sizeof(a);} + inline size_t Size(double a) {return sizeof(a);} + // Don't cause an exception inline float ClampFloat(double d) diff --git a/src/svg-tests/create_grid.py b/src/svg-tests/create_grid.py new file mode 100755 index 0000000..b928991 --- /dev/null +++ b/src/svg-tests/create_grid.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +w = 800 +h = 600 +step = 1 +print '\n \ +\n \ +\n' % (w,h) + +print "\t" + +print "\t" + +print "" diff --git a/src/svg-tests/fox-vector.svg b/src/svg-tests/fox-vector.svg index cd3641c..cc30737 100644 --- a/src/svg-tests/fox-vector.svg +++ b/src/svg-tests/fox-vector.svg @@ -79,13 +79,13 @@ - + style="fill:#ffffff;fill-opacity:1;stroke:none" />--> + + + + + + diff --git a/src/transformationtype.h b/src/transformationtype.h index 4f27d5f..63a743e 100644 --- a/src/transformationtype.h +++ b/src/transformationtype.h @@ -2,8 +2,8 @@ #define _TRANSFORMATIONTYPE_H #ifdef QUADTREE_DISABLED -#define TRANSFORM_OBJECTS_NOT_VIEW -#define TRANSFORM_BEZIERS_TO_PATH +//#define TRANSFORM_OBJECTS_NOT_VIEW +//#define TRANSFORM_BEZIERS_TO_PATH #endif #endif diff --git a/src/view.cpp b/src/view.cpp index 09b7f2c..3de7fb4 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -25,11 +25,12 @@ using namespace std; * @param colour - Colour to use for rendering this view. TODO: Make sure this actually works, or just remove it */ View::View(Document & document, Screen & screen, const VRect & bounds, const Colour & colour) - : m_use_gpu_transform(USE_GPU_TRANSFORM), m_use_gpu_rendering(USE_GPU_RENDERING), m_bounds_dirty(true), m_buffer_dirty(true), + : m_use_gpu_transform(false), m_use_gpu_rendering(USE_GPU_RENDERING), m_bounds_dirty(true), m_buffer_dirty(true), m_render_dirty(true), m_document(document), m_screen(screen), m_cached_display(), m_bounds(bounds), m_colour(colour), m_bounds_ubo(), m_objbounds_vbo(), m_object_renderers(NUMBER_OF_OBJECT_TYPES), m_cpu_rendering_pixels(NULL), m_perform_shading(USE_SHADING), m_show_bezier_bounds(false), m_show_bezier_type(false), - m_show_fill_points(false), m_show_fill_bounds(false), m_lazy_rendering(true) + m_show_fill_points(false), m_show_fill_bounds(false), m_lazy_rendering(true), + m_query_gpu_bounds_on_next_frame(NULL) { Debug("View Created - Bounds => {%s}", m_bounds.Str().c_str()); @@ -109,6 +110,14 @@ void View::Translate(Real x, Real y) */ void View::SetBounds(const Rect & bounds) { + #ifdef TRANSFORM_OBJECTS_NOT_VIEW + ObjectType type = NUMBER_OF_OBJECT_TYPES; + #ifdef TRANSFORM_BEZIERS_TO_PATH + type = PATH; + #endif + SVGMatrix transform = {Real(m_bounds.w)/bounds.w, 0, Real(m_bounds.x) - bounds.x, 0,Real(m_bounds.h)/bounds.h, Real(m_bounds.y) - bounds.y}; + m_document.TransformObjectBounds(transform, type); + #endif m_bounds.x = bounds.x; m_bounds.y = bounds.y; m_bounds.w = bounds.w; @@ -512,6 +521,11 @@ void View::RenderRange(int width, int height, unsigned first_obj, unsigned last_ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) { + if (m_query_gpu_bounds_on_next_frame != NULL) + { + fprintf(m_query_gpu_bounds_on_next_frame,"# View: %s\t%s\t%s\t%s", Str(m_bounds.x).c_str(), Str(m_bounds.y).c_str(), Str(m_bounds.w).c_str(), Str(m_bounds.h).c_str()); + } + //m_objbounds_vbo.Invalidate(); m_objbounds_vbo.SetType(GraphicsBuffer::BufferTypeVertex); m_objbounds_vbo.SetName("Object Bounds VBO"); @@ -549,6 +563,11 @@ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) Float(obj_bounds.y + obj_bounds.h) }; + if (m_query_gpu_bounds_on_next_frame != NULL) + { + fprintf(m_query_gpu_bounds_on_next_frame,"%d\t%f\t%f\t%f\t%f\n", id, Float(obj_bounds.x), Float(obj_bounds.y), Float(obj_bounds.w), Float(obj_bounds.h)); + } + obj_bounds_builder.Add(gpu_bounds); } #else @@ -556,6 +575,10 @@ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) { Path & path = m_document.m_objects.paths[i]; Rect & pbounds = path.GetBounds(m_document.m_objects); // Not very efficient... + //TODO: Add clipping here + //if (!pbounds.Intersects(Rect(0,0,1,1)) || pbounds.w < Real(1)/Real(800)) + // continue; + for (unsigned id = path.m_start; id <= path.m_end; ++id) { if (id < first_obj || id >= last_obj) @@ -580,6 +603,11 @@ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) }; obj_bounds_builder.Add(gpu_bounds); //Debug("Path %d %s -> %s via %s", id, m_document.m_objects.bounds[id].Str().c_str(), obj_bounds.Str().c_str(), pbounds.Str().c_str()); + + if (m_query_gpu_bounds_on_next_frame != NULL) + { + fprintf(m_query_gpu_bounds_on_next_frame,"%d\t%f\t%f\t%f\t%f\n", id, ClampFloat(obj_bounds.x), ClampFloat(obj_bounds.y), ClampFloat(obj_bounds.w), ClampFloat(obj_bounds.h)); + } } GPUObjBounds p_gpu_bounds = { ClampFloat(pbounds.x), @@ -590,6 +618,12 @@ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) obj_bounds_builder.Add(p_gpu_bounds); } #endif + if (m_query_gpu_bounds_on_next_frame != NULL) + { + if (m_query_gpu_bounds_on_next_frame != stdout && m_query_gpu_bounds_on_next_frame != stderr) + fclose(m_query_gpu_bounds_on_next_frame); + m_query_gpu_bounds_on_next_frame = NULL; + } m_objbounds_vbo.UnMap(); } /** @@ -660,3 +694,14 @@ void View::SaveGPUBMP(const char * filename) m_screen.ScreenShot(filename); SetGPURendering(prev); } + +void View::QueryGPUBounds(const char * filename, const char * mode) +{ + m_query_gpu_bounds_on_next_frame = fopen(filename, mode); + Debug("File: %s", filename); + if (m_query_gpu_bounds_on_next_frame == NULL) + Error("Couldn't open file \"%s\" : %s", filename, strerror(errno)); + ForceBoundsDirty(); + ForceBufferDirty(); + ForceRenderDirty(); +} diff --git a/src/view.h b/src/view.h index 4bcff89..712b95a 100644 --- a/src/view.h +++ b/src/view.h @@ -8,14 +8,13 @@ #include "path.h" #include "transformationtype.h" -#define USE_GPU_TRANSFORM true +#define USE_GPU_TRANSFORM false #define USE_GPU_RENDERING true #define USE_SHADING !(USE_GPU_RENDERING) && true -#ifdef TRANSFORM_BEZIERS_TO_PATH + #include "gmprat.h" -#include "paranoidnumber.h" -#endif + namespace IPDF { @@ -73,6 +72,8 @@ namespace IPDF void ForceBufferDirty() {m_buffer_dirty = true;} void ForceRenderDirty() {m_render_dirty = true;} + void QueryGPUBounds(const char * filename, const char * mode="r"); + void SetLazyRendering(bool state = true) {m_lazy_rendering = state;} bool UsingLazyRendering() const {return m_lazy_rendering;} @@ -89,6 +90,8 @@ namespace IPDF float x0, y0; float x1, y1; } __attribute__((packed)); + + void PrepareRender(); // call when m_render_dirty is true void UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj); // call when m_buffer_dirty is true @@ -127,6 +130,8 @@ namespace IPDF bool m_show_fill_bounds; bool m_lazy_rendering;// don't redraw frames unless we need to + + FILE * m_query_gpu_bounds_on_next_frame; #ifndef QUADTREE_DISABLED diff --git a/tools/analysis.ipynb b/tools/analysis.ipynb index a91b2f4..2fc7ea7 100644 --- a/tools/analysis.ipynb +++ b/tools/analysis.ipynb @@ -24,7 +24,7 @@ ] } ], - "prompt_number": 1 + "prompt_number": 2 }, { "cell_type": "code", @@ -35,7 +35,7 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 2 + "prompt_number": 3 }, { "cell_type": "markdown", @@ -120,6 +120,13 @@ "[*****************67%***** ] 2 of 3 complete" ] }, + { + "metadata": {}, + "output_type": "display_data", + "text": [ + "'Failed to build GMPrat'" + ] + }, { "output_type": "stream", "stream": "stdout", @@ -681,37 +688,17 @@ "metadata": {}, "outputs": [ { - "metadata": {}, - "output_type": "display_data", - "text": [ - "'Precision vs Zoom of \"svg-tests/fox-vector.svg\" using single'" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - " \r", - "[****************100%******************] 100 of 100 complete" - ] - }, - { - "metadata": {}, - "output_type": "display_data", - "png": "iVBORw0KGgoAAAANSUhEUgAAAlsAAAHNCAYAAAApEr6yAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3XtYVWXe//HPJjRT8IAiGKh4JjwyleZkSYNYTUqaM4x4\nGBo7TOMhc5pDNU5ipWKHMa2xx8qMPIQ2/kKaGjQnMfNEU5ajWFhhoaKlgKEmKHx/f/S0n1BOKsu9\nwffrurgu9rrXuu/vvvcCPqy19touMzMBAADAET6eLgAAAKA+I2wBAAA4iLAFAADgIMIWAACAgwhb\nAAAADiJsAQAAOIiwBUlSWFiY/v3vf59XHy+//LIuueQSNW3aVJ9++mktVQYAuJCKi4vl5+enhg0b\n6q9//auny6kXCFseFBYWpsaNG8vf318BAQEaMmSI9u7d65FaXC6XXC7Xefdz7bXX6ttvv1W3bt3c\ny+bMmaM2bdqoWbNmuuOOO1RSUlLp9j4+PvLz85O/v7/8/f11991313js/Px8DR8+XH5+fgoLC9Or\nr75a6bo/BMMfxvH399e7775b47FefPFFdenSRf7+/rr55puVl5dX6bq7du3Sz372MzVv3lxdunRR\nampqjfsqLCxUQkKCgoKCFBQUpOnTp5fbdtOmTerbt6+aNm2q3r17a+PGjeXaZ8yYofbt26tZs2aK\nj49XUVGRu23fvn269dZb1bJlS7Vt21YLFiwot+0bb7yhHj16yN/fX9dee6127drlbisuLtaUKVMU\nEhKigIAATZgwQadOnfKK5/z888+rc+fOatasma6++upy7cXFxRo3bpyaNWumNm3aaM6cOe62w4cP\n69prr1WrVq3UrFkzRUZGnlH32ahqrA0bNpTb9/z9/eXj46PXX3+9Rn1XN7+n1+Gtr1V93D937typ\nqKgoNW/eXG3bttVjjz1Wrn3ZsmVq3769/Pz8NHz4cBUUFLjb/vSnP6ldu3Zq2rSpQkND9fvf/75c\n3WerqrG6d+9ebv9r0KCBYmNjJUmXXnqpjh49qtGjR9fK3wVIMnhMWFiY/fvf/zYzsxMnTti4ceNs\n2LBhHq/lXC1atMgGDBhQbll6eroFBQVZVlaWFRQUWFRUlD3wwAOV9uFyueyLL744p/FHjhxpI0eO\ntGPHjtl7771nzZo1s507d1Za63XXXXdO46xbt85at25tWVlZVlJSYr/73e9s4MCBFa578uRJ69Kl\ni82ZM8fKysrsnXfesSZNmlh2dnaN+rr99tstLi7OvvvuO9uzZ4916tTJFi1aZGZmhw8ftoCAAPvH\nP/5hZWVltmTJEmvRooUVFBSYmdnLL79s4eHhtnfvXjt69KjdeuutlpCQ4O47KirKpkyZYqdOnbKP\nP/7YAgICbN26dWZmlp2dbU2bNrWNGzdaaWmpzZo1yzp37mylpaVmZpaYmGjXX3+9FRQU2DfffGPX\nXHONTZs2zePPedu2bebn52cffvihmZk999xzFhgYaGVlZWZm9sADD9j1119vhYWFtmvXLgsODrb0\n9HQz+/5n8JNPPnE/x9TUVGvQoIEVFRWdxd7xf6oa63QZGRnm7+9vx48fr7bf6ub3dN76WtXH/dPM\nLDIy0qZOnWplZWX2+eefW5s2bSwtLc3MzHbs2GH+/v62YcMGO3r0qI0aNcpGjhzp3vaTTz5x72/7\n9u2z7t2723PPPVftPlGR6sY6XYcOHWzx4sXllt1+++02derUcxof5RG2POj0gPPmm29a165d3Y8L\nCwtt7NixFhgYaO3bt7fHHnvM/Udj2rRpNmbMGPe6OTk55nK53L9sBg4caH/961/t2muvNX9/fxs8\neLAdOnTIvf4rr7xi7dq1s5YtW9qMGTPK1bJ161a78sorrWnTphYUFGS///3va/R8Kgpb8fHx9pe/\n/MX9+J133rHg4OBK+3C5XPbZZ5/VaLwfO3r0qDVs2NB2797tXvbrX/+60mBXUa01df/999uECRPc\nj/fv319pSPzvf/9rfn5+5ZYNHjzY/vrXv9aor1atWtn777/vbp85c6Y7JL7xxhsWERFRru+uXbva\nwoULzcxsxIgR9sQTT7jbNm3aZI0aNbLvvvvOioqKzOVy2TfffONuv/vuu23s2LFmZvbMM8/YLbfc\n4m4rKyuzyy67zN555x0zM7vqqqvstddec7cvW7bM2rZt6/HnvHTpUuvbt6+77ejRo+ZyuezAgQNm\nZnb55Zfb22+/7W5/+OGHK/wDVFpaamlpadamTRsrLi52z8GsWbOsU6dO1rJlS4uLi7P8/Pwztv1B\nTccy+/6P2rhx4yrt68eqm9/TeetrVR/3TzOzSy+91Hbt2uV+/Mtf/tKSkpLMzOzBBx+00aNHu9s+\n//xza9iwoR09etROt3fvXuvZs6elpqa6l23evNn69+9vzZs3t969e1tGRsYZ2/3gbMaqLOwTtmoP\npxE9zP7305KOHz+u5cuXq3///u62SZMmqaioSDk5OVq/fr1eeeUVLVq0SJJqdGj31Vdf1csvv6yv\nv/5aJSUlevLJJyVJWVlZGj9+vJYuXar9+/fr8OHD5U5fTp48WVOmTNGRI0f0xRdfKC4uzt3Wu3dv\npaSk1Pj5ZWVlqXfv3u7HvXr10sGDB8sdzj7d9ddfrzZt2mjEiBH68ssvazROdna2fH191blz53K1\n7ty5s8L1XS6Xtm3bpsDAQHXr1k2PPfaYSktLazSWy+Vyv26SVFZWJknasWNHjbYvKytz11WTvk5v\nr2qc6vouLi7W7t273csr67uibc2syrr27t1b7jSQJ57zddddp5ycHGVmZqq0tFQvvfSSIiMjFRQU\npIKCAuXl5Z2xP56+j/Tq1UuXXXaZbr/9dr3++utq2LChJGnevHlKS0vTu+++q7y8PLVo0UITJkyo\nsKaajiVJx44d08qVK5WQkFDpc6xOdXPkja9Vfd0/Bw8erOTkZJ06dUqffPKJNm/erEGDBkk68/dh\nx44ddemllyo7O9u9LCkpSf7+/mrbtq2GDBmiW2+9VdL3p1WHDBmihx9+WAUFBXryySc1YsQIHTp0\nqMLnVJOxfpCcnKxf/OIXuuyyyyrsC7XgAgY7nKZ9+/bm5+dnzZs3twYNGlhISIj997//NTOzU6dO\nWcOGDcv9h7RgwQKLiooys+qPbEVFRdmMGTPc7fPnz7ebbrrJzMymT59u8fHx7rZjx45Zw4YN3Ue2\nrr/+eps2bVq5/yproqKjRZ06dbLVq1e7H5eUlJjL5bIvv/yywj42bNhgJ0+etMLCQps4caL16NHD\nTp06Ve3Y77777hlHzJ5//nn3fJ3uiy++sD179pjZ9//pRkRE2KxZs6odx8xs7dq1FhgYaNu3b7fj\nx4/b3XffbT4+PpaSknLGuiUlJdaxY0d7/PHHraSkxFavXm0NGzZ0vxbV9TVmzBgbMWKEFRUV2e7d\nu61jx47WqFEjMzM7dOiQtWjRwlJSUqykpMRefvll8/HxsXvuucfMzF588UXr2rWr7dmzxwoLC23o\n0KHmcrlsy5YtZmY2YMAAmzRpkp04ccI++OADCwgIsPDwcDMz27VrlzVp0sQyMjKsuLjYHnnkEfPx\n8XH/hz516lS79tpr7ZtvvrG8vDzr27ev+fj42IEDBzz6nM2+/znx9fU1X19fCwwMdB+F+Oqrr8zl\n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\nREQoLi5OERER8vX11fz586s8xQgAAFCfVRu2BgwYUOmtG9auXVvh8oceekgPPfTQ+VUGAABQD3AH\neQAAAAcRtgAAABxE2AIAAHAQYQsAAMBBhC0AAAAHEbYAAAAcRNgCAABwEGELAADAQYQtAAAABxG2\nAAAAHFTtx/UAF0pBQYGnS/AqLVq08HQJ9dqpU6dUVFTk6TLOSklJiWM/J40bN9all17qSN/AxY6w\nBa8RGBioqVOnntU2//znP/XBBx+4H0+bNq1ce0lJiTZs2KDo6Oga97ly5Urt2LHD/bh3794aNmzY\nWdV1vubOnUv4dNjGjRv197//XREREZ4upVovvviiJCkgIEBz586t9f4LCgrUoUMH3XfffbXeNwDC\nFrxMYmJijddt1aqVpk+frtWrV7uXtWzZstw6bdu21aeffqrGjRvXuN8//OEPKi4udj9+/fXX9cAD\nD7gfHzp0qMZ9navk5GTHx4D0q1/9SiNGjPB0GVVq1aqVVqxYoSuvvFITJkw4q5+RmsrJydGqVatq\nvV8A3yNsoc55+umn9f7771cZegoLC5WUlKTc3Nyz7t/Pz09+fn7ux3feeafuvPNO9+PRo0dLkm66\n6SZdcsklkqRRo0ad9ThAZZYtW6bdu3crOzv7goR7AM4ibKFOue222zRr1qxqT3fccccdeu655xyp\nYenSpZKk999/X6WlpZKk/v37S5Jat27NEQKcs08//VS333675syZo+uuu05t27b1dEkAagFhC3XC\n1q1bde+99+r111/X5ZdfXul6BQUFmjRpklauXOl4TVdffbX7+82bN0uSDh48qH79+kmSnnnmGfXs\n2VOXXXaZ47WgbsvMzNScOXPUoEED974EoP4gbMHrvfLKK7rkkku0devWatedMWOGnnrqqQtQVcWC\ngoLcdS5ZskQvvfSSOnTooD//+c8eqwne64033tCKFSt04403at68eQoMDKx2m6KiIo0fP16SNGDA\nAP32t791ukwA54mwBa+2bds2FRcX66677qpyvRMnTujKK6/Uzp07L1Bl1RszZozGjBmjjIwMBQQE\n6PPPP+ft9VBpaam+/fZbderUSffdd58WL158Vtv/5Cc/0e7duyVJKSkp7n2rSZMmatiwoRMlAzhP\nhC14rWXLlunQoUO69957q1yvtLRUs2fP1qZNmy5QZWcnKipK+fn5SkxMlMvlknTmLSpwcXjllVeU\nk5MjM1N+fv459fFD0JKkkSNHauTIke59i/0K8E6ELXitJUuW6K233qp2vdDQUPdRI2+WmJioY8eO\n6cSJE2pp//tUAAAgAElEQVTVqpUyMzPVsWNHT5eFC6RVq1Z65ZVXFBsbq+bNm9dq34mJiSoqKlJE\nRISysrJqtW8A54+wBa+Unp6uSZMmVbnOkSNHlJSUpLy8vAtU1flr0qSJmjRpokOHDun+++/X0KFD\nFRUV5emy4JBly5bpiy++0K5duxy/hYO/v782bdqkRx99VA8++KB8ffn1DngLPhsRXmn58uXu2ylU\nJiEhoU7f8fqpp55STk6OtmzZ4ulSUMv27Nmj/v37q2PHjho7dqz7diFOa968uW6//XZFR0dr5syZ\nF2RMANXjXx94ne3bt6tp06aVnmopLCzU5MmTlZqaeoErq32/+c1vNHnyZDVu3Fi9evXydDk4T5mZ\nmfr73/+uEydOeOwWDm3bttX69euVlpam1NTUC/5RUwDOxJEteJW3335bW7ZsqfLz3x555BElJSVd\nwKqcNXfuXG3ZskVr1671dCk4R6tXr9bYsWOVnZ2tpKQkLV++3NMlKTY2Vg0aNNCMGTM8XQpw0ePI\nFrzKrl27dMstt1TYVlxcrKuvvlrbt2+/wFU57+6779bEiRM1aNAgT5eCGiorK9ORI0fUqVMn3XPP\nPWd9C4cL4ZZbblGzZs2UkpKikSNHeroc4KLFkS14ld27d6tTp05nLDczJSUlaf369R6o6sK4+eab\n9eijj3q6DNTAsmXL9Oijj2ru3LnKz8/36uujBgwYIJfLpaefftrTpQAXLcIW6oSgoCD94Q9/UIsW\nLTxdimNuueUWTZ8+3dNloBqtWrVSo0aNNHnyZCUmJnq6nBr51a9+pUGDBunZZ5/1dCnARYnTiPAq\nzzzzTLnHRUVFSkpK0tdff+2hii6s4uJi3X///Z4uA6d59dVXtWfPHu3YscPxWzg4pUePHtq+fbuW\nLl2q0aNHe7oc4KLCkS14tdGjR1d7v636xMfHR4GBgXXq3mH1WV5envr376+wsDDFx8dfsFs4OGXU\nqFHq0qWLHn/8cU+XAlxUOLIFr3TkyBHdd999SktL83QpF5TL5VLDhg1VXFzs6VIuapmZmXr++ed1\n6NAhj93CwSl9+/bV3r17lZaWptjYWE+XA1wUOLIFr5SYmMhb1nHBvfPOO+5bOCQmJtaLe7lV5Lbb\nbpPL5dLs2bM9XQpwUeDIFrxKcXGxfvrTn+qDDz7wdCke8/vf//6Ma9fgnB9u4RAREaH4+HivvIWD\nE4YOHSp/f3+tXLlSP/nJTzxdDlCvEbbgVZKSkrRmzRpPl4GLxGuvvaYdO3bIzJSbm3vRfZ5gVFSU\nli1bpnnz5ql9+/aeLgeoty6u3yzweklJSRzVkVRQUKBWrVp5uox67eTJk/r222/l4+OjFi1a1Inb\nIhw9elTp6em13u/hw4c1Z86cWu8XwPcIW/Aq3333XY3XPXLkiN588029+eabkqR58+apZcuW5dZZ\ntGiRxo0bp7y8PAUHB9dqrU7q0KGDcnJyPF0GvMyYMWO0ZMkST5cB4CxxgTzqrISEBHXs2FFLly7V\n0qVLzwhaM2fOVIcOHTxUHQAA3+PIFuqUjz/+WB988IEWLFigrVu3VrpeamqqevTooauvvvoCVgcA\nwJk4soU6wcw0duxYZWZmqmPHjlUGrRkzZqhBgwbcQwgA4BU4sgWvd/z4cbVr165GH5OSkpKigQMH\nasCAARegMgAAqseRLXi1/Px8Pf744zUKWk8//bRcLle5oPXkk08qOjrayRIBAKgSR7bg1WJiYrRx\n48Zq13v22Wc1aNAg9ejRo9zyJ554Qn/5y1+cKg8AgGoRtuCV8vLyNHv27BrdSX7p0qUKCAg4I2ht\n3bpVcXFxTpUIAECNcBoRXunjjz/WjTfeWO16jz/+uLp06aJRo0ad0fbCCy/opZdecqI8AABqjLAF\nr7N9+3b961//0s0331zlemlpaercubP69u17Rtvx48fl5+fnVIkAANQYYQte5e2339aWLVs0d+7c\nKtebPXu2XC6XbrvttgrbP/vsM/Xs2dOJEgEAOCtcswWv8umnn2rw4MFVrrNy5Ur169dPUVFRFbYX\nFRVpwoQJ2rBhgwMVAgBwdghbqFPmzZunVq1aVRq0PvnkE6WkpBC0AABeg9OI8CqfffaZOnXqVGHb\nggULNHDgwAovhv9BVlZWpUEMAABPIGzBq/Tp00eXXHLJGcuXLVumxo0bq3fv3pVuu2rVKn311VeE\nLQCAV+E0IrzK7bfffsayv/3tb7r22mvVr1+/SrdbunSpWrZsqfvuu8/B6gAAOHsc2YJXe/PNNxUa\nGlpl0Nq8ebPy8/N10003XcDKAACoGcIWvNYTTzyh0tLSKu8Cv2jRIu3Zs0eTJk26gJUBAFBzhC14\npVWrVikyMlKxsbFntJ08eVIFBQUKCAiQJMXHx1/o8gAAqDGu2YLXefbZZ9W8eXPdeuut5ZZv3bpV\n6enpkiQzU35+vifKAwDgrBC24FVefPFF9e/fX1deeaUk6YsvvnB/HE9CQoIeeughNWzYUP7+/p4s\nEwCAGiNswau89tprevjhh5WXlydJCg4O1rx589ztq1evPus+P/7441qr70JatmxZucdV3V+sPlu7\ndq0GDRpU6/1+/fXXKi4uVtu2bWu9bwD4McIWvMbGjRtlZrXe73333aeWLVvWer9O69ixY7nH/fv3\nl/T9B3AHBgZ6oqQLbt26dbrtttv07bff1nrfu3bt0qFDh+pM2Nq5c+c5/bMBwPMIW/AaVd3e4WJ0\nzTXXlHu8efNmSdKQIUMUEhKiJ598st6fTj18+LCKioo8XYZXOHr0qA4dOuTpMgCcA96NCNQx//zn\nPzV48GB9+OGHni4FAFADhC2gDhoxYoSefPJJR06vAQBqF2ELqKPeeOMNDRw40NNlOGrnzp1q166d\np8vwCunp6erZs6enywBwDqoMWydOnFC/fv3Up08fRURE6MEHH5Qk5efnKyYmRl27dtXgwYNVWFjo\n3mbWrFnq0qWLwsPDtWbNGmerB1Cv7dixQ+3bt/d0GV7hX//6l3r16uXpMgCcgyrDVqNGjbRu3Tp9\n9NFH2r59u9atW6f33ntPSUlJiomJUXZ2tqKjo5WUlCRJysrK0vLly5WVlaX09HSNHz9eZWVlF+SJ\nAKhfQkJC9Nprr3m6DK9wzTXXaMuWLZ4uA8A5qvY0YuPGjSVJJSUlKi0tVYsWLZSWlqaEhARJ399o\nMjU1VdL3H7ESHx+vBg0aKCwsTJ07d1ZmZqaD5QOojxYvXqxFixZ5ugyvsGbNGk2ZMsXTZQA4D9WG\nrbKyMvXp00dBQUG64YYb1L17dx08eFBBQUGSpKCgIB08eFCStH//foWGhrq3DQ0N1b59+xwqHbi4\nRUVFadu2bZ4uo9Zt3LhR3377rQYPHuzpUrzCZ599ph49eni6DADnodr7bPn4+Oijjz7SkSNHdOON\nN2rdunXl2l0ul1wuV6XbV9aWmJjo/j4qKkpRUVE1qxhAvRYTE6Pjx497ugyvsXHjRo0fP97TZQAX\nlYyMDGVkZNRafzW+qWmzZs10yy236IMPPlBQUJAOHDig4OBg5eXlqXXr1pK+v8YiNzfXvc3evXsV\nEhJSYX8/DlsAzs7KlSs1ffp0T5dRq0pLSzVx4kSC1v86ceKEunfvrs8//9zTpQAXndMPAp3v79sq\nTyMeOnTI/U7D7777Tm+//bYiIyMVGxur5ORkSVJycrKGDRsmSYqNjVVKSopKSkqUk5Oj3bt3uz9E\nGEDtqY/v0nvsscd05513eroMr1BcXKzZs2frv//9r6dLAVALqjyylZeXp4SEBJWVlamsrExjx45V\ndHS0IiMjFRcXp4ULFyosLEwrVqyQJEVERCguLk4RERHy9fXV/PnzqzzFCODs9ezZU5s2bapXH9Uz\nfPhwLVq0SM2bN/d0KV4hPDxcO3fudL9BCUDdVmXY6tmzZ4UfCRIQEKC1a9dWuM1DDz2khx56qHaq\nA1DO448/rvT09HoRtD755BN9+OGHevPNN/XYY48RtPT9PQxnz56t6OhoghZQj/BB1EAdUVJSoiNH\njigwMNDTpZy3/v37KyoqSrfeequWLl3q6XK8xm9/+1vNnz+/XrzGAP4PYQuoI5o1a6bvvvvO02Wc\ns08//VTZ2dl67LHHtHXrVk+X41Xy8/M1YcIEbuIK1FOELaAOeOmll/TSSy95uoxzNnbsWF155ZXq\n1KkTQes0kyZNUqNGjTRv3jxPlwLAIYQtwMtlZmbKx8dH8fHxni6lRsrKynTkyBFJUqdOnSR9f+QG\n5ZmZkpKSNHXqVPdNogHUT4QtwMuNGzdOO3bs8HQZNfLqq68qOztbZiaJkFWZN954Qx9++KGuvfZa\nghZwESBsAV7stttu03vvvefpMqrUqlUr9/cLFizQ5MmTeWdhFbKysrRv3z5NmjRJAQEBni4HwAVA\n2AK8VGhoqFavXu3R4PLRRx8pKyvL/fjw4cPasmVLuXUOHTp0ocuqs/7973/r7bffVlJSkqdLAXAB\nEbYAL/Xvf/9b3bp1q9U+09PTz+pjJ4YMGaLo6Gj348jISE2aNKlWa7pYrF+/Xnl5eQQt4CJE2AK8\n1K9//WtPl6C0tDSlpaV5ugw1adJEPXr0KLcsMzPT3da9e/ez7rOoqEiPPvpordRXnY8++kh/+tOf\nNH/+/AsyHgDvQtgCvBS3SPg/zz33nLp3767rr7/evWzJkiWSpCNHjmjLli1q0qSJ/ud//qfGfa5f\nv/6CnAJ96623tH//fl5P4CJG2ALg9X73u99p4sSJ6tWrl/satjFjxrjbJ0yYoIKCAk2fPl333nuv\nWrRoUaN+jx075ki9P7Zz506NGjXK8XEAeC8fTxcAADXx7LPP6umnn9a6desqbG/RooWuv/56zZ07\nV6+//nqN+kxISKjNEs8wffp09e7dWyEhIY6OA8C7EbYA1BnTpk3Txo0bKz39d8MNNygxMVEFBQXl\nbknhKTNnztTgwYM9XQYADyNsAagzXC6Xpk6dqr/+9a/atGlTpeuNGzdOhw4d0sSJE/XVV19Vut51\n112n1NRUJ0oFADfCFoA657nnntNHH31U7Z31Z82aVeWtFiZPnqyJEyfWdnkAUA5hC0CdNH78eD39\n9NPlbrp6On9/f82fP1+DBg3S/v37K1xn27ZtmjlzpsrKymq9xqKiIv3xj3+s9X4B1C2ELQB11osv\nvqh169Zp48aNVa63dOlSLVq0qMK2wMBAHTlyRCUlJbVen6+vr5o1a6bDhw/Xet8A6g7CFoA6bcKE\nCXrllVdUWFhY6TpBQUEyM+3bt6/C9tmzZ6tDhw46fvx4rdbm4+Oj5s2b6+DBg7XaL4C6hbAFoM5b\nsGCBnn76aa1fv77SdaZOnarw8PBK2/Py8vT444/rm2++qdXaJk6cqPT0dK1YsaJW+wVQdxC2ANQL\n06ZN07p166o8wvXll1/q3nvvrbT9gQce0NChQ2u9tt///vcqKyvTe++9V+t9A/B+hC0A9YLL5VJi\nYqL+9Kc/afPmzRWuExAQoD59+uijjz6qsL1Ro0basmWLRo8erTlz5tRqfSNHjtTDDz9cq30CqBsI\nWwDqleeff14ffPCBPvnkk3PuY+nSpfr5z3+u2267rRYr+/4u+GPHjq3VPgF4P8IWgHpn4sSJSkpK\nqvC2EOPGjdNvfvObavvo1q2b/v73v6tfv37asmVLrdQVERGhadOmqV+/fvrggw9qpU8A3o+wBaBe\nevnll/XOO++cV1Bq06aNtm7dqs8//1xjx47VgQMHzruuzp07a+vWrdqxY4fGjh1b5TVmAOoHwhaA\nemvixIl64YUXdOTIkXLLt23bpqioqBr3M3r0aC1evFhDhw7VsGHDVFBQcN61JSQkaPHixerfv78K\nCgp06tSp8+4TgHfy9XQBAOCkhQsXKjExUdHR0bruuuvOq6/3339fn332mebOnSuXy6Wbb75Zffv2\nPa8+d+3apcTERLlcLrVp00Z33333efUHwPtwZAtAvffwww9r9erVOnbs2Hn31blzZyUmJmrixIla\ntmyZAgMDz7vPxMRETZkyRVdccYVSUlLOuz8A3oWwBaDe8/Hx0WOPPaZJkyZp69attdJny5Yt9fTT\nT+vrr7/W6NGjNXr0aC1btkzLli07p/6aNm2q6667ToWFhUpISNCyZctUXFxcK7UC8CxOIwK4aLz0\n0kuaO3euAgICaq1Pl8ulpUuXSpL7Yvz+/fufsd7AgQOVlJRUbX/33HOP7rrrLr3//vu65ZZbdO21\n12r69Om1Vi+AC4+wBeCiMnnyZMfudXXNNddIUoU3Vc3IyFC/fv3cj5955pkq+/Lx8dHMmTO1evVq\nde/eXYsWLeIDrYE6irAFeCmnAsH06dPVsWNHR/quKxYvXqz27dtr3rx5Sk1NvWDjdu3a1f39j4NX\ndW666aazWh+AdyFsAV4oJyfH0yXUe4899phHx1+8eLFHxwdw4XCBPAAAgIMIWwAAAA7iNCI8zs/P\nT//5z380evRoT5cCAECtc5mZXfBBXS55YFgAAICzdr65hdOIAAAADiJsAQAAOIiwBQAA4CDCFgAA\ngIMIWwAAAA4ibAEAADiIsAUAAOAgwhYAAICDCFsAAAAOImwBAAA4iLAFAADgIMIWAACAgwhbAAAA\nDiJsAQAAOIiwBQAA4CDCFgAAgIMIWwAAAA4ibAEAADiIsAUAAOAgwhYAAICDCFsAAAAOImwBAAA4\niLAFAADgIMIWAACAgwhbAAAADqpR2CotLVVkZKSGDh0qScrPz1dMTIy6du2qwYMHq7Cw0L3urFmz\n1KVLF4WHh2vNmjXOVA0AAFBH1ChszZ07VxEREXK5XJKkpKQkxcTEKDs7W9HR0UpKSpIkZWVlafny\n5crKylJ6errGjx+vsrIy56oHAADwctWGrb179+qtt97SnXfeKTOTJKWlpSkhIUGSlJCQoNTUVEnS\nqlWrFB8frwYNGigsLEydO3dWZmamg+UDAAB4t2rD1pQpU/TEE0/Ix+f/Vj148KCCgoIkSUFBQTp4\n8KAkaf/+/QoNDXWvFxoaqn379tV2zQAAAHWGb1WN//znP9W6dWtFRkYqIyOjwnVcLpf79GJl7RVJ\nTEx0fx8VFaWoqKhqiwUAAHBaRkZGpbnnXFQZtjZt2qS0tDS99dZbOnHihL799luNHTtWQUFBOnDg\ngIKDg5WXl6fWrVtLkkJCQpSbm+vefu/evQoJCamw7x+HLQAAAG9x+kGg6dOnn1d/VZ5GnDlzpnJz\nc5WTk6OUlBT97Gc/0+LFixUbG6vk5GRJUnJysoYNGyZJio2NVUpKikpKSpSTk6Pdu3erb9++51Ug\nAABAXVblka3T/XBK8IEHHlBcXJwWLlyosLAwrVixQpIUERGhuLg4RUREyNfXV/Pnz6/yFCMAAEB9\n57If3mJ4IQd1ueSBYQEAAM7a+eYW7iAPAADgIMIWAACAgwhbAAAADiJsAQAAOIiwBQAA4CDCFgAA\ngIMIWwAAAA4ibAEAADiIsAUAAOAgwhYAAICDCFsAAAAOImwBAAA4iLAFAADgIMIWAACAgwhbAAAA\nDiJsAQAAOIiwBQAA4CDCFgAAgIMIWwAAAA4ibAEAADiIsAUAAOAgwhYAAICDCFsAAAAOImwBAAA4\niLAFAADgIMIWAACAgwhbAAAADiJsAQAAOIiwBQAA4CDCFgAAgIMIWwAAAA4ibAEAADiIsAUAAOAg\nwhYAAICDCFsAAAAOImwBAAA4iLAFAADgIMIWAACAgwhbAAAADiJsAQAAOIiwBQAA4CDCFgAAgIMI\nWwAAAA4ibAEAADiIsAUAAOAgwhYAAICDCFsAAAAOImwBAAA4iLAFAADgIMIWAACAgwhbAAAADiJs\nAQAAOIiwBQAA4CDCFgAAgIMIWwAAAA4ibAEAADiIsAUAAOAgwhYAAICDCFsAAAAOImwBAAA4qEZh\nKywsTL169VJkZKT69u0rScrPz1dMTIy6du2qwYMHq7Cw0L3+rFmz1KVLF4WHh2vNmjXOVA4AAFAH\n1ChsuVwuZWRkaNu2bcrMzJQkJSUlKSYmRtnZ2YqOjlZSUpIkKSsrS8uXL1dWVpbS09M1fvx4lZWV\nOfcMAAAAvFiNTyOaWbnHaWlpSkhIkCQlJCQoNTVVkrRq1SrFx8erQYMGCgsLU+fOnd0BDQAA4GJT\n4yNbgwYN0lVXXaUXXnhBknTw4EEFBQVJkoKCgnTw4EFJ0v79+xUaGureNjQ0VPv27avtugEAAOoE\n35qstHHjRrVp00bffPONYmJiFB4eXq7d5XLJ5XJVun1FbYmJie7vo6KiFBUVVbOKAQAAHJSRkaGM\njIxa669GYatNmzaSpMDAQA0fPlyZmZkKCgrSgQMHFBwcrLy8PLVu3VqSFBISotzcXPe2e/fuVUhI\nyBl9/jhsAQAAeIvTDwJNnz79vPqr9jTi8ePHVVRUJEk6duyY1qxZo549eyo2NlbJycmSpOTkZA0b\nNkySFBsbq5SUFJWUlCgnJ0e7d+92v4MRAADgYlPtka2DBw9q+PDhkqRTp05p9OjRGjx4sK666irF\nxcVp4cKFCgsL04oVKyRJERERiouLU0REhHx9fTV//vwqTzECAADUZy47/W2GF2JQl+uMdzcCAAB4\no/PNLdxBHgAAwEGELQAAAAcRtgAAABxE2AIAAHAQYQsAAMBBhC0AAAAHEbYAAAAcRNgCAABwEGEL\nAADAQYQtAAAABxG2AAAAHETYAgAAcBBhCwAAwEGELQAAAAcRtgAAABxE2AIAAHAQYQsAAMBBhC0A\nAAAHEbYAAAAcRNgCAABwEGELAADAQYQtAAAABxG2AAAAHETYAgAAcBBhCwAAwEGELQAAAAcRtgAA\nABxE2AIAAHAQYQsAAMBBhC0AAAAHEbYAAAAcRNgCAABwEGELAADAQYQtAAAABxG2AAAAHETYAgAA\ncBBhCwAAwEGELQAAAAcRtgAAABxE2AIAAHAQYQsAAMBBhC0AAAAHEbYAAAAcRNgCAABwEGELAADA\nQYQtAAAABxG2AAAAHETYAgAAcBBhCwAAwEGELQAAAAcRtgAAABxE2AIAAHAQYQsAAMBBhC0AAAAH\nEbYAAAAcRNgCAABwEGELAADAQYQtAAAABxG2AAAAHETYAgAAcBBhCwAAwEE1CluFhYX6xS9+oSuu\nuEIRERHaunWr8vPzFRMTo65du2rw4MEqLCx0rz9r1ix16dJF4eHhWrNmjWPF1zcZGRmeLsErMS8V\nY17OxJxUjHmpGPNSMeal9tUobE2ePFk///nPtWvXLm3fvl3h4eFKSkpSTEyMsrOzFR0draSkJElS\nVlaWli9frqysLKWnp2v8+PEqKytz9EnUF+zgFWNeKsa8nIk5qRjzUjHmpWLMS+2rNmwdOXJEGzZs\n0Lhx4yRJvr6+atasmdLS0pSQkCBJSkhIUGpqqiRp1apVio+PV4MGDRQWFqbOnTsrMzPTwacAAADg\nvaoNWzk5OQoMDNRvfvMb/eQnP9Fdd92lY8eO6eDBgwoKCpIkBQUF6eDBg5Kk/fv3KzQ01L19aGio\n9u3b51D5AAAAXs6q8f7775uvr69lZmaamdnkyZNt6tSp1rx583LrtWjRwszMJk6caEuWLHEvv+OO\nO2zlypXl1u3du7dJ4osvvvjiiy+++PL6r4EDB1YXl6rkq2qEhoYqNDRUV199tSTpF7/4hWbNmqXg\n4GAdOHBAwcHBysvLU+vWrSVJISEhys3NdW+/d+9ehYSElOvzo48+qm5YAACAeqHa04jBwcFq27at\nsrOzJUlr165V9+7dNXToUCUnJ0uSkpOTNWzYMElSbGysUlJSVFJSopycHO3evVt9+/Z18CkAAAB4\nr2qPbEnSM888o9GjR6ukpESdOnXSokWLVFpaqri4OC1cuFBhYWFasWKFJCkiIkJxcXGKiIiQr6+v\n5s+fL5fL5eiTAAAA8FYuMzNPFwEAAFBfXfA7yKenpys8PFxdunTR7NmzL/TwHjVu3DgFBQWpZ8+e\n7mUX+81hc3NzdcMNN6h79+7q0aOH5s2bJ4l5OXHihPr166c+ffooIiJCDz74oCTm5QelpaWKjIzU\n0KFDJTEvYWFh6tWrlyIjI92XbVzscyJxQ+6KfPrpp4qMjHR/NWvWTPPmzbvo50X6/nl2795dPXv2\n1KhRo1RcXFx783Jel9efpVOnTlmnTp0sJyfHSkpKrHfv3paVlXUhS/Cod9991z788EPr0aOHe9kf\n//hHmz17tpmZJSUl2Z///GczM9u5c6f17t3bSkpKLCcnxzp16mSlpaUeqdtJeXl5tm3bNjMzKyoq\nsq5du1pWVtZFPy9mZseOHTMzs5MnT1q/fv1sw4YNzMv/euqpp2zUqFE2dOhQM+PnKCwszA4fPlxu\n2cU+J2Zmv/71r23hwoVm9v3PUWFhIfPyI6WlpRYcHGxfffXVRT8vOTk51qFDBztx4oSZmcXFxdnL\nL79ca/NyQcPWpk2b7MYbb3Q/njVrls2aNetCluBxOTk55cJWt27d7MCBA2b2ffDo1q2bmZnNnDnT\nkpKS3OvdeOONtnnz5gtbrAfceuut9vbbbzMvP3Ls2DG76qqrbMeOHcyLmeXm5lp0dLS98847NmTI\nEDPj5ygsLMwOHTpUbtnFPieFhYXWoUOHM5Zf7PPyY6tXr7YBAwaYGfNy+PBh69q1q+Xn59vJkydt\nyJAhtmbNmlqblwt6GnHfvn1q27at+zE3PBU3h/2RPXv2aNu2berXrx/zIqmsrEx9+vRRUFCQ+1Qr\n8yJNmTJFTzzxhHx8/u/X18U+Ly6XS4MGDdJVV12lF154QRJzwg25q5eSkqL4+HhJ7C8BAQG6//77\n1a5dO11++eVq3ry5YmJiam1eLmjY4l2JVXO5XFXOUX2ev6NHj2rEiBGaO3eu/P39y7VdrPPi4+Oj\njz76SHv3/v/27p6lkSiMAvARtLKwCFECNhL8YDROBlNZKlZCIBHBFEljZ+WfMKCVja2NgtqqOBJF\nxdlnruIAAAKtSURBVKAR0UlIK5pAFrFQFI0GRuHdKrObXZdlWScue89Tzh3IcBguLyT35AsODw+x\nv79fs65iLpubm2htbYVhGJBfnO1RMZejoyNks1mYpomFhQWk0+madRUzeXt7g2VZmJqagmVZaG5u\ndv7Dt0rFXKps28bGxgbGx8d/WlMxl8vLS8zPz6NYLOL6+hrlchnLy8s19/xNLnUdtn4sPC2VSjWT\noYra2tpwc3MDAH9cDvu/eH19xdjYGOLxuNPXxly+aWlpwejoKM7Pz5XP5fj4GOvr6+jo6EAsFsPe\n3h7i8bjyufh8PgCA1+tFJBLB6emp8pm8V8htWZZTyA2omUuVaZoYGBiA1+sFwD337OwMg4OD8Hg8\naGxsRDQaRSaT+bD3pa7DVigUwsXFBYrFImzbxtraGsLhcD0f4Z8TDoeVLocVEUxOTkLTNExPTzvX\nVc/l9vbWOfVSqVSws7MDwzCUzyWZTKJUKqFQKGB1dRVDQ0NYWlpSOpeXlxc8PT0BAJ6fn5FKpRAI\nBJTOBGAh9++srKw4XyEC3HN7enpwcnKCSqUCEcHu7i40Tfu498XF35u9a2trS7q6usTv90symaz3\nx3+qiYkJ8fl80tTUJO3t7bK4uCh3d3cyPDwsnZ2dMjIyIvf39879MzMz4vf7pbu7W7a3tz/xyd2T\nTqeloaFBdF2XYDAowWBQTNNUPpd8Pi+GYYiu6xIIBGRubk5ERPlcvndwcOCcRlQ5l6urK9F1XXRd\nl97eXmdfVTmTqlwuJ6FQSPr7+yUSicjDwwNzEZFyuSwej0ceHx+da8xFZHZ2VjRNk76+PkkkEmLb\n9oflwlJTIiIiIhfVvdSUiIiISCUctoiIiIhcxGGLiIiIyEUctoiIiIhcxGGLiIiIyEUctoiIiIhc\nxGGLiIiIyEVfAQcK06wQj5M7AAAAAElFTkSuQmCC\n", - "text": [ - "" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" + "ename": "NameError", + "evalue": "name 'precision_vs_zoom' is not defined", + "output_type": "pyerr", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mpz\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mprecision_vs_zoom\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"single\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m0.5\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0.5\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1e-5\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m1e-5\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1e-6\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m1e-6\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m100\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"svg-tests/fox-vector.svg\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mshow_outputs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mNameError\u001b[0m: name 'precision_vs_zoom' is not defined" ] } ], - "prompt_number": 13 + "prompt_number": 1 }, { "cell_type": "code", diff --git a/tools/gpubounds_error.py b/tools/gpubounds_error.py new file mode 100755 index 0000000..ecf13c4 --- /dev/null +++ b/tools/gpubounds_error.py @@ -0,0 +1,51 @@ +#!/usr/bin/python +import sys +import os +import math + +# Calculates the total error in coordinates of GPU bounds rectangles of objects + +def ComputeError(reference, other): + reference = open(reference, "r") + other = open(other, "r") + total = 0.0 + while True: + a = reference.readline() + b = other.readline() + if a == "" and b == "": + reference.close() + other.close() + return total + if a[0] == '#' and b[0] == '#': + continue + a = map(float, a.strip(" \r\n").split("\t")) + b = map(float, b.strip(" \r\n").split("\t")) + deltaArea = abs(b[3]*b[4] - a[3]*a[4]) + + deltaCoord = b[1] - a[1] + b[2] - a[2] + total += math.sqrt(deltaArea) + abs(deltaCoord) + +# Counts the number of unique bounds +def UniqueBounds(other): + other = open(other, "r") + store = {} + for l in other.readlines(): + if l[0] == "#": + continue + #print "L is " + str(l) + l = map(float, l.strip(" \r\n").split("\t")) + l = tuple(l[1:]) + if not l in store.keys(): + store[l] = 1 + else: + store[l] += 1 + other.close() + return len(store.keys()) + +def main(argv): + print str(ComputeError(argv[1], argv[2])) + "\t" + str(UniqueBounds(argv[1])) + "\t" + str(UniqueBounds(argv[2])) + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv))