Browse Source

路径拟合+样条插样

Yalling 3 weeks ago
parent
commit
a2dbed2573

+ 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}\\build\\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
+                }
+            ]
+        }
+    ]
+}

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

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

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

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

BIN
Path_fitting/build/main.exe


+ 180 - 0
Path_fitting/include/Path_JC.c

@@ -0,0 +1,180 @@
+/**
+ ******************************************************************************
+ * @file           : 拟合算法及功能函数
+ * @author         : yall
+ * @brief          :                   
+ * @attention      : None
+ * @date           : 2025/6/18
+ ******************************************************************************
+ */
+#include "Path_JC.h"
+#include "studio_geo_c.h"
+
+double R_EN = 6371000.0;
+
+/**
+ * 交换函数(自用)
+ */
+void swap(double *a, double *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 lon_lat_0 = studio_line_c_get_point(line,0);
+    for (size_t i = 0; i < size; ++i) 
+    {
+        studio_point_c tmp;
+        tmp.x = line->data[i].x - lon_lat_0.x;
+        tmp.y = line->data[i].y - lon_lat_0.y;
+        // 计算平面坐标(米)
+        tmp.x = deg2rad(tmp.x) * R_EN * cos(deg2rad(line->data[i].y));
+        tmp.y = deg2rad(tmp.y) * 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]);
+            }
+        }
+    }
+}

+ 31 - 0
Path_fitting/include/Path_JC.h

@@ -0,0 +1,31 @@
+#ifndef PATH_JC_H
+#define PATH_JC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "studio_geo_c.h"
+
+// 数据初始化
+#define MAX_POINTS 500
+#define max_points 30
+#define PI 3.14159265358979323846
+extern double R_EN; 
+
+
+// 交换函数
+void swap(double *a, double *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

+ 207 - 0
Path_fitting/include/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/include/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

+ 190 - 0
Path_fitting/main.c

@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "include/Path_JC.h"
+#include "include/studio_geo_c.h"
+
+int  main()
+{
+    // 初始化
+    studio_line_c line = studio_line_c_init();
+    studio_line_c tmp_line = studio_line_c_init();
+    studio_line_c_add_point(&line, studio_point_init( 120.0798731, 36.2145540));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798738, 36.2145750));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798675, 36.2146510));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798691, 36.2147368));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798703, 36.2148213));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798723, 36.2149135));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798666, 36.2149940));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798696, 36.2150526));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798878, 36.2151376));
+    studio_line_c_add_point(&line, studio_point_init( 120.0799663, 36.2151995));
+    studio_line_c_add_point(&line, studio_point_init( 120.0800706, 36.2152123));
+    studio_line_c_add_point(&line, studio_point_init( 120.0801838, 36.2152091));
+    studio_line_c_add_point(&line, studio_point_init( 120.0803001, 36.2152075));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804170, 36.2152073));
+    studio_line_c_add_point(&line, studio_point_init( 120.0805423, 36.2152265));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806736, 36.2152321));
+    studio_line_c_add_point(&line, studio_point_init( 120.0808106, 36.2152131));
+    studio_line_c_add_point(&line, studio_point_init( 120.0809561, 36.2152573));
+    studio_line_c_add_point(&line, studio_point_init( 120.0811123, 36.2152301));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812173, 36.2152231));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812853, 36.2152213));
+    studio_line_c_add_point(&line, studio_point_init( 120.0813195, 36.2152221));
+    studio_line_c_add_point(&line, studio_point_init( 120.0813926, 36.2152216));
+    studio_line_c_add_point(&line, studio_point_init( 120.0815376, 36.2152218));
+    studio_line_c_add_point(&line, studio_point_init( 120.0817028, 36.2152380));
+    studio_line_c_add_point(&line, studio_point_init( 120.0818716, 36.2152200));
+    studio_line_c_add_point(&line, studio_point_init( 120.0820525, 36.2152473));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822268, 36.2152360));
+    studio_line_c_add_point(&line, studio_point_init( 120.0824110, 36.2152340));
+    studio_line_c_add_point(&line, studio_point_init( 120.0826048, 36.2152435));
+    studio_line_c_add_point(&line, studio_point_init( 120.0827026, 36.2152465));
+    studio_line_c_add_point(&line, studio_point_init( 120.0828165, 36.2151315));
+    studio_line_c_add_point(&line, studio_point_init( 120.0828205, 36.2149925));
+    studio_line_c_add_point(&line, studio_point_init( 120.0828221, 36.2148178));
+    studio_line_c_add_point(&line, studio_point_init( 120.0828221, 36.2146781));
+    studio_line_c_add_point(&line, studio_point_init( 120.0827581, 36.2145310));
+    studio_line_c_add_point(&line, studio_point_init( 120.0826711, 36.2144438));
+    studio_line_c_add_point(&line, studio_point_init( 120.0825228, 36.2144608));
+    studio_line_c_add_point(&line, studio_point_init( 120.0824073, 36.2144546));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822536, 36.2143848));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822430, 36.2142630));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822438, 36.2140925));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822320, 36.2139576));
+    studio_line_c_add_point(&line, studio_point_init( 120.0821196, 36.2138603));
+    studio_line_c_add_point(&line, studio_point_init( 120.0819660, 36.2138743));
+    studio_line_c_add_point(&line, studio_point_init( 120.0817780, 36.2139215));
+    studio_line_c_add_point(&line, studio_point_init( 120.0816141, 36.2138886));
+    studio_line_c_add_point(&line, studio_point_init( 120.0814238, 36.2138956));
+    studio_line_c_add_point(&line, studio_point_init( 120.0813170, 36.2139134));
+    studio_line_c_add_point(&line, studio_point_init( 120.0811468, 36.2138908));
+    studio_line_c_add_point(&line, studio_point_init( 120.0810021, 36.2138916));
+    studio_line_c_add_point(&line, studio_point_init( 120.0808083, 36.2138886));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806713, 36.2138871));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804978, 36.2138565));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804513, 36.2137123));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804206, 36.2135151));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804290, 36.2134026));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804241, 36.2132476));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804116, 36.2131533));
+    studio_line_c_add_point(&line, studio_point_init( 120.0802560, 36.2131256));
+    studio_line_c_add_point(&line, studio_point_init( 120.0800926, 36.2131391));
+    studio_line_c_add_point(&line, studio_point_init( 120.0799135, 36.2130891));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798561, 36.2129658));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798958, 36.2127938));
+    studio_line_c_add_point(&line, studio_point_init( 120.0798420, 36.2126813));
+    studio_line_c_add_point(&line, studio_point_init( 120.0799233, 36.2125713));
+    studio_line_c_add_point(&line, studio_point_init( 120.0800858, 36.2125850));
+    studio_line_c_add_point(&line, studio_point_init( 120.0803211, 36.2125908));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804851, 36.2125933));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806090, 36.2125443));
+    studio_line_c_add_point(&line, studio_point_init( 120.0805893, 36.2124040));
+    studio_line_c_add_point(&line, studio_point_init( 120.0805901, 36.2122559));
+    studio_line_c_add_point(&line, studio_point_init( 120.0805881, 36.2121241));
+    studio_line_c_add_point(&line, studio_point_init( 120.0805778, 36.2119698));
+    studio_line_c_add_point(&line, studio_point_init( 120.0805850, 36.2118591));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806126, 36.2116988));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806191, 36.2115958));
+    studio_line_c_add_point(&line, studio_point_init( 120.0805838, 36.2114628));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806978, 36.2114123));
+    studio_line_c_add_point(&line, studio_point_init( 120.0808786, 36.2114136));
+    studio_line_c_add_point(&line, studio_point_init( 120.0810340, 36.2114101));
+    studio_line_c_add_point(&line, studio_point_init( 120.0811905, 36.2114678));
+    studio_line_c_add_point(&line, studio_point_init( 120.0811971, 36.2116091));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812023, 36.2117358));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812043, 36.2118245));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812191, 36.2119326));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812308, 36.2120568));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812268, 36.2121850));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812186, 36.2123110));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812106, 36.2124338));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812160, 36.2125433));
+    studio_line_c_add_point(&line, studio_point_init( 120.0813505, 36.2125793));
+    studio_line_c_add_point(&line, studio_point_init( 120.0815203, 36.2125826));
+    studio_line_c_add_point(&line, studio_point_init( 120.0816993, 36.2125836));
+    studio_line_c_add_point(&line, studio_point_init( 120.0818490, 36.2126136));
+    studio_line_c_add_point(&line, studio_point_init( 120.0818573, 36.2127058));
+    studio_line_c_add_point(&line, studio_point_init( 120.0818611, 36.2128105));
+    studio_line_c_add_point(&line, studio_point_init( 120.0818571, 36.2129800));
+    studio_line_c_add_point(&line, studio_point_init( 120.0817858, 36.2130876));
+    studio_line_c_add_point(&line, studio_point_init( 120.0816405, 36.2131116));
+    studio_line_c_add_point(&line, studio_point_init( 120.0814890, 36.2131188));
+    studio_line_c_add_point(&line, studio_point_init( 120.0813440, 36.2131221));
+    studio_line_c_add_point(&line, studio_point_init( 120.0811786, 36.2131273));
+    studio_line_c_add_point(&line, studio_point_init( 120.0809845, 36.2131298));
+    studio_line_c_add_point(&line, studio_point_init( 120.0808101, 36.2131210));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806503, 36.2131143));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804963, 36.2131231));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804051, 36.2131858));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804320, 36.2133146));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804310, 36.2134671));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804475, 36.2135978));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804466, 36.2136908));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804383, 36.2137131));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804383, 36.2137353));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804388, 36.2138191));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804340, 36.2139444));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804275, 36.2140595));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804311, 36.2141696));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804268, 36.2142596));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804221, 36.2143248));
+    studio_line_c_add_point(&line, studio_point_init( 120.0804638, 36.2144208));
+    studio_line_c_add_point(&line, studio_point_init( 120.0806425, 36.2144220));
+    studio_line_c_add_point(&line, studio_point_init( 120.0807880, 36.2144381));
+    studio_line_c_add_point(&line, studio_point_init( 120.0809288, 36.2144316));
+    studio_line_c_add_point(&line, studio_point_init( 120.0810285, 36.2144035));
+    studio_line_c_add_point(&line, studio_point_init( 120.0811473, 36.2143823));
+    studio_line_c_add_point(&line, studio_point_init( 120.0812603, 36.2143681));
+    studio_line_c_add_point(&line, studio_point_init( 120.0813386, 36.2143738));
+    studio_line_c_add_point(&line, studio_point_init( 120.0814586, 36.2143900));
+    studio_line_c_add_point(&line, studio_point_init( 120.0816028, 36.2144006));
+    studio_line_c_add_point(&line, studio_point_init( 120.0817420, 36.2144165));
+    studio_line_c_add_point(&line, studio_point_init( 120.0818983, 36.2144256));
+    studio_line_c_add_point(&line, studio_point_init( 120.0820240, 36.2144223));
+    studio_line_c_add_point(&line, studio_point_init( 120.0821661, 36.2144248));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822980, 36.2144378));
+    studio_line_c_add_point(&line, studio_point_init( 120.0824326, 36.2144521));
+    studio_line_c_add_point(&line, studio_point_init( 120.0825441, 36.2144588));
+    studio_line_c_add_point(&line, studio_point_init( 120.0826215, 36.2144620));
+    studio_line_c_add_point(&line, studio_point_init( 120.0827366, 36.2144941));
+    studio_line_c_add_point(&line, studio_point_init( 120.0827791, 36.2145916));
+    studio_line_c_add_point(&line, studio_point_init( 120.0828050, 36.2146823));
+    studio_line_c_add_point(&line, studio_point_init( 120.0828073, 36.2148071));
+    studio_line_c_add_point(&line, studio_point_init( 120.0828108, 36.2149333));
+    studio_line_c_add_point(&line, studio_point_init( 120.0827991, 36.2150419));
+    studio_line_c_add_point(&line, studio_point_init( 120.0827600, 36.2151475));
+    studio_line_c_add_point(&line, studio_point_init( 120.0826771, 36.2152325));
+    studio_line_c_add_point(&line, studio_point_init( 120.0825873, 36.2152428));
+    studio_line_c_add_point(&line, studio_point_init( 120.0824720, 36.2152433));
+    studio_line_c_add_point(&line, studio_point_init( 120.0823341, 36.2152420));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822156, 36.2152483));
+    studio_line_c_add_point(&line, studio_point_init( 120.0822723, 36.2155193));
+
+    // 转笛卡尔(简)
+    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, sum_dis_tmp, line.size);
+
+    // 样条插样(一阶)
+    spline_interpolation(sum_dis_tmp, &line, line.size, &tmp_line, 100);
+
+    // 打印测试
+    for(int i;i < 100;i++)
+    {
+        printf("%.7f, %.7f;\n",studio_line_c_get_point(&tmp_line, i).x,studio_line_c_get_point(&tmp_line, i).y);
+    }
+
+    // 释放内存
+    studio_line_c_destroy(&line);
+    studio_line_c_destroy(&tmp_line);
+}