地信算法作业——缓冲区算法(c语言)

食用说明:1、c语言,软件VS2022。2、小型作业题分享,没有经过严谨测试。3、程序采用文件输入输出格式,输入文件格式为:点数\n缓冲区半径\n点坐标xi yi。4、分享经验+吐槽并发进行,攻击性较强,谁都攻击

0.编译预处理命令

(本来觉得不会有人这个都不会吧,但是感觉我自己都会忘)

#include<stdio.h>
#include<math.h>
#include<stdbool.h>
#define theta 30 //中间点的缓冲区角每次变化的角度
  1. 两个准备函数

方向角函数azimuth,通过求斜率和tan的反三角函数得到两点确定的直线的方向角。

判断凹凸性的布尔函数aotu,由于本程序全程只考虑逆时针求解,所以向量积为正时直接判断为凸角,不讨论所得角度矢量的方向问题。

double azimuth(double x1, double y1, double x2, double y2)//求方向角的函数
{
    double k; double pi = atan(1) * 4;
    k = (y2 - y1) / (x2 - x1);
    return(atan(k)*180/pi);//弧度转为角度
}

bool aotu(double x1, double y1, double x2, double y2, double x3, double  y3)
{//判断凹凸性,凹用平行线,凸用凸角圆弧法
    double s = 0;//矢量的叉积
    s = (x2 - x1)*(y3 - y2) - (x3 - x2)*(y2 - y1);
    //统一逆时针开始走(线段的右侧)
    if (s > 0)
        return true;//若右侧为凸角,凸角丁真
    else if (s < 0)
        return false;
    else return false;
}

2.Buffer函数

该函数用于求解缓冲区点,共分为三个部分:起点缓冲区,中间点缓冲区(分凹角和凸角讨论),终点缓冲区。

起点缓冲区与终点缓冲区方法一致,即根据缓冲半径和方向角联合求解;中间点缓冲区需使用aotu函数分凹角和凸角进行不同情况讨论:凹角仅求缓冲区平行线交点,根据方程式求解即可;凸角需在在凸起处形成缓冲区圆弧,具体为先根据方程解出圆弧起点和终点,再在变化角度小于起点终点所成角度的条件下,根据缓冲区半径和变化角度求出圆弧上的点。在求解过程中,原始点(输入点)和缓冲区点(输出点)应属于两套循环体系,程序里使用i控制缓冲区点,j控制原始点。

需要注意的是,由于本程序仅讨论逆时针,导致在一次从原始起点到原始终点的遍历过程中只能得到单边(向量右边)的缓冲区,所以需要再从原始终点到原始起点循环一次,才能得到双边结果。

在程序中对缓冲区点数进行记录,最后该函数返回缓冲区点数。

(虽然秃了但是毕竟写出来了,所以很得意地写了一大串感想。另外因为没有安全感所以经常写一步测试一步,注释掉的就是测试中间变量的,嫌冗长直接删了就好)

(beg是起点begin的缩写,不是乞讨的beg,我才没有第一次接触这个缩写时以为它是乞讨)

int buffer(double r, int n ,double *x,double* y, double *A,double* B)
{//r:缓冲区半径bufradus,n:点数,x1和Y1:数组点坐标,AB为缓冲区的点集合
    // 缓冲区点用的i  原线段用的j 
    double azimuthangle[100];//每个原始点的方位角(最后一个点木有)
    int j = 0; int i = 0;

    for (j = 0; j < n - 1; j++)
        azimuthangle[j]= azimuth(x[j], y[j], x[j+1], y[j+1]);//第j个点的方位角

    for ( i = 0; i < 7; i++)
    {
        double ang = azimuthangle[0] + 90 + i * theta;
        double setx = r * cos(ang);
        double sety = r * sin(ang);
        A[i] = x[0]+setx; B[i] = y[0]+sety;
    }
    int i1 = i;//记录一下
    第1轮逆时针
    for ( j = 1; j <= n-2; j++)//非首尾点进j循环,i留给缓冲区点
    {
        bool istu = true;
        istu = aotu(x[j - 1], y[j - 1], x[j], x[j], x[j + 1], y[j + 1]);

        if (istu == true)//(凸角处)
        {//统一逆时针方向弥合(轴线右侧)
            double xbeg, ybeg, xend, yend; double anglebeg, angleend;
            if (x[j] != x[j - 1])//分两种情况讨论圆弧起点位置
            {
                ybeg = y[j] - r * (x[j] - x[j - 1]) / sqrt(pow(x[j] - x[j - 1], 2) + pow(y[j] - y[j - 1], 2));
                xbeg = x[j] - (ybeg - y[j]) * (y[j] - y[j - 1]) / (x[j] - x[j - 1]);
                yend = y[j] - r * (x[j + 1] - x[j]) / sqrt(pow(x[j] - x[j + 1], 2) + pow(y[j] - y[j + 1], 2));
                xend = x[j] - (yend - y[j]) * (y[j] - y[j + 1]) / (x[j] - x[j + 1]);
            }
            else if(x[j] == x[j - 1])
            {
                ybeg = y[j]; xbeg = x[j] + r;
                yend = y[j] - r * (x[j + 1] - x[j]) / sqrt(pow(x[j] - x[j + 1], 2) + pow(y[j] - y[j + 1], 2));
                xend = x[j] - (yend - y[j]) * (y[j] - y[j + 1]) / (x[j] - x[j + 1]);
            }    
            /*printf("\n圆弧的起点:%lf,%lf  终点:%lf,%lf\n", xbeg, ybeg, xend, yend);
            printf("\nx[j]:%lf,  y[j]:%lf\n", x[j],y[j]);*/
            anglebeg = azimuth( x[j],y[j], xbeg, ybeg);
            angleend = azimuth(x[j], y[j], xend, yend);
            //printf("\n起点方向角:%lf,  终点方向角:%lf\n", anglebeg,angleend);
            double angle=anglebeg,angledelta = angleend - anglebeg; //angle:角度变量,angledelta:起点终点角度差
            int k = 0;
            while ((angle + theta) < angleend)
            {
                angle = angle + theta;//theta为每次加的角度常量
                double setx = r * cos(angle);
                double sety = r * sin(angle);
                A[i] = setx + x[j]; B[i] = sety + y[j];
                i++;
                //printf("\n%lf,%lf,%lf\n", setx, sety,angledelta);
            } 
        }
        if (istu == false)//凹角处的点(平行线)
        {
            double xp = r * (cos(azimuthangle[j - 1]) + cos(azimuthangle[j])) / sin(azimuthangle[j] - azimuthangle[j - 1]);
            double yp = r * (sin(azimuthangle[j - 1]) + sin(azimuthangle[j]))/ sin(azimuthangle[j] - azimuthangle[j - 1]);
            A[i] = x[j] - xp;
            B[i] = y[j] - yp;
            i++; 
            //printf("看看I:%d\n", i);
            //printf("看看方向角:%lf,%lf\n", azimuthangle[j-1],azimuthangle[j]);
        }
    }
    int i2 = i;
    //第2轮逆时针,即从终点到起点
    for (j = n - 2; j >= 1; j--)//非首尾点进j循环,i留给缓冲区点
    {
        bool istu = true;
        istu = aotu(x[j - 1], y[j - 1], x[j], x[j], x[j + 1], y[j + 1]);

        if (istu == true)//(凸角处)
        {//统一逆时针方向弥合(轴线右侧)
            double xbeg, ybeg, xend, yend; double anglebeg, angleend;
            if (x[j] != x[j - 1])//分两种情况讨论圆弧起点位置
            {
                ybeg = y[j] - r * (x[j] - x[j - 1]) / sqrt(pow(x[j] - x[j - 1], 2) + pow(y[j] - y[j - 1], 2));
                xbeg = x[j] - (ybeg - y[j]) * (y[j] - y[j - 1]) / (x[j] - x[j - 1]);
                yend = y[j] - r * (x[j + 1] - x[j]) / sqrt(pow(x[j] - x[j + 1], 2) + pow(y[j] - y[j + 1], 2));
                xend = x[j] - (yend - y[j]) * (y[j] - y[j + 1]) / (x[j] - x[j + 1]);
            }
            else if (x[j] == x[j - 1])
            {
                ybeg = y[j]; xbeg = x[j] + r;
                yend = y[j] - r * (x[j + 1] - x[j]) / sqrt(pow(x[j] - x[j + 1], 2) + pow(y[j] - y[j + 1], 2));
                xend = x[j] - (yend - y[j]) * (y[j] - y[j + 1]) / (x[j] - x[j + 1]);
            }
            //printf("\n圆弧的起点:%lf,%lf  终点:%lf,%lf\n", xbeg, ybeg, xend, yend);
            //printf("\nx[j]:%lf,  y[j]:%lf\n", x[j], y[j]);
            anglebeg = azimuth(x[j], y[j], xbeg, ybeg);
            angleend = azimuth(x[j], y[j], xend, yend);
            //printf("\n起点方向角:%lf,  终点方向角:%lf\n", anglebeg, angleend);
            double angle = anglebeg, angledelta = angleend - anglebeg; //angle:角度变量,angledelta:起点终点角度差
            int k = 0;
            while ((angle + theta) < angleend)
            {
                angle = angle + theta;
                double setx = r * cos(angle);
                double sety = r * sin(angle);
                A[i] = setx + x[j]; B[i] = sety + y[j];
                i++;
                //printf("\n%lf,%lf,%lf\n", setx, sety, angledelta);
            }
        }
        if (istu == false)//凹角处的点(平行线)
        {
            double xp = r * (cos(azimuthangle[j - 1]) + cos(azimuthangle[j])) / sin(azimuthangle[j] - azimuthangle[j - 1]);
            double yp = r * (sin(azimuthangle[j - 1]) + sin(azimuthangle[j])) / sin(azimuthangle[j] - azimuthangle[j - 1]);
            A[i] = x[j] - xp;
            B[i] = y[j] - yp;
            i++;
            /*printf("看看I:%d\n", i);*/
        /*    printf("看看方向角:%lf,%lf\n", azimuthangle[j - 1], azimuthangle[j]);*/
        }
    }
    int i3 = i;

    for (i; i < i3+7; i++)
    {
        double ang = azimuthangle[n-2] + 90 + i * theta;
        double setx = r * cos(ang);
        double sety = r * sin(ang);
        A[i] = x[n-1]+setx; B[i] = y[n-1]+sety;
    }
    //printf("第1、2、3个断点时有多少个缓冲区点:%d,%d,%d\n", i1,i2,i3);
    return i;
}
3.主函数

使用fp1和fp2两种参数对”polyline.in”和“polyline.out”两个文件分别进行输入输出,从fp1中读入点数、缓冲区半径、点坐标的信息,使用Buffer函数得到缓冲区点数和坐标,从fp2中输出。

这个文件输入输出记下来以后涉及文件基本可以通用了(也许)。

(最简单的往往是主程序)

int main()
{
    int n = 0, i = 0; FILE* fp1, * fp2; double bufradus = 0.0; int sum=0;
    errno_t err1, err2; double x1[100], y1[100]; 
    double bufferpointx[1000], bufferpointy[1000];
    double pi = atan(1) * 4;//pi
    double azimuthtangle;

    //读入
    printf("文件输入格式:\n点数\n缓冲区半径\n点坐标xi yi,\n");
    err1 = fopen_s(&fp1, "polyline.in", "r");
    if (err1)
      printf("输入文件打开失败!\n");
    else
      printf("输入文件打开成功!\n");
    err2 = fopen_s(&fp2, "polyline.out", "w");
    if (err2)
      printf("输出文件打开失败!");
    else
      printf("输出文件打开成功!\n");

    printf("\n");
    fscanf_s(fp1, "%d", &n);
    fscanf_s(fp1, "%lf", &bufradus);
    for (i = 0; i < n; i++)
    {
        fscanf_s(fp1, "%lf %lf,", &x1[i], &y1[i]);
        sum++;
    }
    //
    int he = 0;
    he = buffer(bufradus, n, x1, y1, bufferpointx, bufferpointy);

    //测试第一个方向角
    /*azimuthtangle = azimuth(x1[0], y1[0], x1[1], y1[1]);*/
    printf("输入点数为:%d\n", n);

    printf("共有%d个缓冲区点,详情见out文件\n", he);

    //输出测试
    //输出所有原始点坐标
    //for (i = 0; i < n; i++)
    //    fprintf(fp2, "原始点坐标是:%lf,%lf\n", x1[i], y1[i]);

    fprintf(fp2,"共有%d个缓冲区点\n", he);
    fprintf(fp2, "\n");
    // 输出缓冲区集合的点(首尾点版)
    for (i = 0; i < he; i++)
        fprintf(fp2,"第%d个点为:%lf,%lf\n",i+1, bufferpointx[i], bufferpointy[i]);

    return 0;
}
4.输入输出

共测试两组数据,一组为自设,使用特殊角度值,方便进行人工验证;另一组使用提供的nanjing-polygon前60组数据,数据精度相对较高(所以我也检查不出来这个到底对不对)。

自设测试数据:

(提供的数据找不到附件上传入口……CSDN也太难用了,图片居中也没有,编辑也不习惯,看个文章还总是收积分)

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
下面是一个简单的生产者-消费者问题的C语言代码实现: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; // 缓冲区数组 int counter = 0; // 缓冲区计数器 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁 pthread_cond_t full = PTHREAD_COND_INITIALIZER; // 缓冲区满条件变量 pthread_cond_t empty = PTHREAD_COND_INITIALIZER; // 缓冲区空条件变量 void *producer(void *arg) { int val; while (1) { val = rand() % 100; // 随机生成数值 pthread_mutex_lock(&mutex); while (counter == BUFFER_SIZE) // 缓冲区满,等待空闲空间 pthread_cond_wait(&empty, &mutex); buffer[counter++] = val; // 放入缓冲区 printf("生产者:%d,缓冲区大小:%d\n", val, counter); pthread_mutex_unlock(&mutex); pthread_cond_signal(&full); // 发送缓冲区号 sleep(1); } return NULL; } void *consumer(void *arg) { int val; while (1) { pthread_mutex_lock(&mutex); while (counter == 0) // 缓冲区空,等待生产者 pthread_cond_wait(&full, &mutex); val = buffer[--counter]; // 从缓冲区取出 printf("消费者:%d,缓冲区大小:%d\n", val, counter); pthread_mutex_unlock(&mutex); pthread_cond_signal(&empty); // 发送缓冲区号 sleep(1); } return NULL; } int main(int argc, char *argv[]) { pthread_t tid1, tid2; srand(time(NULL)); pthread_create(&tid1, NULL, producer, NULL); pthread_create(&tid2, NULL, consumer, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); return 0; } ``` 在上面的代码中,使用了互斥锁和条件变量来实现线程同步。生产者线程和消费者线程分别使用互斥锁来保护共享变量(缓冲区计数器和缓冲区数组),并使用条件变量来等待对方的号。当生产者向缓冲区放入数据时,如果缓冲区已满,则会等待消费者取走数据后再放入;当消费者从缓冲区取出数据时,如果缓冲区已空,则会等待生产者放入数据后再取出。这样就保证了生产者和消费者之间的同步和互斥。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值