src/circularprimitive.h

Sat, 10 Jun 2023 17:26:32 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Sat, 10 Jun 2023 17:26:32 +0300
changeset 382
94d5587bb0c4
parent 379
8d88adffb779
permissions
-rw-r--r--

use a parameter to avoid temporarily changing member variables

#pragma once
#include <glm/gtc/matrix_transform.hpp>
#include "src/basics.h"
#include "src/model.h"
#include "src/ldrawalgorithm.h"

template<typename Fn>
void circular_element_to_polygons(const circular_primitive& circ, Fn&& fn)
{
	std::vector<ModelElement> result;
	const auto xform = [&circ](const glm::vec2& p, float y){
		return glm::vec3{circ.transformation * glm::vec4{p.x, y, p.y, 1}};
	};
	const glm::vec3 primitiveOrigin = xform({0, 0}, 0);
	const bool invertedMatrix = (glm::determinant(circ.transformation) < 0) != circ.inverted;
	switch(circ.type) {
	case circular_primitive_type_e::circle:
		ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&]
		(const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){
			fn(LineSegment{xform(p1, 0), xform(p2, 0)}, EDGE_COLOR);
		});
		break;
	case circular_primitive_type_e::disc:
		ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&]
		(const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){
			fn(Triangle{primitiveOrigin, xform(p1, 0), xform(p2, 0)}, MAIN_COLOR);
		});
		break;
	case circular_primitive_type_e::cylinder:
		ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&]
		(const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){
			Quadrilateral quad{xform(p1, 1), xform(p2, 1), xform(p2, 0), xform(p1, 0)};
			if (invertedMatrix) {
				std::swap(quad.p2, quad.p4);
			}
			fn(quad, MAIN_COLOR);
		});
		break;
	case circular_primitive_type_e::cylinder_open:
		circular_element_to_polygons(circular_primitive{
			.type = circular_primitive_type_e::cylinder,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		circular_element_to_polygons(circular_primitive{
			.type = circular_primitive_type_e::circle,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		circular_element_to_polygons(circular_primitive{
			.type = circular_primitive_type_e::circle,
			.fraction = circ.fraction,
			.transformation = glm::translate(circ.transformation, {0, 1, 0}),
		}, fn);
		break;
	case circular_primitive_type_e::cylinder_closed:
		circular_element_to_polygons(circular_primitive{
			.type = circular_primitive_type_e::cylinder_open,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		circular_element_to_polygons(circular_primitive{
			.type = circular_primitive_type_e::disc,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		break;
	case circular_primitive_type_e::disc_negative:
		{
			unsigned int i = 0;
			ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&]
			(const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){
				constexpr glm::vec2 corners[4] = {
					{+1, +1},
					{-1, +1},
					{-1, -1},
					{+1, -1},
				};
				const glm::vec2& corner = corners[i * 4 / circ.fraction.divisions];
				fn(Triangle{xform(p2, 0), xform(p1, 0), xform(corner, 0)}, MAIN_COLOR);
				++i;
			});
		}
		break;
	case circular_primitive_type_e::chord:
		for (unsigned int i = 1; i < circ.fraction.segments; ++i) {
			const glm::vec2& p1 = ldraw::rimpoint(circ.fraction.divisions, i);
			const glm::vec2& p2 = ldraw::rimpoint(circ.fraction.divisions, i + 1);
			fn(Triangle{xform(p2, 0), xform(p1, 0), xform({1, 0}, 0)}, MAIN_COLOR);
		}
		break;
	}
}

mercurial