~masgk3team/masgk3/roads

7 by fayl
reorganized code; added l-system road generator
1
#include "LSystemGenerator.hpp"
10 by Michał Janiszewski
bring peace to header includes - avoid unnecessary #includes in headers where simple declaration (or nothing at all) suffices
2
#include "RoadJunctionPoint.hpp"
3
#include "Road.hpp"
4
//-----//
5
#include <cmath>
6
#include <QImage>
7 by fayl
reorganized code; added l-system road generator
7
//-----//
8
#include <QDebug>
9
//-----//
10
Utils::Junctions LSystemGenerator::GenerateRoads(const ConfigRoads &c, const QImage *inputImage)
11
{
12
    const ConfigLSystemRoads conf = *((ConfigLSystemRoads*)&c);
13
    const QSize mapSize = inputImage->size();
14
15
    //QVector2D tmpVec((float)rand()/RAND_MAX, (float)rand()/RAND_MAX);
16
    QVector2D tmpVec(1, 0);
17
    QList<LSystemState> aStack;
27 by fayl
L-system generator modified -- height awareness mainly
18
19
    int drawLength = 8,
20
        drawLength2 = 6,
21
        rotationAngle = 90,
22
        rotationAngle2 = 5; // rand(+-x)
23
24
    LSystemState currentState(QVector2D(mapSize.width() / 2, mapSize.height() / 2),
8 by fayl
3D rendering
25
                              tmpVec.normalized(),
27 by fayl
L-system generator modified -- height awareness mainly
26
                              drawLength);
27
7 by fayl
reorganized code; added l-system road generator
28
29
    QString currentWord = conf.system.sInitialWord;
30
    RoadJunctionPoint *rjp = new RoadJunctionPoint(currentState.position);
31
    junctions.push_back(rjp);
32
33
    for (int i = 0; i < conf.system.iIterations; ++i)
34
    {
35
        QString newWord = "";
36
        for (int j = 0; j < currentWord.length(); ++j)
37
        {
38
            if (conf.system.aRules.contains(currentWord.at(j)))
39
            {
40
                newWord += conf.system.aRules[currentWord.at(j)];
41
            }
42
            else
43
                newWord += currentWord.at(j);
44
        }
45
        currentWord = newWord;
46
    }
47
48
    for (int j = 0; j < currentWord.length(); ++j)
49
    {
50
        switch (currentWord.at(j).toAscii())
51
        {
52
        case 'X':
27 by fayl
L-system generator modified -- height awareness mainly
53
            currentState.drawLength = drawLength2;
54
            CreateRoad(rjp, currentState, inputImage);
7 by fayl
reorganized code; added l-system road generator
55
            break;
56
        case 'F':
27 by fayl
L-system generator modified -- height awareness mainly
57
            currentState.drawLength = drawLength;
58
            CreateRoad(rjp, currentState, inputImage);
7 by fayl
reorganized code; added l-system road generator
59
            break;
60
        case '+':
61
            currentState.direction = RotateVectorByAngle(currentState.direction, -rotationAngle);
62
            break;
63
        case '-':
64
            currentState.direction = RotateVectorByAngle(currentState.direction,  rotationAngle);
65
            break;
66
        case 'R':
67
            currentState.direction = RotateVectorByAngle(currentState.direction, (rand() % (rotationAngle2 * 2 + 1) - rotationAngle2) );
68
            break;
69
        case '[':
70
            aStack.push_back(currentState);
71
            break;
72
        case ']':
73
            currentState = aStack.last();
74
            aStack.pop_back();
75
            break;
76
        }
77
    }
78
79
    return junctions;
80
}
81
//-----//
27 by fayl
L-system generator modified -- height awareness mainly
82
void LSystemGenerator::CreateRoad(RoadJunctionPoint *rjp, LSystemState &state, const QImage *map)
83
{
84
    int heightAngles[] = { -30, -22, -15, -8, 0, 8, 15, 22, 30 };
85
    //int heightAngles[] = { 0 };
86
    int num = 9;
87
88
    Road *r;
89
90
    Road *lowestSlopeRoad = NULL;
91
    int slope = INT_MAX;
92
    for (int i = 0; i < num; ++i)
93
    {
94
        QVector2D rotation = RotateVectorByAngle(state.direction, heightAngles[i]);
95
        QVector2D newPosition =
96
            Clamp(QVector2D(state.position.x() + state.drawLength * rotation.x(),
97
                            state.position.y() + state.drawLength * rotation.y()),
98
                  map->size());
99
        r = new Road(state.position, newPosition);
100
        if (ValidPoint(map, newPosition) && r->Valid(map))
101
        {
102
            int heightDiff = abs(qRed(map->pixel(state.position.toPoint())) - qRed(map->pixel(newPosition.toPoint())));
103
            if (heightDiff < slope)
104
            {
105
                slope = heightDiff;
106
                if (lowestSlopeRoad)
107
                    delete lowestSlopeRoad;
108
                lowestSlopeRoad = r;
109
            }
110
            else
111
            {
112
                delete r;
113
            }
114
        }
115
        else
116
            delete r;
117
118
    }
119
120
    if (lowestSlopeRoad)
121
    {
122
        rjp->AddRoad(lowestSlopeRoad);
123
        state.position = lowestSlopeRoad->End();
124
    }
125
}
126
//-----//
127
bool LSystemGenerator::JunctionExists(const QVector2D &v) const
128
{
129
    unsigned num = 0;
130
    float epsilon = 2.0f;
131
    RoadJunctionPoint *rjp = junctions.first();
132
    //for (Utils::Junctions::const_iterator iter = junctions.begin(); iter != junctions.end(); ++iter)
133
    {
134
        for (Utils::Roads::const_iterator iter = rjp->StartingRoads().begin(); iter != rjp->StartingRoads().end(); ++iter)
135
        {
136
            QVector2D p1 = (*iter)->Start();
137
            QVector2D p2 = (*iter)->End();
138
            if ((fabs(p1.x() - v.x()) < epsilon && fabs(p1.y() - v.y()) < epsilon) ||
139
                (fabs(p2.x() - v.x()) < epsilon && fabs(p2.y() - v.y()) < epsilon))
140
            {
141
                ++num;
142
            }
143
        }
144
    }
145
    return num > 5;
146
}
147
//-----//
148
void LSystemGenerator::FilterRoads()
149
{
150
151
}
152
//-----//
7 by fayl
reorganized code; added l-system road generator
153
QVector2D LSystemGenerator::RotateVectorByAngle(const QVector2D &vec, int angle)
154
{
155
    float tmpSin = sin((float)angle * M_PI / 180);
156
    float tmpCos = cos((float)angle * M_PI / 180);
157
    float tmpPosX = vec.x() * tmpCos - vec.y() * tmpSin;
158
    float tmpPosY = vec.x() * tmpSin + vec.y() * tmpCos;
159
    return QVector2D(tmpPosX, tmpPosY).normalized();
160
}
161
//-----//
27 by fayl
L-system generator modified -- height awareness mainly
162
QVector2D LSystemGenerator::Clamp(const QVector2D pt, const QSize &bounds) const
7 by fayl
reorganized code; added l-system road generator
163
{
9 by Michał Janiszewski
Qt-ify project, port QPoint based classes to QVector2D
164
	return QVector2D(qBound(0.0, pt.x(), (qreal)bounds.width()),
165
					 qBound(0.0, pt.y(), (qreal)bounds.height()));
7 by fayl
reorganized code; added l-system road generator
166
}
8 by fayl
3D rendering
167
//-----//
9 by Michał Janiszewski
Qt-ify project, port QPoint based classes to QVector2D
168
bool LSystemGenerator::ValidPoint(const QImage *i, const QVector2D &p) const
8 by fayl
3D rendering
169
{
27 by fayl
L-system generator modified -- height awareness mainly
170
    return i->rect().contains(p.toPoint()) &&
171
           qGray(i->pixel(p.toPoint())) > Utils::LEVEL_WATER
172
          ;//&& !JunctionExists(p);
173
8 by fayl
3D rendering
174
}