////////////// 函数实现(可视化) //////////////
/**
*
@Brief 绘制运动规律图像
*/
void DrawMotionCurve()
{
setaspectratio(1, -1);
setorigin(320, 240);
float visual_ratio_x = 30.f;
float visual_ratio_y = 4.f;
for (float theta = 0; theta <= 2 * PI; theta += 0.01f)
{
float s = GetDisplacementAt(theta);
putpixel((int)(visual_ratio_x * theta), (int)(visual_ratio_y * s), WHITE);
}
}
/**
* @brief 绘制凸轮
*/
void DrawCam(float offset)
{
setaspectratio(1, -1);
setorigin(320, 240);
// 手动放大比 setaspectratio 的效果好
float visual_ratio = 3.f;
// 推杆轴与基圆的交点 y 坐标
float fBaseY = sqrtf(g_r0 * g_r0 - g_e * g_e);
// 中心点
setlinecolor(WHITE);
setfillcolor(WHITE);
fillcircle(0, 0, 1);
// 基圆(由于最终画的是包络线,所以基圆半径要减掉滚子半径)
setlinecolor(GREEN);
circle(0, 0, (int)((g_r0 - g_r_r) * visual_ratio));
// 偏心圆
setlinecolor(BLUE);
circle(0, 0, (int)(g_e * visual_ratio));
// 包络线(近似的)
for (float theta = 0; theta <= 2 * PI; theta += 0.01f)
{
PointF pt = CamPointAt(theta, offset);
putpixel((int)(visual_ratio * pt.x), (int)(visual_ratio * pt.y), WHITE);
}
// 运动规律图像
if (b_show_motion_curve)
{
// 确定图幅(x 方向)
int nCurveW = 60; // 图幅宽度(会乘以 visual_ratio)
float recal_offset = offset;
while (recal_offset < 0.f)
{
recal_offset += 2 * PI;
}
while (recal_offset > 2 * PI)
{
recal_offset -= 2 * PI;
}
// 1. 绘制坐标轴主体 (黄色)
setlinecolor(YELLOW);
int ax_x0 = (int)(visual_ratio * (-recal_offset / (2 * PI) * nCurveW + g_e));
int ax_y0 = (int)(visual_ratio * fBaseY);
int ax_x_end = ax_x0 + (int)(visual_ratio * (nCurveW + g_e + 5)); // 稍微增长一点画箭头
int ax_y_end = (int)(visual_ratio * (fBaseY + g_h + 5));
// x 轴
line(ax_x0, ax_y0, ax_x_end, ax_y0);
// x 轴箭头
line(ax_x_end, ax_y0, ax_x_end - 5, ax_y0 + 3);
line(ax_x_end, ax_y0, ax_x_end - 5, ax_y0 - 3);
// y 轴
line(ax_x0, ax_y0, ax_x0, ax_y_end);
// y 轴箭头
line(ax_x0, ax_y_end, ax_x0 - 3, ax_y_end - 5);
line(ax_x0, ax_y_end, ax_x0 + 3, ax_y_end - 5);
// 绘制文字 (需要反转 aspect ratio 否则文字是倒下的)
setaspectratio(1, 1);
settextcolor(YELLOW);
setbkmode(TRANSPARENT);
// 注意:在 1, 1 坐标系下,原本 y 轴正方向的值要取反才能对齐
outtextxy(ax_x_end + 5, -ax_y0 - 8, L"delta");
outtextxy(ax_x0 - 20, -ax_y_end - 15, L"s");
// 恢复原本的 y 轴向上坐标系
setaspectratio(1, -1);
// 绘制图像
for (float theta = 0; theta <= 2 * PI; theta += 0.01f)
{
float s = GetDisplacementAt(theta);
putpixel((int)(visual_ratio * ((theta - recal_offset) / (2 * PI) * nCurveW + g_e)),
(int)(visual_ratio * (fBaseY + s)), WHITE);
}
}
// 滚子
if (b_show_roller)
{
float posY_r = fBaseY + GetDisplacementAt(offset);
setlinecolor(GRAY);
rectangle((int)((g_e - g_r_r / 6) * visual_ratio), (int)(posY_r * visual_ratio),
(int)((g_e + g_r_r / 6) * visual_ratio), (int)((posY_r + 3 * g_r_r) * visual_ratio));
circle((int)(g_e * visual_ratio), (int)(posY_r * visual_ratio), (int)(g_r_r * visual_ratio));
}
///// DEBUG /////
// 显示包络
if (b_show_envelope_circles)
{
float r_r_save = g_r_r;
g_r_r = 0;
for (float theta = 0; theta <= 2 * PI; theta += 0.3f)
{
PointF pt = CamPointAt(theta, offset);
putpixel((int)(visual_ratio * pt.x), (int)(visual_ratio * pt.y), WHITE);
setlinecolor(RED);
circle((int)(visual_ratio * pt.x), (int)(visual_ratio * pt.y), (int)(visual_ratio * r_r_save));
}
g_r_r = r_r_save;
}
setaspectratio(1, 1);
setorigin(0, 0);
}