#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// 光栅化中点画线算法
void drawPatch(Mat image, int x1, int y1, int x2, int y2)
{
// 计算直线参数
int a = y1 - y2;
int b = x2 - x1;
int c = x1 * y2 - x2 * y1;
// 计算斜率
float slope = (y2 * 1.0 - y1 * 1.0) / (x2 * 1.0 - x1 * 1.0);
float slope_abs = abs(slope);
int x, y, end_x, end_y;
if (a == 0)
{
for (int i = min(x1, x2); i <= max(x1, x2); i = i + 10)
{
int xn = (i / 10) * 10;
int yn = (y1 / 10) * 10;
for (int k = xn; k < xn + 10; k++)
for (int j = yn; j < yn + 10; j++)
image.at<Vec3b>(Point(k, j)) = Vec3b(200, 200, 200); // 浅灰色
}
return;
}
if (b == 0)
{
for (int i = min(y1, y2); i < max(y1, y2); i = i + 10)
{
int xn = (x1 / 10) * 10;
int yn = (i / 10) * 10;
for (int k = xn; k < xn + 10; k++)
for (int j = yn; j < yn + 10; j++)
image.at<Vec3b>(Point(k, j)) = Vec3b(200, 200, 200); // 浅灰色
}
return;
}
if (x1 < x2)
{
x = x1;
y = y1;
end_y = y2;
end_x = x2;
}
else
{
x = x2;
y = y2;
end_y = y1;
end_x = x1;
}
int d, d1, d2;
if (slope <= -1)
{
d = 2 * (a * (x + 0.5) + b * (y - 1) + c);
d1 = 2 * (a - b);
d2 = 2 * b * (-1);
}
else if (slope <= 0)
{
d = 2 * (a * (x + 1) + b * (y - 0.5) + c);
d1 = 2 * (a - b);
d2 = 2 * a;
}
else if (slope <= 1)
{
d = 2 * (a * (x + 1) + b * (y + 0.5) + c);
d1 = 2 * (a + b);
d2 = 2 * a;
}
else
{
d = 2 * (a * (x + 0.5) + b * (y + 1) + c);
d1 = 2 * (a + b);
d2 = 2 * b;
}
int min_d, max_d, d3;
min_d = min(d1, d2);
max_d = max(d1, d2);
int flag = (slope > 0) ? 1 : -1;
int con = 0;
if (slope_abs >= 1)
{
for (; y != end_y;)
{
int xn = (x / 10) * 10;
int yn = (y / 10) * 10;
if (con > 4)
for (int i = xn; i < xn + 10; i++)
for (int j = yn; j < yn + 10; j++)
image.at<Vec3b>(Point(i, j)) = Vec3b(200, 200, 200); // 浅灰色
do
{
if (y == end_y)
return;
con++;
if (d > 0)
{
y = y + flag;
d3 = min_d;
d += min_d;
}
else
{
y = y + flag;
d3 = max_d;
d += max_d;
}
if (d3 == d1)
x += 1;
image.at<Vec3b>(Point(x, y)) = Vec3b(0, 255, 0);
} while (y % 10 != 5);
}
}
else
{
for (; x != end_x;)
{
int xn = (x / 10) * 10;
int yn = (y / 10) * 10;
if (con > 4)
for (int i = xn; i < xn + 10; i++)
for (int j = yn; j < yn + 10; j++)
image.at<Vec3b>(Point(i, j)) = Vec3b(200, 200, 200); // 浅灰色
do
{
if (x == end_x)
return;
con++;
if (d > 0)
{
x = x + 1;
d3 = min_d;
d += min_d;
}
else
{
x = x + 1;
d3 = max_d;
d += max_d;
}
if (d3 == d1)
y += flag;
image.at<Vec3b>(Point(x, y)) = Vec3b(0, 255, 0);
} while (x % 10 != 5);
}
}
}
void drawLine(Mat image, int x1, int y1, int x2, int y2)
{
// 计算直线参数
int a = y1 - y2;
int b = x2 - x1;
int c = x1 * y2 - x2 * y1;
// 计算斜率
float slope = (y2 * 1.0 - y1 * 1.0) / (x2 * 1.0 - x1 * 1.0);
float slope_abs = abs(slope);
int x, y, end_x, end_y;
if (a == 0)
{
for (int i = min(x1, x2); i <= max(x1, x2); i++)
image.at<Vec3b>(Point(i, y1)) = Vec3b(0, 255, 0);
return;
}
if (b == 0)
{
for (int i = min(y1, y2); i <= max(y1, y2); i++)
image.at<Vec3b>(Point(x1, i)) = Vec3b(0, 255, 0);
return;
}
if (x1 < x2)
{
x = x1;
y = y1;
end_y = y2;
end_x = x2;
}
else
{
x = x2;
y = y2;
end_y = y1;
end_x = x1;
}
int d, d1, d2;
if (slope <= -1)
{
d = 2 * (a * (x + 0.5) + b * (y - 1) + c);
d1 = 2 * (a - b);
d2 = 2 * b * (-1);
}
else if (slope <= 0)
{
d = 2 * (a * (x + 1) + b * (y - 0.5) + c);
d1 = 2 * (a - b);
d2 = 2 * a;
}
else if (slope <= 1)
{
d = 2 * (a * (x + 1) + b * (y + 0.5) + c);
d1 = 2 * (a + b);
d2 = 2 * a;
}
else
{
d = 2 * (a * (x + 0.5) + b * (y + 1) + c);
d1 = 2 * (a + b);
d2 = 2 * b;
}
int min_d, max_d, d3;
min_d = min(d1, d2);
max_d = max(d1, d2);
int flag = (slope > 0) ? 1 : -1;
if (slope_abs >= 1)
{
for (; y != end_y;)
{
if (d > 0)
{
y = y + flag;
d3 = min_d;
d += min_d;
}
else
{
y = y + flag;
d3 = max_d;
d += max_d;
}
if (d3 == d1)
x += 1;
image.at<Vec3b>(Point(x, y)) = Vec3b(0, 255, 0);
}
}
else
{
for (; x != end_x;)
{
if (d > 0)
{
x = x + 1;
d3 = min_d;
d += min_d;
}
else
{
x = x + 1;
d3 = max_d;
d += max_d;
}
if (d3 == d1)
y += flag;
image.at<Vec3b>(Point(x, y)) = Vec3b(0, 255, 0);
}
}
}
// Liang-Barsky裁剪算法
bool LiangBarsky(float x1, float y1, float x2, float y2, float &u1, float &u2, float xmin, float xmax, float ymin, float ymax)
{
float p[4] = {-(x2 - x1), x2 - x1, -(y2 - y1), y2 - y1};
float q[4] = {x1 - xmin, xmax - x1, y1 - ymin, ymax - y1};
u1 = 0, u2 = 1;
for (int i = 0; i < 4; i++)
{
if (p[i] == 0)
{
if (q[i] < 0)
return false; // 线段平行于裁剪窗口的边界且在窗口之外
}
else
{
float u = q[i] / p[i];
if (p[i] < 0 && u1 < u) // 入边
u1 = u;
else if (p[i] > 0 && u2 > u) // 出边
u2 = u;
}
}
if (u1 > u2)
return false; // 线段在窗口之外
return true;
}
int main()
{
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
// 创建画布
Mat canvas(500, 500, CV_8UC3, Scalar(255, 255, 255));
// 绘制矩形
rectangle(canvas, Point(100, 100), Point(400, 400), Scalar(0, 0, 0), 2);
// 绘制线段
x1 = x1 * 10;
y1 = y1 * 10;
x2 = x2 * 10;
y2 = y2 * 10;
Point line_start(x1, y1);
Point line_end(x2, y2);
line(canvas, line_start, line_end, Scalar(0, 0, 255), 1);
// 显示画布
imshow("Canvas", canvas);
while (true)
{
int key = waitKey(0);
if (key == 27) // 按下Esc键
{
float u1, u2;
if (LiangBarsky(x1, y1, x2, y2, u1, u2, 100, 400, 100, 400))
{
// 裁剪线段
Point clipped_start(x1 + u1 * (x2 - x1), y1 + u1 * (y2 - y1));
Point clipped_end(x1 + u2 * (x2 - x1), y1 + u2 * (y2 - y1));
// drawPatch(canvas, clipped_start.x, clipped_start.y, clipped_end.x, clipped_end.y);
for (int i = 10; i < 40; i++)
rectangle(canvas, Point(i * 10, 100), Point(i * 10, 400), Scalar(0, 0, 0), 0.5);
for (int i = 10; i < 40; i++)
rectangle(canvas, Point(100, i * 10), Point(400, i * 10), Scalar(0, 0, 0), 0.5);
// drawLine(canvas, clipped_start.x, clipped_start.y, clipped_end.x, clipped_end.y);
line(canvas, clipped_start, clipped_end, Scalar(0, 255, 0), 2);
imshow("Canvas", canvas);
}
}
if (key == 'a')
break;
}
return 0;
}
Liang-Barsky裁剪算法+中点画线法光栅画法
于 2024-04-27 10:44:34 首次发布