1313#include " planetgrid.h"
1414
1515#include < algorithm>
16+ #include < cassert>
1617#include < cmath>
18+ #include < iterator>
1719
1820#include < Eigen/Geometry>
1921#include < fmt/format.h>
@@ -38,7 +40,7 @@ namespace render = celestia::render;
3840
3941namespace
4042{
41- constexpr unsigned circleSubdivisions = 100 ;
43+ constexpr unsigned int circleSubdivisions = 100U ;
4244
4345void longLatLabel (const std::string& labelText,
4446 double longitude,
@@ -88,78 +90,128 @@ void longLatLabel(const std::string& labelText,
8890 Renderer::LabelVerticalAlignment::Bottom);
8991 }
9092}
91- } // namespace
9293
93- PlanetographicGrid::PlanetographicGrid (const Body& _body) :
94- body(_body)
94+ void
95+ latitudeLabel (std::string& buf,
96+ int latitude,
97+ PlanetographicGrid::NorthDirection northDirection)
9598{
96- setIAULongLatConvention ();
99+ buf.clear ();
100+ char ns = (latitude < 0 ) != (northDirection == PlanetographicGrid::NorthDirection::NorthNormal)
101+ ? ' N'
102+ : ' S' ;
103+
104+ fmt::format_to (std::back_inserter (buf), " {}{}" , std::abs (latitude), ns);
97105}
98106
99107void
100- PlanetographicGrid::render (render::ReferenceMarkRenderer* refMarkRenderer,
101- const Eigen::Vector3f& pos,
102- float discSizeInPixels,
103- double tdb,
104- const Matrices& m) const
108+ longitudeLabel (std::string& buf,
109+ int longitude,
110+ PlanetographicGrid::LongitudeConvention longitudeConvention)
105111{
106- Renderer& renderer = refMarkRenderer->renderer ();
112+ buf.clear ();
113+ auto it = std::back_inserter (buf);
114+ switch (longitudeConvention)
115+ {
116+ case PlanetographicGrid::LongitudeConvention::EastWest:
117+ if (longitude >= 0 )
118+ fmt::format_to (it, " {}E" , longitude);
119+ else
120+ fmt::format_to (it, " {}W" , -longitude);
121+ break ;
107122
108- // Compatibility
109- Eigen::Quaterniond q = math::YRot180<double > * body.getEclipticToBodyFixed (tdb);
123+ case PlanetographicGrid::LongitudeConvention::Eastward:
124+ fmt::format_to (it, " {}E" , longitude > 0 ? 360 - longitude : std::abs (longitude));
125+ break ;
126+
127+ case PlanetographicGrid::LongitudeConvention::Westward:
128+ fmt::format_to (it, " {}W" , longitude > 0 ? 360 - longitude : std::abs (longitude));
129+
130+ default :
131+ assert (0 );
132+ break ;
133+ }
134+ }
135+
136+ class RenderDetails
137+ {
138+ public:
139+ explicit RenderDetails (render::ReferenceMarkRenderer&,
140+ const Body&,
141+ const Eigen::Vector3f&,
142+ float ,
143+ double ,
144+ const Matrices&);
145+
146+ RenderDetails (const RenderDetails&) = delete ;
147+ RenderDetails& operator =(const RenderDetails&) = delete ;
148+
149+ void renderLatitude (int , std::string&, bool , PlanetographicGrid::NorthDirection) const ;
150+ void renderLongitude (int , std::string&, bool , PlanetographicGrid::LongitudeConvention) const ;
151+
152+ private:
153+ Eigen::Matrix4f modelView;
154+ Eigen::Matrix4f projection;
155+ Eigen::Quaterniond q;
156+ Eigen::Vector3d posd;
157+ Eigen::Vector3d viewRayOrigin;
158+ Eigen::Vector3d viewNormal;
159+ Eigen::Vector3f semiAxes;
160+ float offset;
161+ Renderer& renderer;
162+ render::PlanetGridRenderer& planetGridRenderer;
163+ };
164+
165+ RenderDetails::RenderDetails (render::ReferenceMarkRenderer& refMarkRenderer,
166+ const Body& body,
167+ const Eigen::Vector3f& pos,
168+ float discSizeInPixels,
169+ double tdb,
170+ const Matrices& m) :
171+ projection (*m.projection),
172+ q (math::YRot180<double > * body.getEclipticToBodyFixed(tdb)), // Celestia coordinates
173+ posd (pos.cast<double >()),
174+ semiAxes (body.getSemiAxes()),
175+ renderer (refMarkRenderer.renderer()),
176+ planetGridRenderer (refMarkRenderer.planetGridRenderer())
177+ {
110178 Eigen::Quaternionf qf = q.cast <float >();
111179
112180 // The grid can't be rendered exactly on the planet sphere, or
113181 // there will be z-fighting problems. Render it at a height above the
114182 // planet that will place it about one pixel away from the planet.
115183 float scale = (discSizeInPixels + 1 ) / discSizeInPixels;
116184 scale = std::max (scale, 1 .001f );
117- float offset = scale - 1 .0f ;
185+ offset = scale - 1 .0f ;
118186
119- Eigen::Vector3f semiAxes = body.getSemiAxes ();
120- Eigen::Vector3d posd = pos.cast <double >();
121- Eigen::Vector3d viewRayOrigin = q * -posd;
187+ viewRayOrigin = q * -posd;
122188
123189 // Calculate the view normal; this is used for placement of the long/lat
124190 // label text.
125- Eigen::Vector3f vn = renderer.getCameraOrientationf ().conjugate () * -Eigen::Vector3f::UnitZ ();
126- Eigen::Vector3d viewNormal = vn.cast <double >();
127-
128- Renderer::PipelineState ps;
129- ps.depthMask = true ;
130- ps.depthTest = true ;
131- ps.smoothLines = true ;
132- renderer.setPipelineState (ps);
191+ Eigen::Vector3f vn = refMarkRenderer.renderer ().getCameraOrientationf ().conjugate () * -Eigen::Vector3f::UnitZ ();
192+ viewNormal = vn.cast <double >();
133193
134194 Eigen::Affine3f transform = Eigen::Translation3f (pos) * qf.conjugate () * Eigen::Scaling (scale * semiAxes);
135- Eigen::Matrix4f projection = *m.projection ;
136- Eigen::Matrix4f modelView = *m.modelview * transform.matrix ();
137-
138- // Only show the coordinate labels if the body is sufficiently large on screen
139- bool showCoordinateLabels = false ;
140- if (discSizeInPixels > 50 )
141- showCoordinateLabels = true ;
142-
143- float latitudeStep = minLatitudeStep;
144- float longitudeStep = minLongitudeStep;
145- if (discSizeInPixels < 200 )
146- {
147- latitudeStep = 30 .0f ;
148- longitudeStep = 30 .0f ;
149- }
195+ modelView = *m.modelview * transform.matrix ();
196+ }
150197
151- render::PlanetGridRenderer& planetGridRenderer = refMarkRenderer->planetGridRenderer ();
198+ void
199+ RenderDetails::renderLatitude (int latitudeStep,
200+ std::string& buf,
201+ bool showCoordinateLabels,
202+ PlanetographicGrid::NorthDirection northDirection) const
203+ {
152204 render::LineRenderer& latitudeRenderer = planetGridRenderer.latitudeRenderer ();
153205 render::LineRenderer& equatorRenderer = planetGridRenderer.equatorRenderer ();
154- render::LineRenderer& longitudeRenderer = planetGridRenderer.longitudeRenderer ();
155206
156- for (float latitude = -90 . 0f + latitudeStep; latitude < 90 . 0f ; latitude += latitudeStep)
207+ for (int latitude = -90 + latitudeStep; latitude < 90 ; latitude += latitudeStep)
157208 {
158- float phi = math::degToRad (latitude);
159- float r = std::cos (phi);
209+ float sphi;
210+ float r;
211+ math::sincos (math::degToRad (static_cast <float >(latitude)), sphi, r);
160212
161- Eigen::Matrix4f mvcur = modelView * math::translate (0 .0f , std::sin (phi) , 0 .0f ) * math::scale (r);
162- if (latitude == 0 . 0f )
213+ Eigen::Matrix4f mvcur = modelView * math::translate (0 .0f , sphi , 0 .0f ) * math::scale (r);
214+ if (latitude == 0 )
163215 {
164216 latitudeRenderer.finish ();
165217 equatorRenderer.render ({&projection, &mvcur},
@@ -174,84 +226,81 @@ PlanetographicGrid::render(render::ReferenceMarkRenderer* refMarkRenderer,
174226 circleSubdivisions+1 );
175227 }
176228
177- if (showCoordinateLabels)
229+ if (showCoordinateLabels && latitude != 0 && std::abs (latitude) < 90 )
178230 {
179- if (latitude != 0 .0f && abs (latitude) < 90 .0f )
180- {
181- char ns;
182- if (latitude < 0 .0f )
183- ns = northDirection == NorthDirection::NorthNormal ? ' S' : ' N' ;
184- else
185- ns = northDirection == NorthDirection::NorthNormal ? ' N' : ' S' ;
186-
187- auto buf = fmt::format (" {}{}" , static_cast <int >(std::fabs (latitude)), ns);
188- longLatLabel (buf, 0.0 , latitude, viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
189- longLatLabel (buf, 180.0 , latitude, viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
190- }
231+ latitudeLabel (buf, latitude, northDirection);
232+ longLatLabel (buf, 0.0 , latitude, viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
233+ longLatLabel (buf, 180.0 , latitude, viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
191234 }
192235 }
193236 latitudeRenderer.finish ();
194237 equatorRenderer.finish ();
238+ }
195239
196- for (float longitude = 0 .0f ; longitude <= 180 .0f ; longitude += longitudeStep)
240+ void
241+ RenderDetails::renderLongitude (int longitudeStep,
242+ std::string& buf,
243+ bool showCoordinateLabels,
244+ PlanetographicGrid::LongitudeConvention longitudeConvention) const
245+ {
246+ render::LineRenderer& longitudeRenderer = planetGridRenderer.longitudeRenderer ();
247+ for (int longitude = 0 ; longitude <= 180 ; longitude += longitudeStep)
197248 {
198- Eigen::Matrix4f mvcur = modelView * math::rotate (Eigen::AngleAxisf (math::degToRad (longitude), Eigen::Vector3f::UnitY ()));
249+ Eigen::Matrix4f mvcur = modelView * math::rotate (Eigen::AngleAxisf (math::degToRad (static_cast <float >(longitude)),
250+ Eigen::Vector3f::UnitY ()));
199251
200252 longitudeRenderer.render ({&projection, &mvcur},
201253 Renderer::PlanetographicGridColor,
202- circleSubdivisions+ 1 );
254+ circleSubdivisions + 1 );
203255
204- if (showCoordinateLabels)
256+ if (!showCoordinateLabels)
257+ continue ;
258+
259+ longitudeLabel (buf, longitude, longitudeConvention);
260+ longLatLabel (buf, longitude, 0.0 , viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
261+ if (longitude > 0 && longitude < 180 )
205262 {
206- int showLongitude = 0 ;
207- char ew = ' E' ;
208-
209- switch (longitudeConvention)
210- {
211- case LongitudeConvention::EastWest:
212- ew = ' E' ;
213- showLongitude = (int ) longitude;
214- break ;
215- case LongitudeConvention::Eastward:
216- if (longitude > 0 .0f )
217- showLongitude = 360 - static_cast <int >(longitude);
218- ew = ' E' ;
219- break ;
220- case LongitudeConvention::Westward:
221- if (longitude > 0 .0f )
222- showLongitude = 360 - static_cast <int >(longitude);
223- ew = ' W' ;
224- break ;
225- }
226-
227- auto buf = fmt::format (" {}{}" , showLongitude, ew);
228- longLatLabel (buf, longitude, 0.0 , viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
229- if (longitude > 0 .0f && longitude < 180 .0f )
230- {
231- showLongitude = (int ) longitude;
232- switch (longitudeConvention)
233- {
234- case LongitudeConvention::EastWest:
235- ew = ' W' ;
236- showLongitude = static_cast <int >(longitude);
237- break ;
238- case LongitudeConvention::Eastward:
239- showLongitude = static_cast <int >(longitude);
240- ew = ' E' ;
241- break ;
242- case LongitudeConvention::Westward:
243- showLongitude = static_cast <int >(longitude);
244- ew = ' W' ;
245- break ;
246- }
247-
248- buf = fmt::format (" {}{}" , showLongitude, ew);
249- longLatLabel (buf, -longitude, 0.0 , viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
250- }
263+ longitudeLabel (buf, -longitude, longitudeConvention);
264+ longLatLabel (buf, -longitude, 0.0 , viewRayOrigin, viewNormal, posd, q, semiAxes, offset, renderer);
251265 }
252266 }
267+
253268 longitudeRenderer.finish ();
269+ }
270+
271+ } // namespace
272+
273+ PlanetographicGrid::PlanetographicGrid (const Body& _body) :
274+ body(_body)
275+ {
276+ setIAULongLatConvention ();
277+ }
278+
279+ void
280+ PlanetographicGrid::render (render::ReferenceMarkRenderer* refMarkRenderer,
281+ const Eigen::Vector3f& pos,
282+ float discSizeInPixels,
283+ double tdb,
284+ const Matrices& m) const
285+ {
286+ RenderDetails renderDetails (*refMarkRenderer, body, pos, discSizeInPixels, tdb, m);
287+
288+ Renderer& renderer = refMarkRenderer->renderer ();
289+
290+ Renderer::PipelineState ps;
291+ ps.depthMask = true ;
292+ ps.depthTest = true ;
293+ ps.smoothLines = true ;
294+ renderer.setPipelineState (ps);
295+
296+ // Only show the coordinate labels if the body is sufficiently large on screen
297+ bool showCoordinateLabels = discSizeInPixels > 50 ;
298+
299+ int stepSize = discSizeInPixels < 200 ? 30 : 10 ;
300+ std::string buf;
254301
302+ renderDetails.renderLatitude (stepSize, buf, showCoordinateLabels, northDirection);
303+ renderDetails.renderLongitude (stepSize, buf, showCoordinateLabels, longitudeConvention);
255304}
256305
257306float
0 commit comments