// CPageGraph1.cpp: 实现文件
|
//
|
|
#include "stdafx.h"
|
#include "Servo.h"
|
#include "CPageGraph1.h"
|
#include "afxdialogex.h"
|
#include "Common.h"
|
|
|
|
// Image
|
#define IMAGE_ROBOT 2
|
|
#define INDICATE_BONDER1 1
|
#define INDICATE_BONDER2 2
|
#define INDICATE_FLIPER 3
|
#define INDICATE_ALIGNER 4
|
#define INDICATE_LPORT4 5
|
#define INDICATE_LPORT3 6
|
#define INDICATE_LPORT2 7
|
#define INDICATE_LPORT1 8
|
#define INDICATE_ROBOT_ARM1 9
|
#define INDICATE_ROBOT_ARM2 10
|
#define INDICATE_VACUUM_BAKE 11
|
#define INDICATE_BAKE_COOLING 12
|
#define INDICATE_MEASUREMENT 13
|
|
// CPageGraph1 对话框
|
|
IMPLEMENT_DYNAMIC(CPageGraph1, CDialogEx)
|
|
CPageGraph1::CPageGraph1(CWnd* pParent /*=nullptr*/)
|
: CDialogEx(IDD_PAGE_GRAPH1, pParent)
|
{
|
m_pGraph = nullptr;
|
m_pObserver = nullptr;
|
m_bIsRobotMoving = FALSE;
|
m_crBkgnd = PAGE_GRPAH1_BACKGROUND_COLOR;
|
m_hbrBkgnd = nullptr;
|
}
|
|
CPageGraph1::~CPageGraph1()
|
{
|
}
|
|
void CPageGraph1::DoDataExchange(CDataExchange* pDX)
|
{
|
CDialogEx::DoDataExchange(pDX);
|
}
|
|
|
BEGIN_MESSAGE_MAP(CPageGraph1, CDialogEx)
|
ON_WM_CTLCOLOR()
|
ON_WM_DESTROY()
|
ON_WM_SIZE()
|
ON_NOTIFY(BYSERVOGRAPH_ITEM_CLICKED, IDC_SERVO_GRAPH1, &CPageGraph1::OnGraphItemClicked)
|
ON_WM_ERASEBKGND()
|
ON_WM_TIMER()
|
END_MESSAGE_MAP()
|
|
|
// CPageGraph1 消息处理程序
|
|
|
void CPageGraph1::InitRxWindows()
|
{
|
/* code */
|
// 订阅数据
|
IRxWindows* pRxWindows = RX_GetRxWindows();
|
pRxWindows->enableLog(5);
|
if (m_pObserver == NULL) {
|
m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
|
// onNext
|
pAny->addRef();
|
int code = pAny->getCode();
|
if (RX_CODE_EQ_ALIVE == code) {
|
// 通知设备状态
|
SERVO::CEquipment* pEquipment = nullptr;
|
if (pAny->getPtrValue("ptr", (void*&)pEquipment)) {
|
if (pEquipment != nullptr) {
|
int nID = pEquipment->getID();
|
BOOL bAlive = pEquipment->isAlive();
|
if (EQ_ID_EFEM == nID) {
|
DeviceStatus status = bAlive ? DeviceStatus::ONLINE : DeviceStatus::OFFLINE;
|
UpdateDeviceStatus(INDICATE_ROBOT_ARM1, status);
|
UpdateDeviceStatus(INDICATE_ROBOT_ARM2, status);
|
}
|
}
|
}
|
}
|
|
pAny->release();
|
}, [&]() -> void {
|
// onComplete
|
}, [&](IThrowable* pThrowable) -> void {
|
// onErrorm
|
pThrowable->printf();
|
});
|
|
theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
|
->subscribe(m_pObserver);
|
}
|
}
|
|
BOOL CPageGraph1::OnInitDialog()
|
{
|
CDialogEx::OnInitDialog();
|
SetTimer(1, 3000, nullptr);
|
|
|
// 图示
|
m_pGraph = CServoGraph::Hook(GetDlgItem(IDC_SERVO_GRAPH1)->GetSafeHwnd());
|
CString strPath;
|
strPath.Format(_T("%s\\res\\Servo001.bmp"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
|
m_pGraph->AddImage(1, (LPTSTR)(LPCTSTR)strPath, 0, 0);
|
|
strPath.Format(_T("%s\\res\\Robot001.bmp"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
|
m_pGraph->AddImage(IMAGE_ROBOT, (LPTSTR)(LPCTSTR)strPath, 170, 270);
|
|
// 添加指示器
|
// Bonder
|
m_pGraph->AddIndicateBox(INDICATE_BONDER1, 220, 172, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_BONDER1, "10", "Bonder 1");
|
m_pGraph->AddIndicateBox(INDICATE_BONDER2, 220, 516, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_BONDER2, "11", "Bonder 2");
|
|
|
// 翻转
|
m_pGraph->AddIndicateBox(INDICATE_FLIPER, 338, 172, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_FLIPER, "8", "Fliper");
|
|
|
// 对位
|
m_pGraph->AddIndicateBox(INDICATE_ALIGNER, 428, 172, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_ALIGNER, "7", "Aligner");
|
|
|
// Load port 4
|
m_pGraph->AddIndicateBox(INDICATE_LPORT4, 518, 172, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_LPORT4, "4", "LPort4");
|
|
|
// Load port 3
|
m_pGraph->AddIndicateBox(INDICATE_LPORT3, 606, 172, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_LPORT3, "3", "LPort3");
|
|
|
// Load port 2
|
m_pGraph->AddIndicateBox(INDICATE_LPORT2, 690, 172, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_LPORT2, "2", "LPort2");
|
|
|
// Load port 1
|
m_pGraph->AddIndicateBox(INDICATE_LPORT1, 774, 172, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_LPORT1, "1", "LPort1");
|
|
|
// Robot
|
m_pGraph->AddIndicateBox(INDICATE_ROBOT_ARM1, 190, 294, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_ROBOT_ARM1, "5", "Robot");
|
m_pGraph->AddIndicateBox(INDICATE_ROBOT_ARM2, 243, 294, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_ROBOT_ARM2, "6", "Robot");
|
|
|
|
|
// Vacuum bake
|
m_pGraph->AddIndicateBox(INDICATE_VACUUM_BAKE, 396, 516, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_VACUUM_BAKE, "9", "Vacuum bake");
|
|
|
// Bake cooling
|
m_pGraph->AddIndicateBox(INDICATE_BAKE_COOLING, 566, 516, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_BAKE_COOLING, "12", "Bake cooling");
|
|
|
// 精度检
|
m_pGraph->AddIndicateBox(INDICATE_MEASUREMENT, 737, 516, 48, RGB(22, 22, 22),
|
RGB(255, 127, 39), EQ_BOX_OFFLINE);
|
m_pGraph->SetBoxText(INDICATE_MEASUREMENT, "13", "Measurement");
|
|
|
// 绑定数据
|
{
|
SERVO::CEquipment* pEquipment = theApp.m_model.m_master.getEquipment(EQ_ID_EFEM);
|
m_pGraph->SetIndicateBoxData(INDICATE_ROBOT_ARM1, pEquipment);
|
}
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
// 异常: OCX 属性页应返回 FALSE
|
}
|
|
void CPageGraph1::UpdateDeviceStatus(int id, DeviceStatus status)
|
{
|
// 根据状态设置颜色
|
COLORREF newBackgroundColor;
|
COLORREF newFrameColor1;
|
COLORREF newFrameColor2;
|
|
switch (status) {
|
case ONLINE:
|
newBackgroundColor = EQ_BOX_ONLINE;
|
newFrameColor1 = EQ_BOX_FRAME1;
|
newFrameColor2 = EQ_BOX_FRAME2;
|
break;
|
case OFFLINE:
|
newBackgroundColor = RGB(222, 222, 222);
|
newFrameColor1 = EQ_BOX_FRAME1;
|
newFrameColor2 = EQ_BOX_FRAME2;
|
break;
|
default:
|
newBackgroundColor = RGB(255, 255, 255); // 默认白色背景
|
newFrameColor1 = RGB(0, 0, 0); // 默认黑色框架1
|
newFrameColor2 = RGB(0, 0, 0); // 默认黑色框架2
|
break;
|
}
|
|
m_pGraph->UpdateIndicateBox1Colors(id, newBackgroundColor, newFrameColor1, newFrameColor2);
|
|
// 刷新界面
|
Invalidate();
|
UpdateWindow();
|
}
|
|
BOOL CPageGraph1::OnEraseBkgnd(CDC* pDC)
|
{
|
// TODO: 在此添加消息处理程序代码和/或调用默认值
|
if (m_bIsRobotMoving) {
|
// 禁止刷新背景,避免闪烁
|
return TRUE;
|
}
|
|
return CDialogEx::OnEraseBkgnd(pDC);
|
}
|
|
HBRUSH CPageGraph1::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
|
{
|
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
|
|
if (nCtlColor == CTLCOLOR_STATIC) {
|
pDC->SetBkColor(m_crBkgnd);
|
pDC->SetTextColor(RGB(0, 0, 0));
|
}
|
|
if (m_hbrBkgnd == nullptr) {
|
m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
|
}
|
|
return m_hbrBkgnd;
|
}
|
|
void CPageGraph1::OnDestroy()
|
{
|
CDialogEx::OnDestroy();
|
|
if (m_hbrBkgnd != nullptr) {
|
::DeleteObject(m_hbrBkgnd);
|
}
|
}
|
|
void CPageGraph1::OnSize(UINT nType, int cx, int cy)
|
{
|
CDialogEx::OnSize(nType, cx, cy);
|
if (GetDlgItem(IDC_SERVO_GRAPH1) == nullptr) return;
|
|
CRect rcClient;
|
GetClientRect(&rcClient);
|
GetDlgItem(IDC_SERVO_GRAPH1)->MoveWindow(0, 0, rcClient.Width(), rcClient.Height());
|
}
|
|
void CPageGraph1::UpdateRobotPosition(float percentage)
|
{
|
// 限制百分比范围在 [0, 1] 之间
|
if (percentage < 0.0f) percentage = 0.0f;
|
if (percentage > 1.0f) percentage = 1.0f;
|
|
// 根据百分比计算目标 X 坐标
|
int startX = m_pGraph->GetImage(IMAGE_ROBOT)->x;
|
int endX = static_cast<int>(170 + percentage * (700 - 170));
|
|
int arm1Offset = 20; // 从图片到ARM1的偏移
|
int arm2Offset = 73; // 从图片到ARM2的偏移
|
|
// 计算移动所需的时间
|
int distance = abs(endX - startX);
|
int duration = static_cast<int>((distance / 100.0) * 1000);
|
|
auto startTime = std::chrono::steady_clock::now();
|
auto endTime = startTime + std::chrono::milliseconds(duration);
|
|
// 开始移动,设置标记
|
m_bIsRobotMoving = TRUE;
|
|
// 开始平滑移动
|
while (std::chrono::steady_clock::now() < endTime) {
|
auto currentTime = std::chrono::steady_clock::now();
|
float progress = std::chrono::duration<float, std::milli>(currentTime - startTime).count() / duration;
|
progress = min(progress, 1.0f);
|
|
// 根据进度计算当前位置
|
int currentX = static_cast<int>(startX + progress * (endX - startX));
|
m_pGraph->UpdateImageCoordinates(IMAGE_ROBOT, currentX, 270);
|
m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM1, currentX + arm1Offset, 294);
|
m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM2, currentX + arm2Offset, 294);
|
|
// 刷新界面
|
Invalidate();
|
UpdateWindow();
|
|
// 控制帧率约为 60 FPS
|
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
}
|
|
// 确保最后位置精确到目标位置
|
m_pGraph->UpdateImageCoordinates(IMAGE_ROBOT, endX, 270);
|
m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM1, endX + arm1Offset, 294);
|
m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM2, endX + arm2Offset, 294);
|
|
// 界面重绘
|
Invalidate();
|
|
// 动画结束,设置标记
|
m_bIsRobotMoving = FALSE;
|
}
|
|
void CPageGraph1::RotateRobot(float angleInDegrees)
|
{
|
// 将角度转换为弧度
|
float angleInRadians = static_cast<float>(std::acos(-1)) / 180.0f * angleInDegrees;
|
|
// 获取机器人图片的当前坐标和中心
|
auto* pImage = m_pGraph->GetImage(IMAGE_ROBOT);
|
if (!pImage) return;
|
|
// 更新 Rotate 图片的角度,确保角度保持在 [0, 360) 范围内
|
m_pGraph->UpdateImageAngle(IMAGE_ROBOT, static_cast<float>(fmod(pImage->angle + angleInDegrees + 360, 360)));
|
|
int cx = pImage->x + pImage->bmWidth / 2; // 图片中心 X
|
int cy = pImage->y + pImage->bmHeight / 2; // 图片中心 Y
|
|
// 旋转指示框的坐标
|
auto* pRobot1 = m_pGraph->GetIndicateBox(INDICATE_ROBOT_ARM1);
|
auto* pRobot2 = m_pGraph->GetIndicateBox(INDICATE_ROBOT_ARM2);
|
|
if (pRobot1 && pRobot2) {
|
int newArmX1 = pImage->x + 20;
|
int newArmY1 = 294;
|
|
int newArmX2 = pImage->x + 73;
|
int newArmY2 = 294;
|
|
if (angleInDegrees != 0.0f) {
|
// 计算指示框1的新坐标
|
newArmX1 = static_cast<int>(cx + (pRobot1->x - cx) * cos(angleInRadians) - (pRobot1->y - cy) * sin(angleInRadians));
|
newArmY1 = static_cast<int>(cy + (pRobot1->x - cx) * sin(angleInRadians) + (pRobot1->y - cy) * cos(angleInRadians));
|
|
// 计算指示框2的新坐标
|
newArmX2 = static_cast<int>(cx + (pRobot2->x - cx) * cos(angleInRadians) - (pRobot2->y - cy) * sin(angleInRadians));
|
newArmY2 = static_cast<int>(cy + (pRobot2->x - cx) * sin(angleInRadians) + (pRobot2->y - cy) * cos(angleInRadians));
|
}
|
|
// 更新指示框的位置
|
m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM1, newArmX1, newArmY1);
|
m_pGraph->UpdateIndicateBoxCoordinates(INDICATE_ROBOT_ARM2, newArmX2, newArmY2);
|
}
|
|
// 强制重绘界面
|
Invalidate();
|
}
|
|
void CPageGraph1::OnGraphItemClicked(NMHDR* pNMHDR, LRESULT* pResult)
|
{
|
BYSERVOGRAPH_NMHDR* pGraphNmhdr = reinterpret_cast<BYSERVOGRAPH_NMHDR*>(pNMHDR);
|
CString s; s.Format(_T("OnGraphItemClicked %d"), pGraphNmhdr->dwData);
|
SERVO::CEquipment* pEquipment = (SERVO::CEquipment*)m_pGraph->GetIndicateBoxData(pGraphNmhdr->dwData);
|
if (pEquipment != nullptr) {
|
AfxMessageBox(pEquipment->getName().c_str());
|
}
|
|
|
*pResult = 0;
|
}
|
|
void CPageGraph1::OnTimer(UINT_PTR nIDEvent)
|
{
|
if (1 == nIDEvent) {
|
KillTimer(1);
|
InitRxWindows();
|
}
|
|
CDialogEx::OnTimer(nIDEvent);
|
}
|