Group base normal calculations to separate class

master
Jeremy HU 2022-10-11 08:38:03 +11:00
parent 5d5a1c04bd
commit 91e6460815
8 changed files with 275 additions and 101 deletions

View File

@ -261,6 +261,8 @@ SOURCES += ../dust3d/base/vector3.cc
HEADERS += ../dust3d/base/vector2.h
HEADERS += ../dust3d/base/uuid.h
SOURCES += ../dust3d/base/uuid.cc
HEADERS += ../dust3d/mesh/base_normal.h
SOURCES += ../dust3d/mesh/base_normal.cc
HEADERS += ../dust3d/mesh/box_mesh.h
SOURCES += ../dust3d/mesh/box_mesh.cc
HEADERS += ../dust3d/mesh/centripetal_catmull_rom_spline.h
@ -303,6 +305,8 @@ HEADERS += ../dust3d/mesh/triangulate.h
SOURCES += ../dust3d/mesh/triangulate.cc
HEADERS += ../dust3d/mesh/trim_vertices.h
SOURCES += ../dust3d/mesh/trim_vertices.cc
HEADERS += ../dust3d/mesh/tube_mesh_builder.h
SOURCES += ../dust3d/mesh/tube_mesh_builder.cc
HEADERS += ../dust3d/mesh/weld_vertices.h
SOURCES += ../dust3d/mesh/weld_vertices.cc
HEADERS += ../dust3d/util/obj.h

105
dust3d/mesh/base_normal.cc Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2016-2022 Jeremy HU <jeremy-at-dust3d dot org>. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <dust3d/mesh/base_normal.h>
namespace dust3d
{
std::pair<size_t, int> BaseNormal::findNearestAxis(const Vector3 &direction)
{
float maxDot = -1;
size_t nearAxisIndex = 0;
int positive = 1;
for (size_t i = 0; i < 3; ++i) {
const auto axis = axisDirection(i);
auto dot = Vector3::dotProduct(axis, direction);
auto positiveDot = std::abs(dot);
if (positiveDot >= maxDot) {
if (dot < 0)
positive = -1;
maxDot = positiveDot;
nearAxisIndex = i;
}
}
return {nearAxisIndex, positive};
}
std::vector<Vector3> BaseNormal::calculateCircleVertices(double radius,
size_t points,
const Vector3 &aroundAxis,
const Vector3 &startDirection,
const Vector3 &origin)
{
constexpr auto roundAngle = 2.0 * Math::Pi;
auto stepAngle = roundAngle / points;
std::vector<Vector3> circlePoints;
circlePoints.reserve(points);
for (double angle = stepAngle * -0.5;
circlePoints.size() < points;
angle += stepAngle) {
circlePoints.push_back(origin + startDirection.rotated(aroundAxis, angle) * radius);
}
return circlePoints;
}
Vector3 BaseNormal::calculateCircleBaseNormal(const std::vector<Vector3> &vertices)
{
std::vector<Vector3> edgeDirections(vertices.size());
for (size_t i = 0; i < edgeDirections.size(); ++i) {
size_t j = (i + 1) % edgeDirections.size();
edgeDirections[i] = (vertices[j] - vertices[i]).normalized();
}
Vector3 baseNormal;
for (size_t i = 0; i < edgeDirections.size(); ++i) {
size_t j = (i + 1) % edgeDirections.size();
baseNormal += Vector3::crossProduct(-edgeDirections[i], edgeDirections[j]);
}
return baseNormal.normalized();
}
Vector3 BaseNormal::calculateTubeBaseNormal(const std::vector<Vector3> &vertices)
{
std::vector<Vector3> edgeDirections(vertices.size());
for (size_t i = 1; i < edgeDirections.size(); ++i) {
size_t h = i - 1;
edgeDirections[h] = (vertices[i] - vertices[h]).normalized();
}
Vector3 baseNormal;
for (size_t i = 1; i < edgeDirections.size(); ++i) {
size_t h = i - 1;
// >15 degrees && < 165 degrees
if (std::abs(Vector3::dotProduct(edgeDirections[h], edgeDirections[i])) < 0.966)
baseNormal += Vector3::crossProduct(edgeDirections[h], edgeDirections[i]);
}
if (baseNormal.isZero()) {
for (size_t h = 0; h + 1 < edgeDirections.size(); ++h) {
const auto &sectionNormal = edgeDirections[h];
auto axis = BaseNormal::findNearestAxis(sectionNormal);
baseNormal += axis.second *
Vector3::crossProduct(sectionNormal, BaseNormal::nextAxisDirection(axis.first)).normalized();
}
}
return baseNormal.normalized();
}
}

60
dust3d/mesh/base_normal.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2016-2022 Jeremy HU <jeremy-at-dust3d dot org>. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef DUST3D_MESH_BASE_NORMAL_H_
#define DUST3D_MESH_BASE_NORMAL_H_
#include <vector>
#include <dust3d/base/vector3.h>
namespace dust3d
{
class BaseNormal
{
public:
static std::pair<size_t, int> findNearestAxis(const Vector3 &direction);
static inline const Vector3 &axisDirection(size_t index)
{
static const std::vector<Vector3> axisList = {
Vector3 {1, 0, 0},
Vector3 {0, 1, 0},
Vector3 {0, 0, 1},
};
return axisList[index];
}
static inline const Vector3 &nextAxisDirection(size_t index)
{
return axisDirection((index + 1) % 3);
}
static std::vector<Vector3> calculateCircleVertices(double radius,
size_t points,
const Vector3 &aroundAxis=Vector3(0.0, 0.0, 1.0),
const Vector3 &startDirection=Vector3(0.0, 1.0, 0.0),
const Vector3 &origin=Vector3(0.0, 0.0, 0.0));
static Vector3 calculateCircleBaseNormal(const std::vector<Vector3> &vertices);
static Vector3 calculateTubeBaseNormal(const std::vector<Vector3> &vertices);
};
}
#endif

View File

@ -22,6 +22,7 @@
#include <dust3d/base/debug.h>
#include <dust3d/base/math.h>
#include <dust3d/mesh/base_normal.h>
#include <dust3d/mesh/rope_mesh.h>
namespace dust3d
@ -42,96 +43,19 @@ const std::vector<std::vector<size_t>> &RopeMesh::resultTriangles()
return m_resultTriangles;
}
std::pair<size_t, int> RopeMesh::findNearestAxis(const Vector3 &direction)
{
float maxDot = -1;
size_t nearAxisIndex = 0;
int positive = 1;
for (size_t i = 0; i < 3; ++i) {
const auto axis = axisDirection(i);
auto dot = Vector3::dotProduct(axis, direction);
auto positiveDot = std::abs(dot);
if (positiveDot >= maxDot) {
if (dot < 0)
positive = -1;
maxDot = positiveDot;
nearAxisIndex = i;
}
}
return {nearAxisIndex, positive};
}
std::vector<Vector3> RopeMesh::calculateCircleVertices(double radius,
size_t points,
const Vector3 &aroundAxis,
const Vector3 &startDirection,
const Vector3 &origin)
{
constexpr auto roundAngle = 2.0 * Math::Pi;
auto stepAngle = roundAngle / points;
std::vector<Vector3> circlePoints;
circlePoints.reserve(points);
for (double angle = stepAngle * -0.5;
circlePoints.size() < points;
angle += stepAngle) {
circlePoints.push_back(origin + startDirection.rotated(aroundAxis, angle) * radius);
}
return circlePoints;
}
Vector3 RopeMesh::calculateCircleBaseNormal(const std::vector<Vector3> &vertices)
{
std::vector<Vector3> edgeDirections(vertices.size());
for (size_t i = 0; i < edgeDirections.size(); ++i) {
size_t j = (i + 1) % edgeDirections.size();
edgeDirections[i] = (vertices[j] - vertices[i]).normalized();
}
Vector3 baseNormal;
for (size_t i = 0; i < edgeDirections.size(); ++i) {
size_t j = (i + 1) % edgeDirections.size();
baseNormal += Vector3::crossProduct(-edgeDirections[i], edgeDirections[j]);
}
return baseNormal.normalized();
}
Vector3 RopeMesh::calculateTubeBaseNormal(const std::vector<Vector3> &vertices)
{
std::vector<Vector3> edgeDirections(vertices.size());
for (size_t i = 1; i < edgeDirections.size(); ++i) {
size_t h = i - 1;
edgeDirections[h] = (vertices[i] - vertices[h]).normalized();
}
Vector3 baseNormal;
for (size_t i = 1; i < edgeDirections.size(); ++i) {
size_t h = i - 1;
// >15 degrees && < 165 degrees
if (std::abs(Vector3::dotProduct(edgeDirections[h], edgeDirections[i])) < 0.966)
baseNormal += Vector3::crossProduct(edgeDirections[h], edgeDirections[i]);
}
if (baseNormal.isZero()) {
for (size_t h = 0; h + 1 < edgeDirections.size(); ++h) {
const auto &sectionNormal = edgeDirections[h];
auto axis = RopeMesh::findNearestAxis(sectionNormal);
baseNormal += axis.second *
Vector3::crossProduct(sectionNormal, RopeMesh::nextAxisDirection(axis.first)).normalized();
}
}
return baseNormal.normalized();
}
void RopeMesh::addRope(const std::vector<Vector3> &positions, bool isCircle)
{
if (positions.size() < 2) {
dust3dDebug << "Expected at least 2 nodes, current:" << positions.size();
return;
}
Vector3 baseNormal = isCircle ? calculateCircleBaseNormal(positions) : calculateTubeBaseNormal(positions);
Vector3 baseNormal = isCircle ? BaseNormal::calculateCircleBaseNormal(positions) : BaseNormal::calculateTubeBaseNormal(positions);
std::vector<std::vector<size_t>> circles;
circles.reserve(positions.size());
Vector3 forwardDirection = (positions[1] - positions[0]).normalized();
for (size_t i = isCircle ? 0 : 1; i < positions.size(); ++i) {
size_t j = (i + 1) % positions.size();
auto circlePositions = calculateCircleVertices(m_buildParameters.defaultRadius,
auto circlePositions = BaseNormal::calculateCircleVertices(m_buildParameters.defaultRadius,
m_buildParameters.sectionSegments,
forwardDirection,
baseNormal,

View File

@ -46,27 +46,6 @@ private:
std::vector<Vector3> m_resultVertices;
std::vector<std::vector<size_t>> m_resultTriangles;
BuildParameters m_buildParameters;
static std::pair<size_t, int> findNearestAxis(const Vector3 &direction);
static inline const Vector3 &axisDirection(size_t index)
{
static const std::vector<Vector3> axisList = {
Vector3 {1, 0, 0},
Vector3 {0, 1, 0},
Vector3 {0, 0, 1},
};
return axisList[index];
}
static inline const Vector3 &nextAxisDirection(size_t index)
{
return axisDirection((index + 1) % 3);
}
static std::vector<Vector3> calculateCircleVertices(double radius,
size_t points,
const Vector3 &aroundAxis=Vector3(0.0, 0.0, 1.0),
const Vector3 &startDirection=Vector3(0.0, 1.0, 0.0),
const Vector3 &origin=Vector3(0.0, 0.0, 0.0));
static Vector3 calculateCircleBaseNormal(const std::vector<Vector3> &vertices);
static Vector3 calculateTubeBaseNormal(const std::vector<Vector3> &vertices);
};
};

View File

@ -64,7 +64,7 @@ private:
std::vector<Vector3> m_generatedVertices;
std::vector<std::vector<size_t>> m_generatedFaces;
std::vector<Vector3> m_generatedNormals;
size_t m_targetSegments = 15;
size_t m_targetSegments = 0;
void interpolateSplinesToHaveEqualSizeOfNodesExceptClosingSplines();
std::vector<std::vector<StitchingPoint>> convertSplinesToStitchingPoints(const std::vector<Spline> &splines);

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016-2022 Jeremy HU <jeremy-at-dust3d dot org>. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <dust3d/mesh/tube_mesh_builder.h>
namespace dust3d
{
TubeMeshBuilder::TubeMeshBuilder(std::vector<Node> &&nodes, bool isCircle):
m_nodes(std::move(nodes)),
m_isCircle(isCircle)
{
}
void TubeMeshBuilder::preprocessNodes()
{
// TODO:
}
void TubeMeshBuilder::build()
{
preprocessNodes();
if (m_nodes.empty())
return;
// TODO:
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2016-2022 Jeremy HU <jeremy-at-dust3d dot org>. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef DUST3D_MESH_TUBE_MESH_BUILDER_H_
#define DUST3D_MESH_TUBE_MESH_BUILDER_H_
#include <dust3d/base/uuid.h>
#include <dust3d/base/vector3.h>
namespace dust3d
{
class TubeMeshBuilder
{
public:
struct Node
{
Vector3 origin;
double radius;
Uuid sourceId;
};
TubeMeshBuilder(std::vector<Node> &&nodes, bool isCircle);
void build();
private:
std::vector<Node> m_nodes;
bool m_isCircle = false;
void preprocessNodes();
};
};
#endif