bezier曲线拟合椭圆弧线

椭圆弧线用bezier曲线拟合 。
先计算出 椭圆中心 起始角度 旋转角度

S t e p 1 : C o m p u t e ( x 1 ′ , y 1 ′ ) Step 1: Compute(x'_1, y'_1) Step1:Compute(x1,y1)
( x 1 ′ y 1 ′ ) = ( cos ⁡ φ sin ⁡ φ − sin ⁡ φ cos ⁡ φ ) ⋅ ( x 1 − x 2 2 y 1 − y 2 2 ) \begin{pmatrix} x'_1 \\ \\ y'_1 \end{pmatrix} = \begin{pmatrix} \cos\varphi & \sin\varphi \\ \\ -\sin\varphi & \cos\varphi \end{pmatrix} \cdot \begin{pmatrix} \dfrac{ x_1-x_2}{2} \\ \\ \dfrac{ y_1-y_2}{2} \end{pmatrix} x1y1 = cosφsinφsinφcosφ 2x1x22y1y2

S t e p 2 : C o m p u t e ( c x ′ , c y ′ ) Step 2: Compute(c'_x, c'_y) Step2:Compute(cx,cy)
( c x ′ c y ′ ) = ± r x 2 y y 2 − r x 2 ( y 1 ′ ) 2 − r y 2 ( x 1 ′ ) 2 r x 2 ( y 1 ′ ) 2 + r y 2 ( x 1 ′ ) 2 ( r x y 1 ′ r y − r y x 1 ′ r x ) \begin{pmatrix} c'_x \\ \\ c'_y \end{pmatrix} = \pm \sqrt { \dfrac{ r^2_x y^2_y - r^2_x(y'_1)^2 - r^2_y (x'_1)^2} {r^2_x (y'_1)^2 + r^2_y(x'_1)^2 } } \begin{pmatrix} \dfrac{ r_xy'_1}{r_y} \\ \\ -\dfrac{ r_y x'_1}{r_x} \end{pmatrix} cxcy =±rx2(y1)2+ry2(x1)2rx2yy2rx2(y1)2ry2(x1)2 ryrxy1rxryx1

在这里插入图片描述

然后拟合
在这里插入图片描述

在这里插入图片描述

附代码

#include <math.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define PI 3.1415926

static float angle(float ux, float uy, float vx, float vy) {   
  float res = (ux*vx + uy*vy)/sqrtf((ux*ux+uy*uy)*(vx*vx+vy*vy));
  res = MIN(MAX(res,-1),1);  //-1 <= res <= 1;

  float a ; 
  if ((ux*vy - uy*vx) < 0)
   a = -acosf(res);
  else
   a = acosf(res);

  return a;
}

static int calcEllipse(float rx, float ry, float ph, int fa, int fs, 
        float x1, float y1, float x2, float y2, 
        float* pcx, float* pcy, float* pth, float* pdth) 
{
    if (!rx || !ry) return -1; 
    rx = (rx > 0) ? rx : -rx;
    ry = (ry > 0) ? ry : -ry;

    float xp, yp; 
    {   
        float tx = (x1 - x2) / 2;
        float ty = (y1 - y2) / 2;

        xp = cosf(ph)*tx + sinf(ph)*ty;
        yp = -sinf(ph)*tx + cosf(ph)*ty;

        float lambda = xp*xp/(rx*rx) + yp*yp/(ry*ry);

        if (lambda > 1) {
            lambda = sqrtf(lambda);

            rx = lambda*rx;
            ry = lambda*ry;
        }
    }

    float cx,cy;
    float th, dth;
    {
        float pr;
        {
            float tp = rx*rx*yp*yp + ry*ry*xp*xp;
            pr = sqrtf((rx*rx*ry*ry - tp)/tp);
        }

        float cxp,cyp;

        if (fa != fs) {
            cxp =  pr * rx * yp / ry;
            cyp = -pr * ry * xp / rx;
        } else {
            cxp = -pr * rx * yp / ry;
            cyp =  pr * ry * xp / rx;
        }
        cx = cosf(ph)*cxp - sinf(ph)*cyp + (x1+x2)/2;
        cy = sinf(ph)*cxp + cosf(ph)*cyp + (y1+y2)/2;

        th = angle(1, 0, (xp - cxp) / rx, (yp - cyp) / ry);
        dth = angle((xp-cxp)/rx,(yp-cyp)/ry,(-xp-cxp)/rx,(-yp-cyp)/ry);
        dth = fmod(dth,2*PI);
    }

    if ( fs==0 && dth > 0)
        dth -= 2*PI;
    if ( fs==1 && dth < 0)
        dth += 2*PI;

    *pcx = cx;
    *pcy = cy;
    *pth = th;
    *pdth = dth;
    return 0;
}
//  EFAULT pathname points outside your accessible address space
static int adrNotValid(void* p)
{
    int fd = open(p, 0, 0);
    int e = errno;
    if (fd == -1 && e == EFAULT)
        return 1;
    else if (fd != -1)
        close(fd);
    return 0;
}

static int _bezierEllipse(float cx, float cy, float rx, float ry,float th, float sth, float eth,float* res)
{
    if(!res || adrNotValid(res) || adrNotValid(&res[5]))
        return -1;

    float x1 = cx + rx * cosf(th)*cosf(sth) - ry * sinf(th)*sinf(sth);
    float y1 = cy + rx * sinf(th)*cosf(sth) + ry * cosf(th)*sinf(sth);

    float x2 = cx + rx * cosf(th)*cosf(eth) - ry * sinf(th)*sinf(eth);
    float y2 = cy + rx * sinf(th)*cosf(eth) + ry * cosf(th)*sinf(eth);

    float dx1 = -1 * rx * cosf(th) * sinf(sth) - ry * sinf(th) * cosf(sth);
    float dy1 = -1 * rx * sinf(th) * sinf(sth) + ry * cosf(th) * cosf(sth);

    float dx2 = -1 * rx * cosf(th) * sinf(eth) - ry * sinf(th) * cosf(eth);
    float dy2 = -1 * rx * sinf(th) * sinf(eth) + ry * cosf(th) * cosf(eth);
    float tmp = tan((eth-sth)/2);
    float alpha = sinf(eth - sth)*(sqrtf(4+3*tmp*tmp)-1)/3;

 //   *res++ = x1;
 //   *res++ = y1;
    *res++ = x1 + alpha*dx1; // p1x
    *res++ = y1 + alpha*dy1; // p1y
    *res++ = x2 - alpha*dx2; // p2x
    *res++ = y2 - alpha*dy2; // p2y
    *res++ = x2;
    *res++ = y2;
    return 0;
}

int bezierEllipse(float cx, float cy, float rx, float ry,float th, float sth, float eth, int n,float* res)
{
    if (n <= 0 || sth == eth) return -1;

    float step = (eth - sth)/n;
    float tmp = sth;
    for (int i = 0; i < n; i++) {
        int e = _bezierEllipse(cx, cy, rx, ry,th, tmp, tmp+step,res);
        if (e) return -1;
        tmp += step;
        res += 6;
    }
    return 0;
}

int main()
{
 float rx = 50;
 float ry = 40;
 float phi = -120.0/180 * PI ;
 float x1 = 100;
 float y1 = 80;
 float x2 = 120;
 float y2 = 60;

 float cx,cy,th,dth;

 calcEllipse( rx, ry, phi, 1, 0, x1, y1, x2, y2,&cx,&cy,&th,&dth);
 printf("%f %f %f %f\n",cx,cy,th,dth);

 int dn = ceilf(((dth > 0)? dth : -dth)  * 4 / PI) ;

 if (dn < 1)
     return 0;

 int size = 2+6*dn;
 float* data = (float*)malloc(size*sizeof(float));

 data[0] = x1;
 data[1] = y1;

 bezierEllipse(cx, cy, rx, ry,phi, th, th+dth, dn,data+2);

 data[size-2] = x2;
 data[size-1] = y2;
 printf("M %f %f ",x1,y1);
 for(int i = 0; i < dn; i++) {
     printf(" C ");
     for(int j = 0; j < 6; j++)
     printf(" %f ",data[2+6*i+j]);
 }
 printf("\n");
}

拟合圆 椭圆 测试结果
在这里插入图片描述

参考 https://www.w3.org/TR/SVG/implnote.html
https://paperzz.com/doc/7611457/drawing-an-elliptical-arc-using-polylines–quadratic-or

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/472794.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JMH微基准测试框架学习笔记

一、简介 JMH&#xff08;Java Microbenchmark Harness&#xff09;是一个用于编写、构建和运行Java微基准测试的框架。它提供了丰富的注解和工具&#xff0c;用于精确控制测试的执行和结果测量&#xff0c;从而帮助我们深入了解代码的性能特性。 二、案例实战 在你的pom文件…

2024最新自动化测试面试题合集 (附答案)

1、你会封装自动化测试框架吗&#xff1f; 这个问得最多&#xff0c;甚至有很多公司直接写在招聘要求中&#xff01; 当然可以&#xff0c;自动化框架主要的核心框架就是分层PO模式&#xff1a;分别为&#xff1a;基础封装层BasePage&#xff0c;PO页面对象层&#xff0c;Tes…

Linux系统

yum 命令 安装软件 1.安装yum包&#xff1a; $ yum install PACKAGE_NAME Bash 2.yum包装&#xff1a; $ yum remove PACKAGE_NAME Shell 3.重新安装一个yum包&#xff1a; $ yum reinstall PACKAGE_NAME Bash 4.搜索yum包&#xff1a; $ yum search PACKAGE_NAME …

媒体发稿途径,怎么样去网络媒体投稿,媒体发布一般价格多少钱?

在信息爆炸的时代&#xff0c;媒体作为传递信息的重要渠道&#xff0c;成为企业推广的重要手段。然而&#xff0c;如何去网络媒体投稿&#xff0c;以及媒体发布的价格却是困扰很多企业和个人的问题。今天&#xff0c;我们将会为大家介绍一种简单易行的方式&#xff1a;媒介多多…

蓝桥杯练习05水果摆盘

水果摆盘 介绍 目前CSS3中新增的Flex弹性布局已经成为前端页面布局的首选方式&#xff0c;这次试题将利用Flex实现经典布局效果。 准备 开始答题前&#xff0c;需要先打开本题的项目代码文件夹&#xff0c;目录结构如下&#xff1a; 其中&#xff1a; index.css是本次需要补…

Visual Studio 2013 - 重置窗口布局

Visual Studio 2013 - 重置窗口布局 1. Microsoft Visual Studio 2013 - 重置窗口布局References 1. Microsoft Visual Studio 2013 - 重置窗口布局 窗口 -> 重置窗口布局 References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

闭包机制的底层实现原理

说明:此次分享不涉及ES6的let,const,块级作用域,这些其实都是对本次分享内容的扩展。 闭包的重要性 JS的内功心法,闭包是JavaScript中非常重要的核心概念,关系着JS里很多核心的机制,理解了它,很多问题都会迎刃而解,不理解闭包用JS永远像隔着一层窗户纸。 前端发展日新…

2 使用GPU理解并行计算

2.1 简介 本章旨在对并行程序设计的基本概念及其与GPU技术的联系做一个宽泛的介绍。本章主要面向具有串行程序设计经验&#xff0c;但对并行处理概念缺乏了解的读者。我们将用GPU的基本知识来讲解并行程序设计的基本概念。 2.2 传统的串行代码 绝大多数程序员是在串行程序占据…

备战蓝桥杯D33 - 真题 - 松散子序列

题目描述 解题思路 ps&#xff1a;思路是我看了大佬的题解后自己的理解&#xff0c;自己给自己捋清楚思路。 1.设置输入&#xff0c;将字符串输入 2.因为输入的是字符&#xff0c;但要找出字符的最大价值&#xff0c;所以先将字符串转化成对应的数值。 这时候就要用到ord函…

中国(京津冀)太阳能光伏展

中国(京津冀)太阳能光伏展是一场关于太阳能光伏技术和产业的展览会&#xff0c;主要在中国的京津冀地区举办。该展览会旨在推动太阳能光伏产业的发展&#xff0c;促进技术交流和商业合作。 在中国&#xff0c;太阳能光伏产业一直是重点发展的领域之一。中国政府制定了一系列政策…

水电能源智能化监控系统

水电能源智能化监控系统是利用现代信息技术&#xff0c;对水电站的运行状态、设备性能、环境参数等进行实时监测和管理的一种智能化系统。随着我国水电能源事业的快速发展&#xff0c;水电能源智能化监控系统在水电能源行业中的应用越来越广泛&#xff0c;为我国水电能源事业的…

【Qt学习笔记】(六)界面优化

界面优化 1 QSS1.1 背景介绍1.2 基本语法1.3 QSS设置方式1.3.1 指定控件样式设计1.3.2 全局样式设置1.3.3 使用 Qt Designer 编辑样式 1.4 选择器1.4.1选择器概况1.4.2 子控件选择器&#xff08;Sub-Controls&#xff09;1.4.3伪类选择器(Pseudo-States) 1.5 样式属性1.5.1 盒模…

[C++]20:unorderedset和unorderedmap结构和封装。

unorderedset和unorderedmap结构和封装 一.哈希表&#xff1a;1.直接定址法&#xff1a;2.闭散列的开放定址法&#xff1a;1.基本结构&#xff1a;2.insert3.find4.erase5.补充&#xff1a;6.pair<k,v> k的数据类型&#xff1a; 3.开散列的拉链法/哈希桶&#xff1a;1.基…

PyTorch 深度学习(GPT 重译)(四)

第二部分&#xff1a;从现实世界的图像中学习&#xff1a;肺癌的早期检测 第 2 部分的结构与第 1 部分不同&#xff1b;它几乎是一本书中的一本书。我们将以几章的篇幅深入探讨一个单一用例&#xff0c;从第 1 部分学到的基本构建模块开始&#xff0c;构建一个比我们迄今为止看…

图书馆RFID(射频识别)数据模型压缩/解压缩算法实现小工具

1. 前言 最近闲来无聊&#xff0c;看了一下《图书馆射频识别数据模型第1部分&#xff1a;数据元素的设置及应用规则》以及《图书馆射频识别数据模型第2部分&#xff1a;基于ISO/IEC 15962的数据元素编码方案》&#xff0c;决定根据上面的编码方法实现一下该算法&#xff0c;于…

算法沉淀——贪心算法四(leetcode真题剖析)

算法沉淀——贪心算法四 01.最长回文串02.增减字符串匹配03.分发饼干04.最优除法 01.最长回文串 题目链接&#xff1a;https://leetcode.cn/problems/longest-palindrome/ 给定一个包含大写字母和小写字母的字符串 s &#xff0c;返回 通过这些字母构造成的 最长的回文串 。 …

【软件测试】如何设计自动化测试脚本

企业中如何设计自动化测试脚本呢&#xff1f;今天我们就来为大家分享一些干货。 一、线性设计 线性脚本设计方式是以脚本的方式体现测试用例&#xff0c;是一种非结构化的编码方式&#xff0c;多数采用录制回放的方式&#xff0c;测试工程师通过录制回访的访问对被测系统进行…

在ComfyUI中,IP-Adapter的一大堆模型应该怎么放?

&#x1f381;背景介绍 IP-Adapter有一大堆的模型&#xff0c;那么这个模型在ComfyUI中&#xff0c;这些模型到底应该怎么放呢&#xff1f;这篇文章简单介绍一下。 首先&#xff0c;大家需要到huggingface上找到对应的模型&#xff0c;把所有的模型先下载下来。 huggingface…

vue2 项目认识 vue2 各个文件夹作用 vue工程文件作用 main.js是什么 package.json是什么

1. node_modules : 项目依赖文件夹&#xff0c;相当于java类库。依赖包 2. public 文件夹: 一般放置一些静态资源&#xff08;图片&#xff09;&#xff0c;注意&#xff1a; 放在public文件夹内的文件&#xff0c;webpack打包时候&#xff0c;会原封不动打包到dist文件夹中 …

隐私计算实训营学习二:隐私计算开源如何助力数据要素流通

文章目录 一、数据要素流转与数据内外循环二、数据外循环中的信任焦虑三、数据要素流通对隐私计算的期望四、隐私计算开源助力数据要素流通 一、数据要素流转与数据内外循环 数据要素流转过程(从数据采集加工->到数据价值释放)&#xff1a; 链路主要包括采集、存储、加工、…