513 lines
16 KiB
C++
513 lines
16 KiB
C++
#include "parkingLotManager.h"
|
|
#include "ParkingLotWidget.h"
|
|
#include "ParkingSpaceWidget.h"
|
|
#include "path.h"
|
|
#include <QDebug>
|
|
#include <QPainter>
|
|
#include <QPoint>
|
|
#include <QRect>
|
|
#include <QGraphicsScene>
|
|
#include <QApplication>
|
|
#include "logwindow.h"
|
|
#include "car.h"
|
|
#include "carlist.h"
|
|
|
|
#define GET_SITUATION(l, n) (m_widgets[l]->getSpaceList().at(n)->getSituation())
|
|
#define BANNED (ParkingSpaceWidget::Situation::banned)
|
|
#define OCCUPIED (ParkingSpaceWidget::Situation::occupied)
|
|
#define FREE (ParkingSpaceWidget::Situation::free)
|
|
|
|
#define NODE_TYPE ParkingLotGraph::Node::Type
|
|
|
|
|
|
ParkingLotManager::ParkingLotManager(QObject* objectParent, QGraphicsScene* scene):
|
|
QObject(objectParent), m_scene(scene)
|
|
{
|
|
|
|
// 找到xml文件路径
|
|
QString filePath = __FILE__;
|
|
QStringList list = filePath.split("\\");
|
|
QString result;
|
|
for (int i = 0; i < list.size() - 1; i++)
|
|
result.append(list.at(i)).append("\\");
|
|
QStringList l = {"parkinglot_b1.xml", "parkinglot_f1.xml"};
|
|
for (int i = 0; i < 2; i++) {
|
|
QString t(result);
|
|
m_xml_path.push_back(t.append(l.at(i)));
|
|
}
|
|
m_cars.resize(m_num_of_layer); // 停在每一层的车
|
|
m_waitting.resize(m_num_of_entry); // 在每个入口等待的车
|
|
for (uint i = 0; i < m_num_of_layer; i++) { // 全部为饿汉模式
|
|
ParkingLotWidget* widget = new ParkingLotWidget(Q_NULLPTR, m_xml_path.at(i)); // 生成一个widget
|
|
// m_pixmap.push_back(new QPixmap(widget->size())); // 创建一层的pixmap
|
|
// qDebug() << "widget size x=" << widget->size().width() << " y=" <<widget->size().height();
|
|
// widget->render(m_pixmap[i]); // 渲染pixmap
|
|
m_capacity.push_back(widget->getCapacity()); // 获得这一层的最大容量
|
|
m_cars[i].resize(m_capacity.at(i)); // 初始化一层的车位
|
|
m_name.push_back(widget->getName()); // 这一层的名字
|
|
m_num_of_cars.push_back(0); // 初始停车数量为0
|
|
widget->hide();
|
|
m_widgets.push_back(widget);
|
|
m_scene->addWidget(widget);
|
|
m_graph.push_back(new ParkingLotGraph(widget));
|
|
m_graph_pixmap.push_back(new QGraphicsPixmapItem(*m_graph.last()->getPixmap()));
|
|
QObject::connect(this, &ParkingLotManager::showMarginSignal, widget, &ParkingLotWidget::showMarginSlot);
|
|
QObject::connect(widget, &ParkingLotWidget::banParkingSpace, [i, this](bool b, int n){banSpace(b, i, n);});
|
|
}
|
|
generatePool(true);
|
|
Adapter *adapter = new Adapter(objectParent, &m_all_cars); // 注册model
|
|
CarList::getInstance()->setAdapter(adapter);
|
|
|
|
timer = new QTimer(this);
|
|
connect(timer, &QTimer::timeout, this, &ParkingLotManager::periodWork);
|
|
QTimer* priceTimer = new QTimer(this);
|
|
connect(priceTimer, &QTimer::timeout, this, &ParkingLotManager::requestPrice);
|
|
priceTimer->start(1000);
|
|
}
|
|
|
|
void ParkingLotManager::showParkingLot(uint pos)
|
|
{
|
|
if (pos >= m_num_of_layer) {
|
|
qDebug() << "ParkingLotManager: 层数错误";
|
|
return;
|
|
}
|
|
for (uint i = 0; i < m_num_of_layer; i++)
|
|
m_widgets.at(i)->hide();
|
|
qDebug()<<(QString("LINE:%1").arg(__LINE__));
|
|
m_widgets.at(pos)->show();
|
|
for (QGraphicsPixmapItem* p: m_graph_pixmap)
|
|
if (m_scene->items().contains(p))
|
|
m_scene->removeItem(p);
|
|
if (m_showGraph) {
|
|
qDebug()<<(QString("LINE:%1").arg(__LINE__));
|
|
m_scene->addItem(m_graph_pixmap.at(m_current_floor));
|
|
}
|
|
for (auto c: m_all_cars) {
|
|
if (c->getCurrentFloor() != static_cast<int>(pos))
|
|
c->hide();
|
|
else
|
|
c->show();
|
|
}
|
|
m_scene->setSceneRect(m_widgets[pos]->rect()); // 固定位置
|
|
emit setCapacity(QString::number(m_capacity.at(pos)));
|
|
emit setLoad(QString::number(m_capacity.at(pos) - m_num_of_cars[pos]));
|
|
emit setLayerName(m_name.at(pos));
|
|
}
|
|
|
|
void ParkingLotManager::showParkingLot()
|
|
{
|
|
showParkingLot(m_current_floor);
|
|
}
|
|
|
|
void ParkingLotManager::showDownStairFloor()
|
|
{
|
|
if (m_current_floor == m_num_of_layer - 1) // 当前是最顶层
|
|
emit enableUpButton(true);
|
|
if (m_current_floor == 1)
|
|
emit enableDownButton(false); // 到底
|
|
if (m_current_floor > 0)
|
|
--m_current_floor;
|
|
showParkingLot(m_current_floor);
|
|
}
|
|
|
|
void ParkingLotManager::showUpStairFloor()
|
|
{
|
|
if (m_current_floor == 0)
|
|
emit enableDownButton(true);
|
|
if (m_current_floor == m_num_of_layer - 2)
|
|
emit enableUpButton(false);
|
|
if (m_current_floor < m_num_of_layer - 1)
|
|
++ m_current_floor;
|
|
showParkingLot(m_current_floor);
|
|
}
|
|
|
|
ParkingLotGraph::Node::Type getType(int n) {
|
|
if (n > 0)
|
|
return ParkingLotGraph::Node::Type::space;
|
|
else
|
|
return ParkingLotGraph::Node::Type::act;
|
|
}
|
|
|
|
void ParkingLotManager::drawPath(int n1, int n2)
|
|
{
|
|
if (n1 < -8 || n1 > 104 || n2 < -8 || n2 > 104)
|
|
return ;
|
|
QPen pen(QColor(242, 23, 242));
|
|
pen.setWidth(3);
|
|
Path *p = m_graph[m_current_floor]->findPath(getType(n1), n1, getType(n2), n2);
|
|
for(int i = 1; i < p->pointsCount(); i++) {
|
|
QLineF line(p->getPoint(i-1).point, p->getPoint(i).point);
|
|
QPointF dir(qCos(qDegreesToRadians(p->getPoint(i-1).dir)) * 10,
|
|
qSin(qDegreesToRadians(p->getPoint(i-1).dir)) * 10);
|
|
QLineF dirLine(p->getPoint(i-1).point, p->getPoint(i-1).point + dir);
|
|
m_scene->addLine(line);
|
|
m_scene->addLine(dirLine, pen);
|
|
m_scene->addText(QString::number(p->getPoint(i-1).dir))->moveBy(p->getPoint(i-1).point.x(),
|
|
p->getPoint(i-1).point.y());
|
|
}
|
|
}
|
|
|
|
void ParkingLotManager::drawPath(Path* p)
|
|
{
|
|
QPen pen(QColor(242, 23, 242));
|
|
pen.setWidth(3);
|
|
for(int i = 1; i < p->pointsCount(); i++) {
|
|
QLineF line(p->getPoint(i-1).point, p->getPoint(i).point);
|
|
QPointF dir(qCos(qDegreesToRadians(p->getPoint(i-1).dir)) * 10,
|
|
qSin(qDegreesToRadians(p->getPoint(i-1).dir)) * 10);
|
|
QLineF dirLine(p->getPoint(i-1).point, p->getPoint(i-1).point + dir);
|
|
m_scene->addLine(line);
|
|
m_scene->addLine(dirLine, pen);
|
|
m_scene->addText(QString::number(p->getPoint(i-1).dir))->moveBy(p->getPoint(i-1).point.x(),
|
|
p->getPoint(i-1).point.y());
|
|
}
|
|
}
|
|
|
|
bool ParkingLotManager::checkSame(const QString &plate)
|
|
{
|
|
for (auto c: m_all_cars)
|
|
if (c->getPlateNumber() == plate)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
QString ParkingLotManager::getParkingLotName(int pos)
|
|
{
|
|
return m_widgets.at(pos)->getName();
|
|
}
|
|
|
|
QPair<QString, int> ParkingLotManager::search(const QString& plate)
|
|
{
|
|
for (auto c: m_all_cars) {
|
|
if (c->getPlateNumber() == plate) {
|
|
if (c->getStatus() == Car::Status::parking ||
|
|
c->getStatus() == Car::Status::moving)
|
|
return qMakePair(m_widgets.at(c->getTargetFloor())->getName(),
|
|
c->getNum());
|
|
else if (c->getStatus() == Car::Status::waiting)
|
|
return qMakePair(QString("0"), 0);
|
|
}
|
|
}
|
|
return qMakePair(QString("-1"), -1);
|
|
}
|
|
|
|
bool comp2(const Car* c1, const Car* c2) {
|
|
return c1->getPlateNumber() < c2->getPlateNumber();
|
|
}
|
|
|
|
int comp(const QString& p1, const Car* c2) {
|
|
return strcmp(p1.toStdString().c_str(), c2->getPlateNumber().toStdString().c_str());
|
|
}
|
|
|
|
QPair<QString, int> ParkingLotManager::biSearch(const QString &plate)
|
|
{
|
|
sort(m_all_cars.begin(), m_all_cars.end(), &comp2);
|
|
int left = 0, right = m_all_cars.size(), mid = m_all_cars.size() / 2;
|
|
while (left != right) {
|
|
int flag = comp(plate, m_all_cars.at(mid));
|
|
if (flag == -1) {
|
|
right = mid;
|
|
} else if (flag == 1) {
|
|
left = mid;
|
|
} else if (flag == 0) {
|
|
Car* c = m_all_cars.at(mid);
|
|
if (c->getStatus() == Car::Status::parking ||
|
|
c->getStatus() == Car::Status::moving)
|
|
return qMakePair(m_widgets.at(c->getTargetFloor())->getName(),
|
|
c->getNum());
|
|
else if (c->getStatus() == Car::Status::waiting)
|
|
return qMakePair(QString("0"), 0);
|
|
}
|
|
mid = (right + left) / 2;
|
|
}
|
|
return qMakePair(QString("-1"), -1);
|
|
}
|
|
|
|
void ParkingLotManager::showMode(bool enable)
|
|
{
|
|
if (enable)
|
|
timer->start(1000);
|
|
else
|
|
timer->stop();
|
|
}
|
|
|
|
void ParkingLotManager::requestOut(Car *car, int exit)
|
|
{
|
|
if (exit == -1)
|
|
exit = rand() % m_num_of_entry + 1;
|
|
Path *p;
|
|
if (car->getCurrentFloor() == 1)
|
|
p = m_graph[1]->findPath(NODE_TYPE::space, car->getNum(), NODE_TYPE::exit, exit);
|
|
else
|
|
p = m_graph[car->getCurrentFloor()]->
|
|
findPath(NODE_TYPE::space, car->getNum(), NODE_TYPE::stair, exit);
|
|
if (GET_SITUATION(car->getCurrentFloor(), car->getNum()-1) != BANNED)
|
|
m_pool.append(qMakePair(car->getCurrentFloor(), car->getNum() - 1));
|
|
m_widgets[car->getCurrentFloor()]->
|
|
getSpaceList()[car->getNum() - 1]->setSituation(ParkingSpaceWidget::free);
|
|
car->setNum(-exit); // 负数代表出口
|
|
car->setPath(p);
|
|
car->setTargetFloor(1);
|
|
car->setStatus(Car::moving);
|
|
car->followPath();
|
|
}
|
|
|
|
void ParkingLotManager::requestStair(Car *car)
|
|
{
|
|
int l = car->getTargetFloor();
|
|
int n = car->getNum();
|
|
int e = car->getEntryNum();
|
|
Path *p;
|
|
if (n > 0)
|
|
p = m_graph[l]->findPath(NODE_TYPE::stair, e, NODE_TYPE::space, n);
|
|
else
|
|
p = m_graph[l]->findPath(NODE_TYPE::stair, e, NODE_TYPE::exit, -n);
|
|
// drawPath(p);
|
|
car->setPath(p);
|
|
car->setCurrentFloor(l);
|
|
if (l == static_cast<int>(m_current_floor))
|
|
car->show();
|
|
else
|
|
car->hide();
|
|
car->followPath();
|
|
}
|
|
|
|
void ParkingLotManager::requestBack(Car *car)
|
|
{
|
|
Path* p = m_graph[1]->findPath(car, car->getEntryNum());
|
|
car->setPath(p);
|
|
car->followPath();
|
|
m_all_cars.removeOne(car);
|
|
m_waitting[car->getEntryNum() - 1].removeOne(car);
|
|
}
|
|
|
|
void ParkingLotManager::requestIn(Car* car)
|
|
{
|
|
int entry = car->getEntryNum();
|
|
car->requested = true;
|
|
if (!m_pool.empty()) {
|
|
uint l = m_pool.first().first;
|
|
int n = m_pool.first().second + 1;
|
|
if (m_widgets[l]->getSpaceList().at(n - 1)->getSituation() != FREE)
|
|
return;
|
|
// l = 0;
|
|
m_pool.removeAt(0);
|
|
Log::i(QString("分配第%1层%2号车位,剩余%3个空车位").arg(l).arg(n).arg(m_pool.size()));
|
|
Path* p;
|
|
if (l == 1)
|
|
p = m_graph[1]->findPath(NODE_TYPE::queueHead, entry, NODE_TYPE::space, n);
|
|
else {
|
|
p = m_graph[1]->findPath(NODE_TYPE::queueHead, entry, NODE_TYPE::stair, entry);
|
|
}
|
|
// drawPath(p);
|
|
m_waitting[entry - 1].pop_front(); // 移除等候
|
|
m_cars[l][n - 1] = car;
|
|
car->setPath(p);
|
|
car->setTargetFloor(l);
|
|
car->setNum(n);
|
|
car->followPath();
|
|
car->setStartTime(QTime::currentTime());
|
|
car->setStatus(Car::parking);
|
|
m_num_of_cars[l] += 1;
|
|
m_widgets[l]->getSpaceList()[n - 1]->setSituation(ParkingSpaceWidget::occupied);
|
|
qDebug()<<(QString("LINE:%1 %2").arg(__LINE__).arg(m_current_floor));
|
|
emit setLoad(QString::number(m_capacity.at(m_current_floor) - m_num_of_cars[m_current_floor]));
|
|
} else {
|
|
Log::i("请求失败,车位已满");
|
|
}
|
|
}
|
|
|
|
void ParkingLotManager::leave(Car* car)
|
|
{
|
|
int l = car->getCurrentFloor();
|
|
Log::i(QString("有车离开,已产生费用%1元,当前共有%2个空车位").arg(car->getFee()).arg(m_pool.size()));
|
|
emit money(car->getFee().toDouble());
|
|
callIn();
|
|
car->hide();
|
|
m_all_cars.removeOne(car);
|
|
delete car;
|
|
m_num_of_cars[l] -= 1;
|
|
qDebug()<<(QString("LINE:%1").arg(__LINE__));
|
|
emit setLoad(QString::number(m_capacity.at(m_current_floor) - m_num_of_cars[m_current_floor]));
|
|
}
|
|
|
|
void ParkingLotManager::addCarR()
|
|
{
|
|
int entry = (rand() % m_num_of_entry);
|
|
if (m_waitting[entry].size() > 10)
|
|
return;
|
|
|
|
Car *car = new Car(this);
|
|
Log::i(QString("生成车:%1").arg(car->getPlateNumber()));
|
|
car->setEntryNum(entry + 1);
|
|
m_waitting[entry].append(car);
|
|
Path *p = m_graph[1]->findPath(NODE_TYPE::entry, entry + 1, NODE_TYPE::queueHead, entry + 1);
|
|
car->setPath(p);
|
|
car->setCurrentFloor(1); // 刚添加的车一定是在一层
|
|
car->setTargetFloor(1);
|
|
car->followPath();
|
|
car->setStatus(Car::waiting);
|
|
m_all_cars.append(car);
|
|
m_scene->addItem(car);
|
|
if (m_current_floor != 1)
|
|
car->hide();
|
|
}
|
|
|
|
void ParkingLotManager::addCar(QString plate, int color, int entry)
|
|
{
|
|
if (entry == -1)
|
|
entry = (rand() % m_num_of_entry) + 1;
|
|
if (m_waitting[entry - 1].size() > 10)
|
|
return;
|
|
Car *car = new Car(this, nullptr, 0, static_cast<Car::Color>(color));
|
|
car->setPlateNumber(plate);
|
|
car->setEntryNum(entry);
|
|
m_waitting[entry-1].append(car);
|
|
Path *p = m_graph[1]->findPath(NODE_TYPE::entry, entry, NODE_TYPE::queueHead, entry);
|
|
car->setPath(p);
|
|
car->setCurrentFloor(1); // 刚添加的车一定是在一层
|
|
car->setTargetFloor(1);
|
|
car->followPath();
|
|
car->setStatus(Car::waiting);
|
|
m_all_cars.append(car);
|
|
m_scene->addItem(car);
|
|
Log::i(QString("生成车:%1").arg(car->getPlateNumber()));
|
|
if (m_current_floor != 1)
|
|
car->hide();
|
|
}
|
|
|
|
void ParkingLotManager::showMargin(bool enable)
|
|
{
|
|
// qDebug() << "show margin" << enable;
|
|
emit showMarginSignal(enable);
|
|
}
|
|
|
|
void ParkingLotManager::showGraph(bool enable)
|
|
{
|
|
// qDebug() << "show graph" << enable;
|
|
m_showGraph = enable;
|
|
showParkingLot();
|
|
}
|
|
|
|
void ParkingLotManager::banSpace(bool banned, int l , int n)
|
|
{
|
|
if (banned) {
|
|
m_pool.removeOne(qMakePair(l, n - 1));
|
|
Log::i(QString("禁用第%1层%2号车位,剩余%3个空车位").arg(l).arg(n).arg(m_pool.size()));
|
|
} else {
|
|
m_pool.append(qMakePair(l, n - 1));
|
|
Log::i(QString("启用第%1层%2号车位,剩余%3个空车位").arg(l).arg(n).arg(m_pool.size()));
|
|
callIn();
|
|
}
|
|
}
|
|
|
|
void ParkingLotManager::generatePool(bool sequence, int max)
|
|
{
|
|
m_pool.clear();
|
|
if (max == -1)
|
|
max = 65536;
|
|
for (int l = m_num_of_layer - 1; l >= 0; l--) {
|
|
for (int n = 0; n < m_capacity[l]; n++) {
|
|
if (max-- == 0)
|
|
goto OUT;
|
|
if (GET_SITUATION(l, n) == FREE) {
|
|
m_pool.append(qMakePair(l, n));
|
|
}
|
|
}
|
|
}
|
|
OUT:
|
|
if (!sequence)
|
|
std::random_shuffle(m_pool.begin(), m_pool.end());
|
|
Log::i(QString("生成车位池成功,当前共有") + QString::number(m_pool.size()) + "个空车位");
|
|
}
|
|
|
|
void ParkingLotManager::periodWork()
|
|
{
|
|
int generateProbability = 80;
|
|
if (rand() % 100 + 1 < generateProbability)
|
|
addCarR();
|
|
for (auto c: m_all_cars) {
|
|
c->leaveProbability(2);
|
|
}
|
|
callIn();
|
|
}
|
|
|
|
void ParkingLotManager::callIn()
|
|
{
|
|
for (uint i = 0 ; i < m_num_of_entry; i++) {
|
|
if (m_waitting[lastInEntry].size() != 0) {
|
|
Log::i(QString("从%1召唤车").arg(lastInEntry));
|
|
Car *c = m_waitting[lastInEntry][0];
|
|
if (c->requested)
|
|
c->requestSpace();
|
|
}
|
|
lastInEntry = (lastInEntry + 1) % m_num_of_entry ;
|
|
}
|
|
}
|
|
|
|
double ParkingLotManager::getYellow_price() const
|
|
{
|
|
return yellow_price;
|
|
}
|
|
|
|
void ParkingLotManager::setYellow_price(double value)
|
|
{
|
|
yellow_price = value;
|
|
}
|
|
|
|
double ParkingLotManager::getRed_price() const
|
|
{
|
|
return red_price;
|
|
}
|
|
|
|
void ParkingLotManager::setRed_price(double value)
|
|
{
|
|
red_price = value;
|
|
}
|
|
|
|
double ParkingLotManager::getPink_price() const
|
|
{
|
|
return pink_price;
|
|
}
|
|
|
|
void ParkingLotManager::setPink_price(double value)
|
|
{
|
|
pink_price = value;
|
|
}
|
|
|
|
void ParkingLotManager::setMax(int max)
|
|
{
|
|
int n = m_max;
|
|
int mmax = max;
|
|
m_max = max;
|
|
Log::i(QString("设置最大容量%1").arg(max));
|
|
for (int l = m_num_of_layer - 1; l >= 0; l--) {
|
|
for (int n = 0; n < m_capacity[l]; n++) {
|
|
if (max > 0) {
|
|
if (GET_SITUATION(l, n) != OCCUPIED) {
|
|
m_widgets.at(l)->getSpaceList().at(n)->setSituation(FREE);
|
|
m_widgets.at(l)->getSpaceList().at(n)->update();
|
|
}
|
|
max--;
|
|
}
|
|
else {
|
|
m_widgets.at(l)->getSpaceList().at(n)->setSituation(BANNED);
|
|
m_widgets.at(l)->getSpaceList().at(n)->update();
|
|
}
|
|
}
|
|
}
|
|
generatePool(m_sequence, mmax);
|
|
if (max - n == 1)
|
|
callIn();
|
|
else if (max - n >= 2) {
|
|
callIn();
|
|
callIn();
|
|
}
|
|
}
|
|
|
|
void ParkingLotManager::setSequence(bool sequence)
|
|
{
|
|
m_sequence = sequence;
|
|
generatePool(m_sequence, m_max);
|
|
}
|