Browse Source

路径拟合(简易样条)

Yalling 3 weeks ago
parent
commit
eb4a8acb03

+ 35 - 0
Path_fitting/.vscode/launch.json

@@ -0,0 +1,35 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "(gdb) 启动",
+            "type": "cppdbg",
+            "request": "launch",
+            //"program": "输入程序名称,例如 ${workspaceFolder}/a.exe",
+            "program": "${fileDirname}\\main.exe",
+            "args": [],
+            "stopAtEntry": false,
+            "cwd": "${fileDirname}",
+            "environment": [],
+            "externalConsole": false,
+            "MIMode": "gdb",
+            //"miDebuggerPath": "/path/to/gdb",
+            "miDebuggerPath": "C:\\Program Files\\mingw64\\bin\\gdb.exe",
+            "setupCommands": [
+                {
+                    "description": "为 gdb 启用整齐打印",
+                    "text": "-enable-pretty-printing",
+                    "ignoreFailures": true
+                },
+                {
+                    "description": "将反汇编风格设置为 Intel",
+                    "text": "-gdb-set disassembly-flavor intel",
+                    "ignoreFailures": true
+                }
+            ]
+        }
+    ]
+}

+ 8 - 0
Path_fitting/.vscode/settings.json

@@ -0,0 +1,8 @@
+{
+    "files.associations": {
+        "studio_geo_c.h": "c",
+        "path_jc.h": "c",
+        "stdio.h": "c",
+        "stdlib.h": "c"
+    }
+}

+ 30 - 0
Path_fitting/.vscode/tasks.json

@@ -0,0 +1,30 @@
+{
+    "tasks": [
+        {
+            "type": "cppbuild",
+            "label": "C/C++: gcc.exe 生成活动文件",
+            "command": "C:\\Program Files\\mingw64\\bin\\gcc.exe",
+            "args": [
+                "-fdiagnostics-color=always",
+                "-g",
+                //"${file}",
+                "*.c",//当前文件夹所有的.c文件
+                "-o",
+                //"${fileDirname}\\${fileBasenameNoExtension}.exe"
+                "${fileDirname}\\main.exe"//生成的可执行程序
+            ],
+            "options": {
+                "cwd": "${fileDirname}"
+            },
+            "problemMatcher": [
+                "$gcc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            },
+            "detail": "调试器生成的任务。"
+        }
+    ],
+    "version": "2.0.0"
+}

+ 286 - 0
Path_fitting/Path_JC.c

@@ -0,0 +1,286 @@
+/**
+ ******************************************************************************
+ * @file           : 拟合算法及功能函数
+ * @author         : yall
+ * @brief          :                   
+ * @attention      : None
+ * @date           : 2025/6/18
+ ******************************************************************************
+ */
+#include "Path_JC.h"
+#include "studio_geo_c.h"
+
+/**
+ * 交换函数(自用)
+ */
+void swap(float *a, float *b) {
+    float temp = *a;
+    *a = *b;
+    *b = temp;
+}
+
+/** 
+ * 角转弧
+ */
+double deg2rad(double deg) {
+    return deg * PI / 180.0;
+}
+
+/**
+ * 累计距离
+ */
+void cumdist(studio_line_c *line, float *s, unsigned int size){
+    for (int i = 1; i < size; i++) {
+        float dx = line->data[i].x - line->data[i+1].x;
+        float dy = line->data[i].y - line->data[i+1].y;
+        s[i] = s[i - 1] + sqrtf(dx * dx + dy * dy);
+    }
+}
+
+/**
+ * 转笛卡尔(弧度简易版)
+ */
+void deg2Des(studio_line_c *line, unsigned int size)
+ {
+    // 计算差值
+    studio_point_c p_0 = studio_line_c_get_point(line,0);
+    for (int i = 0; i < size; i++)
+    {
+        studio_point_c tmp;
+        studio_point_c p_i = studio_line_c_get_point(line,i);
+        tmp.x = p_i.x - p_0.x;
+        tmp.y = p_i.y - p_0.y;
+        studio_line_c_set_point(line, i, tmp);
+    }
+    // 转化成m
+    for (int i = 0; i < size; i++)
+    {
+        studio_point_c tmp;
+        studio_point_c p_i = studio_line_c_get_point(line,i);
+        tmp.x = p_i.x * (PI / 180.0) * R_EN * cos(deg2rad(tmp.y));
+        tmp.y = p_i.y * (PI / 180.0) * R_EN;
+        studio_line_c_set_point(line, i, tmp);
+    }
+ }
+
+/**
+ * 中值滤波
+ */
+void median_filter_2d(studio_line_c *input, studio_line_c *output, unsigned int size, int window_size) 
+{
+    int half = window_size / 2;
+    studio_point_c  window[window_size];
+
+    for (int i = 0; i < size; i++) 
+    {
+        int k = 0;
+        for (int j = i - half; j <= i + half; j++)
+        {
+            int idn = j;
+            // 边界处理:复制边界值
+            if (idn < 0) idn = 0;
+            if (idn >= size) idn = size - 1;
+
+            window[k++] = input->data[idn];            
+        } 
+        //排序(冒泡)
+        for(int i = 0; i < window_size - 1; i++) 
+        {
+            for(int j = 0; j < window_size - 1 - i; j++) 
+            {
+                if(window[j].x > window[j + 1].x) 
+                {
+                    swap(&window[j].x, &window[j + 1].x);
+                }
+                if(window[j].y > window[j + 1].y)
+                {
+                    swap(&window[j].y, &window[j + 1].y);
+                }
+            }
+        }
+        studio_line_c_add_point(output, window[window_size / 2]);
+    }
+}
+
+/**
+ * 残差滤波--计算量偏大
+ */
+void var_filter(studio_line_c *in_before, studio_line_c *in_after, unsigned int size, float threshold) 
+{
+
+    // 残差
+    for (int i = 0; i < size; i++) {
+        in_after->data[i].x = in_before->data[i].x - in_after->data[i].x;
+        in_after->data[i].y = in_before->data[i].y - in_after->data[i].y;
+    }
+
+    // 方差--可优化存储
+    float mean_rx = 0, mean_ry = 0;
+    for (int i = 0; i < size; i++) {
+        mean_rx += in_after->data[i].x;
+        mean_ry += in_after->data[i].y;
+    }
+    mean_rx /= size;
+    mean_ry /= size;
+
+    float std_rx = 0, std_ry = 0;
+    for (int i = 0; i < size; i++) {
+        std_rx += pow(in_after->data[i].x - mean_rx, 2);
+        std_ry += pow(in_after->data[i].y - mean_ry, 2);
+    }
+    std_rx = sqrt(std_rx / size);
+    std_ry = sqrt(std_ry / size);
+
+    // 阈值判断
+    bool outliers[size];
+    for (int i = 0; i < size; i++) {
+        outliers[i] = (fabs(in_after->data[i].x) > threshold * std_rx) || (fabs(in_after->data[i].y) > threshold * std_ry);
+    }
+
+    int idx = 0;
+    for (int i = 0; i < size; i++) {
+        if (outliers[i]) {
+            studio_line_c_remove_point(in_before, idx);
+            idx++;
+        }
+    }
+}
+
+/**
+ * 样条插样
+ */
+void spline_interpolation(float *s, studio_line_c *line, unsigned int size, studio_line_c *tmp, int set_outs) {
+    // 输入检查
+    if (size < 2 ) {
+        printf("erro...SPLINE");
+        return;
+    }
+    // 步长
+    float step = (s[size - 1] - s[0]) / (set_outs - 1);
+    // 计算插值
+    int idx = 0;
+    for (int i = 0; i < set_outs; i++) {
+        float tar = s[0] + i * step; 
+        // 检索区间
+        while (idx < size - 1 && s[idx + 1] < tar) {
+            idx++;
+        }
+        // 边界检查
+        if (tar <= s[0]) {
+            tmp->data[i].x = line->data[0].x;
+            tmp->data[i].y = line->data[0].y;
+        } else if (tar >= s[size - 1]) {
+            tmp->data[i].x = line->data[size - 1].x;
+            tmp->data[i].y = line->data[size - 1].y;
+        } else {
+            // 插值计算
+            if (fabs(s[idx + 1] - s[idx]) < 1e-10) {
+                tmp->data[i].x = (line->data[idx].x + line->data[idx+1].x) / 2.0;
+                tmp->data[i].y = (line->data[idx].y + line->data[idx+1].y) / 2.0;  // 取平均值
+            } else {
+                tmp->data[i].x = line->data[idx].x + (line->data[idx+1].x - line->data[idx].x) * (tar - s[idx]) / (s[idx+1] + s[idx]);
+                tmp->data[i].y = line->data[idx].y + (line->data[idx+1].y - line->data[idx].y) * (tar - s[idx]) / (s[idx+1] + s[idx]);
+            }
+        }
+    }
+}
+
+/**
+拟合过程
+
+struct ArrayWrapper Path_fit(double data[MAX_POINTS][2], int window_size)
+ {
+    // 实际数据点数
+    int n = MAX_POINTS; 
+
+    // 提取经纬度数据
+    double longitude[MAX_POINTS], latitude[MAX_POINTS];
+    for (int i = 0; i < n; i++) {
+        longitude[i] = data[i][0];
+        latitude[i] = data[i][1];
+    }
+
+    // 计算与第一个点的经纬度差值
+    double delta_lon[MAX_POINTS], delta_lat[MAX_POINTS];
+    for (int i = 0; i < n; i++) {
+        delta_lon[i] = longitude[i] - longitude[0];
+        delta_lat[i] = latitude[i] - latitude[0];
+    }
+
+    // 转换为米单位坐标
+    double delta_x[MAX_POINTS], delta_y[MAX_POINTS];
+    for (int i = 0; i < n; i++) {
+        delta_x[i] = delta_lon[i] * (PI / 180.0) * R_EN * cos(deg2rad(latitude[i]));
+        delta_y[i] = delta_lat[i] * (PI / 180.0) * R_EN;
+    }
+
+    // 中值滤波
+    double x_filtered[MAX_POINTS], y_filtered[MAX_POINTS];
+    medfilt1(delta_x, x_filtered, n, window_size);
+    medfilt1(delta_y, y_filtered, n, window_size);
+
+    // 删除离群值
+    double residual_x[MAX_POINTS], residual_y[MAX_POINTS];
+    for (int i = 0; i < n; i++) {
+        residual_x[i] = delta_x[i] - x_filtered[i];
+        residual_y[i] = delta_y[i] - y_filtered[i];
+    }
+    double threshold_x = 0.1, threshold_y = 0.1; // 阈值
+    int outliers[MAX_POINTS] = {0};
+    for (int i = 0; i < n; i++) {
+        if (fabs(residual_x[i]) > threshold_x || fabs(residual_y[i]) > threshold_y) {
+            outliers[i] = 1;
+        }
+    }
+    double x_cleaned[MAX_POINTS], y_cleaned[MAX_POINTS];
+    int cleaned_count = 0;
+    for (int i = 0; i < n; i++) {
+        if (!outliers[i]) {
+            x_cleaned[cleaned_count] = x_filtered[i];
+            y_cleaned[cleaned_count] = y_filtered[i];
+            cleaned_count++;
+        }
+    }
+
+    // 参数化数据点:计算累积距离
+    double dist[MAX_POINTS] = {0};
+    for (int i = 1; i < cleaned_count; i++) {
+        dist[i] = sqrt(pow(x_cleaned[i] - x_cleaned[i - 1], 2) + pow(y_cleaned[i] - y_cleaned[i - 1], 2));
+    }
+    double cumdist[MAX_POINTS] = {0};
+    for (int i = 1; i < cleaned_count; i++) {
+        cumdist[i] = cumdist[i - 1] + dist[i];
+    }
+
+    // 生成均匀分布的参数值
+    int num_points = 10000;
+    double t_uniform[num_points];
+    for (int i = 0; i < num_points; i++) {
+        t_uniform[i] = (cumdist[cleaned_count - 1] * i) / (num_points - 1);
+    }
+
+    // 样条插值拟合
+    double x_fit[num_points], y_fit[num_points];
+    spline_interpolation(cumdist, x_cleaned, cleaned_count, t_uniform, x_fit, num_points);
+    spline_interpolation(cumdist, y_cleaned, cleaned_count, t_uniform, y_fit, num_points);
+
+    // 均匀采样30个点
+    int num_uniform = 30;
+    double t_uniform_samples[num_uniform];
+    for (int i = 0; i < num_uniform; i++) {
+        t_uniform_samples[i] = (cumdist[cleaned_count - 1] * i) / (num_uniform - 1);
+    }
+    double x_uniform[num_uniform], y_uniform[num_uniform];
+    spline_interpolation(cumdist, x_cleaned, cleaned_count, t_uniform_samples, x_uniform, num_uniform);
+    spline_interpolation(cumdist, y_cleaned, cleaned_count, t_uniform_samples, y_uniform, num_uniform);
+
+    struct ArrayWrapper xy;
+    // 输出均匀采样的点
+    for (int i = 0; i < num_uniform; i++) {
+        xy.data_xy[i][0] = x_uniform[i];
+        xy.data_xy[i][1] = y_uniform[i];
+    }
+
+    return xy;
+}
+ */

+ 29 - 0
Path_fitting/Path_JC.h

@@ -0,0 +1,29 @@
+#ifndef PATH_JC_H
+#define PATH_JC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+// 数据初始化
+#define MAX_POINTS 500
+#define max_points 30
+#define PI 3.14159265358979323846
+const double R_EN = 6371000.0;
+
+// 交换函数
+void swap(float *a, float *b);
+// 角转弧
+double deg2rad(double deg);
+// 转笛卡尔
+void deg2Des(studio_line_c *line, unsigned int size);
+// 中值滤波
+void median_filter_2d(studio_line_c *input, studio_line_c *output, unsigned int size, int window_size); 
+// 残差滤波
+void var_filter(studio_line_c *in_before, studio_line_c *in_after, unsigned int size, float threshold); 
+// 累计误差
+void cumdist(studio_line_c *line, float *s, unsigned int size);
+// 样条插样
+void spline_interpolation(float *s, studio_line_c *line, unsigned int size, studio_line_c *tmp, int set_outs);
+
+#endif

+ 37 - 0
Path_fitting/main.c

@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "Path_JC.h"
+#include "studio_geo_c.h"
+
+
+int  main()
+{
+    // 初始化
+    studio_line_c line = studio_line_c_init();
+    studio_line_c tmp_line = studio_line_c_init();
+
+
+    
+    // 转笛卡尔(简)
+    deg2Des(&line, line.size);
+
+    // 中值滤波
+    median_filter_2d(&line, &tmp_line, line.size, 3);
+
+    // 残差滤波(可不用)
+    var_filter(&line, &tmp_line, line.size, 0.5); 
+
+    // 累计距离
+    float *sum_dis_tmp = (float*)malloc(line.size * sizeof(float));
+    cumdist(line.data, sum_dis_tmp, line.size);
+
+    // 样条插样(一阶)
+    spline_interpolation(sum_dis_tmp, line, line.size, &tmp_line, 30);
+
+    // 释放内存
+    studio_line_c_destroy(&line);
+    studio_line_c* out_line = (studio_line_c*)realloc(&tmp_line, 30 * sizeof(studio_line_c));
+
+}

+ 207 - 0
Path_fitting/studio_geo_c.c

@@ -0,0 +1,207 @@
+/**
+******************************************************************************
+* @file           : studio_geo_c.h
+* @author         : wangyingjie
+* @brief          : 几何矢量类型 C 语言版
+* @attention      : None
+* @date           : 2025/5/10
+******************************************************************************
+*/
+
+#include "studio_geo_c.h"
+
+////////////// 点 //////////////
+
+studio_point_c studio_point_init(double xx, double yy)
+{
+    studio_point_c point = {xx, yy};
+    return point;
+}
+
+bool studio_point_equal(const studio_point_c* p1, const studio_point_c* p2)
+{
+    bool is_equal = fabs(p1->x - p2->x) <= AO_EPSILON && fabs(p1->y - p2->y) <= AO_EPSILON;
+    return is_equal;
+}
+
+////////////// 线 //////////////
+
+studio_line_c studio_line_c_init()
+{
+    studio_line_c line;
+    line.size = 0;
+    line.capacity = 4;
+    line.data = (studio_point_c*)malloc(line.capacity * sizeof(studio_point_c));
+    return line; // 注意: 返回结构体副本 (需配合 C99 或更高标准)
+}
+
+void studio_line_c_destroy(studio_line_c* line)
+{
+    if (line->data)
+    {
+        free(line->data);
+        line->data = NULL;
+        line->size = 0;
+        line->capacity = 0;
+    }
+}
+
+void studio_line_c_add_point(studio_line_c* line, studio_point_c point)
+{
+    // 容量不足时扩容 (策略: 增加固定容量 10)
+    if (line->size >= line->capacity)
+    {
+        line->capacity += 10;
+        studio_point_c* new_data = (studio_point_c*)realloc(line->data, line->capacity * sizeof(studio_point_c));
+        if (!new_data)
+        {
+            // 此处可添加错误处理 (例如: 终止程序或返回错误码)
+            return;
+        }
+        line->data = new_data;
+    }
+
+    // 添加新元素
+    line->data[line->size++] = point;
+}
+
+bool studio_line_c_remove_point(studio_line_c* line, unsigned int index)
+{
+    if (index >= line->size)
+    {
+        return false; // 索引无效
+    }
+    // 将后续点前移
+    for (unsigned int i = index; i < line->size - 1; i++)
+    {
+        line->data[i] = line->data[i + 1];
+    }
+    line->size--;
+    // 缩小容量以节省内存
+    if (line->capacity > 10 && line->size < line->capacity / 2)
+    {
+        unsigned int new_capacity = line->capacity / 2;
+        studio_point_c* new_data = (studio_point_c*)realloc(line->data, new_capacity * sizeof(studio_point_c));
+        if (new_data)
+        {
+            line->data = new_data;
+            line->capacity = new_capacity;
+        }
+    }
+    return true;
+}
+
+unsigned int studio_line_c_size(const studio_line_c* line)
+{
+    return line->size;
+}
+
+
+studio_point_c studio_line_c_get_point(const studio_line_c* line, unsigned int index)
+{
+    studio_point_c tmp;
+    if (index < line->size)
+    {
+        tmp = line->data[index];
+        return tmp;
+    }
+    return tmp; // 越界返回0,0点
+}
+
+bool studio_line_c_set_point(studio_line_c* line, unsigned int index, studio_point_c point)
+{
+    bool status = false;
+    if (index > line->size)
+    {
+        return status;
+    }
+    line->data[index] = point;
+    status = true;
+    return status;
+}
+
+
+////////////// 矩形 //////////////
+
+studio_rect_c studio_rect_init(double l, double t, double r, double b)
+{
+    studio_rect_c rect = {studio_point_init(l, t), studio_point_init(r, b)};
+    return rect;
+}
+
+void studio_rect_correct(studio_rect_c* rect)
+{
+    if (rect->left_top.x > rect->right_bottom.x)
+    {
+        double temp = rect->left_top.x;
+        rect->left_top.x = rect->right_bottom.x;
+        rect->right_bottom.x = temp;
+    }
+    if (rect->left_top.y < rect->right_bottom.y)
+    {
+        double temp = rect->left_top.y;
+        rect->left_top.y = rect->right_bottom.y;
+        rect->right_bottom.y = temp;
+    }
+}
+
+bool studio_rect_intersect(const studio_rect_c* r1, const studio_rect_c* r2)
+{
+    return !(r1->right_bottom.x < r2->left_top.x || r1->left_top.x > r2->right_bottom.x || r1->right_bottom.y > r2->
+                                                                                                                left_top.y || r1->left_top.y < r2->right_bottom.y);
+}
+
+////////////// 圆 //////////////
+
+studio_circle_c studio_circle_init(studio_point_c center, double radius)
+{
+    studio_circle_c circle = {center, radius};
+    return circle;
+}
+
+double studio_circle_area(const studio_circle_c* circle)
+{
+    return AO_M_PI * circle->radius * circle->radius;
+}
+
+////////////// 三角形 //////////////
+
+studio_triangle_c studio_triangle_init(studio_point_c a, studio_point_c b, studio_point_c c)
+{
+    studio_triangle_c triangle = {a, b, c};
+    return triangle;
+}
+
+double studio_triangle_oriented_area(const studio_triangle_c* triangle)
+{
+    return (triangle->a.x * (triangle->b.y - triangle->c.y) + triangle->b.x * (triangle->c.y - triangle->a.y) + triangle
+                                                                                                                ->c.x * (triangle->a.y - triangle->b.y)) / 2.0;
+}
+
+double studio_triangle_area(const studio_triangle_c* triangle)
+{
+    return fabs(studio_triangle_oriented_area(triangle));
+}
+
+////////////// 椭圆 //////////////
+
+studio_ellipse_c studio_ellipse_init(studio_point_c center, double rx, double ry)
+{
+    studio_ellipse_c ellipse = {center, rx, ry};
+    return ellipse;
+}
+
+double studio_ellipse_area(const studio_ellipse_c* ellipse)
+{
+    return AO_M_PI * ellipse->rx * ellipse->ry;
+}
+
+double studio_ellipse_circumference(const studio_ellipse_c* ellipse, int Ramanujan)
+{
+    if (Ramanujan == 1)
+    {
+        return AO_M_PI * (3 * (ellipse->rx + ellipse->ry) - sqrt(
+                              (3 * ellipse->rx + ellipse->ry) * (ellipse->rx + 3 * ellipse->ry)));
+    }
+    return 2 * AO_M_PI * sqrt((ellipse->rx * ellipse->rx + ellipse->ry * ellipse->ry) / 2);
+}

+ 189 - 0
Path_fitting/studio_geo_c.h

@@ -0,0 +1,189 @@
+/**
+ ******************************************************************************
+ * @file           : studio_geo_c.h
+ * @author         : wangyingjie
+ * @brief          : 几何矢量类型 C 语言版
+ *                  包括: 点、多点、线、环、面 、圆、 三角、 椭圆
+ * @attention      : None
+ * @date           : 2025/5/10
+ ******************************************************************************
+ */
+
+#ifndef STUDIO_GEO_C_H
+#define STUDIO_GEO_C_H
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define AO_EPSILON 1e-6
+#define AO_M_PI 3.14159265358979323846
+
+/****************************************/
+/// 点
+/****************************************/
+typedef struct
+{
+    double x;
+    double y;
+} studio_point_c;
+
+/// 初始化点
+/// \param xx
+/// \param yy
+/// \return
+studio_point_c studio_point_init(double xx, double yy);
+
+/// 判断两个点是否相等
+/// \param p1
+/// \param p2
+/// \return true 表示 相等
+bool studio_point_equal(const studio_point_c* p1, const studio_point_c* p2);
+
+/****************************************/
+/// 线
+/****************************************/
+
+// 该变量类型的定义为: studio_line_c temp_line = studio_line_c_init();
+// 并且 需要调用 studio_line_c_destroy(&temp_line); 释放内存
+typedef struct
+{
+    studio_point_c* data;  // 点数据指针
+    unsigned int size;     // 当前元素个数
+    unsigned int capacity; // 当前分配的内存容量
+} studio_line_c;
+
+// 初始化线段 (默认容量为4)
+
+/// 初始化线
+/// @return 返回初始化的点类型
+studio_line_c studio_line_c_init();
+
+/// 销毁线段 (释放内存)
+/// @param line
+void studio_line_c_destroy(studio_line_c* line);
+
+/// 尾部添加点
+/// @param line 线段指针
+/// @param point 点
+void studio_line_c_add_point(studio_line_c* line, studio_point_c point);
+
+/// 从线段中删除指定索引的点
+/// \param line 线段指针
+/// \param index 要删除的点的索引 (索引从0开始)
+/// \return true 表示删除成功,false 表示索引无效
+bool studio_line_c_remove_point(studio_line_c* line, unsigned int index);
+
+/// 获取当前元素数量
+/// @param line 线段
+/// @return 当前元素数量
+unsigned int studio_line_c_size(const studio_line_c* line);
+
+// 获取指定位置的点的引用 (注意索引越界问题)
+
+/// 获取指定位置的点的引用,如果下标越界 则返回 (0,0)
+/// @param line 线段
+/// @param index 索引 (索引从0开始)
+/// @return 点
+studio_point_c studio_line_c_get_point(const studio_line_c* line, unsigned int index);
+
+/// 修改指定索引位置的值
+/// @param line 线段
+/// @param index 索引 (索引从0开始)
+/// @param point 点
+/// @return true 表示修改成功,false 表示索引无效
+bool studio_line_c_set_point(studio_line_c* line, unsigned int index, studio_point_c point);
+
+/****************************************/
+/// 矩形框
+/****************************************/
+typedef struct
+{
+    studio_point_c left_top;
+    studio_point_c right_bottom;
+} studio_rect_c;
+
+studio_rect_c studio_rect_init(double l, double t, double r, double b);
+
+/// 矩形框校正
+/// \param rect
+void studio_rect_correct(studio_rect_c* rect);
+
+/// 矩形框是否相交
+/// \param r1
+/// \param r2
+/// \return
+bool studio_rect_intersect(const studio_rect_c* r1, const studio_rect_c* r2);
+
+/****************************************/
+/// 圆
+/****************************************/
+typedef struct
+{
+    studio_point_c center;
+    double radius;
+} studio_circle_c;
+
+/// 初始化圆
+/// \param center 圆心
+/// \param radius 半径
+/// \return
+studio_circle_c studio_circle_init(studio_point_c center, double radius);
+
+/// 计算圆的面积
+/// \param circle
+/// \return
+double studio_circle_area(const studio_circle_c* circle);
+
+/****************************************/
+/// 三角形
+/****************************************/
+typedef struct
+{
+    studio_point_c a;
+    studio_point_c b;
+    studio_point_c c;
+} studio_triangle_c;
+
+/// 初始化三角形
+/// \param a
+/// \param b
+/// \param c
+/// \return
+studio_triangle_c studio_triangle_init(studio_point_c a, studio_point_c b, studio_point_c c);
+
+/// 计算三角形的面积
+/// \param triangle
+/// \return
+double studio_triangle_oriented_area(const studio_triangle_c* triangle);
+
+/// 计算三角形的面积
+/// \param triangle
+/// \return
+double studio_triangle_area(const studio_triangle_c* triangle);
+
+/****************************************/
+/// 椭圆
+/****************************************/
+typedef struct
+{
+    studio_point_c center;
+    double rx;
+    double ry;
+} studio_ellipse_c;
+
+studio_ellipse_c studio_ellipse_init(studio_point_c center, double rx, double ry);
+
+/// 计算椭圆的面积
+/// \param ellipse
+/// \return
+double studio_ellipse_area(const studio_ellipse_c* ellipse);
+
+/// 计算椭圆的周长
+/// \param ellipse
+/// \param Ramanujan
+/// \return
+double studio_ellipse_circumference(const studio_ellipse_c* ellipse, int Ramanujan);
+
+#endif  //  STUDIO_GEO_C_H