src/circularprimitive.h

Sat, 08 Apr 2023 12:55:11 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Sat, 08 Apr 2023 12:55:11 +0300
changeset 343
4a82990affd5
parent 305
d891da20abca
child 379
8d88adffb779
permissions
-rw-r--r--

Fix BFC formatting not working due to being evaluated after comment format

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

template<typename Fn>
void rasterize(const CircularPrimitive& 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 CircularPrimitive::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 CircularPrimitive::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 CircularPrimitive::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 CircularPrimitive::CylinderOpen:
		rasterize(CircularPrimitive{
			.type = CircularPrimitive::Cylinder,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		rasterize(CircularPrimitive{
			.type = CircularPrimitive::Circle,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		rasterize(CircularPrimitive{
			.type = CircularPrimitive::Circle,
			.fraction = circ.fraction,
			.transformation = glm::translate(circ.transformation, {0, 1, 0}),
		}, fn);
		break;
	case CircularPrimitive::CylinderClosed:
		rasterize(CircularPrimitive{
			.type = CircularPrimitive::CylinderOpen,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		rasterize(CircularPrimitive{
			.type = CircularPrimitive::Disc,
			.fraction = circ.fraction,
			.transformation = circ.transformation,
		}, fn);
		break;
	case CircularPrimitive::DiscNegative:
		{
			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 CircularPrimitive::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