Blob Blame Raw
/*
    ......... 2015 Ivan Mahonin

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "contourbuilder.h"

using namespace std;

void ContourBuilder::build_simple(vector<Vector> &c) {
	const float min_segment_length = 0.001f;
	const float rounds = 10.f;
	const float rounds2 = 1.f;

	vector<Vector> back;

	float angle = 360.f;
	float offset = 0.25f/(rounds + 1.f);

	// go front
	while(true) {
		float radius = angle/360.f/(rounds + 1.f);
		float step = min_segment_length*180.f/M_PI/radius;
		if (radius > 1.f - 2.f*offset) break;

		float fr = radius + offset;
		float fx = fr*sinf(angle/180.f*M_PI);
		float fy = fr*cosf(angle/180.f*M_PI);

		float br = radius - offset;
		float bx = br*sinf(angle/180.f*M_PI);
		float by = br*cosf(angle/180.f*M_PI);

		c.push_back(Vector(fx, fy));
		back.push_back(Vector(bx, by));

		angle += step;
	}

	float max_angle = angle;

	while(true) {
		float radius = max_angle/360.f/(rounds + 1.f)
				     + (max_angle-angle)/360.f/rounds2;
		float step = min_segment_length*180.f/M_PI/radius;
		if (radius < 1.f/(rounds + 1.f))
			break;

		float fr = radius + offset;
		float fx = fr*sinf(angle/180.f*M_PI);
		float fy = fr*cosf(angle/180.f*M_PI);

		float br = radius - offset;
		float bx = br*sinf(angle/180.f*M_PI);
		float by = br*cosf(angle/180.f*M_PI);

		c.push_back(Vector(fx, fy));
		back.push_back(Vector(bx, by));

		angle += step;
	}


	// go back
	c.reserve(c.size() + back.size() + 1);
	for(vector<Vector>::reverse_iterator ri = back.rbegin(); ri != back.rend(); ++ri)
		c.push_back(*ri);

	// close
	c.push_back(c.front());
}

void ContourBuilder::build_car(Contour &c, const Vector &o, Real s) {
	c.move_to(  Vector( 5, -1)*s + o);
	c.line_to(  Vector( 4, -1)*s + o);
	c.conic_to( Vector( 2, -1)*s + o, Vector( 0, -1)*s);
	c.line_to(  Vector(-2, -1)*s + o);
	c.conic_to( Vector(-4, -1)*s + o, Vector( 0, -1)*s);
	c.line_to(  Vector(-5, -1)*s + o);
	c.line_to(  Vector(-5,  1)*s + o);
	c.line_to(  Vector(-4,  1)*s + o);
	c.cubic_to( Vector(-1,  3)*s + o, Vector( 0,  2)*s, Vector( 4,  0)*s);
	c.cubic_to( Vector( 3,  1)*s + o, Vector( 4,  0)*s, Vector( 2, -2)*s);
	c.line_to(  Vector( 5,  1)*s + o);
	c.close();
}

void ContourBuilder::build(Contour &c) {
	Real scale = 0.8/5.0;

	int count = 100;
	Real size = (Real)(count + 2)/(Real)(count);
	Real step = 2.0*size/(Real)(count + 1);
	Real origin = step - size;
	Real s = 2*size*scale/(Real)(count);
	for(int i = 0; i < count; ++i)
		for(int j = 0; j < count; ++j)
			build_car(c, Vector(origin + i*step, origin + j*step), s);

	count = 100;
	size = (Real)(count + 2)/(Real)(count);
	step = 2.0*size/(Real)(count + 1);
	origin = step - size;
	s = size*scale/(Real)(count);
	for(int i = 0; i < count; ++i)
		for(int j = 0; j < count; ++j)
			build_car(c, Vector(origin + i*step, origin + j*step), s);

	build_car(c, Vector::zero(), scale);
	build_car(c, Vector::zero(), 0.5*scale);
}