无尖点且无自交的 Catmull-rom 曲线

2023-12-02

我有以下代码来计算四个控制点之间的点以生成 catmull-rom 曲线:

CGPoint interpolatedPosition(CGPoint p0, CGPoint p1, CGPoint p2, CGPoint p3, float t)
{
    float t3 = t * t * t;
    float t2 = t * t;

    float f1 = -0.5 * t3 + t2 - 0.5 * t;
    float f2 = 1.5 * t3 - 2.5 * t2 + 1.0;
    float f3 = -1.5 * t3 + 2.0 * t2 + 0.5 * t;
    float f4 = 0.5 * t3 - 0.5 * t2;

    float x = p0.x * f1 + p1.x * f2 + p2.x * f3 + p3.x * f4;
    float y = p0.y * f1 + p1.y * f2 + p2.y * f3 + p3.y * f4;

    return CGPointMake(x, y);
}

这工作得很好,但我想创建一些我认为称为向心参数化的东西。这意味着曲线将没有尖点,也没有自相交。如果我将一个控制点移动到非常靠近另一个控制点,曲线应该变得“更小”。我在谷歌上搜索了一番,试图找到一种方法来做到这一点。有人知道怎么做吗?


我也需要在工作中实现这一点。您需要开始的基本概念是,常规 Catmull-Rom 实现和修改版本之间的主要区别在于它们处理时间的方式。

Catmull-Rom Time

在原始 Catmull-Rom 实现的未参数化版本中,t 从 0 开始,以 1 结束,并计算从 P1 到 P2 的曲线。在参数化时间实现中,t 在 P0 处从 0 开始,并在所有四个点上不断增加。因此,在统一情况下,P1 处为 1,P2 处为 2,您将传入 1 到 2 范围内的值进行插值。

和弦情况显示 |Pi+1 - P|随着时间跨度的变化。这只是意味着您可以使用每段点之间的直线距离来计算要使用的实际长度。向心情况只是使用稍微不同的方法来计算每个段的最佳时间长度。

Catmull-Rom Parameterization

所以现在我们只需要知道如何提出方程,让我们代入新的时间值。典型的 Catmull-Rom 方程中只有一个 t,即您尝试计算值的时间。我在这里找到了描述如何计算这些参数的最佳文章:http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf。他们专注于曲线的数学评估,但其中蕴藏着巴里和戈德曼的关键公式。(1)

Cubic Catmull-Rom curve formulation

在上图中,箭头表示“乘以”箭头中给出的比率。

然后,这为我们提供了实际执行计算以获得所需结果所需的内容。 X 和 Y 是独立计算的,尽管我使用“距离”因子来根据 2D 距离而不是 1D 距离修改时间。

检测结果:

Catmull-Rom Test Results

(1) P. J. 巴里和 R. N. 高盛。一类 catmull-rom 样条的递归评估算法。 SIGGRAPH 计算机图形学,22(4):199{204,1988。

我最终用 Java 实现的源代码如下所示:

/**
 * This method will calculate the Catmull-Rom interpolation curve, returning
 * it as a list of Coord coordinate objects.  This method in particular
 * adds the first and last control points which are not visible, but required
 * for calculating the spline.
 *
 * @param coordinates The list of original straight line points to calculate
 * an interpolation from.
 * @param pointsPerSegment The integer number of equally spaced points to
 * return along each curve.  The actual distance between each
 * point will depend on the spacing between the control points.
 * @return The list of interpolated coordinates.
 * @param curveType Chordal (stiff), Uniform(floppy), or Centripetal(medium)
 * @throws gov.ca.water.shapelite.analysis.CatmullRomException if
 * pointsPerSegment is less than 2.
 */
public static List<Coord> interpolate(List<Coord> coordinates, int pointsPerSegment, CatmullRomType curveType)
        throws CatmullRomException {
    List<Coord> vertices = new ArrayList<>();
    for (Coord c : coordinates) {
        vertices.add(c.copy());
    }
    if (pointsPerSegment < 2) {
        throw new CatmullRomException("The pointsPerSegment parameter must be greater than 2, since 2 points is just the linear segment.");
    }

    // Cannot interpolate curves given only two points.  Two points
    // is best represented as a simple line segment.
    if (vertices.size() < 3) {
        return vertices;
    }

    // Test whether the shape is open or closed by checking to see if
    // the first point intersects with the last point.  M and Z are ignored.
    boolean isClosed = vertices.get(0).intersects2D(vertices.get(vertices.size() - 1));
    if (isClosed) {
        // Use the second and second from last points as control points.
        // get the second point.
        Coord p2 = vertices.get(1).copy();
        // get the point before the last point
        Coord pn1 = vertices.get(vertices.size() - 2).copy();

        // insert the second from the last point as the first point in the list
        // because when the shape is closed it keeps wrapping around to
        // the second point.
        vertices.add(0, pn1);
        // add the second point to the end.
        vertices.add(p2);
    } else {
        // The shape is open, so use control points that simply extend
        // the first and last segments

        // Get the change in x and y between the first and second coordinates.
        double dx = vertices.get(1).X - vertices.get(0).X;
        double dy = vertices.get(1).Y - vertices.get(0).Y;

        // Then using the change, extrapolate backwards to find a control point.
        double x1 = vertices.get(0).X - dx;
        double y1 = vertices.get(0).Y - dy;

        // Actaully create the start point from the extrapolated values.
        Coord start = new Coord(x1, y1, vertices.get(0).Z);

        // Repeat for the end control point.
        int n = vertices.size() - 1;
        dx = vertices.get(n).X - vertices.get(n - 1).X;
        dy = vertices.get(n).Y - vertices.get(n - 1).Y;
        double xn = vertices.get(n).X + dx;
        double yn = vertices.get(n).Y + dy;
        Coord end = new Coord(xn, yn, vertices.get(n).Z);

        // insert the start control point at the start of the vertices list.
        vertices.add(0, start);

        // append the end control ponit to the end of the vertices list.
        vertices.add(end);
    }

    // Dimension a result list of coordinates. 
    List<Coord> result = new ArrayList<>();
    // When looping, remember that each cycle requires 4 points, starting
    // with i and ending with i+3.  So we don't loop through all the points.
    for (int i = 0; i < vertices.size() - 3; i++) {

        // Actually calculate the Catmull-Rom curve for one segment.
        List<Coord> points = interpolate(vertices, i, pointsPerSegment, curveType);
        // Since the middle points are added twice, once for each bordering
        // segment, we only add the 0 index result point for the first
        // segment.  Otherwise we will have duplicate points.
        if (result.size() > 0) {
            points.remove(0);
        }

        // Add the coordinates for the segment to the result list.
        result.addAll(points);
    }
    return result;

}

/**
 * Given a list of control points, this will create a list of pointsPerSegment
 * points spaced uniformly along the resulting Catmull-Rom curve.
 *
 * @param points The list of control points, leading and ending with a 
 * coordinate that is only used for controling the spline and is not visualized.
 * @param index The index of control point p0, where p0, p1, p2, and p3 are
 * used in order to create a curve between p1 and p2.
 * @param pointsPerSegment The total number of uniformly spaced interpolated
 * points to calculate for each segment. The larger this number, the
 * smoother the resulting curve.
 * @param curveType Clarifies whether the curve should use uniform, chordal
 * or centripetal curve types. Uniform can produce loops, chordal can
 * produce large distortions from the original lines, and centripetal is an
 * optimal balance without spaces.
 * @return the list of coordinates that define the CatmullRom curve
 * between the points defined by index+1 and index+2.
 */
public static List<Coord> interpolate(List<Coord> points, int index, int pointsPerSegment, CatmullRomType curveType) {
    List<Coord> result = new ArrayList<>();
    double[] x = new double[4];
    double[] y = new double[4];
    double[] time = new double[4];
    for (int i = 0; i < 4; i++) {
        x[i] = points.get(index + i).X;
        y[i] = points.get(index + i).Y;
        time[i] = i;
    }

    double tstart = 1;
    double tend = 2;
    if (!curveType.equals(CatmullRomType.Uniform)) {
        double total = 0;
        for (int i = 1; i < 4; i++) {
            double dx = x[i] - x[i - 1];
            double dy = y[i] - y[i - 1];
            if (curveType.equals(CatmullRomType.Centripetal)) {
                total += Math.pow(dx * dx + dy * dy, .25);
            } else {
                total += Math.pow(dx * dx + dy * dy, .5);
            }
            time[i] = total;
        }
        tstart = time[1];
        tend = time[2];
    }
    double z1 = 0.0;
    double z2 = 0.0;
    if (!Double.isNaN(points.get(index + 1).Z)) {
        z1 = points.get(index + 1).Z;
    }
    if (!Double.isNaN(points.get(index + 2).Z)) {
        z2 = points.get(index + 2).Z;
    }
    double dz = z2 - z1;
    int segments = pointsPerSegment - 1;
    result.add(points.get(index + 1));
    for (int i = 1; i < segments; i++) {
        double xi = interpolate(x, time, tstart + (i * (tend - tstart)) / segments);
        double yi = interpolate(y, time, tstart + (i * (tend - tstart)) / segments);
        double zi = z1 + (dz * i) / segments;
        result.add(new Coord(xi, yi, zi));
    }
    result.add(points.get(index + 2));
    return result;
}

/**
 * Unlike the other implementation here, which uses the default "uniform"
 * treatment of t, this computation is used to calculate the same values but
 * introduces the ability to "parameterize" the t values used in the
 * calculation. This is based on Figure 3 from
 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
 *
 * @param p An array of double values of length 4, where interpolation
 * occurs from p1 to p2.
 * @param time An array of time measures of length 4, corresponding to each
 * p value.
 * @param t the actual interpolation ratio from 0 to 1 representing the
 * position between p1 and p2 to interpolate the value.
 * @return
 */
public static double interpolate(double[] p, double[] time, double t) {
    double L01 = p[0] * (time[1] - t) / (time[1] - time[0]) + p[1] * (t - time[0]) / (time[1] - time[0]);
    double L12 = p[1] * (time[2] - t) / (time[2] - time[1]) + p[2] * (t - time[1]) / (time[2] - time[1]);
    double L23 = p[2] * (time[3] - t) / (time[3] - time[2]) + p[3] * (t - time[2]) / (time[3] - time[2]);
    double L012 = L01 * (time[2] - t) / (time[2] - time[0]) + L12 * (t - time[0]) / (time[2] - time[0]);
    double L123 = L12 * (time[3] - t) / (time[3] - time[1]) + L23 * (t - time[1]) / (time[3] - time[1]);
    double C12 = L012 * (time[2] - t) / (time[2] - time[1]) + L123 * (t - time[1]) / (time[2] - time[1]);
    return C12;
}   
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无尖点且无自交的 Catmull-rom 曲线 的相关文章

  • Python 利用 curve_fit 进行 e 指数函数拟合

    可能对大家有参考价值的信息是 xff1a 如何用 curve fit 进行 e 指数函数拟合 xff1b 如何将拟合后的结果输出到画布上 xff1b 坐标轴 标签 图例样式的设计 xff1b 文本框内容和格式 话不多说 xff0c 直接上代
  • MATLAB之Curve Fitting Tool的使用及说明

    文章目录 MATLAB之Curve Fitting Tool的使用及说明Curve Fitting Tool的使用Curve Fitting Tool中表示拟合好坏程度的参数说明 MATLAB之Curve Fitting Tool的使用及说
  • 三次贝塞尔曲线上的最近点?

    如何沿着三次贝塞尔曲线找到最接近平面上任意点 P 的点 B t 我编写了一些快速而简单的代码来估计任意阶贝塞尔曲线的这一点 注意 这是伪暴力 而不是封闭式解决方案 Demo http phrogz net svg closest point
  • Matplotlib,添加多行文本。添加可以跟随曲线的文本

    我已将文本添加到绘图中 在每行中进行编码 然后调整它看起来不错 增加或减少宽度 或更改位置 但是 有没有办法让 Python 知道您想要文本的位置以及如何设置它 然后我可以添加文本 Python 将计算出详细信息 例如 看看下面的图片 在图
  • 二次贝塞尔曲线:计算点

    我想计算二次曲线上的点 与 HTML5 的 canvas 元素一起使用 当我使用quadraticCurveTo JavaScript 中的函数 我有一个源点 一个目标点和一个控制点 假设我如何计算创建的二次曲线上的点t 0 5 只 知道这
  • 无尖点且无自交的 Catmull-rom 曲线

    我有以下代码来计算四个控制点之间的点以生成 catmull rom 曲线 CGPoint interpolatedPosition CGPoint p0 CGPoint p1 CGPoint p2 CGPoint p3 float t fl
  • 在 Python 中拟合分箱对数正态数据

    我有一系列按体积分数排列的粒度分布数据 如下所示 size 6 68 0 05 9 92 1 15 etc 我需要将这些数据拟合到对数正态分布 我计划使用 python 来实现stats lognorm fit函数 但这似乎期望输入作为变量
  • 适用于 Android 的 catmull-rom 样条线

    我正在尝试找到一种在android平台上实现catmull rom样条线的方法 以便通过n个点平滑地绘制一条线 理想情况下 我能够通过 Path 及其cubicTo 方法调整三次贝塞尔曲线 如本线程中提到的 如何在 Android 中通过树
  • OpenGL 中的厚贝塞尔曲线

    我正在使用 jogl opengl 绑定在 java 中编写一个程序 我需要创建一条厚度沿曲线变化的贝塞尔曲线 到目前为止 我只管理了一条细的单点贝塞尔曲线 我很确定这不是一件容易的事 但我不知道从哪里开始寻找解决方案 如果有人能指出我如何
  • 绘制隐式方程[重复]

    这个问题在这里已经有答案了 我需要在Python3中画一些曲线 我很习惯matplotlib pyplot 但我以前从未画过这样的东西 我真的很感激一些提示 特别是如何以 整洁 的方式编码的提示 和帮助 有一个例子 让我们用一颗心 x 2
  • 固定长度的Javascript画布曲线

    我想绘制任何 随机 曲线 给定 起点 终点 曲线长度 我怎么能做这样的事情受限于画布边界 加上曲线不能交叉 我试图找到一些解决方案 但我无法弄清楚 谢谢你的时间 这是我想要完成的更详细的视图 这是在画布上绘制的二次曲线 一切安好 问题是 如
  • 如何使用 ggplot 创建多面折线图?

    我有一个用以下代码创建的数据框 require reshape2 foo lt data frame abs cbind rnorm 3 rnorm 3 mean 8 rnorm 3 mean 9 rnorm 3 mean 1 qux lt
  • 在 LIBGDX 中绘制弯曲的自定义对象?

    我最近一直在研究LibGDX 似乎碰壁了 如图所示 蓝点代表用户的手指 它本身的地图生成是我似乎陷入困境的地方 LibGDX是否提供了动态绘制的方法弯曲的物体 我可以简单地自己将它们生成为图像 但是图像会被极大地拉伸到手指可以容纳 3 个手
  • 如何使用 svg 或其他响应式解决方案制作弯曲标题

    我正在尝试制作一个弯曲的标题 我想知道是否有人可以为我指出正确的方向 或标题的最佳方法 如下图所示 我不是开发人员 所以我很辛苦 这是主题和弯曲标题的图像 http i hizliresim com G9Rb1r png 这是我的代码 我怎
  • 如何在具有多个峰值的数据集中找到 FWHM?

    我正在使用一个 Python 脚本 它可以在特定的值范围内沿着一维轮廓查找峰值 或在我的例子中为谷值 的索引 我的目标是测量每个感兴趣的山谷的半高宽 这是一维轮廓的示例 https i stack imgur com UTj33 png 这
  • 使用 python 对点进行排序以获得连续曲线

    我有一个未排序点的列表 列表 50 6261 74 3683 63 2489 75 0038 76 0384 75 6219 79 8451 75 7855 30 9626 168 085 27 381 170 967 22 9191 17
  • 如何计算直线和曲线的最近点? ..还是曲线和曲线?

    给定直线和二次贝塞尔曲线的点 如何计算它们的最近点 INRIA 有一篇关于这个问题的科学论文 计算两条贝塞尔曲线之间的最小距离 http hal inria fr inria 00518351 en PDF here http hal in
  • 耳朵图像处理 - 在 MATLAB 中查找直线和曲线的交点

    1 https i stack imgur com j3ZRQ jpg我有一只耳朵的 Canny 边缘输出 我用一条线 绿色 连接了最远的两个边界 现在我想从这条线的中点到外边界 左侧 绘制一条法线 我编写的代码帮助我绘制法线 但我希望红线
  • 在 Matlab/Java 中将手部运动建模为 3D 曲线

    我只需要一些关于我遇到的问题 在哪里查看等的指导 我在我的一个项目中使用了运动跟踪手套 它返回每个手指和手掌的 X Y 和 Z 值 我想做的是首先根据这些坐标创建每个手指运动的表示 然后将它们每个附加到手掌的运动 以获得手的表示 一旦我完成
  • 给定 X 在三次贝塞尔曲线上求 Y?

    我需要一种方法 允许我在给定 x 坐标的情况下找到三次贝塞尔曲线上的 Y 坐标 我遇到过很多地方告诉我将其视为三次函数 然后尝试找到根 我理解这一点 然而 三次贝塞尔曲线的方程是 对于 x 坐标 X t 1 t 3 X0 3 1 t 2 t

随机推荐

  • 将参数从 Cloud 函数传递到 Dataflow

    我想将 Google Cloud Storage 上上传的文件的文件名从 Cloud Functions 传递到 Dataflow 以便我可以处理上传的文件 我为云函数编写的代码是 const google require googleap
  • NavigationView 获取/查找标题布局

    在我的 NavigationView 中 我有一个带有 id viewId 和活动按钮的标题布局 要设置这些按钮 我在活动中执行以下操作onPostCreate final View panel findViewById R id view
  • ndarray.resize:为 refcheck 参数传递正确的值

    和许多其他人一样 我的情况是我有一个类收集大量数据 并提供一种方法将数据作为 numpy 数组返回 即使在返回数组之后 其他数据也可以继续流入 由于创建数组是一项昂贵的操作 因此我只想在必要时创建它 并尽可能高效地完成它 具体来说 在可能的
  • YARN 应用程序日志在发送到 S3 之前存储在 EMR 中的何处

    我需要将 Yarn 应用程序日志从 EMR 写入 S3 以外的其他源 您能否告诉我应用程序日志在 EMR 主实例中保存在哪里 如果申请作为一个步骤提交给 emr 那么日志将驻留在 var log hadoop steps lt
  • Angular 5将动态html文件添加到DIV中

    我对 Angular 很陌生 我正在尝试将 html 文件作为我的字符串插入并插入到 DIV 元素中 我有我的search component html called div div 组件 ts import Component from
  • Ionic Cordova 构建始终使用 androidx.appcompat:appcompatn 的最新版本并且失败

    我正在运行 ionic cordova build android 并失败 经过两天的研究 尝试了几种方法 终于找到了问题所在 但找不到解决办法 我使用cordova平台10 1 0 它生成像这样的project properties ta
  • 使用 CoreNFC 检测 ISO/IEC 14443(Mifare Ultralight 或 Classic)NFC 卡

    所以我在 WWDC 上能够使用以下代码检测 Apple Labs 提供的 NFC 卡 nfcSession NFCNDEFReaderSession delegate self queue nil invalidateAfterFirstR
  • Eclipse、PyDev 和 Python 配置错误

    我决定尝试使用 Eclipse 和 PyDev 而不是 IDLE 我成功 安装 了 Eclipse SDK 3 7 之后 我按照 PyDev 网站上显示的步骤成功安装了该插件 但是 当尝试配置我的解释器 Python 3 2 3 时 我总是
  • 如何在厨师中运行具有依赖项的食谱?

    我已经配置了工作站这一步开始使用 操作系统 redhat 6 5 我已经启动了一个节点 我这样修改了一本食谱 myCookbook metadata rb name myCookbook maintainer YOUR COMPANY NA
  • 根据条件和分组更新列

    我的数据是 Prod Vend Capac Dema Price p1 v2 2 6 1 p1 v1 3 6 2 p1 v3 3 6 2 p2 v1 1 1 1 p2 v3 2 1 2 p2 v2 5 1 2 p3 v1 5 3 3 p3
  • getSystemService(Context.AUDIO_SERVICE) 上的异常

    我想创建一个应用程序 根据某些设置来挂断来电 这在 Android 1 6 上似乎是不可能的 因此 我决定编写一个应用程序 在通话中断时将铃声更改为静音 问题是 当我调用 getSystemService Context AUDIO SER
  • 旋转多部分对象

    我创建了一个对象 它有大约 7 个以上的部分 包括它的主体和在不同位置 附着 到它的较小部分 我的目标是旋转整个对象 我试着简单地打电话glRotatef angle 0 1 0 在构造整个对象之前 但我意识到这似乎围绕原点旋转 一切 无论
  • 尝试运行 Qt 应用程序时 LD_LIBRARY_PATH 失败

    我想在 Linux 上使用动态库运行基于 Qt 5 的应用程序 总之 脚本将复制可执行文件和其他相关文件 包括 a 中所有必需的 solib文件夹 到所需的目的地和脚本调用gksudo将作为应用程序的调用者 到目前为止 一切正常 直到我调用
  • 如何设置 QT Creator 以使用 Autodesk FBX SDK 作为库?

    QMesh 的 Qt 文档位于以下链接 https doc qt io qt 5 11 qt3drender qmesh html 表明使用 Autodesk FBX SDK 时 QMesh 支持 FBX 它没有提供有关如何进行设置的资源
  • 尝试从 MATLAB R2014b 加载 Python 时出现“未定义的变量“py”或类”?

    def c1 a1 b1 a1 2 b1 3 cc a1 b1 return cc 我已将此功能保存在test py 当我在MATLAB中使用这个函数时 我遇到了这个问题 import py test c1 2 3 Undefined fu
  • 执行 INSERT INTO 语句时出现语法错误

    我输入的是正确的dataSource但它并没有解决我无法解决的问题cmd ExecuteNonQuery 说 INSERT INTO 语句中存在语法错误 Code Private Sub btnadd1 Click ByVal sender
  • 使用 JS 循环遍历映射列表以过滤映射键值

    如何使用JS循环遍历地图列表以从下面具有记录地图的列表中过滤出SearchMap键值 Map var searchMap new Map searchMap set ed mood strong searchMap set ed targe
  • 如何重新安装 cpan-autobundle

    我目前正在处理备份 而不是备份整个磁盘 对我来说 备份系统配置会更有效 因此 对于 perl 部分的内容 我希望有一种方法来列出已安装的模块 并在需要时重新安装这些模块 I read 如何获取已安装的 CPAN 模块的列表 关于如何获取列表
  • 如何使用Sceneform、ARCore绘制多边形?

    假设我有来自 ArFragment 命中结果的三个锚点 锚点anchor hitResult createAnchor 如何使用 Sceneform 绘制三角形并应用自定义纹理 第一步是创建一个列表AnchorNodes 能够获取坐标Anc
  • 无尖点且无自交的 Catmull-rom 曲线

    我有以下代码来计算四个控制点之间的点以生成 catmull rom 曲线 CGPoint interpolatedPosition CGPoint p0 CGPoint p1 CGPoint p2 CGPoint p3 float t fl