/* -*- c++ -*- * Copyright ©2008 Hugo Mills * * This software is distributed under the terms of the GNU GPL v3 * For more information on the GPL, see the file COPYING or * visit http://www.gnu.org/ * * This software is distributed without warranty */ #include "rendercontext.h" #include #include "magellan/options.h" // Copy constructor RenderContext::RenderContext(const RenderContext& that) : layer(that.layer), display(that.display) { viewport = new XfView(*(that.viewport)); // Copy the viewport myviewport = true; // Remember that *we* control this one } RenderContext::~RenderContext() { if(myviewport) viewport->destroy(); } bool RenderContext::operator<(const RenderContext& that) const { if(this->viewport->bottom_left[0] == that.viewport->bottom_left[0]) { if(this->viewport->bottom_left[1] == that.viewport->bottom_left[1]) return this->layer < that.layer; return this->viewport->bottom_left[1] < that.viewport->bottom_left[1]; } return this->viewport->bottom_left[0] < that.viewport->bottom_left[0]; } bool RenderContext::overlaps(const RenderContext* that) const { if(this->viewport->bottom_left[0] >= that->viewport->top_right[0]) return false; if(that->viewport->bottom_left[0] >= this->viewport->top_right[0]) return false; if(this->viewport->bottom_left[1] >= that->viewport->top_right[1]) return false; if(that->viewport->bottom_left[1] >= this->viewport->top_right[1]) return false; return true; } bool RenderContext::contains(const RenderContext* that) const { return ( this->viewport->bottom_left[0] <= that->viewport->bottom_left[0] && this->viewport->bottom_left[1] <= that->viewport->bottom_left[1] && that->viewport->top_right[0] <= this->viewport->top_right[0] && that->viewport->top_right[1] <= this->viewport->top_right[1] ); } bool RenderContext::contains_point(const ivec2& p) const { return ( this->viewport->bottom_left[0] <= p[0] && p[0] < this->viewport->top_right[0] && this->viewport->bottom_left[1] <= p[1] && p[1] < this->viewport->top_right[1] ); } bool RenderContext::bestsplit(RenderContext** r0, RenderContext** r1, const RenderContext* what) const { int min_epsilon = std::numeric_limits::max(); bool found = false; ivec2 best_from; ivec2 best_to; *r0 = NULL; *r1 = NULL; // Bottom edge ivec2 from = what->viewport->bottom_left; ivec2 to; to[0] = what->viewport->top_right[0]; to[1] = what->viewport->bottom_left[1]; int e = this->canslice(from, to); if( e != -1 ) { if(e < min_epsilon) { best_from = from; best_to = to; min_epsilon = e; found = true; } } // Right-hand edge from = to; to = what->viewport->top_right; e = this->canslice(from, to); if( e != -1 ) { if(e < min_epsilon) { best_from = from; best_to = to; min_epsilon = e; found = true; } } // Top edge from[0] = what->viewport->bottom_left[0]; from[1] = what->viewport->top_right[1]; e = this->canslice(from, to); if( e != -1 ) { if(e < min_epsilon) { best_from = from; best_to = to; min_epsilon = e; found = true; } } // Left-hand edge to = from; from = what->viewport->bottom_left; e = this->canslice(from, to); if( e != -1 ) { if(e < min_epsilon) { best_from = from; best_to = to; min_epsilon = e; found = true; } } if(found) slice(r0, r1, best_from, best_to); return found; } void RenderContext::halve(RenderContext** r0, RenderContext** r1) const { *r0 = new RenderContext(*this); *r1 = new RenderContext(*this); if(xsize() > ysize()) { int div = viewport->bottom_left[0] + xsize()/2; (*r0)->viewport->top_right[0] = div; (*r1)->viewport->bottom_left[0] = div; } else { int div = viewport->bottom_left[1] + ysize()/2; (*r0)->viewport->top_right[1] = div; (*r1)->viewport->bottom_left[1] = div; } } int RenderContext::epsilon(const RenderContext* that) const { int as = this->size(); int bs = that->size(); int d = (as + bs)/2 - as; if(d < 0) return -d; return d; } int RenderContext::canslice(const ivec2& from, const ivec2& to) const { if(opts->debug_render() >= 3) { std::cerr << "Test slicing " << *this << " against line (" << from[0] << ", " << from[1] << ")-(" << to[0] << ", " << to[1] << ")" << std::endl; } ivec2 blA = viewport->bottom_left; ivec2 trA = viewport->top_right; ivec2 blB = blA; ivec2 trB = trA; if( contains_point(from) || contains_point(to) ) { if( from[0] == to[0] ) { trA[0] = from[0]; blB[0] = from[0]; } if( from[1] == to[1] ) { trA[1] = from[1]; blB[1] = from[1]; } int areaA = (trA[0]-blA[0]) * (trA[1]-blA[1]); int areaB = (trB[0]-blB[0]) * (trB[1]-blB[1]); int d = (areaA + areaB)/2 - areaA; if(d < 0) return -d; return d; } return -1; } bool RenderContext::slice(RenderContext** r0, RenderContext** r1, const ivec2& from, const ivec2& to) const { if(opts->debug_render() >= 3) { std::cerr << "Slicing " << *this << " against line (" << from[0] << ", " << from[1] << ")-(" << to[0] << ", " << to[1] << ")" << std::endl; } if( contains_point(from) || contains_point(to) ) { if( from[0] == to[0] ) { *r0 = new RenderContext(*this); *r1 = new RenderContext(*this); (*r0)->viewport->top_right[0] = from[0]; (*r1)->viewport->set_left(from[0]); return true; } if( from[1] == to[1] ) { *r0 = new RenderContext(*this); *r1 = new RenderContext(*this); (*r0)->viewport->top_right[1] = from[1]; (*r1)->viewport->set_bottom(from[1]); return true; } } return false; } std::ostream& RenderContext::print(std::ostream& o) const { o << "(" << viewport->bottom_left[0] << ", " << viewport->bottom_left[1] << ")-(" << viewport->top_right[0] << ", " << viewport->top_right[1] << ") +(" << viewport->centre[0] << ", " << viewport->centre[1] << ") " << layer; return o; }