93 /* |
93 /* |
94 * Assuming we're currently viewing from a fixed camera, draw a backdrop into it. Currently this means drawing the grid. |
94 * Assuming we're currently viewing from a fixed camera, draw a backdrop into it. Currently this means drawing the grid. |
95 */ |
95 */ |
96 void Canvas::drawFixedCameraBackdrop() |
96 void Canvas::drawFixedCameraBackdrop() |
97 { |
97 { |
|
98 static const enum { Cartesian, Polar } gridType = Cartesian; |
|
99 |
98 // Find the top left corner of the grid |
100 // Find the top left corner of the grid |
99 Vertex topLeft = currentCamera().idealize(currentCamera().convert2dTo3d({0, 0})); |
101 Vertex topLeft = currentCamera().idealize(currentCamera().convert2dTo3d({0, 0})); |
100 Vertex bottomRight = currentCamera().idealize(currentCamera().convert2dTo3d({width(), height()})); |
102 Vertex bottomRight = currentCamera().idealize(currentCamera().convert2dTo3d({width(), height()})); |
101 qreal gridSize = grid()->coordinateSnap(); |
103 qreal gridSize = grid()->coordinateSnap(); |
102 qreal x0 = sign(topLeft.x()) * (fabs(topLeft.x()) - fmod(fabs(topLeft.x()), gridSize)); |
|
103 qreal y0 = sign(topLeft.y()) * (fabs(topLeft.y()) - fmod(fabs(topLeft.y()), gridSize)); |
|
104 glEnable(GL_LINE_STIPPLE); |
104 glEnable(GL_LINE_STIPPLE); |
105 glBegin(GL_LINES); |
105 glBegin(GL_LINES); |
106 |
106 |
107 static const auto prepareGridLine = [](qreal value) -> bool |
107 if (gridType == Cartesian) |
108 { |
108 { |
109 if (not isZero(value)) |
109 qreal x0 = sign(topLeft.x()) * (fabs(topLeft.x()) - fmod(fabs(topLeft.x()), gridSize)); |
110 { |
110 qreal y0 = sign(topLeft.y()) * (fabs(topLeft.y()) - fmod(fabs(topLeft.y()), gridSize)); |
111 if (isZero(fmod(value, 10.0))) |
111 |
112 glColor4f(0, 0, 0, 0.6); |
112 static const auto prepareGridLine = [](qreal value) -> bool |
|
113 { |
|
114 if (not isZero(value)) |
|
115 { |
|
116 if (isZero(fmod(value, 10.0))) |
|
117 glColor4f(0, 0, 0, 0.6); |
|
118 else |
|
119 glColor4f(0, 0, 0, 0.25); |
|
120 |
|
121 return true; |
|
122 } |
113 else |
123 else |
114 glColor4f(0, 0, 0, 0.25); |
124 { |
115 |
125 return false; |
116 return true; |
126 } |
117 } |
127 }; |
118 else |
128 |
119 { |
129 for (qreal x = x0; x < bottomRight.x(); x += gridSize) |
120 return false; |
130 { |
121 } |
131 if (prepareGridLine(x)) |
122 }; |
132 { |
123 |
133 glVertex(currentCamera().realize({x, -10000, 999})); |
124 for (qreal x = x0; x < bottomRight.x(); x += gridSize) |
134 glVertex(currentCamera().realize({x, 10000, 999})); |
125 { |
135 } |
126 if (prepareGridLine(x)) |
136 } |
127 { |
137 |
128 glVertex(currentCamera().realize({x, -10000, 999})); |
138 for (qreal y = y0; y < bottomRight.y(); y += gridSize) |
129 glVertex(currentCamera().realize({x, 10000, 999})); |
139 { |
130 } |
140 if (prepareGridLine(y)) |
131 } |
141 { |
132 |
142 glVertex(currentCamera().realize({-10000, y, 999})); |
133 for (qreal y = y0; y < bottomRight.y(); y += gridSize) |
143 glVertex(currentCamera().realize({10000, y, 999})); |
134 { |
144 } |
135 if (prepareGridLine(y)) |
145 } |
136 { |
146 } |
137 glVertex(currentCamera().realize({-10000, y, 999})); |
147 else |
138 glVertex(currentCamera().realize({10000, y, 999})); |
148 { |
|
149 const QPointF pole = grid()->pole(); |
|
150 const qreal size = grid()->coordinateSnap(); |
|
151 Vertex topLeft = currentCamera().idealize(currentCamera().convert2dTo3d({0, 0})); |
|
152 Vertex bottomRight = currentCamera().idealize(currentCamera().convert2dTo3d({width(), height()})); |
|
153 QPointF topLeft2d {topLeft.x(), topLeft.y()}; |
|
154 QPointF bottomLeft2d {topLeft.x(), bottomRight.y()}; |
|
155 QPointF bottomRight2d {bottomRight.x(), bottomRight.y()}; |
|
156 QPointF topRight2d {bottomRight.x(), topLeft.y()}; |
|
157 qreal smallestRadius = distanceFromPointToRectangle(pole, QRectF{topLeft2d, bottomRight2d}); |
|
158 qreal largestRadius = max(QLineF {topLeft2d, pole}.length(), |
|
159 QLineF {bottomLeft2d, pole}.length(), |
|
160 QLineF {bottomRight2d, pole}.length(), |
|
161 QLineF {topRight2d, pole}.length()); |
|
162 |
|
163 // Snap the radii to the grid. |
|
164 smallestRadius = round(smallestRadius / size) * size; |
|
165 largestRadius = round(largestRadius / size) * size; |
|
166 |
|
167 // Is the pole at (0, 0)? If so, then don't render the polar axes above the real ones. |
|
168 bool poleIsOrigin = isZero(pole.x()) and isZero(pole.y()); |
|
169 glColor4f(0, 0, 0, 0.25); |
|
170 |
|
171 // Render the axes |
|
172 for (int i = 0; i < grid()->polarDivisions() / 2; ++i) |
|
173 { |
|
174 qreal azimuth = (2.0 * pi) * i / grid()->polarDivisions(); |
|
175 |
|
176 if (not poleIsOrigin or not isZero(fmod(azimuth, pi / 4))) |
|
177 { |
|
178 QPointF extremum = {cos(azimuth) * 10000, sin(azimuth) * 10000}; |
|
179 QPointF A = pole + extremum; |
|
180 QPointF B = pole - extremum; |
|
181 glVertex(currentCamera().realize({A.x(), A.y(), 999})); |
|
182 glVertex(currentCamera().realize({B.x(), B.y(), 999})); |
|
183 } |
|
184 } |
|
185 |
|
186 for (qreal radius = smallestRadius; radius <= largestRadius; radius += size) |
|
187 { |
|
188 if (not isZero(radius)) |
|
189 { |
|
190 Vertex points[48]; |
|
191 |
|
192 for (int i = 0; i < grid()->polarDivisions(); ++i) |
|
193 { |
|
194 qreal azimuth = (2.0 * pi) * i / grid()->polarDivisions(); |
|
195 QPointF point = pole + QPointF {radius * cos(azimuth), radius * sin(azimuth)}; |
|
196 points[i] = currentCamera().realize({point.x(), point.y(), 999}); |
|
197 } |
|
198 |
|
199 for (int i = 0; i < grid()->polarDivisions(); ++i) |
|
200 { |
|
201 glVertex(points[i]); |
|
202 glVertex(ring(points, grid()->polarDivisions())[i + 1]); |
|
203 } |
|
204 } |
139 } |
205 } |
140 } |
206 } |
141 |
207 |
142 glEnd(); |
208 glEnd(); |
143 glDisable(GL_LINE_STIPPLE); |
209 glDisable(GL_LINE_STIPPLE); |