|
1 #pragma once |
|
2 #include <glm/gtc/matrix_transform.hpp> |
|
3 #include "basics.h" |
|
4 #include "model.h" |
|
5 #include "ldrawalgorithm.h" |
|
6 |
|
7 template<typename Fn> |
|
8 void rasterize(const CircularPrimitive& circ, Fn&& fn) |
|
9 { |
|
10 std::vector<ModelElement> result; |
|
11 const auto xform = [&circ](const glm::vec2& p, float y){ |
|
12 return glm::vec3{circ.transformation * glm::vec4{p.x, y, p.y, 1}}; |
|
13 }; |
|
14 const glm::vec3 origin = xform({0, 0}, 0); |
|
15 switch(circ.type) { |
|
16 case CircularPrimitive::Circle: |
|
17 ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] |
|
18 (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ |
|
19 fn(edge(xform(p1, 0), xform(p2, 0))); |
|
20 }); |
|
21 break; |
|
22 case CircularPrimitive::Disc: |
|
23 ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] |
|
24 (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ |
|
25 fn(triangle(origin, xform(p1, 0), xform(p2, 0))); |
|
26 }); |
|
27 break; |
|
28 case CircularPrimitive::Cylinder: |
|
29 ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] |
|
30 (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ |
|
31 fn(quadrilateral(xform(p1, 1), xform(p2, 1), xform(p2, 0), xform(p1, 0))); |
|
32 }); |
|
33 break; |
|
34 case CircularPrimitive::CylinderOpen: |
|
35 rasterize(CircularPrimitive{ |
|
36 .type = CircularPrimitive::Cylinder, |
|
37 .fraction = circ.fraction, |
|
38 .transformation = circ.transformation, |
|
39 }, fn); |
|
40 rasterize(CircularPrimitive{ |
|
41 .type = CircularPrimitive::Circle, |
|
42 .fraction = circ.fraction, |
|
43 .transformation = circ.transformation, |
|
44 }, fn); |
|
45 rasterize(CircularPrimitive{ |
|
46 .type = CircularPrimitive::Circle, |
|
47 .fraction = circ.fraction, |
|
48 .transformation = glm::translate(circ.transformation, {0, 1, 0}), |
|
49 }, fn); |
|
50 break; |
|
51 case CircularPrimitive::CylinderClosed: |
|
52 rasterize(CircularPrimitive{ |
|
53 .type = CircularPrimitive::CylinderOpen, |
|
54 .fraction = circ.fraction, |
|
55 .transformation = circ.transformation, |
|
56 }, fn); |
|
57 rasterize(CircularPrimitive{ |
|
58 .type = CircularPrimitive::Disc, |
|
59 .fraction = circ.fraction, |
|
60 .transformation = circ.transformation, |
|
61 }, fn); |
|
62 break; |
|
63 case CircularPrimitive::DiscNegative: |
|
64 { |
|
65 unsigned int i = 0; |
|
66 ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] |
|
67 (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ |
|
68 constexpr glm::vec2 corners[4] = { |
|
69 {+1, +1}, |
|
70 {-1, +1}, |
|
71 {-1, -1}, |
|
72 {+1, -1}, |
|
73 }; |
|
74 const glm::vec2& corner = corners[i * 4 / circ.fraction.divisions]; |
|
75 fn(triangle(xform(p2, 0), xform(p1, 0), xform(corner, 0))); |
|
76 ++i; |
|
77 }); |
|
78 } |
|
79 break; |
|
80 case CircularPrimitive::Chord: |
|
81 for (unsigned int i = 1; i < circ.fraction.segments; ++i) { |
|
82 const glm::vec2& p1 = ldraw::rimpoint(circ.fraction.divisions, i); |
|
83 const glm::vec2& p2 = ldraw::rimpoint(circ.fraction.divisions, i + 1); |
|
84 fn(triangle(xform(p2, 0), xform(p1, 0), xform({1, 0}, 0))); |
|
85 } |
|
86 break; |
|
87 } |
|
88 } |