能不能更新一版可旋转的绘制图形

0

求绘制的图形可以像图片那样旋转

ava
天下无双

2023-12-6

0

你可以把绘制图形绘制的对象设置为图片,然后可以直接旋转图片,再或者使用 正弦和余统函数来进行三角变换来旋转你的绘制图形:

例如下面的代码是一个基本的示例:

#include <graphics.h>
#include <math.h>
#include<stdio.h>
#define PI1 3.14159265358979323846
class vectorline
{
	// 封装的内部变量。
private:

	// 矢量直线是基于缓冲区绘图的。
	DWORD* g_pBuf11 = GetImageBuffer();

	// 矢量直线的透明度和线宽变量声明。
	int alpha = 128, linesize1 = 1;

	// 矢量直线要用到旋转。
	double PI = 3.1415926535;

	// 这一块属于是缓冲区画点里的变量。
	int WIDTH = getwidth(), HEIGHT = getheight(), puti = 0;
	int r1 = 0, g1 = 0, b1 = 0, r2 = 0, g2 = 0, b2 = 0;
	COLORREF backdropcolor = 0, rgb_alpha = 0, color = WHITE;

	// 这一块是绘图直线的变量,是属于矢量直线 line_ss 函数,这边负责,把直线矢量化的关键操作。
	int dxss = 0, dyss = 0, stepsss = 0;
	float xIncrementss = 0, yIncrementss = 0, xss = 0, yss = 0;

	// 这一块是绘图直线的变量,是属于矢量直线 line_sss 函数,是负责分段绘图矢量直线,例如:上边和下边,同时也是控制矢量直线的粗细宽度。
	int dxsss = 0, dx1sss = 0, dysss = 0, dy1sss = 0, dsss = 150, d1sss = 150, stepssss = 0, steps1sss = 0;
	float	xIncrementsss = 0,
		xIncrement1sss = 0,
		yIncrementsss = 0,
		yIncrement1sss = 0,
		xsss = 0, x111sss = 0,
		ysss = 0, y111sss = 0;

	// 计算待转换坐标 (x2, y2) 相对于确定坐标 (x1, y1) 的相对坐标
	double relativeX = 0, relativeY = 0, radians = 0, degrees = 0;
	double a = 0, a11 = 0, a1 = 0, a22 = 0;
	int s = 0;

public:
	// 设置矢量直线透明度函数。
	void linealpha(int al) { alpha = al; }
	// 设置矢量直线颜色函数。
	void linecolor(COLORREF color1) { color = color1; setlinecolor(color1); }
	// 设置矢量直线粗细大小。
	void linesize(int size) { linesize1 = size / 3; }

	// 快速缓冲区半透明画点函数 2
	void putpixealpha(int x, int y)
	{	// 把坐标转换为,缓冲区位数。
		puti = y * WIDTH + x;
		// 如果 puti 超出缓冲区范围,直接返回。
		if (puti < 0 || puti >= (WIDTH * HEIGHT)) { return; }
		// 读取屏幕所有绘图下方的颜色进行半透明混合。
		backdropcolor = BGR(g_pBuf11[puti]);
		// 在半透明计算前的颜色分配。
		r1 = GetRValue(color), g1 = GetGValue(color), b1 = GetBValue(color),
			r2 = GetRValue(backdropcolor), g2 = GetGValue(backdropcolor), b2 = GetBValue(backdropcolor);
		// 进行半透明核心算法计算。
		rgb_alpha = RGB((r1 * alpha + r2 * (256 - alpha)) >> 8, (g1 * alpha + g2 * (256 - alpha)) >> 8, (b1 * alpha + b2 * (256 - alpha)) >> 8);
		// 把半透明混合计算后的结果写入缓冲区。
		g_pBuf11[puti] = BGR(rgb_alpha);
	}

	// 普通半透明缓冲区直线(DDA 算法,效率虽低,但矢量化效果的最好),用于把一条直线矢量化的关键函数,只矢量化一条粗直线的边缘。
	void line_ss(int x1, int y1, int x2, int y2)
	{	// DDA 算法过程。
		dxss = x2 - x1;
		dyss = y2 - y1;
		stepsss = abs(dxss) > abs(dyss) ? abs(dxss) : abs(dyss);
		xIncrementss = dxss / (float)stepsss;
		yIncrementss = dyss / (float)stepsss;
		xss = x1;
		yss = y1;
		// 绘图矢量直线里的半透明画点。
		for (int i = 0; i <= stepsss; i++)
		{
			putpixealpha((int)xss, (int)yss);
			xss += xIncrementss;
			yss += yIncrementss;
		}
	}

	// 双层 DDA 直线,用于绘制矢量直线,x1, y1, 到 x2, y2,的长度里宽度里的直线内容,包括矢量化的边和,中间的填充直线。
	void line_sss(int x1, int y1, int x2, int y2, int x11, int y11, int x22, int y22)
	{
		// 双层 DDA 直线算法,效率比 Bresenham 效果好,线条厚。
		dxsss = x2 - x1, dx1sss = x22 - x11,
			dysss = y2 - y1, dy1sss = y22 - y11,
			stepssss = abs(dxsss) > abs(dysss) ? abs(dxsss) : abs(dysss),
			steps1sss = abs(dx1sss) > abs(dy1sss) ? abs(dx1sss) : abs(dy1sss);

		xIncrementsss = dxsss / (float)stepssss,
			xIncrement1sss = dx1sss / (float)steps1sss,
			yIncrementsss = dysss / (float)stepssss,
			yIncrement1sss = dy1sss / (float)steps1sss,
			xsss = x1, x111sss = x11,
			ysss = y1, y111sss = y11;

		// 如果小于 4 就把矢量线进一步细化,与普通直线大小差不多。
		if (linesize1 < 4)stepssss = stepssss / 2;

		// 核心程序,开始矢量化直线边缘和用直线填充矢量直线中间,并连接矢量直线宽度上的所有线。
		for (int i = 0; i <= stepssss; i++)
		{
			// 绘制矢量直线中间空的线,因为矢量化是矢量直线的边缘。
			if (i < stepssss - 3) { line((int)xsss, (int)ysss, (int)x111sss, (int)y111sss); }

			if (i >= stepssss - 3)
			{
				// 控制细线矢量精度专用透明比例。
				if (linesize1 < 4)
				{
					if (i == stepssss - 4) { linealpha(250); }
					else if (i == stepssss - 3) { linealpha(120); }
					else if (i == stepssss - 2) { linealpha(80); }
					else if (i == stepssss - 1) { linealpha(40); }
					else if (i == stepssss) { linealpha(20); }
				}
				else
				{
					//	 控制粗线矢量精度专用透明比例。
					if (i == stepssss - 4) { linealpha(180); }
					else if (i == stepssss - 3) { linealpha(150); }
					else if (i == stepssss - 2) { linealpha(120); }
					else if (i == stepssss - 1) { linealpha(90); }
					else if (i == stepssss) { linealpha(60); }
				}

				// 下面算法是把半透明直线,线相互交合起来,缺一不可,已经调教成最好配方了,是矢量化直线边缘核心函数,不参与矢量线中间段绘图。
				line_ss((int)xsss, (int)ysss, (int)x111sss, (int)y111sss);

				line_ss((int)xsss, (int)ysss + 1, (int)x111sss, (int)y111sss + 1);
				line_ss((int)xsss, (int)ysss + 1, (int)x111sss, (int)y111sss);
				line_ss((int)xsss, (int)ysss, (int)x111sss, (int)y111sss + 1);

				line_ss((int)xsss, (int)ysss - 1, (int)x111sss, (int)y111sss - 1);
				line_ss((int)xsss, (int)ysss - 1, (int)x111sss, (int)y111sss);
				line_ss((int)xsss, (int)ysss, (int)x111sss, (int)y111sss - 1);

				line_ss((int)xsss - 1, (int)ysss, (int)x111sss - 1, (int)y111sss);
				line_ss((int)xsss - 1, (int)ysss, (int)x111sss, (int)y111sss);
				line_ss((int)xsss, (int)ysss, (int)x111sss - 1, (int)y111sss);

				line_ss((int)xsss + 1, (int)ysss, (int)x111sss + 1, (int)y111sss);
				line_ss((int)xsss + 1, (int)ysss, (int)x111sss, (int)y111sss);
				line_ss((int)xsss, (int)ysss, (int)x111sss + 1, (int)y111sss);

				line_ss((int)xsss + 1, (int)ysss - 1, (int)x111sss + 1, (int)y111sss - 1);
				line_ss((int)xsss + 1, (int)ysss - 1, (int)x111sss, (int)y111sss);
				line_ss((int)xsss, (int)ysss, (int)x111sss + 1, (int)y111sss - 1);

			}
			xsss += xIncrementsss;
			ysss += yIncrementsss;
			x111sss += xIncrement1sss;
			y111sss += yIncrement1sss;
		}
	}

	// 绘图一条矢量直线,也是矢量系统的启动核心线函数。
	void linev(int x1, int y1, int x2, int y2)
	{
		// 设置线条粗细为 2,对半透明直线无效,只对矢量中间普通画线生效。
		setlinestyle(PS_SOLID, 2);
		// 计算待转换坐标 (x2, y2) 相对于确定坐标 (x1, y1) 的相对坐标。
		relativeX = x2 - x1;
		relativeY = y2 - y1;
		radians = atan2(relativeY, relativeX);
		// 将弧度转换为角度。
		degrees = radians * 180 / -PI;
		// 将角度限制在 0 到 360 之间。
		if (degrees < 0) { degrees += 360; }

		// 角度给值,以经设定好了数值。
		a = degrees,
			a11 = degrees;
		s = 0;
		a = -a + 225,
			a11 = -a11 + 225;
		a1 = a + 180, a22 = a11 + 181;
		// 在用鼠标控制矢量直线会随便鼠标移动,鼠标旋转,而端点也会随着旋转角度,保证矢量直线绘制的完成,不可缺少!
		// 矢量线分两个线组成,例如:在水平线上,从直线中间开始,分别绘制上半段,与下半段,会随着角度的变化而变化,不固定。
		line_sss
		(
			x1, y1,
			(linesize1)*cos(a / 57.29) - linesize1 * sin(a / 57.29) + x1,
			(linesize1)*sin(a / 57.29) + linesize1 * cos(a / 57.29) + y1,
			x2, y2,
			(linesize1)*cos(a11 / 57.29) - linesize1 * sin(a11 / 57.29) + x2,
			(linesize1)*sin(a11 / 57.29) + linesize1 * cos(a11 / 57.29) + y2
		);
		// 在用鼠标控制矢量直线会随便鼠标移动,鼠标旋转,而端点会随着旋转角度,保证矢量直线绘制的完成,不可缺少!
		// 矢量线分两个线组成,例如:在水平线上,从直线中间开始,分别绘制上半段,与下半段,会随着角度的变化而变化,不固定。
		line_sss
		(
			x1, y1,
			(linesize1)*cos(a1 / 57.29) - linesize1 * sin(a1 / 57.29) + x1,
			(linesize1)*sin(a1 / 57.29) + linesize1 * cos(a1 / 57.29) + y1,
			x2, y2,
			(linesize1)*cos(a22 / 57.29) - linesize1 * sin(a22 / 57.29) + x2,
			(linesize1)*sin(a22 / 57.29) + linesize1 * cos(a22 / 57.29) + y2
		);
	}
};

int main()
{
    initgraph(640, 480);
	vectorline v;
	v.linecolor(RGB(176,8,76));
    int xxx = 0;
    BeginBatchDraw();
   while(1) 
   {
       // 定义正方体的 8 个顶点坐标
       int x[8] = { -50, 50, 50, -50, -50, 50, 50, -50 };
       int y[8] = { 50, 50, -50, -50, 50, 50, -50, -50 };
       int z[8] = { 50, 50, 50, 50, -50, -50, -50, -50 };
       bool a=true;
       // 定义旋转角度和旋转中心坐标
       double angle = 0;
       int cx = 320;
       int cy = 240;
      
   while (a)
    {
	if(xxx==120)
	{
	xxx=0;
	break;
	}
   xxx++;
  
        // 清空屏幕
        cleardevice();

        // 绘制正方体
        for (int i = 0; i < 4; i++)
        {
            v.linev(x[i] + cx, y[i] + cy, x[i + 4] + cx, y[i + 4] + cy);
			v.linev(x[i] + cx, y[i] + cy, x[(i + 1) % 4] + cx, y[(i + 1) % 4] + cy);
			v.linev(x[i + 4] + cx, y[i + 4] + cy, x[(i + 1) % 4 + 4] + cx, y[(i + 1) % 4 + 4] + cy);
        }

        // 计算旋转后的坐标
        for (int i = 0; i < 8; i++)
        {
            int x1 = x[i];
            int y1 = y[i] * cos(angle) + z[i] * sin(angle);
            int z1 = -y[i] * sin(angle) + z[i] * cos(angle);

            x[i] = x1 * cos(angle) - z1 * sin(angle);
            y[i] = y1;
            z[i] = x1 * sin(angle) + z1 * cos(angle);
        }

        // 更新旋转角度
        angle += PI1 / 180;

        // 延时一段时间
        Sleep(50);

        FlushBatchDraw();

    }
    }
    EndBatchDraw();
    closegraph();
    return 0;
}
ava
随波逐流

2023-12-6

技术讨论社区