forked from bartvdbraak/blender
2418daede5
This is an alternative method for fitting a curve which incrementally simplifies the curve, then re-fits. Generally gives better results, also improves corner detection.
316 lines
7.2 KiB
C
316 lines
7.2 KiB
C
/*
|
|
* Copyright (c) 2016, Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of the <organization> nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
/** \file curve_fit_inline.h
|
|
* \ingroup curve_fit
|
|
*/
|
|
|
|
/** \name Simple Vector Math Lib
|
|
* \{ */
|
|
|
|
#ifdef _MSC_VER
|
|
# define MINLINE static __forceinline
|
|
#else
|
|
# define MINLINE static inline
|
|
#endif
|
|
|
|
MINLINE double sq(const double d)
|
|
{
|
|
return d * d;
|
|
}
|
|
|
|
#ifndef _MSC_VER
|
|
MINLINE double min(const double a, const double b)
|
|
{
|
|
return b < a ? b : a;
|
|
}
|
|
|
|
MINLINE double max(const double a, const double b)
|
|
{
|
|
return a < b ? b : a;
|
|
}
|
|
#endif
|
|
|
|
MINLINE void zero_vn(
|
|
double v0[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v0[j] = 0.0;
|
|
}
|
|
}
|
|
|
|
MINLINE void flip_vn_vnvn(
|
|
double v_out[], const double v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] = v0[j] + (v0[j] - v1[j]);
|
|
}
|
|
}
|
|
|
|
MINLINE void copy_vnvn(
|
|
double v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v0[j] = v1[j];
|
|
}
|
|
}
|
|
|
|
MINLINE void copy_vnfl_vndb(
|
|
float v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v0[j] = (float)v1[j];
|
|
}
|
|
}
|
|
|
|
MINLINE void copy_vndb_vnfl(
|
|
double v0[], const float v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v0[j] = (double)v1[j];
|
|
}
|
|
}
|
|
|
|
MINLINE double dot_vnvn(
|
|
const double v0[], const double v1[], const uint dims)
|
|
{
|
|
double d = 0.0;
|
|
for (uint j = 0; j < dims; j++) {
|
|
d += v0[j] * v1[j];
|
|
}
|
|
return d;
|
|
}
|
|
|
|
MINLINE void add_vn_vnvn(
|
|
double v_out[], const double v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] = v0[j] + v1[j];
|
|
}
|
|
}
|
|
|
|
MINLINE void sub_vn_vnvn(
|
|
double v_out[], const double v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] = v0[j] - v1[j];
|
|
}
|
|
}
|
|
|
|
MINLINE void iadd_vnvn(
|
|
double v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v0[j] += v1[j];
|
|
}
|
|
}
|
|
|
|
MINLINE void isub_vnvn(
|
|
double v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v0[j] -= v1[j];
|
|
}
|
|
}
|
|
|
|
MINLINE void madd_vn_vnvn_fl(
|
|
double v_out[],
|
|
const double v0[], const double v1[],
|
|
const double f, const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] = v0[j] + v1[j] * f;
|
|
}
|
|
}
|
|
|
|
MINLINE void msub_vn_vnvn_fl(
|
|
double v_out[],
|
|
const double v0[], const double v1[],
|
|
const double f, const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] = v0[j] - v1[j] * f;
|
|
}
|
|
}
|
|
|
|
MINLINE void miadd_vn_vn_fl(
|
|
double v_out[], const double v0[], double f, const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] += v0[j] * f;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
MINLINE void misub_vn_vn_fl(
|
|
double v_out[], const double v0[], double f, const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] -= v0[j] * f;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
MINLINE void mul_vnvn_fl(
|
|
double v_out[],
|
|
const double v0[], const double f, const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v_out[j] = v0[j] * f;
|
|
}
|
|
}
|
|
|
|
MINLINE void imul_vn_fl(double v0[], const double f, const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
v0[j] *= f;
|
|
}
|
|
}
|
|
|
|
|
|
MINLINE double len_squared_vnvn(
|
|
const double v0[], const double v1[], const uint dims)
|
|
{
|
|
double d = 0.0;
|
|
for (uint j = 0; j < dims; j++) {
|
|
d += sq(v0[j] - v1[j]);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
MINLINE double len_squared_vn(
|
|
const double v0[], const uint dims)
|
|
{
|
|
double d = 0.0;
|
|
for (uint j = 0; j < dims; j++) {
|
|
d += sq(v0[j]);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
MINLINE double len_vnvn(
|
|
const double v0[], const double v1[], const uint dims)
|
|
{
|
|
return sqrt(len_squared_vnvn(v0, v1, dims));
|
|
}
|
|
|
|
MINLINE double len_vn(
|
|
const double v0[], const uint dims)
|
|
{
|
|
return sqrt(len_squared_vn(v0, dims));
|
|
}
|
|
|
|
/* special case, save us negating a copy, then getting the length */
|
|
MINLINE double len_squared_negated_vnvn(
|
|
const double v0[], const double v1[], const uint dims)
|
|
{
|
|
double d = 0.0;
|
|
for (uint j = 0; j < dims; j++) {
|
|
d += sq(v0[j] + v1[j]);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
MINLINE double len_negated_vnvn(
|
|
const double v0[], const double v1[], const uint dims)
|
|
{
|
|
return sqrt(len_squared_negated_vnvn(v0, v1, dims));
|
|
}
|
|
|
|
MINLINE double normalize_vn(
|
|
double v0[], const uint dims)
|
|
{
|
|
double d = len_squared_vn(v0, dims);
|
|
if (d != 0.0 && ((d = sqrt(d)) != 0.0)) {
|
|
imul_vn_fl(v0, 1.0 / d, dims);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
/* v_out = (v0 - v1).normalized() */
|
|
MINLINE double normalize_vn_vnvn(
|
|
double v_out[],
|
|
const double v0[], const double v1[], const uint dims)
|
|
{
|
|
double d = 0.0;
|
|
for (uint j = 0; j < dims; j++) {
|
|
double a = v0[j] - v1[j];
|
|
d += sq(a);
|
|
v_out[j] = a;
|
|
}
|
|
if (d != 0.0 && ((d = sqrt(d)) != 0.0)) {
|
|
imul_vn_fl(v_out, 1.0 / d, dims);
|
|
}
|
|
return d;
|
|
}
|
|
|
|
MINLINE bool is_almost_zero_ex(double val, double eps)
|
|
{
|
|
return (-eps < val) && (val < eps);
|
|
}
|
|
|
|
MINLINE bool is_almost_zero(double val)
|
|
{
|
|
return is_almost_zero_ex(val, 1e-8);
|
|
}
|
|
|
|
MINLINE bool equals_vnvn(
|
|
const double v0[], const double v1[], const uint dims)
|
|
{
|
|
for (uint j = 0; j < dims; j++) {
|
|
if (v0[j] != v1[j]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MINLINE void project_vn_vnvn(
|
|
double v_out[], const double p[], const double v_proj[], const uint dims)
|
|
{
|
|
const double mul = dot_vnvn(p, v_proj, dims) / dot_vnvn(v_proj, v_proj, dims);
|
|
mul_vnvn_fl(v_out, v_proj, mul, dims);
|
|
}
|
|
|
|
MINLINE void project_vn_vnvn_normalized(
|
|
double v_out[], const double p[], const double v_proj[], const uint dims)
|
|
{
|
|
const double mul = dot_vnvn(p, v_proj, dims);
|
|
mul_vnvn_fl(v_out, v_proj, mul, dims);
|
|
}
|
|
|
|
MINLINE void project_plane_vn_vnvn_normalized(
|
|
double v_out[], const double v[], const double v_plane[], const uint dims)
|
|
{
|
|
assert(v != v_out);
|
|
project_vn_vnvn_normalized(v_out, v, v_plane, dims);
|
|
sub_vn_vnvn(v_out, v, v_out, dims);
|
|
}
|
|
|
|
/** \} */
|