18static QMatrix4x4 buildOrthonormalBasis(
const QVector3D &normal)
21 const QVector3D forward = normal;
25 float absX = std::fabs(forward.x());
26 float absY = std::fabs(forward.y());
27 float absZ = std::fabs(forward.z());
29 if (absX <= absY && absX <= absZ)
30 ref = QVector3D(1, 0, 0);
31 else if (absY <= absZ)
32 ref = QVector3D(0, 1, 0);
34 ref = QVector3D(0, 0, 1);
36 const QVector3D right = QVector3D::crossProduct(ref, forward).normalized();
37 const QVector3D up = QVector3D::crossProduct(forward, right);
39 QMatrix4x4 transform(Qt::Uninitialized);
40 transform.setRow(0, QVector4D(right, 0.0f));
41 transform.setRow(1, QVector4D(up, 0.0f));
42 transform.setRow(2, QVector4D(forward, 0.0f));
43 transform.setRow(3, QVector4D(0.0f, 0.0f, 0.0f, 1.0f));
49 std::array<
int, 2> { 0, 1 }, std::array<
int, 2> { 1, 2 }, std::array<
int, 2> { 2, 3 }, std::array<
int, 2> { 3, 0 },
50 std::array<
int, 2> { 4, 5 }, std::array<
int, 2> { 5, 6 }, std::array<
int, 2> { 6, 7 }, std::array<
int, 2> { 7, 4 },
51 std::array<
int, 2> { 0, 4 }, std::array<
int, 2> { 1, 5 }, std::array<
int, 2> { 2, 6 }, std::array<
int, 2> { 3, 7 },
75 constexpr QColor colorBox = QColorConstants::Yellow;
86 float shortestAxisSq = (box[0] - box[1]).lengthSquared();
87 shortestAxisSq =
std::min(shortestAxisSq, (box[0] - box[4]).lengthSquared());
88 shortestAxisSq =
std::min(shortestAxisSq, (box[0] - box[3]).lengthSquared());
89 const float axisLength = qSqrt(shortestAxisSq) * 0.5f;
91 auto drawAxisLine = [&](
const QVector3D &from,
const QVector3D &to,
const QColor &axisColor) {
92 const QVector3D dir = (to - from).normalized();
93 const QVector3D mid = from + dir * axisLength;
94 debugDrawSystem->drawLine(from, mid, axisColor);
95 debugDrawSystem->drawLine(mid, to, colorBox);
101 drawAxisLine(box[0], box[1], QColorConstants::Red);
102 debugDrawSystem->drawLine(box[1], box[2], colorBox);
103 drawAxisLine(box[0], box[3], QColorConstants::Green);
104 debugDrawSystem->drawLine(box[2], box[3], colorBox);
107 drawAxisLine(box[0], box[4], QColorConstants::Blue);
108 debugDrawSystem->drawLine(box[1], box[5], colorBox);
109 debugDrawSystem->drawLine(box[2], box[6], colorBox);
110 debugDrawSystem->drawLine(box[3], box[7], colorBox);
113 debugDrawSystem->drawLine(box[4], box[5], colorBox);
114 debugDrawSystem->drawLine(box[5], box[6], colorBox);
115 debugDrawSystem->drawLine(box[6], box[7], colorBox);
116 debugDrawSystem->drawLine(box[7], box[4], colorBox);
118 debugDrawSystem->setEnabled(
true);
189 const QSSGBoxPoints &castingBox,
190 QSSGDebugDrawSystem *debugDrawSystem,
194 QList<Vertex> vertices;
195 vertices.reserve(castingBox.size());
196 for (
const auto &p : castingBox) {
199 vertices.push_back(point);
202 for (
auto line : BOX_LINE_INDICES) {
203 vertices[line[0]].addNeighbor(line[1]);
204 vertices[line[1]].addNeighbor(line[0]);
207 QList<QVector2D> planePoints;
208 QList<QPair<quint8, quint8>> lines;
209 QList<
bool> intersecting;
210 QList<quint8> newVertexIndices;
211 QList<Vertex> verticesPrev;
213 for (
const auto &plane : planes) {
214 const QVector3D center = plane[0];
215 const QVector3D normal = plane[1];
216 newVertexIndices.clear();
217 verticesPrev = vertices;
218 for (
int vertIndexI = 0, vertEnd = vertices.length(); vertIndexI < vertEnd; ++vertIndexI) {
219 Vertex vertex = vertices[vertIndexI];
224 if (QVector3D::dotProduct(vertex.position - center, normal) >= 0) {
230 vertices[vertIndexI].active =
false;
231 for (
int neighborIndex : vertex.neighbors) {
232 if (neighborIndex == -1)
234 vertices[neighborIndex].removeNeighbor(vertIndexI);
237 for (
int neighborIndex : vertex.neighbors) {
238 if (neighborIndex == -1)
241 const quint32 idx0 = vertIndexI;
242 const quint32 idx1 = neighborIndex;
245 if (QVector3D::dotProduct(vertices[idx1].position - center, normal) < 0)
248 QVector3D planePoint = center;
249 QVector3D planeNormal = normal;
250 QVector3D linePoint = vertices[idx0].position;
251 QVector3D lineDirection = vertices[idx0].position - vertices[idx1].position;
252 QSSGPlane plane(planePoint, planeNormal);
253 QSSGRenderRay ray(linePoint, lineDirection);
255 if (
auto intersect = QSSGRenderRay::intersect(plane, ray); intersect.has_value()) {
256 int addedIdx = vertices.length();
257 Q_ASSERT(addedIdx <= 255);
259 p.position = intersect.value();
261 vertices[idx1].addNeighbor(addedIdx);
262 vertices.push_back(p);
263 newVertexIndices.push_back(addedIdx);
268 if (newVertexIndices.isEmpty())
272 const QMatrix4x4 transform = buildOrthonormalBasis(normal);
274 planePoints.reserve(newVertexIndices.length());
275 for (
auto &p0 : newVertexIndices) {
276 QVector3D p = transform.map(vertices[p0].position);
277 planePoints.push_back(QVector2D(p.x(), p.y()));
283 lines.reserve((planePoints.length() * planePoints.length()) / 4);
284 for (
int i = 0, length = planePoints.length(); i < length; ++i) {
285 for (
int j = i + 1; j < length; ++j) {
286 lines.push_back({ i, j });
291 intersecting.clear();
292 intersecting.resize(lines.length(),
false);
293 for (
int i = 0, length = lines.length(); i < length; ++i) {
294 QPair<quint8, quint8> lineI = lines[i];
295 QVector2D a = planePoints[lineI.first];
296 QVector2D b = planePoints[lineI.second];
297 for (
int j = i + 1; j < length; ++j) {
298 QPair<quint8, quint8> lineJ = lines[j];
301 if (lineJ.first == lineI.first || lineJ.first == lineI.second || lineJ.second == lineI.first
302 || lineJ.second == lineI.second)
305 QVector2D c = planePoints[lineJ.first];
306 QVector2D d = planePoints[lineJ.second];
307 if (lineLineIntersection(a, b, c, d)) {
308 intersecting[i] =
true;
309 intersecting[j] =
true;
314 for (
int i = 0, length = lines.length(); i < length; ++i) {
315 if (intersecting[i]) {
319 QPair<quint8, quint8> lineI = lines[i];
320 int a = newVertexIndices[lineI.first];
321 int b = newVertexIndices[lineI.second];
322 vertices[a].addNeighbor(b);
323 vertices[b].addNeighbor(a);
327 for (
const Vertex &point : std::as_const(vertices)) {
328 if (point.active && (point.borked || !point.allNeighbors())) {
329 vertices = verticesPrev;
335 QList<QVector3D> result;
336 result.reserve(vertices.length());
337 for (
const Vertex &vertex : std::as_const(vertices)) {
339 result.push_back(vertex.position);
342 if (debugDrawSystem) {
343 debugDrawSystem->setEnabled(
true);
344 for (
int i = 0; i < vertices.length(); i++) {
345 Vertex point = vertices[i];
349 QVector3D position = vertices[i].position;
350 debugDrawSystem->drawLine(position, vertices[point.neighbors[0]].position, color);
351 debugDrawSystem->drawLine(position, vertices[point.neighbors[1]].position, color);
352 debugDrawSystem->drawLine(position, vertices[point.neighbors[2]].position, color);
385 const float minX = boxBounds.minimum.x();
386 const float minY = boxBounds.minimum.y();
387 const float minZ = boxBounds.minimum.z();
388 const float maxX = boxBounds.maximum.x();
389 const float maxY = boxBounds.maximum.y();
390 const float maxZ = boxBounds.maximum.z();
392 QSSGBoxPoints points;
393 points[0] = QVector3D(minX, minY, minZ);
394 points[1] = QVector3D(maxX, minY, minZ);
395 points[2] = QVector3D(maxX, maxY, minZ);
396 points[3] = QVector3D(minX, maxY, minZ);
397 points[4] = QVector3D(minX, minY, maxZ);
398 points[5] = QVector3D(maxX, minY, maxZ);
399 points[6] = QVector3D(maxX, maxY, maxZ);
400 points[7] = QVector3D(minX, maxY, maxZ);
404 static constexpr std::array<
int, 4> LEFT = { 0, 3, 7, 4 };
405 static constexpr std::array<
int, 4> TOP = { 3, 2, 6, 7 };
406 static constexpr std::array<
int, 4> BOTTOM = { 4, 5, 1, 0 };
407 static constexpr std::array<
int, 4> RIGHT = { 2, 1, 5, 6 };
408 static constexpr std::array<
std::array<
int, 4>, 4> faceIndices = { LEFT, TOP, BOTTOM, RIGHT };
410 QList<std::array<QVector3D, 2>> faces;
411 faces.resize(faceIndices.size());
412 for (
int i = 0; i <
int(faceIndices.size()); ++i) {
413 std::array<
int, 4> face = faceIndices[i];
414 QVector3D center = points[face[0]];
415 QVector3D b = points[face[1]] - points[face[0]];
416 QVector3D a = points[face[2]] - points[face[0]];
417 QVector3D n = -QVector3D::crossProduct(a, b).normalized();
418 faces[i] = { center, n };
421 return sliceBoxByPlanes(faces, box,
nullptr, QColorConstants::Black);