Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions include/threepp/loaders/AssimpLoader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,15 +395,32 @@ namespace threepp {
}
sum = std::sqrt(sum);

for (unsigned i = 0; i < 4; i++) {
// Only normalize if sum is not zero
if (sum > 0.0f) {
for (unsigned i = 0; i < 4; i++) {

pairs[i].second = pairs[i].second / sum;

pairs[i].second = pairs[i].second / sum;
while (indexes.size() <= i) indexes.emplace_back();
while (weights.size() <= i) weights.emplace_back();

while (indexes.size() <= i) indexes.emplace_back();
while (weights.size() <= i) weights.emplace_back();
indexes[i] = pairs[i].first;
weights[i] = pairs[i].second;
}
} else {
// Fallback: If all weights are zero (degenerate case), distribute equally.
// This maintains compatibility with downstream code expecting 4 weights,
// though in practice this should rarely occur in well-formed models.
for (unsigned i = 0; i < 4; i++) {

indexes[i] = pairs[i].first;
weights[i] = pairs[i].second;
pairs[i].second = 0.25f;

while (indexes.size() <= i) indexes.emplace_back();
while (weights.size() <= i) weights.emplace_back();

indexes[i] = pairs[i].first;
weights[i] = pairs[i].second;
}
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/threepp/extras/curves/SplineCurve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,21 @@ SplineCurve::SplineCurve(std::vector<Vector2> points)

void SplineCurve::getPoint(float t, Vector2& point) const {

// Validate input: need at least 1 point
if (points.empty()) {
point.set(0.0f, 0.0f);
return;
}

const auto p = static_cast<float>(points.size() - 1) * t;

const auto intPoint = static_cast<size_t>(std::floor(p));
const auto weight = p - static_cast<float>(intPoint);

const auto p0 = points[intPoint == 0 ? intPoint : intPoint - 1];
const auto p1 = points[intPoint];
const auto p2 = points[intPoint > points.size() - 2 ? points.size() - 1 : intPoint + 1];
const auto p3 = points[intPoint > points.size() - 3 ? points.size() - 1 : intPoint + 2];
const auto p2 = points[intPoint >= points.size() - 1 ? points.size() - 1 : intPoint + 1];
const auto p3 = points[intPoint >= points.size() - 2 ? points.size() - 1 : intPoint + 2];

point.set(
interpolants::CatmullRom(weight, p0.x, p1.x, p2.x, p3.x),
Expand Down
5 changes: 5 additions & 0 deletions src/threepp/geometries/LatheGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ using namespace threepp;

LatheGeometry::LatheGeometry(const std::vector<Vector2>& points, unsigned int segments, float phiStart, float phiLength) {

// Validate input: need at least 2 points to create geometry
if (points.size() < 2) {
return;
}

// clamp phiLength so it's in range of [ 0, 2PI ]

phiLength = std::clamp(phiLength, 0.f, math::TWO_PI);
Expand Down
1 change: 1 addition & 0 deletions src/threepp/loaders/SVGLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ unsigned int pointsToStrokeWithBuffers(

float strokeWidth2 = style.strokeWidth / 2;

// Safe division since we already checked numPoints >= 2
float deltaU = 1.f / static_cast<float>(numPoints - 1);
float u0 = 0, u1;

Expand Down
7 changes: 6 additions & 1 deletion src/threepp/loaders/svg/SVGFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,14 @@ namespace threepp::svg {

t = bx / ax;

} else {
} else if (ay != 0) {

t = by / ay;

} else {
// Both ax and ay are 0, degenerate case
classifyResult.loc = IntersectionLocationType::BEHIND;
return;
}

classifyResult.loc = IntersectionLocationType::BETWEEN;
Expand Down
22 changes: 19 additions & 3 deletions src/threepp/math/Lut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ Lut& Lut::setColorMap(const std::string& colormap, int numberofcolors) {
this->map = ColorMapKeywords[colormap];
this->n = numberofcolors;

// Validate input: need at least 1 color. Clamp to 1 to prevent division by zero.
// Using silent correction to maintain backward compatibility with existing code.
if (this->n <= 0) {
this->n = 1;
}

const float step = 1.f / static_cast<float>(this->n);


Expand All @@ -49,7 +55,9 @@ Lut& Lut::setColorMap(const std::string& colormap, int numberofcolors) {
Color minColor(this->map[j].second);
Color maxColor(this->map[j + 1].second);

Color color = minColor.lerp(maxColor, (alpha - min) / (max - min));
// Avoid division by zero if min == max
float t = (max - min > 0.0f) ? (alpha - min) / (max - min) : 0.0f;
Color color = minColor.lerp(maxColor, t);

this->lut.emplace_back(color);
}
Expand All @@ -72,10 +80,18 @@ void Lut::copy(const Lut& lut) {

Color Lut::getColor(float alpha) const {
alpha = std::clamp(alpha, this->minV, this->maxV);
alpha = (alpha - this->minV) / (this->maxV - this->minV);
// Avoid division by zero if minV == maxV
if (this->maxV - this->minV > 0.0f) {
alpha = (alpha - this->minV) / (this->maxV - this->minV);
} else {
alpha = 0.0f;
}
const int colorPosition = static_cast<int>(std::round(alpha * static_cast<float>(this->n)));

return this->lut[colorPosition];
// Clamp colorPosition to valid range [0, n-1] to prevent out-of-bounds access
const int clampedPosition = std::min(colorPosition, static_cast<int>(this->n - 1));

return this->lut[clampedPosition];
}

void Lut::addColorMap(const std::string& name, const std::vector<std::pair<float, Color>>& arrayOfColors) {
Expand Down