#include "generatorsandboxview.h"
GeneratorSandBoxView::GenPoint::GenPoint(const IntVector2 &coord):
coord(coord)
{
UInt x = UInt(coord.x);
UInt y = UInt(coord.y);
UInt step_x = coord.x ? (x^(x - 1)) >> 1 : UInt(-1);
UInt step_y = coord.y ? (y^(y - 1)) >> 1 : UInt(-1);
UInt step_xy = (step_x < step_y ? step_x : step_y) + 1;
diamond = step_x != step_y;
if (!step_xy || step_xy > one) step_xy = one;
step = Int(step_xy);
level = -1;
for(int l = 0; l <= max_level; ++l)
if (step == (1 << (max_level - l)))
level = l;
assert(level >= 0);
}
void
GeneratorSandBoxView::GenPoint::get_parents(Set &out_points) const
{
if (!level || out_points.count(*this)) return;
GenPoint points[4];
if (diamond) {
points[0] = GenPoint(coord.x - step, coord.y);
points[1] = GenPoint(coord.x + step, coord.y);
points[2] = GenPoint(coord.x, coord.y - step);
points[3] = GenPoint(coord.x, coord.y + step);
} else {
points[0] = GenPoint(coord.x - step, coord.y - step);
points[1] = GenPoint(coord.x - step, coord.y + step);
points[2] = GenPoint(coord.x + step, coord.y - step);
points[3] = GenPoint(coord.x + step, coord.y + step);
}
for(int i = 0; i < 4; ++i) {
points[i].get_parents(out_points);
out_points.insert(points[i]);
}
}
void
GeneratorSandBoxView::GenPoint::draw(const Cairo::RefPtr<Cairo::Context> &context) const {
Real fstep = 1/Real(one);
Real fsize = pow(Real(0.9), Real(level)) * fstep;
Vector2 fcoord(coord.x*fstep, coord.y*fstep);
if (!level) {
Real s = fsize/sqrt(M_PI);
context->arc(fcoord.x, fcoord.y, s, 0, 2*M_PI);
} else
if (diamond) {
Real s = fsize*sqrt(0.5);
context->move_to(fcoord.x - s, fcoord.y);
context->line_to(fcoord.x, fcoord.y - s);
context->line_to(fcoord.x + s, fcoord.y);
context->line_to(fcoord.x, fcoord.y + s);
context->close_path();
} else {
Real s = fsize*0.5;
context->move_to(fcoord.x - s, fcoord.y - s);
context->line_to(fcoord.x - s, fcoord.y + s);
context->line_to(fcoord.x + s, fcoord.y + s);
context->line_to(fcoord.x + s, fcoord.y - s);
context->close_path();
}
context->fill();
}
GeneratorSandBoxView::GeneratorSandBoxView():
p0(new View::Point( Vector2(-0.25, -0.25) )),
p1(new View::Point( Vector2( 0.25, 0.25) ))
{
transform.scale(200, 200);
points.push_back(p0);
points.push_back(p1);
}
void
GeneratorSandBoxView::on_draw_view(const Cairo::RefPtr<Cairo::Context> &context) {
context->save();
const Real ps = get_pixel_size();
context->set_line_width(ps);
Pair2 bounds(p0->position, p1->position);
// calc view bounds
int w = get_allocated_width();
int h = get_allocated_height();
Matrix m = transform_from_pixels();
Pair2 view_bounds(Vector2(INFINITY, INFINITY), Vector2(-INFINITY, -INFINITY));
view_bounds.expand((m*Vector4(0, 0, 0, 1)).vec2());
view_bounds.expand((m*Vector4(w, 0, 0, 1)).vec2());
view_bounds.expand((m*Vector4(0, h, 0, 1)).vec2());
view_bounds.expand((m*Vector4(w, h, 0, 1)).vec2());
// calc int bounds
Real fstep = 1/Real(GenPoint::one);
IntPair2 bounds_int(
IntVector2( Int(ceil (bounds.p0.x/fstep - real_precision)),
Int(ceil (bounds.p0.y/fstep - real_precision)) ),
IntVector2( Int(floor(bounds.p1.x/fstep + real_precision)),
Int(floor(bounds.p1.y/fstep + real_precision)) ));
IntPair2 view_bounds_int(
IntVector2( Int(floor(view_bounds.p0.x/fstep - 2 + real_precision)),
Int(floor(view_bounds.p0.y/fstep - 2 + real_precision)) ),
IntVector2( Int(ceil (view_bounds.p1.x/fstep + 2 - real_precision)),
Int(ceil (view_bounds.p1.y/fstep + 2 - real_precision)) ));
// draw background points
context->set_source_rgba(0.5, 0.5, 0.5, 0.75);
for(Int x = view_bounds_int.p0.x; x <= view_bounds_int.p1.x; ++x)
for(Int y = view_bounds_int.p0.y; y <= view_bounds_int.p1.y; ++y)
GenPoint(x, y).draw(context);
// ganer parent points
GenPoint::Set parents;
for(Int x = bounds_int.p0.x; x <= bounds_int.p1.x; ++x)
for(Int y = bounds_int.p0.y; y <= bounds_int.p1.y; ++y)
GenPoint(x, y).get_parents(parents);
context->set_source_rgba(1, 0, 0, 1);
for(GenPoint::Set::const_iterator i = parents.begin(); i != parents.end(); ++i)
i->draw(context);
// draw selected points
context->set_source_rgba(0, 0, 1, 0.55);
for(Int x = bounds_int.p0.x; x <= bounds_int.p1.x; ++x)
for(Int y = bounds_int.p0.y; y <= bounds_int.p1.y; ++y)
GenPoint(x, y).draw(context);
// draw bounds
context->set_source_rgba(0, 0, 1, 0.75);
context->move_to(bounds.p0.x, bounds.p0.y);
context->line_to(bounds.p1.x, bounds.p0.y);
context->line_to(bounds.p1.x, bounds.p1.y);
context->line_to(bounds.p0.x, bounds.p1.y);
context->close_path();
context->stroke();
context->restore();
}