11 template <
typename value_t,
size_t DIM,
size_t SIDES>
12 template <
size_t D, std::enable_if_t<D == 2,
int>>
17 using rotation_t = Eigen::Rotation2D<value_type>;
19 static_assert(SIDES == 2,
"2D frustum can only have 2 sides");
20 assert(opening_angle < M_PI);
24 Eigen::Rotation2D<value_type> rot(angle);
26 value_type normal_angle = 0.5 * M_PI - 0.5 * opening_angle;
27 VertexType normal1 = rotation_t(normal_angle) * VertexType::UnitX();
28 VertexType normal2 = rotation_t(-normal_angle) * VertexType::UnitX();
30 m_normals = {rot * VertexType::UnitX(), rot * normal1, rot * normal2};
33 template <
typename value_t,
size_t DIM,
size_t SIDES>
34 template <
size_t D, std::enable_if_t<D == 3,
int>>
39 static_assert(SIDES > 2,
"3D frustum must have 3 or more sides");
40 assert(opening_angle < M_PI);
41 using angle_axis_t = Eigen::AngleAxis<value_type>;
47 transform = (Eigen::Quaternion<value_type>().setFromTwoVectors(ldir, dir));
53 rot = angle_axis_t(phi_sep, ldir);
55 value_type half_opening_angle = opening_angle / 2.;
56 auto calculate_normal =
59 return (-1 * (angle_axis_t(half_opening_angle, tilt_axis) *
out))
64 m_normals[1] = calculate_normal(current_outward);
67 current_outward = rot * current_outward;
68 m_normals[
i + 1] = calculate_normal(current_outward);
72 normal = transform * normal;
76 template <
typename value_t,
size_t DIM,
size_t SIDES>
77 template <
size_t D, std::enable_if_t<D == 3,
int>>
80 static_assert(DIM == 3,
"Drawing is only supported in 3D");
87 VertexType far_center = m_normals[0] * far_distance;
88 std::array<std::pair<VertexType, VertexType>, SIDES> planeFarIXs;
90 auto ixPlanePlane = [](
const auto& n1,
const auto& p1,
const auto& n2,
91 const auto& p2) -> std::pair<VertexType, VertexType> {
93 const double j = (n2.dot(p2 - p1)) / (n2.dot(n1.cross(m)));
98 auto ixLineLine = [](
const auto& p1,
const auto& d1,
const auto& p2,
100 return p1 + (((p2 - p1).
cross(d2)).
norm() / (d1.cross(d2)).
norm()) * d1;
104 for (
size_t i = 1;
i < n_normals;
i++) {
106 ixPlanePlane(far_normal, far_center, m_normals[
i], VertexType::Zero());
107 planeFarIXs.at(i - 1) = ixLine;
110 std::array<VertexType, SIDES> points;
113 size_t j = (
i + 1) % std::size(planeFarIXs);
114 const auto&
l1 = planeFarIXs.at(
i);
115 const auto&
l2 = planeFarIXs.at(j);
117 m_origin + ixLineLine(
l1.second,
l1.first,
l2.second,
l2.first);
122 size_t j = (
i + 1) % std::size(points);
124 std::vector<VertexType>({m_origin, points.at(
i), points.at(j)}));
128 template <
typename value_t,
size_t DIM,
size_t SIDES>
129 template <
size_t D, std::enable_if_t<D == 2,
int>>
135 static_assert(DIM == 2,
"SVG is only supported in 2D");
143 trf = trf * Eigen::Scaling(
VertexType(1, -1));
146 std::array<std::string, 3> colors({
"orange",
"blue",
"red"});
154 os <<
"x1=\"" << left.x() <<
"\" ";
155 os <<
"y1=\"" << left.y() <<
"\" ";
156 os <<
"x2=\"" << right.x() <<
"\" ";
157 os <<
"y2=\"" << right.y() <<
"\" ";
159 os <<
" stroke=\"" << color <<
"\" stroke-width=\"" <<
width <<
"\"/>\n";
166 os <<
"cx=\"" << p.x() <<
"\" cy=\"" << p.y() <<
"\" r=\"" <<
r <<
"\"";
167 os <<
" fill=\"" << color <<
"\"";
171 using vec3 = Eigen::Matrix<value_type, 3, 1>;
175 const vec3 p1(p1_2.x(), p1_2.y(), 0);
176 const vec3 p2(p2_2.x(), p2_2.y(), 0);
177 const vec3 d1(d1_2.x(), d1_2.y(), 0);
178 const vec3 d2(d2_2.x(), d2_2.y(), 0);
180 vec3 num = (p2 - p1).
cross(d2);
181 vec3 den = d1.cross(d2);
184 value_type dot = num.normalized().dot(den.normalized());
185 if (std::abs(dot) - 1 < 1
e-9 && dot < 0) {
189 const vec3
p = p1 + f * (num.norm() / den.norm()) * d1;
190 assert(std::abs(p.z()) < 1
e-9);
191 return {p.x(), p.y()};
194 const VertexType far_dir = {m_normals[0].y(), -m_normals[0].x()};
195 const VertexType far_point = m_normals[0] * far_distance;
197 std::array<VertexType, 2> points;
199 for (
size_t i = 1;
i < n_normals;
i++) {
202 const VertexType ix = ixLineLine(far_point, far_dir, {0, 0}, plane_dir);
203 draw_point(m_origin + ix,
"black", 3);
204 draw_line(m_origin, m_origin + ix,
"black", 2);
205 points.at(
i - 1) = ix;
208 draw_line(m_origin + points.at(0), m_origin + points.at(1),
"black", 2);
210 draw_line(m_origin, m_origin + m_normals[0] * 2, colors[0], 3);
212 draw_point({0, 0},
"yellow", 5);
213 draw_point(m_origin,
"green", 5);
218 template <
typename value_t,
size_t DIM,
size_t SIDES>
222 const auto& rot = trf.rotation();
224 std::array<VertexType, n_normals> new_normals;
225 for (
size_t i = 0;
i < n_normals;
i++) {
226 new_normals[
i] = rot * m_normals[
i];