c++实现两个点一个宽度生成一个旋转矩形和计算旋转矩形的四个点坐标
·
从两个点和一个宽度生成旋转矩形
宽度
┌───────────┐
│ │
P1●─┼───────────┼─●P2 长度 = |P1P2|
│ │
└───────────┘
宽度
- 矩形中心 = P1和P2的中点
- 矩形长度 = |P1P2| (两点距离)
- 矩形宽度 = 输入的width参数
- 矩形角度 = 向量P1P2的方向
void __fastcall point_point_width_to_rrect(
double x1, // 第一个点x
double y1, // 第一个点y
double x2, // 第二个点x
double y2, // 第二个点y
double width, // 矩形宽度
float *out // 输出旋转矩形参数
)
{
// 计算矩形的方向向量
double dx = x2 - x1; // x方向差值
double dy = y2 - y1; // y方向差值
// 计算矩形的中心点(两点中点)
float center_y = (y1 + y2) * 0.5f;
float center_x = (x1 + x2) * 0.5f;
out[1] = center_y; // 中心点y坐标
out[0] = center_x; // 中心点x坐标
// 计算两点间距离(这是矩形的长度)
double distance_sq = dx * dx + dy * dy;
double distance = sqrt(distance_sq);
// 半长 = 长度的一半
float half_length = distance * 0.5f;
out[4] = width; // 矩形的宽度
out[3] = half_length; // 矩形的一半长度
// 计算矩形的旋转角度
// atan2(dx, dy) 计算线段与y轴的夹角
// 转换为度,并减去90度得到标准数学角度
float angle = atan2(dx, dy) * 180.0f / 3.141592653589793f - 90.0f;
out[2] = angle; // 旋转角度
}
计算旋转矩形的四个顶点坐标。输出是12个double,所以可能是6个点(每个点x,y)。
#include <cmath>
// 计算旋转矩形的顶点
// 输入: center_x, center_y, angle_deg, half_width, half_height
// 输出: 6个点(可能是闭合多边形的顶点,包括起点重复)
void calculate_rotated_rectangle(
float center_x, float center_y, float angle_deg,
float half_width, float half_height,
double* output) // 输出数组,12个元素
{
// 角度加90度后转弧度(可能是坐标系统不同)
double rad = (angle_deg + 90.0) * M_PI / 180.0;
double cos_a = cos(rad);
double sin_a = sin(rad);
// 计算矩形的轴向量
// 由于角度加了90°,所以:
// 水平轴方向: (sin_a, cos_a) // 对应宽度方向
// 垂直轴方向: (-cos_a, sin_a) // 对应高度方向
double width_vec_x = sin_a * half_width;
double width_vec_y = cos_a * half_width;
double height_vec_x = -cos_a * half_height;
double height_vec_y = sin_a * half_height;
// 计算四个顶点
// 顶点0: 中心 - 宽度向量 - 高度向量
output[0] = center_x - width_vec_x - height_vec_x;
output[1] = center_y - width_vec_y - height_vec_y;
// 顶点1: 中心 + 宽度向量 - 高度向量
output[2] = center_x + width_vec_x - height_vec_x;
output[3] = center_y + width_vec_y - height_vec_y;
// 顶点2: 中心 + 宽度向量 + 高度向量
output[4] = center_x + width_vec_x + height_vec_x;
output[5] = center_y + width_vec_y + height_vec_y;
// 顶点3: 中心 - 宽度向量 + 高度向量
output[6] = center_x - width_vec_x + height_vec_x;
output[7] = center_y - width_vec_y + height_vec_y;
// 如果输出是6个点(12个double),可能是:
// 四个顶点 + 第一个顶点重复(形成闭合多边形)
output[8] = output[0]; // 重复第一个点
output[9] = output[1];
output[10] = output[2]; // 或者可能是中心点?
output[11] = output[3];
}
这是一个计算旋转矩形6个顶点的函数,可用于:
- 绘制带边框的矩形(4个外角 + 2个内角或其他)
- 特定的碰撞检测形状
- 或者只是简单地计算矩形的4个角,但数组分配了12个元素,实际只用了8个
关键点:
- 输入角度加了90°,因为图像坐标系(Y轴向下)
a1[3]和a1[4]是半宽和半高- 通过旋转矩阵计算矩形的四个角点坐标
生成圆弧卡尺
/**
* 生成圆形卡尺测量点
*
* @param center_x 圆心X坐标
* @param center_y 圆心Y坐标
* @param radius 测量半径
* @param width 卡尺宽度
* @param step_angle 角度步长控制(度)
* @param direction 方向:>=0顺时针,<0逆时针
* @param num_points 指定点数(<=0时自动计算)
* @param buffer_mgr 缓冲区管理器
* @return 成功返回0,失败返回-1
*/
int generate_circular_caliper_points(
double center_x,
double center_y,
double radius,
double width,
double step_angle, // 控制点密度
int direction,
int num_points,
BufferManager& buffer_mgr
) {
// 1. 计算分段数
int segments = num_points;
if (segments <= 0) {
// 自动计算:圆周长 / (step_angle * 3)
// 这里 step_angle 是角度,需要转弧度
double step_rad = step_angle * DEG_TO_RAD;
double circumference = radius * TWO_PI;
segments = static_cast<int>(circumference / (step_rad * 3.0));
}
// 确保不超过最大合理分段数
double max_segments = radius * TWO_PI / (step_angle * DEG_TO_RAD * 3.0);
if (segments > max_segments) {
segments = static_cast<int>(max_segments);
}
if (segments <= 0) {
return -1; // 错误
}
// 2. 确保缓冲区足够
buffer_mgr.ensure_capacity(segments);
// 3. 角度增量
double angle_increment = TWO_PI / segments;
// 4. 生成测量点
for (int i = 0; i < segments; i++) {
// 计算当前角度
double angle_rad = i * angle_increment;
// 计算测量点坐标
double x = center_x + sin(angle_rad) * radius;
double y = center_y + cos(angle_rad) * radius;
// 计算测量方向角度
// 圆上点的法线方向是径向方向
double normal_angle_rad = angle_rad; // 从圆心指向测量点的方向
double measure_angle_deg = normal_angle_rad * RAD_TO_DEG;
// 方向调整
if (direction >= 0) { // 顺时针
measure_angle_deg -= 90.0f; // 垂直于法线方向
} else { // 逆时针
measure_angle_deg = measure_angle_deg - 90.0f + 180.0f;
}
// 规整化角度到 [0, 360)
while (measure_angle_deg >= 360.0) measure_angle_deg -= 360.0;
while (measure_angle_deg < 0.0) measure_angle_deg += 360.0;
// 写入缓冲区
CaliperPoint* point = buffer_mgr.get_current();
point->x = static_cast<float>(x);
point->y = static_cast<float>(y);
point->angle = static_cast<float>(measure_angle_deg);
point->param1 = static_cast<float>(width); // 存储宽度
point->param2 = static_cast<float>(step_angle); // 存储步长参数
buffer_mgr.advance(1);
}
return 0; // 成功
}
测量函数
// 核心测量函数
MeasurementResult measure(
const unsigned char* image_data,
int image_width,
int image_height,
const MeasurementParams& params,
const char* edge_select_mode = "strongest"
) {
MeasurementResult result;
// 1. 计算方向向量
double angle_rad = (params.angle_deg + 90.0) * M_PI / 180.0;
double cos_a = cos(angle_rad);
double sin_a = sin(angle_rad);
// 2. 沿宽度方向生成采样点
int width_samples = (int)(2 * params.width + 1);
std::vector<double> sample_points_x(width_samples);
std::vector<double> sample_points_y(width_samples);
for (int i = 0; i < width_samples; i++) {
double offset = i - params.width;
sample_points_x[i] = params.start_x + offset * sin_a;
sample_points_y[i] = params.start_y + offset * cos_a;
}
// 3. 对每个采样点,沿高度方向采样强度剖面
int height_samples = (int)(2 * params.height + 1);
std::vector<std::vector<double>> intensity_profiles(width_samples);
std::vector<double> average_intensities(width_samples, 0.0);
for (int i = 0; i < width_samples; i++) {
std::vector<double>& profile = intensity_profiles[i];
profile.resize(height_samples);
double sum = 0.0;
for (int j = 0; j < height_samples; j++) {
double vert_offset = j - params.height;
// 计算采样点坐标
double px = sample_points_x[i] + vert_offset * (-cos_a);
double py = sample_points_y[i] + vert_offset * sin_a;
// 像素插值
double pixel_value = 0.0;
if (config_.interpolation_type == 0) {
pixel_value = bilinear_interpolate(image_data, image_width,
image_height, px, py);
} else {
pixel_value = bicubic_interpolate(image_data, image_width,
image_height, px, py);
}
profile[j] = pixel_value;
sum += pixel_value;
}
average_intensities[i] = sum / height_samples;
}
// 4. 高斯滤波
std::vector<double> gaussian_kernel;
generate_gaussian_kernel(gaussian_kernel, config_.sigma);
std::vector<double> smoothed_intensities;
gaussian_filter_1d(average_intensities, smoothed_intensities, gaussian_kernel);
// 5. 计算一阶导数
std::vector<double> derivatives;
compute_derivative(smoothed_intensities, derivatives);
// 6. 检测边缘
std::vector<EdgeInfo> edges;
detect_edges(derivatives, smoothed_intensities, edges, config_.threshold);
result.edge_count = (int)edges.size();
if (edges.empty()) {
return result; // 没有检测到边缘
}
// 7. 边缘选择
EdgeInfo selected_edge;
if (!select_edge(edges, edge_select_mode, selected_edge)) {
return result; // 选择失败
}
// 8. 转换为世界坐标
double world_offset = (selected_edge.position - width_samples/2.0);
double edge_x = params.start_x + world_offset * sin_a;
double edge_y = params.start_y + world_offset * cos_a;
// 9. 返回结果
result.success = true;
result.edge_x = edge_x;
result.edge_y = edge_y;
result.edge_strength = selected_edge.strength;
return result;
}
更多推荐


所有评论(0)