中点法画椭圆_2021秋季《计算机图形学》_基于《计算机图形学(第四版)》D.H.&M.P.B.&W.R.C.

// g++ Ellipse.cpp -o test libglfw3dll.a libopengl32.a
// .\test

#include <bits/stdc++.h>
#include <GL/gl.h>
#include "glfw3.h"

using namespace std;

class screenPt
{
    private:
        float x, y;
    public:
        // ScreenPt()
        // {
        //     x = y = 0;  // 默认在原点
        // }

        void setCoords(float xCoordValue, float yCoordValue)
        {
            x = xCoordValue;
            y = yCoordValue;
        }

        float getx() const
        {
            return x;
        }

        float gety() const
        {
            return y;
        }

        void incrementx()
        {
            x++;
        }

        void decrementy()
        {
            y--;
        }
};

void setPixel(float xCoord, float yCoord)  // 自定义画点函数
{
    glBegin(GL_POINTS);
        glVertex2f((float)(xCoord)/1000, (float)(yCoord)/1000);
    glEnd;
}

// inline int round(const float a)
// {
//     return int(a+0.5);
// }

void ellipseMidpoint(float xc, float yc, float Rx, float Ry)  // 将椭圆圆心、x轴截距和y轴截距传入,此处默认y轴截距更大
{
    int Rx2 = Rx*Rx;
    int Ry2 = Ry*Ry;

    screenPt ellipsePt;

    float p1 = (Ry2-Rx2*Ry+0.25*Rx2);  // 初始化区域1

    ellipsePt.setCoords(0, Ry);

    void ellipsePlotPoints(float, float, screenPt);
    ellipsePlotPoints(xc, yc, ellipsePt);  // 画四个顶点

    /***********************区域二**********************/
    while (Ry2*ellipsePt.getx() <= Rx2*ellipsePt.gety()) 
    {
        ellipsePt.incrementx();
        if(p1<0)
        {
            p1 += Ry2*(2*ellipsePt.getx()+1);
        }
        else
        {
            ellipsePt.decrementy();
            p1 += Ry2*(2*ellipsePt.getx()+1)-2*Rx2*ellipsePt.gety();
        }
        ellipsePlotPoints(xc, yc, ellipsePt);
    }
    /**********************区域二***********************/
    // Rx2 = Rx*Rx, Ry2 = Ry*Ry;
    // cout<<"x="<<ellipsePt.getx()<<' '<<"y="<<ellipsePt.gety()<<Rx<<Ry<<endl;
    float combx = (ellipsePt.getx()+0.5)*(ellipsePt.getx()+0.5);
    float comby = (ellipsePt.gety()-1)*(ellipsePt.gety()-1);
    // cout<<"combx="<<combx<<' '<<"comby="<<comby<<endl;
    float p2 = (Ry2*combx+Rx2*comby-Rx2*Ry2)/1000;  // 为什么需要手动除以1000?
    // cout<<"initp2="<<p2<<endl;
    while(ellipsePt.gety()>0)
    {
        // cout<<"p2="<<p2<<endl;
        ellipsePt.decrementy();
        if(p2>0)
        {
            // cout<<'*'<<endl;
            // cout<<"1 "<<p2<<endl;
            cout<<'&'<<Rx2*(1-2*ellipsePt.gety())<<endl;
            p2 += Rx2*(1-2*ellipsePt.gety());
            // cout<<"2 "<<p2<<endl;

        }
        else
        {
            // cout<<'*'<<endl;
            ellipsePt.incrementx();
            p2 += 2*Ry2*ellipsePt.getx()+Rx2*(1-2*ellipsePt.gety());
        }
        ellipsePlotPoints(xc, yc, ellipsePt);
    }
    
}

void ellipsePlotPoints(float xc, float yc, screenPt ellipsePt)
{
    setPixel(xc+ellipsePt.getx(), yc+ellipsePt.gety());
    setPixel(xc+ellipsePt.getx(), yc-ellipsePt.gety());
    setPixel(xc-ellipsePt.getx(), yc+ellipsePt.gety());
    setPixel(xc-ellipsePt.getx(), yc-ellipsePt.gety());
}


/********************************************************************/
void processInput(GLFWwindow *window)
{
    if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}


int main()
{
    if (!glfwInit()) return -1;

    GLFWwindow* window;

    window = glfwCreateWindow(960, 960, "MidPointEllipse", NULL ,NULL); //创建窗口对象

    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);

    while (!glfwWindowShouldClose(window))
    {
        processInput(window);

        ellipseMidpoint(0, 0, 800, 900);

        glfwSwapBuffers(window);

        glfwPollEvents();
    }

    glfwTerminate();
    
    return 0;
}

在原始代码的基础上,发现需要将p2的初始值调小1000倍。调试过程中发现在画区域二的时候p2始终无法小于0,因为 Δ p 2 \Delta p_2 Δp2的数量级比p2小了1e3,需要1000+次后才可能进入p2<0的条件判断,而一共也没有这么多点。
仍然会出现连接处空洞的问题,即y趋近0的一段消失,尝试发现椭圆形状越接近圆连接处空洞越小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值