Blob Blame Raw

#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();
}