Parking-练习倒车入库的小程序

Parking是一款运行于Windows 10 x64和OSX 10.9以上平台的桌面单机2D小程序,用于车辆转弯、倒车及入库的精确计算、教学演示及计算机辅助训练。写这个软件的一个原因是:对GUI组件的2D仿射变换和图形的几何处理做些更深入的研究。

上图:Parking运行主界面

:下载之前请先阅读《UnderwaySoft开源软件授权协议》。如不同意,请勿下载使用。


这个小项目完成后,有些东西需总结一下,暂记于此。


// ParkingLot类中移动车辆的核心函数中,旋转教练车(组件)的语句
trainingCar->setTransform (AffineTransform::rotation (pathHudu, polePoint.getX(), polePoint.getY())); 
 
// 旋转线条,实则线条应用仿射变换
lineObject.applyTransform (trainingCar->getTransform());


g.setColour (Colours::lightgreen);
g.strokePath (pathObject, PathStrokeType (0.5f));


void ParkingLot::placeAfterSetDirection (const int newAngle)
{
    if (newAngle == 0)
        return;
    
    // first, place the pole-point base on transformed car
    const float fromInnerWheel = trainingCar->getDistanceFromInnerWheel();
 
    Point leftRearPoint (trainingCar->getX() + 0.f, trainingCar->getY() + 190.f);
    Point rightRearPoint (trainingCar->getRight() + 0.f, trainingCar->getY() + 190.f);
    leftRearPoint.applyTransform (trainingCar->getTransform());
    rightRearPoint.applyTransform (trainingCar->getTransform());
 
    Line banjing (leftRearPoint, rightRearPoint);
    const bool isTurningLeft = newAngle < 0; // place the pole point
 
    polePoint = banjing.getPointAlongLine (isTurningLeft ? -fromInnerWheel : 
                                          (fromInnerWheel + CarWidth)); 
    
    // second, place the car base on pole-point 
    const double centerX = polePoint.getX() + (isTurningLeft ? (fromInnerWheel + 50.0) : 
                                              (-fromInnerWheel - 50.0)); 
 
    const double centerY = polePoint.getY() - 70.0; 
 
    trainingCar->setCentrePosition (roundToIntAccurate (centerX), roundToIntAccurate (centerY));
    trainingCar->setTransform (AffineTransform::rotation (pathHudu, polePoint.getX(), polePoint.getY()));
}


void ParkingLot::mouseDown (const MouseEvent& e)
{
    if (isMeasuringDistance)
    {
        const Point startP = e.getMouseDownPosition();
        MeasuringComp* m = new MeasuringComp (startP);
        addAndMakeVisible (m);
 
        measurings.add (m);
        m->setTopLeftPosition (startP.getX(), startP.getY());
    }
}
//=============================================================
void ParkingLot::mouseDrag (const MouseEvent& e)
{
    if (isMeasuringDistance)
    {
        MeasuringComp* m = measurings.getLast();
 
        const Point startP = e.getMouseDownPosition();
        const Point endP = e.getPosition();
        
        const int x = (startP.getX() < endP.getX()) ? startP.getX() : endP.getX();
        const int y = (startP.getY() < endP.getY()) ? startP.getY() : endP.getY(); 
        const int w = jmax (std::abs (startP.getX() - endP.getX()), 56); 
        const int h = jmax (std::abs (startP.getY() - endP.getY()), 22); m->setEndPoint (endP);
 
        m->setBounds (x - 1, y - 1, w + 2, h + 2);
    }
}
//=============================================================
void ParkingLot::mouseUp (const MouseEvent& e)
{
    if (isMeasuringDistance)
    {
        MeasuringComp* m = measurings.getLast();
 
        const Point startP = e.getMouseDownPosition();
        const Point endP = e.getPosition();
 
        const int x = (startP.getX() < endP.getX()) ? startP.getX() : endP.getX();
        const int y = (startP.getY() < endP.getY()) ? startP.getY() : endP.getY(); 
        const int w = jmax (std::abs (startP.getX() - endP.getX()), 54); 
        const int h = jmax (std::abs (startP.getY() - endP.getY()), 20); 
 
        m->setEndPoint (endP);
        m->setBounds (x - 1, y - 1, w + 2, h + 2);
    }
}


const bool ParkingLot::isCrashed()
{
    AffineTransform atf (trainingCar->getTransform());
 
    for (int i = checkPoints.size(); --i >= 0; )
    {
        const Point p (checkPoints[i].transformedBy (atf));
        if (!contains (p))
        {
            stopTimer ();  // stop auto move
            return true;
        }
 
        Component* comp = getComponentAt (p);
 
        for (int j = 0; j < restingCars.size(); ++j) 
        { 
            if (comp == restingCars[j]) 
            { 
                stopTimer(); // stop auto move 
                return true; 
            } 
        } 
     } 
 
     return false; 
} 
//=========================================================== 
const bool ParkingLot::isSuccessful() 
{ 
    if (stopAreaOne == nullptr || stopAreaTwo == nullptr || stopAreaThree == nullptr) 
        return false; 
 
    AffineTransform atf (trainingCar->getTransform());
 
    for (int i = checkPoints.size(); --i >= 0; )
    {
        const Point p (checkPoints[i].transformedBy (atf));
 
        Rectangle stopOne (stopAreaOne->getBounds().transformedBy (stopAreaOne->getTransform()));
        Rectangle stopTwo (stopAreaTwo->getBounds().transformedBy (stopAreaTwo->getTransform()));
        Rectangle stopThree (stopAreaThree->getBounds().transformedBy (stopAreaThree->getTransform()));
 
        if (!(stopOne.contains (p) || stopTwo.contains (p) || stopThree.contains (p)))
            return false;
    }
 
    stopTimer();  // stop auto move
    return true;
}

其它


Email: underwaySoft@126.com 微信公众号: UnderwaySoft