Changeset 5105 for geovis/trunk
- Timestamp:
- Mar 9, 2015, 12:02:47 AM (10 years ago)
- Location:
- geovis/trunk
- Files:
-
- 2 added
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
geovis/trunk/Makefile.in
r4635 r5105 121 121 SERVER_SRCS = \ 122 122 CmdProc.cpp \ 123 ColorMap.cpp \ 123 124 FileUtil.cpp \ 124 125 PPMWriter.cpp \ … … 188 189 189 190 CmdProc.o: CmdProc.h 191 ColorMap.o: ColorMap.h 190 192 CommandQueue.o: CommandQueue.h Trace.h 191 193 md5.o: md5.h -
geovis/trunk/RenderServer.h
r4957 r5105 21 21 class Stats; 22 22 23 #define GEOVIS_VERSION_STRING "0. 6.1"23 #define GEOVIS_VERSION_STRING "0.7.0" 24 24 25 25 #define MSECS_ELAPSED(t1, t2) \ -
geovis/trunk/Renderer.cpp
r5026 r5105 80 80 81 81 #include "Renderer.h" 82 #include "ColorMap.h" 82 83 #if 0 83 84 #include "SingleWindow.h" … … 179 180 if (!_colorMaps.empty()) 180 181 return; 181 182 #if 0 182 183 osg::TransferFunction1D *defaultColorMap = new osg::TransferFunction1D; 183 184 defaultColorMap->allocate(256); … … 195 196 defaultGrayColorMap->updateImage(); 196 197 addColorMap("grayDefault", defaultGrayColorMap); 198 #endif 199 } 200 201 void Renderer::saveCLRFile(const std::string& path, osg::TransferFunction1D *xfer) 202 { 203 std::ofstream out(path.c_str()); 204 float value; 205 unsigned int r, g, b, a; 206 for (osg::TransferFunction1D::ColorMap::const_iterator itr = xfer->getColorMap().begin(); 207 itr != xfer->getColorMap().end(); ++itr) { 208 value = itr->first; 209 r = (unsigned int)(255.0 * itr->second.r()); 210 g = (unsigned int)(255.0 * itr->second.g()); 211 b = (unsigned int)(255.0 * itr->second.b()); 212 a = (unsigned int)(255.0 * itr->second.a()); 213 out << value << " " << r << " " << g << " " << b << " " << a << std::endl; 214 } 215 } 216 217 void Renderer::getColorMapRange(const ColorMapId& id, float *min, float *max) const 218 { 219 ColorMapHashmap::const_iterator itr = _colorMaps.find(id); 220 if (itr == _colorMaps.end()) { 221 ERROR("Unknown ColorMap %s", id.c_str()); 222 return; 223 } 224 225 *min = itr->second->getMinimum(); 226 *max = itr->second->getMaximum(); 227 } 228 229 std::string Renderer::getColorMapFilePath(const ColorMapId& id) const 230 { 231 std::ostringstream path; 232 path << "/tmp/" << id << "_" << getpid() << ".clr"; 233 return path.str(); 197 234 } 198 235 … … 200 237 { 201 238 _colorMaps[id] = xfer; 239 saveCLRFile(getColorMapFilePath(id), xfer); 202 240 } 203 241 … … 253 291 do { 254 292 itr->second->allocate(numEntries); 255 itr->second->updateImage();256 293 } while (doAll && ++itr != _colorMaps.end()); 294 } 295 296 bool 297 Renderer::renderColorMap(const ColorMapId& id, int width, int height, 298 osg::Image *imgData, 299 bool opaque, float bgColor[3], 300 bool bgr, int bytesPerPixel) const 301 { 302 ColorMapHashmap::const_iterator itr = _colorMaps.find(id); 303 if (itr == _colorMaps.end()) { 304 ERROR("Unknown ColorMap %s", id.c_str()); 305 return false; 306 } 307 308 ColorMap::renderColorMap(itr->second, width, height, imgData, opaque, bgColor, bgr, bytesPerPixel); 309 return true; 257 310 } 258 311 … … 671 724 672 725 void Renderer::resetMap(osgEarth::MapOptions::CoordinateSystemType type, 726 const osg::Vec4f& bgColor, 673 727 const char *profile, 674 728 double bounds[4]) … … 724 778 #endif 725 779 // Set background layer color 726 mpOpt.color() = osg::Vec4(1, 1, 1, 1);780 mpOpt.color() = bgColor; 727 781 //mpOpt.minLOD() = 1; 728 782 // Sets shader uniform for terrain renderer (config var defaults to false) … … 843 897 } 844 898 899 void Renderer::setTerrainColor(const osg::Vec4f& color) 900 { 901 902 _needsRedraw = true; 903 } 904 845 905 void Renderer::setTerrainLighting(bool state) 846 906 { … … 1153 1213 bool enableCache, 1154 1214 bool makeShared, 1155 bool visible) 1215 bool visible, 1216 int minLOD, int maxLOD) 1156 1217 { 1157 1218 if (!_map.valid()) { … … 1177 1238 layerOpts.visible() = false; 1178 1239 } 1240 layerOpts.minLevel() = minLOD; 1241 layerOpts.maxLevel() = maxLOD; 1179 1242 osg::ref_ptr<osgEarth::ImageLayer> layer = new osgEarth::ImageLayer(layerOpts); 1180 1243 _map->addImageLayer(layer.get()); … … 1273 1336 } 1274 1337 1338 void Renderer::setImageLayerVisibleRange(const char *name, float min, float max) 1339 { 1340 if (!_map.valid()) { 1341 ERROR("No map"); 1342 return; 1343 } 1344 osgEarth::ImageLayer *layer = _map->getImageLayerByName(name); 1345 if (layer != NULL) { 1346 layer->setMinVisibleRange(min); 1347 layer->setMaxVisibleRange(max); 1348 _needsRedraw = true; 1349 } else { 1350 TRACE("Image layer not found: %s", name); 1351 } 1352 } 1353 1275 1354 void Renderer::setImageLayerVisibility(const char *name, bool state) 1276 1355 { … … 1291 1370 osgEarth::TileSourceOptions& opts, 1292 1371 bool enableCache, 1293 bool visible) 1372 bool visible, 1373 int minLOD, int maxLOD) 1294 1374 { 1295 1375 if (!_map.valid()) { … … 1299 1379 TRACE("layer: %s", name); 1300 1380 if (!opts.tileSize().isSet()) { 1301 opts.tileSize() = 1 5;1381 opts.tileSize() = 17; 1302 1382 } 1303 1383 osgEarth::ElevationLayerOptions layerOpts(name, opts); … … 1308 1388 layerOpts.visible() = false; 1309 1389 } 1390 layerOpts.minLevel() = minLOD; 1391 layerOpts.maxLevel() = maxLOD; 1310 1392 // XXX: GDAL does not report vertical datum, it should be specified here 1311 1393 // Common options: geodetic (default), egm96, egm84, egm2008 … … 1602 1684 { 1603 1685 if (!_placeNodes.valid()) { 1604 ERROR("No place nodes");1686 TRACE("No place nodes"); 1605 1687 return; 1606 1688 } … … 1649 1731 { 1650 1732 if (!_placeNodes.valid()) { 1651 ERROR("No place nodes");1733 TRACE("No place nodes"); 1652 1734 return; 1653 1735 } … … 1746 1828 #endif 1747 1829 } 1748 1830 #if 0 1831 void Renderer::setModelLayerVisibleRange(const char *name, float min, float max) 1832 { 1833 if (!_map.valid()) { 1834 ERROR("No map"); 1835 return; 1836 } 1837 osgEarth::ModelLayer *layer = _map->getModelLayerByName(name); 1838 if (layer != NULL) { 1839 layer->minVisibleRange(min); 1840 layer->maxVisibleRange(max); 1841 _needsRedraw = true; 1842 } else { 1843 TRACE("Model layer not found: %s", name); 1844 } 1845 } 1846 #endif 1749 1847 void Renderer::setModelLayerVisibility(const char *name, bool state) 1750 1848 { … … 2136 2234 _lastFrameTime = osg::Timer::instance()->delta_s(_startFrameTime, endFrameTick); 2137 2235 if (_lastFrameTime > _minFrameTime) { 2138 ERROR("BROKE FRAME by %.2f msec", (_lastFrameTime - _minFrameTime)*1000.0f);2236 TRACE("BROKE FRAME by %.2f msec", (_lastFrameTime - _minFrameTime)*1000.0f); 2139 2237 } else { 2140 2238 TRACE("Frame time: %.2f msec", _lastFrameTime*1000.0f); -
geovis/trunk/Renderer.h
r5026 r5105 168 168 void setColorMapNumberOfTableEntries(const ColorMapId& id, int numEntries); 169 169 170 bool renderColorMap(const ColorMapId& id, int width, int height, 171 osg::Image *imgData, 172 bool opaque, float bgColor[3], 173 bool bgr = false, 174 int bytesPerPixel = 3) const; 175 176 void getColorMapRange(const ColorMapId& id, float *min, float *max) const; 177 178 std::string getColorMapFilePath(const ColorMapId& id) const; 179 180 void saveCLRFile(const std::string& path, osg::TransferFunction1D *xfer); 181 170 182 // Scene 171 183 … … 173 185 174 186 void resetMap(osgEarth::MapOptions::CoordinateSystemType type, 187 const osg::Vec4f& bgColor = osg::Vec4f(1,1,1,1), 175 188 const char *profile = NULL, 176 189 double bounds[4] = NULL); … … 197 210 198 211 void setLighting(bool state); 212 213 void setTerrainColor(const osg::Vec4f& color); 214 215 void setTerrainEdges(bool state) {} 216 217 void setTerrainLineColor(const osg::Vec4f& color) {} 218 219 void setTerrainLineWidth(float width) {} 199 220 200 221 void setTerrainLighting(bool state); … … 230 251 bool addImageLayer(const char *name, osgEarth::TileSourceOptions& opts, 231 252 bool enableCache = true, bool makeShared = false, 232 bool visible = true); 253 bool visible = true, 254 int minLOD = 0, int maxLOD = 23); 233 255 234 256 void removeImageLayer(const char *name); 235 257 236 258 void moveImageLayer(const char *name, unsigned int pos); 259 260 void setImageLayerVisibleRange(const char *name, float min, float max); 261 262 void setImageLayerLODRange(const char *name, int min, int max); 237 263 238 264 void setImageLayerOpacity(const char *name, double opacity); … … 265 291 266 292 void addElevationLayer(const char *name, osgEarth::TileSourceOptions& opts, 267 bool enableCache = true, bool visible = true); 293 bool enableCache = true, bool visible = true, 294 int minLOD = 0, int maxLOD = 23); 268 295 269 296 void removeElevationLayer(const char *name); 270 297 271 298 void moveElevationLayer(const char *name, unsigned int pos); 299 300 void setElevationLayerVisibleRange(const char *name, float min, float max); 272 301 273 302 void setElevationLayerVisibility(const char *name, bool state); … … 298 327 299 328 void moveModelLayer(const char *name, unsigned int pos); 329 330 //void setModelLayerVisibleRange(const char *name, float min, float max); 300 331 301 332 void setModelLayerOpacity(const char *name, double opacity); -
geovis/trunk/RendererCmd.cpp
r5026 r5105 23 23 #include <osgDB/FileNameUtils> 24 24 25 #include <osgEarth/Version> 25 26 #include <osgEarth/Registry> 26 27 #include <osgEarthFeatures/FeatureModelSource> … … 32 33 #include <osgEarthSymbology/RenderSymbol> 33 34 35 #if OSGEARTH_MIN_VERSION_REQUIRED(2, 5, 1) 36 #include <osgEarthDrivers/osg/ColorRampOptions> 37 #endif 34 38 #include <osgEarthDrivers/debug/DebugOptions> 35 39 #include <osgEarthDrivers/gdal/GDALOptions> … … 528 532 { 529 533 const char *name = Tcl_GetString(objv[2]); 530 int cmapc , omapc;534 int cmapc; 531 535 Tcl_Obj **cmapv = NULL; 532 Tcl_Obj **omapv = NULL;533 536 534 537 if (Tcl_ListObjGetElements(interp, objv[3], &cmapc, &cmapv) != TCL_OK) { 535 538 return TCL_ERROR; 536 539 } 537 if ((cmapc % 4) != 0) {540 if ((cmapc % 5) != 0) { 538 541 Tcl_AppendResult(interp, "wrong # elements in colormap: should be ", 539 "{ value r g b ... }", (char*)NULL);542 "{ value r g b a... }", (char*)NULL); 540 543 return TCL_ERROR; 541 544 } … … 544 547 colorMap->allocate(256); 545 548 546 for (int i = 0; i < cmapc; i += 4) {547 double val[ 4];548 for (int j = 0; j < 4; j++) {549 for (int i = 0; i < cmapc; i += 5) { 550 double val[5]; 551 for (int j = 0; j < 5; j++) { 549 552 if (Tcl_GetDoubleFromObj(interp, cmapv[i+j], &val[j]) != TCL_OK) { 550 553 delete colorMap; 551 554 return TCL_ERROR; 552 555 } 553 if ((val[j] < 0.0) || (val[j] > 1.0)) { 556 // Need to permit un-normalized values 557 if (j > 0 && (val[j] < 0.0 || val[j] > 1.0)) { 554 558 Tcl_AppendResult(interp, "bad colormap value \"", 555 559 Tcl_GetString(cmapv[i+j]), … … 559 563 } 560 564 } 561 colorMap->setColor(val[0], osg::Vec4f(val[1], val[2], val[3], 1.0), false);565 colorMap->setColor(val[0], osg::Vec4f(val[1], val[2], val[3], val[4]), false); 562 566 } 563 567 564 568 colorMap->updateImage(); 565 569 566 if (Tcl_ListObjGetElements(interp, objv[4], &omapc, &omapv) != TCL_OK) {567 delete colorMap;568 return TCL_ERROR;569 }570 if ((omapc % 2) != 0) {571 Tcl_AppendResult(interp, "wrong # elements in opacitymap: should be ",572 "{ value alpha ... }", (char*)NULL);573 delete colorMap;574 return TCL_ERROR;575 }576 for (int i = 0; i < omapc; i += 2) {577 double val[2];578 for (int j = 0; j < 2; j++) {579 if (Tcl_GetDoubleFromObj(interp, omapv[i+j], &val[j]) != TCL_OK) {580 delete colorMap;581 return TCL_ERROR;582 }583 if ((val[j] < 0.0) || (val[j] > 1.0)) {584 Tcl_AppendResult(interp, "bad opacitymap value \"",585 Tcl_GetString(omapv[i+j]),586 "\": should be in the range [0,1]", (char*)NULL);587 delete colorMap;588 return TCL_ERROR;589 }590 }591 #if 0592 ColorMap::OpacityControlPoint ocp;593 ocp.value = val[0];594 ocp.alpha = val[1];595 colorMap->addOpacityControlPoint(ocp);596 #endif597 }598 599 //colorMap->build();600 570 g_renderer->addColorMap(name, colorMap); 601 571 return TCL_OK; … … 646 616 647 617 static CmdSpec colorMapOps[] = { 648 {"add", 1, ColorMapAddOp, 5, 5, "colorMapName colormap alphamap"},649 {"define", 3, ColorMapAddOp, 5, 5, "colorMapName colormap alphamap"},618 {"add", 1, ColorMapAddOp, 4, 4, "colorMapName colormap"}, 619 {"define", 3, ColorMapAddOp, 4, 4, "colorMapName colormap"}, 650 620 {"delete", 3, ColorMapDeleteOp, 2, 3, "?colorMapName?"}, 651 621 {"res", 1, ColorMapNumTableEntriesOp, 3, 4, "numTableEntries ?colorMapName?"} … … 767 737 } 768 738 return (*proc) (clientData, interp, objc, objv); 739 } 740 741 static int 742 LegendCmd(ClientData clientData, Tcl_Interp *interp, int objc, 743 Tcl_Obj *const *objv) 744 { 745 if (objc != 4) { 746 Tcl_AppendResult(interp, "wrong # args: should be \"", 747 Tcl_GetString(objv[0]), " colormapName width height\"", (char*)NULL); 748 return TCL_ERROR; 749 } 750 const char *colorMapName = Tcl_GetString(objv[1]); 751 752 int width, height; 753 if (Tcl_GetIntFromObj(interp, objv[2], &width) != TCL_OK || 754 Tcl_GetIntFromObj(interp, objv[3], &height) != TCL_OK) { 755 return TCL_ERROR; 756 } 757 758 bool opaque = true; 759 float bgColor[3]; 760 memset(bgColor, 0, sizeof(float)*3); 761 osg::ref_ptr<osg::Image> imgData = new osg::Image(); 762 763 #if defined(RENDER_TARGA) || defined(DEBUG) 764 if (!g_renderer->renderColorMap(colorMapName, width, height, imgData, opaque, 765 bgColor, true)) { 766 Tcl_AppendResult(interp, "Color map \"", 767 colorMapName, "\" was not found", (char*)NULL); 768 return TCL_ERROR; 769 } 770 #else 771 if (!g_renderer->renderColorMap(colorMapName, width, height, imgData, opaque, 772 bgColor)) { 773 Tcl_AppendResult(interp, "Color map \"", 774 colorMapName, "\" was not found", (char*)NULL); 775 return TCL_ERROR; 776 } 777 #endif 778 779 #ifdef DEBUG 780 # ifdef RENDER_TARGA 781 writeTGAFile("/tmp/legend.tga", imgData->data(), width, height, 782 TARGA_BYTES_PER_PIXEL); 783 # else 784 writeTGAFile("/tmp/legend.tga", imgData->data(), width, height, 785 TARGA_BYTES_PER_PIXEL, true); 786 # endif 787 #else 788 char cmd[256]; 789 float min, max; 790 g_renderer->getColorMapRange(colorMapName, &min, &max); 791 snprintf(cmd, sizeof(cmd), "nv>legend {%s} %g %g", colorMapName, min, max); 792 793 # ifdef USE_THREADS 794 # ifdef RENDER_TARGA 795 queueTGA(g_outQueue, cmd, imgData->data(), width, height, 796 TARGA_BYTES_PER_PIXEL); 797 # else 798 queuePPM(g_outQueue, cmd, imgData->data(), width, height); 799 # endif 800 # else 801 # ifdef RENDER_TARGA 802 writeTGA(g_fdOut, cmd, imgData->data(), width, height, 803 TARGA_BYTES_PER_PIXEL); 804 # else 805 writePPM(g_fdOut, cmd, imgData->data(), width, height); 806 # endif 807 # endif // USE_THREADS 808 #endif // DEBUG 809 810 return TCL_OK; 769 811 } 770 812 … … 947 989 Tcl_Obj *const *objv) 948 990 { 949 char *type = Tcl_GetString(objv[3]); 991 char *name = Tcl_GetString(objv[3]); 992 char *type = Tcl_GetString(objv[4]); 950 993 if (type[0] == 'i' && strcmp(type, "image") == 0) { 951 994 bool ret; 952 char *name; 953 char *driver = Tcl_GetString(objv[4]); 995 char *driver = Tcl_GetString(objv[5]); 954 996 std::string url; 955 997 if (objc > 6) { 956 char *urlIn = Tcl_GetString(objv[ 5]);998 char *urlIn = Tcl_GetString(objv[6]); 957 999 url = g_renderer->getCanonicalPath(std::string(urlIn)); 958 1000 if (url.empty()) { … … 964 1006 bool cache = true; 965 1007 if (objc > 7) { 966 if (GetBooleanFromObj(interp, objv[ 6], &cache) != TCL_OK) {1008 if (GetBooleanFromObj(interp, objv[7], &cache) != TCL_OK) { 967 1009 return TCL_ERROR; 968 1010 } 969 1011 } 970 if (driver[0] == 'd' && strcmp(driver, "debug") == 0) { 1012 bool shared = false; 1013 bool visible = true; 1014 int minLOD = 0; 1015 int maxLOD = 23; 1016 float minRange = 0.f; 1017 float maxRange = FLT_MAX; 1018 #if OSGEARTH_MIN_VERSION_REQUIRED(2, 5, 1) 1019 if (driver[0] == 'c' && strcmp(driver, "colorramp") == 0) { 1020 osgEarth::Drivers::ColorRampOptions colorRampOpts; 1021 osgEarth::Drivers::GDALOptions opts; 1022 opts.url() = url; 1023 char *profile = Tcl_GetString(objv[8]); 1024 char *colormap = Tcl_GetString(objv[9]); 1025 osgEarth::ElevationLayerOptions elevOpts(name, opts); 1026 if (!cache) { 1027 elevOpts.cachePolicy() = osgEarth::CachePolicy(osgEarth::CachePolicy::USAGE_NO_CACHE); 1028 } 1029 if (profile != NULL) { 1030 //elevOpts.driver()->profile()->srsString() = "epsg:4326"; 1031 elevOpts.driver()->profile() = osgEarth::ProfileOptions(profile); 1032 } 1033 colorRampOpts.elevationLayer() = elevOpts; 1034 colorRampOpts.ramp() = g_renderer->getColorMapFilePath(colormap); 1035 ret = g_renderer->addImageLayer(name, colorRampOpts, cache, shared, visible, minLOD, maxLOD); 1036 } else 1037 #endif 1038 if (driver[0] == 'd' && strcmp(driver, "debug") == 0) { 971 1039 osgEarth::Drivers::DebugOptions opts; 972 name = Tcl_GetString(objv[5]); 973 ret = g_renderer->addImageLayer(name, opts, cache); 1040 ret = g_renderer->addImageLayer(name, opts, cache, shared, visible, minLOD, maxLOD); 974 1041 } else if (driver[0] == 'g' && strcmp(driver, "gdal") == 0) { 975 1042 osgEarth::Drivers::GDALOptions opts; 976 1043 opts.url() = url; 977 name = Tcl_GetString(objv[7]);978 ret = g_renderer->addImageLayer(name, opts, cache);1044 ret = g_renderer->addImageLayer(name, opts, cache, shared, visible, minLOD, maxLOD); 1045 g_renderer->setImageLayerVisibleRange(name, minRange, maxRange); 979 1046 } else if (driver[0] == 't' && strcmp(driver, "tms") == 0) { 980 1047 osgEarth::Drivers::TMSOptions opts; 981 //char *tmsType = Tcl_GetString(objv[ 5]);982 //char *format = Tcl_GetString(objv[ 6]);1048 //char *tmsType = Tcl_GetString(objv[8]); 1049 //char *format = Tcl_GetString(objv[9]); 983 1050 opts.url() = url; 984 1051 //opts.tmsType() = tmsType; 985 1052 //opts.format() = format; 986 name = Tcl_GetString(objv[7]);987 ret = g_renderer->addImageLayer(name, opts, cache);1053 ret = g_renderer->addImageLayer(name, opts, cache, shared, visible, minLOD, maxLOD); 1054 g_renderer->setImageLayerVisibleRange(name, minRange, maxRange); 988 1055 } else if (driver[0] == 'w' && strcmp(driver, "wms") == 0) { 989 1056 osgEarth::Drivers::WMSOptions opts; 990 char *wmsLayers = Tcl_GetString(objv[ 7]);991 char *format = Tcl_GetString(objv[ 8]);1057 char *wmsLayers = Tcl_GetString(objv[8]); 1058 char *format = Tcl_GetString(objv[9]); 992 1059 bool transparent; 993 if (GetBooleanFromObj(interp, objv[ 9], &transparent) != TCL_OK) {1060 if (GetBooleanFromObj(interp, objv[10], &transparent) != TCL_OK) { 994 1061 return TCL_ERROR; 995 1062 } … … 999 1066 opts.transparent() = transparent; 1000 1067 1001 name = Tcl_GetString(objv[10]);1002 ret = g_renderer->addImageLayer(name, opts, cache);1068 ret = g_renderer->addImageLayer(name, opts, cache, shared, visible, minLOD, maxLOD); 1069 g_renderer->setImageLayerVisibleRange(name, minRange, maxRange); 1003 1070 } else if (driver[0] == 'x' && strcmp(driver, "xyz") == 0) { 1004 1071 osgEarth::Drivers::XYZOptions opts; … … 1007 1074 //bool invertY = false; 1008 1075 //opts.invertY() = invertY; 1009 //opts.format() = Tcl_GetString(objv[ 6]);1010 name = Tcl_GetString(objv[7]);1011 ret = g_renderer->addImageLayer(name, opts, cache);1076 //opts.format() = Tcl_GetString(objv[8]); 1077 ret = g_renderer->addImageLayer(name, opts, cache, shared, visible, minLOD, maxLOD); 1078 g_renderer->setImageLayerVisibleRange(name, minRange, maxRange); 1012 1079 } else { 1013 1080 Tcl_AppendResult(interp, "unknown image driver \"", driver, … … 1020 1087 } 1021 1088 } else if (type[0] == 'e' && strcmp(type, "elevation") == 0) { 1022 char *driver = Tcl_GetString(objv[4]); 1089 char *driver = Tcl_GetString(objv[5]); 1090 char *urlIn = Tcl_GetString(objv[6]); 1091 std::string url = g_renderer->getCanonicalPath(std::string(urlIn)); 1092 if (url.empty()) { 1093 Tcl_AppendResult(interp, "file not found: \"", 1094 urlIn, "\"", (char*)NULL); 1095 return TCL_ERROR; 1096 } 1097 bool cache = true; 1098 bool visible = true; 1099 int minLOD = 0; 1100 int maxLOD = 23; 1101 if (driver[0] == 'g' && strcmp(driver, "gdal") == 0) { 1102 osgEarth::Drivers::GDALOptions opts; 1103 opts.url() = url; 1104 g_renderer->addElevationLayer(name, opts, cache, visible, minLOD, maxLOD); 1105 } else if (driver[0] == 't' && strcmp(driver, "tms") == 0) { 1106 osgEarth::Drivers::TMSOptions opts; 1107 //char *tmsType = Tcl_GetString(objv[7]); 1108 //char *format = Tcl_GetString(objv[8]); 1109 opts.url() = url; 1110 //opts.tmsType() = tmsType; 1111 //opts.format() = format; 1112 g_renderer->addElevationLayer(name, opts, cache, visible, minLOD, maxLOD); 1113 } else { 1114 Tcl_AppendResult(interp, "unknown elevation driver \"", driver, 1115 "\": should be 'gdal' or 'tms'", (char*)NULL); 1116 return TCL_ERROR; 1117 } 1118 } else if (type[0] == 'p' && strcmp(type, "point") == 0) { 1119 osgEarth::Drivers::OGRFeatureOptions opts; 1023 1120 char *urlIn = Tcl_GetString(objv[5]); 1024 1121 std::string url = g_renderer->getCanonicalPath(std::string(urlIn)); … … 1028 1125 return TCL_ERROR; 1029 1126 } 1030 1031 if (driver[0] == 'g' && strcmp(driver, "gdal") == 0) { 1032 osgEarth::Drivers::GDALOptions opts; 1033 opts.url() = url; 1034 char *name = Tcl_GetString(objv[6]); 1035 g_renderer->addElevationLayer(name, opts); 1036 } else if (driver[0] == 't' && strcmp(driver, "tms") == 0) { 1037 osgEarth::Drivers::TMSOptions opts; 1038 //char *tmsType = Tcl_GetString(objv[6]); 1039 //char *format = Tcl_GetString(objv[7]); 1040 opts.url() = url; 1041 //opts.tmsType() = tmsType; 1042 //opts.format() = format; 1043 char *name = Tcl_GetString(objv[6]); 1044 g_renderer->addElevationLayer(name, opts); 1045 } else { 1046 Tcl_AppendResult(interp, "unknown elevation driver \"", driver, 1047 "\": should be 'gdal' or 'tms'", (char*)NULL); 1048 return TCL_ERROR; 1049 } 1050 } else if (type[0] == 'p' && strcmp(type, "point") == 0) { 1051 osgEarth::Drivers::OGRFeatureOptions opts; 1052 char *urlIn = Tcl_GetString(objv[4]); 1053 std::string url = g_renderer->getCanonicalPath(std::string(urlIn)); 1054 if (url.empty()) { 1055 Tcl_AppendResult(interp, "file not found: \"", 1056 urlIn, "\"", (char*)NULL); 1057 return TCL_ERROR; 1058 } 1059 char *name = Tcl_GetString(objv[5]); 1060 1127 float r, g, b; 1128 if (GetFloatFromObj(interp, objv[6], &r) != TCL_OK || 1129 GetFloatFromObj(interp, objv[7], &g) != TCL_OK || 1130 GetFloatFromObj(interp, objv[8], &b) != TCL_OK) { 1131 return TCL_ERROR; 1132 } 1133 float ptSize; 1134 if (GetFloatFromObj(interp, objv[9], &ptSize) != TCL_OK) { 1135 return TCL_ERROR; 1136 } 1061 1137 opts.url() = url; 1062 1138 1063 1139 osgEarth::Symbology::Style style; 1064 osgEarth::Symbology::PointSymbol * ls = style.getOrCreateSymbol<osgEarth::Symbology::PointSymbol>();1065 ls->fill()->color() = osgEarth::Symbology::Color::Black;1066 ls->size() = 2.0f;1140 osgEarth::Symbology::PointSymbol *ps = style.getOrCreateSymbol<osgEarth::Symbology::PointSymbol>(); 1141 ps->fill()->color() = osgEarth::Symbology::Color(r, g, b); 1142 ps->size() = ptSize; 1067 1143 1068 1144 osgEarth::Symbology::RenderSymbol* rs = style.getOrCreateSymbol<osgEarth::Symbology::RenderSymbol>(); … … 1075 1151 geomOpts.styles()->addStyle(style); 1076 1152 geomOpts.enableLighting() = false; 1153 geomOpts.minRange() = 0.f; 1154 geomOpts.maxRange() = FLT_MAX; 1155 //geomOpts.renderOrder = int; 1156 //geomOpts.depthTestEnabled = bool; 1077 1157 g_renderer->addModelLayer(name, geomOpts); 1078 1158 } else if (type[0] == 'p' && strcmp(type, "polygon") == 0) { 1079 1159 osgEarth::Drivers::OGRFeatureOptions opts; 1080 char *urlIn = Tcl_GetString(objv[ 4]);1160 char *urlIn = Tcl_GetString(objv[5]); 1081 1161 std::string url = g_renderer->getCanonicalPath(std::string(urlIn)); 1082 1162 if (url.empty()) { … … 1085 1165 return TCL_ERROR; 1086 1166 } 1087 char *name = Tcl_GetString(objv[5]); 1167 float r, g, b; 1168 if (GetFloatFromObj(interp, objv[6], &r) != TCL_OK || 1169 GetFloatFromObj(interp, objv[7], &g) != TCL_OK || 1170 GetFloatFromObj(interp, objv[8], &b) != TCL_OK) { 1171 return TCL_ERROR; 1172 } 1088 1173 opts.url() = url; 1089 1174 1090 1175 osgEarth::Symbology::Style style; 1091 osgEarth::Symbology::PolygonSymbol * ls = style.getOrCreateSymbol<osgEarth::Symbology::PolygonSymbol>();1092 ls->fill()->color() = osgEarth::Symbology::Color::White;1176 osgEarth::Symbology::PolygonSymbol *ps = style.getOrCreateSymbol<osgEarth::Symbology::PolygonSymbol>(); 1177 ps->fill()->color() = osgEarth::Symbology::Color(r, g, b); 1093 1178 #if 1 1094 1179 osgEarth::Symbology::AltitudeSymbol *alt = style.getOrCreateSymbol<osgEarth::Symbology::AltitudeSymbol>(); … … 1106 1191 geomOpts.styles()->addStyle(style); 1107 1192 geomOpts.enableLighting() = false; 1193 geomOpts.minRange() = 0.f; 1194 geomOpts.maxRange() = FLT_MAX; 1108 1195 g_renderer->addModelLayer(name, geomOpts); 1109 1196 } else if (type[0] == 'l' && strcmp(type, "line") == 0) { 1110 1197 osgEarth::Drivers::OGRFeatureOptions opts; 1111 char *urlIn = Tcl_GetString(objv[ 4]);1198 char *urlIn = Tcl_GetString(objv[5]); 1112 1199 std::string url = g_renderer->getCanonicalPath(std::string(urlIn)); 1113 1200 if (url.empty()) { … … 1116 1203 return TCL_ERROR; 1117 1204 } 1118 char *name = Tcl_GetString(objv[5]); 1205 float r, g, b; 1206 if (GetFloatFromObj(interp, objv[6], &r) != TCL_OK || 1207 GetFloatFromObj(interp, objv[7], &g) != TCL_OK || 1208 GetFloatFromObj(interp, objv[8], &b) != TCL_OK) { 1209 return TCL_ERROR; 1210 } 1211 float lineWidth; 1212 if (GetFloatFromObj(interp, objv[9], &lineWidth) != TCL_OK) { 1213 return TCL_ERROR; 1214 } 1119 1215 opts.url() = url; 1120 1216 1121 1217 osgEarth::Symbology::Style style; 1122 1218 osgEarth::Symbology::LineSymbol *ls = style.getOrCreateSymbol<osgEarth::Symbology::LineSymbol>(); 1123 ls->stroke()->color() = osgEarth::Symbology::Color ::Black;1124 ls->stroke()->width() = 2.0f;1219 ls->stroke()->color() = osgEarth::Symbology::Color(r, g, b); 1220 ls->stroke()->width() = lineWidth; 1125 1221 #if 1 1126 1222 osgEarth::Symbology::AltitudeSymbol *alt = style.getOrCreateSymbol<osgEarth::Symbology::AltitudeSymbol>(); … … 1139 1235 geomOpts.styles()->addStyle(style); 1140 1236 geomOpts.enableLighting() = false; 1237 geomOpts.minRange() = 0.f; 1238 geomOpts.maxRange() = FLT_MAX; 1239 if (objc > 10) { 1240 float min, max; 1241 if (GetFloatFromObj(interp, objv[10], &min) != TCL_OK || 1242 GetFloatFromObj(interp, objv[11], &max) != TCL_OK) { 1243 return TCL_ERROR; 1244 } 1245 geomOpts.minRange() = min; 1246 geomOpts.maxRange() = max; 1247 } 1141 1248 g_renderer->addModelLayer(name, geomOpts); 1142 1249 } else if (type[0] == 't' && strcmp(type, "text") == 0) { 1143 1250 osgEarth::Drivers::OGRFeatureOptions opts; 1144 char *urlIn = Tcl_GetString(objv[ 4]);1251 char *urlIn = Tcl_GetString(objv[5]); 1145 1252 std::string url = g_renderer->getCanonicalPath(std::string(urlIn)); 1146 1253 if (url.empty()) { … … 1149 1256 return TCL_ERROR; 1150 1257 } 1151 char *content = Tcl_GetString(objv[5]); 1152 char *priority = Tcl_GetString(objv[6]); 1153 char *name = Tcl_GetString(objv[7]); 1154 1155 #if 0 1156 double fgR = 1.0, fgG = 1.0, fgB = 1.0; 1157 double bgR = 0.0, bgG = 0.0, bgB = 0.0; 1158 if (objc > 8) { 1159 if (Tcl_GetDoubleFromObj(interp, objv[8], &fgR) != TCL_OK || 1160 Tcl_GetDoubleFromObj(interp, objv[9], &fgG) != TCL_OK || 1161 Tcl_GetDoubleFromObj(interp, objv[10], &fgB) != TCL_OK || 1162 Tcl_GetDoubleFromObj(interp, objv[11], &bgR) != TCL_OK || 1163 Tcl_GetDoubleFromObj(interp, objv[12], &bgG) != TCL_OK || 1164 Tcl_GetDoubleFromObj(interp, objv[13], &bgB) != TCL_OK) { 1165 return TCL_ERROR; 1166 } 1167 } 1168 #endif 1258 char *content = Tcl_GetString(objv[6]); 1259 char *priority = Tcl_GetString(objv[7]); 1260 float fgR, fgG, fgB; 1261 float bgR, bgG, bgB; 1262 float haloWidth, ftSize; 1263 if (GetFloatFromObj(interp, objv[8], &fgR) != TCL_OK || 1264 GetFloatFromObj(interp, objv[9], &fgG) != TCL_OK || 1265 GetFloatFromObj(interp, objv[10], &fgB) != TCL_OK || 1266 GetFloatFromObj(interp, objv[11], &bgR) != TCL_OK || 1267 GetFloatFromObj(interp, objv[12], &bgG) != TCL_OK || 1268 GetFloatFromObj(interp, objv[13], &bgB) != TCL_OK || 1269 GetFloatFromObj(interp, objv[14], &haloWidth) != TCL_OK || 1270 GetFloatFromObj(interp, objv[15], &ftSize) != TCL_OK) { 1271 return TCL_ERROR; 1272 } 1273 bool removeDupes, declutter; 1274 if (GetBooleanFromObj(interp, objv[16], &removeDupes) != TCL_OK || 1275 GetBooleanFromObj(interp, objv[17], &declutter) != TCL_OK) { 1276 return TCL_ERROR; 1277 } 1169 1278 opts.url() = url; 1170 1279 1171 1280 osgEarth::Symbology::Style style; 1172 1281 osgEarth::Symbology::TextSymbol *ts = style.getOrCreateSymbol<osgEarth::Symbology::TextSymbol>(); 1173 ts->halo()->color() = osgEarth::Symbology::Color ::Black; //::Color(bgR, bgG, bgB);1174 ts->halo()->width() = 2.0f;1175 ts->fill()->color() = osgEarth::Symbology::Color ::White; //::Color(fgR, fgG, fgB);1282 ts->halo()->color() = osgEarth::Symbology::Color(bgR, bgG, bgB); 1283 ts->halo()->width() = haloWidth; 1284 ts->fill()->color() = osgEarth::Symbology::Color(fgR, fgG, fgB); 1176 1285 ts->content() = osgEarth::Symbology::StringExpression(content); 1177 1286 ts->priority() = osgEarth::Symbology::NumericExpression(priority); 1178 ts->removeDuplicateLabels() = true; 1179 ts->size() = 16.0f; 1287 ts->removeDuplicateLabels() = removeDupes; 1288 //ts->font() = "Arial"; 1289 ts->size() = ftSize; 1180 1290 ts->alignment() = osgEarth::Symbology::TextSymbol::ALIGN_CENTER_CENTER; 1181 ts->declutter() = true; 1291 ts->declutter() = declutter; 1292 ts->encoding() = osgEarth::Symbology::TextSymbol::ENCODING_UTF8; 1182 1293 1183 1294 osgEarth::Symbology::RenderSymbol* rs = style.getOrCreateSymbol<osgEarth::Symbology::RenderSymbol>(); … … 1190 1301 geomOpts.styles()->addStyle(style); 1191 1302 geomOpts.enableLighting() = false; 1303 geomOpts.minRange() = 0.f; 1304 geomOpts.maxRange() = FLT_MAX; 1305 if (objc > 10) { 1306 float min, max; 1307 if (GetFloatFromObj(interp, objv[18], &min) != TCL_OK || 1308 GetFloatFromObj(interp, objv[19], &max) != TCL_OK) { 1309 return TCL_ERROR; 1310 } 1311 geomOpts.minRange() = min; 1312 geomOpts.maxRange() = max; 1313 } 1192 1314 g_renderer->addModelLayer(name, geomOpts); 1193 1315 } else { … … 1323 1445 1324 1446 static CmdSpec mapLayerOps[] = { 1325 {"add", 1, MapLayerAddOp, 6, 0, " type driver ?url? ?args? name"},1447 {"add", 1, MapLayerAddOp, 6, 0, "name type driver ?url? ?args?"}, 1326 1448 {"delete", 1, MapLayerDeleteOp, 3, 4, "?name?"}, 1327 1449 {"move", 1, MapLayerMoveOp, 5, 5, "pos name"}, … … 1519 1641 return TCL_ERROR; 1520 1642 } 1521 1643 float color[3]; 1644 if (GetFloatFromObj(interp, objv[3], &color[0]) != TCL_OK || 1645 GetFloatFromObj(interp, objv[4], &color[1]) != TCL_OK || 1646 GetFloatFromObj(interp, objv[5], &color[2]) != TCL_OK) { 1647 return TCL_ERROR; 1648 } 1649 1650 osg::Vec4f bgColor(color[0],color[1],color[2],1); 1522 1651 if (type == osgEarth::MapOptions::CSTYPE_PROJECTED) { 1523 if (objc < 4) {1652 if (objc < 7) { 1524 1653 Tcl_AppendResult(interp, "wrong # arguments: profile required for projected maps", (char*)NULL); 1525 1654 return TCL_ERROR; 1526 1655 } 1527 char *profile = Tcl_GetString(objv[ 3]);1528 if (objc > 4) {1529 if (objc < 8) {1656 char *profile = Tcl_GetString(objv[6]); 1657 if (objc > 7) { 1658 if (objc < 11) { 1530 1659 Tcl_AppendResult(interp, "wrong # arguments: 4 bounds arguments required", (char*)NULL); 1531 1660 return TCL_ERROR; … … 1533 1662 double bounds[4]; 1534 1663 for (int i = 0; i < 4; i++) { 1535 if (Tcl_GetDoubleFromObj(interp, objv[ 4+i], &bounds[i]) != TCL_OK) {1664 if (Tcl_GetDoubleFromObj(interp, objv[7+i], &bounds[i]) != TCL_OK) { 1536 1665 return TCL_ERROR; 1537 1666 } 1538 1667 } 1668 #if 1 1539 1669 // Check if min > max 1540 1670 if (bounds[0] > bounds[2] || … … 1579 1709 } 1580 1710 } 1581 g_renderer->resetMap(type, profile, bounds); 1711 #endif 1712 g_renderer->resetMap(type, bgColor, profile, bounds); 1582 1713 } else { 1583 1714 if (osgEarth::Registry::instance()->getNamedProfile(profile) == NULL) { … … 1586 1717 return TCL_ERROR; 1587 1718 } 1588 g_renderer->resetMap(type, profile);1719 g_renderer->resetMap(type, bgColor, profile); 1589 1720 } 1590 1721 } else { 1591 1722 // No profile required for geocentric (3D) maps 1592 g_renderer->resetMap(type );1723 g_renderer->resetMap(type, bgColor); 1593 1724 } 1594 1725 … … 1644 1775 1645 1776 static int 1646 MapTerrain EdgesOp(ClientData clientData, Tcl_Interp *interp, int objc,1777 MapTerrainColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 1647 1778 Tcl_Obj *const *objv) 1648 {1649 bool state;1650 if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {1651 return TCL_ERROR;1652 }1653 TRACE("Not implemented");1654 //g_renderer->setTerrainEdges(state);1655 return TCL_OK;1656 }1657 1658 static int1659 MapTerrainLightingOp(ClientData clientData, Tcl_Interp *interp, int objc,1660 Tcl_Obj *const *objv)1661 {1662 bool state;1663 if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) {1664 return TCL_ERROR;1665 }1666 1667 g_renderer->setTerrainLighting(state);1668 return TCL_OK;1669 }1670 1671 static int1672 MapTerrainLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc,1673 Tcl_Obj *const *objv)1674 1779 { 1675 1780 float color[3]; … … 1679 1784 return TCL_ERROR; 1680 1785 } 1681 TRACE("Not implemented"); 1682 //g_renderer->setTerrainLineColor(color); 1786 g_renderer->setTerrainColor(osg::Vec4f(color[0],color[1],color[2],1)); 1787 return TCL_OK; 1788 } 1789 1790 static int 1791 MapTerrainEdgesOp(ClientData clientData, Tcl_Interp *interp, int objc, 1792 Tcl_Obj *const *objv) 1793 { 1794 bool state; 1795 if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) { 1796 return TCL_ERROR; 1797 } 1798 g_renderer->setTerrainEdges(state); 1799 return TCL_OK; 1800 } 1801 1802 static int 1803 MapTerrainLightingOp(ClientData clientData, Tcl_Interp *interp, int objc, 1804 Tcl_Obj *const *objv) 1805 { 1806 bool state; 1807 if (GetBooleanFromObj(interp, objv[3], &state) != TCL_OK) { 1808 return TCL_ERROR; 1809 } 1810 1811 g_renderer->setTerrainLighting(state); 1812 return TCL_OK; 1813 } 1814 1815 static int 1816 MapTerrainLineColorOp(ClientData clientData, Tcl_Interp *interp, int objc, 1817 Tcl_Obj *const *objv) 1818 { 1819 float color[3]; 1820 if (GetFloatFromObj(interp, objv[3], &color[0]) != TCL_OK || 1821 GetFloatFromObj(interp, objv[4], &color[1]) != TCL_OK || 1822 GetFloatFromObj(interp, objv[5], &color[2]) != TCL_OK) { 1823 return TCL_ERROR; 1824 } 1825 g_renderer->setTerrainLineColor(osg::Vec4f(color[0], color[1], color[2],1)); 1826 return TCL_OK; 1827 } 1828 1829 static int 1830 MapTerrainLineWidthOp(ClientData clientData, Tcl_Interp *interp, int objc, 1831 Tcl_Obj *const *objv) 1832 { 1833 float width; 1834 if (GetFloatFromObj(interp, objv[3], &width) != TCL_OK) { 1835 return TCL_ERROR; 1836 } 1837 g_renderer->setTerrainLineWidth(width); 1683 1838 return TCL_OK; 1684 1839 } … … 1711 1866 1712 1867 static CmdSpec mapTerrainOps[] = { 1868 {"color", 1, MapTerrainColorOp, 6, 6, "r g b"}, 1713 1869 {"edges", 1, MapTerrainEdgesOp, 4, 4, "bool"}, 1714 1870 {"lighting", 2, MapTerrainLightingOp, 4, 4, "bool"}, 1715 {"linecolor", 2, MapTerrainLineColorOp, 6, 6, "r g b"}, 1871 {"linecolor", 5, MapTerrainLineColorOp, 6, 6, "r g b"}, 1872 {"linewidth", 5, MapTerrainLineWidthOp, 4, 4, "val"}, 1716 1873 {"vertscale", 1, MapTerrainVertScaleOp, 4, 4, "val"}, 1717 1874 {"wireframe", 1, MapTerrainWireframeOp, 4, 4, "bool"}, … … 1778 1935 {"pin", 2, MapPinOp, 3, 0, "op ?params...?"}, 1779 1936 {"posdisp", 2, MapPositionDisplayOp, 3, 5, "bool ?format? ?precision?"}, 1780 {"reset", 1, MapResetOp, 3, 8, "type?profile xmin ymin xmax ymax?"},1937 {"reset", 1, MapResetOp, 6, 11, "type r g b ?profile xmin ymin xmax ymax?"}, 1781 1938 {"scalebar", 1, MapScaleBarOp, 3, 4, "bool ?units?"}, 1782 1939 {"setpos", 1, MapSetPositionOp, 2, 4, "x y"}, … … 2293 2450 Tcl_CreateObjCommand(interp, "imgflush", ImageFlushCmd, clientData, NULL); 2294 2451 Tcl_CreateObjCommand(interp, "key", KeyCmd, clientData, NULL); 2452 Tcl_CreateObjCommand(interp, "legend", LegendCmd, clientData, NULL); 2295 2453 Tcl_CreateObjCommand(interp, "map", MapCmd, clientData, NULL); 2296 2454 Tcl_CreateObjCommand(interp, "mouse", MouseCmd, clientData, NULL); … … 2310 2468 Tcl_DeleteCommand(interp, "imgflush"); 2311 2469 Tcl_DeleteCommand(interp, "key"); 2470 Tcl_DeleteCommand(interp, "legend"); 2312 2471 Tcl_DeleteCommand(interp, "map"); 2313 2472 Tcl_DeleteCommand(interp, "mouse"); -
geovis/trunk/geovis_protocol.txt
r5026 r5105 74 74 clientinfo <list> 75 75 76 colormap add <colorMapName> <colorMap> <opacityMap>76 colormap add <colorMapName> <colorMap> 77 77 (Re-)define a colormap. If colorMapName doesn't exist, it is created, 78 78 otherwise the colormap is redefined and all users will be updated. 79 colorMap = Tcl list of {value r g b} control points 80 opacityMap = Tcl list of {value alpha} control points 81 colormap define <colorMapName> <colorMap> <opacityMap> 79 colorMap = Tcl list of {value r g b a} control points 80 colormap define <colorMapName> <colorMap> 82 81 (Re-)define a colormap (same as 'add') 83 82 colormap delete <?colorMapName?> … … 159 158 160 159 Feature/model layers: 161 map layer add point <url> < layerName>160 map layer add point <url> <r> <g> <b> <size> <layerName> 162 161 Add a point feature layer from a file or URL 163 map layer add polygon <url> < layerName>162 map layer add polygon <url> <r> <g> <b> <width> <layerName> 164 163 Add a polygon feature layer from a file or URL 165 map layer add line <url> < layerName>164 map layer add line <url> <r> <g> <b> <width> <layerName> 166 165 Add a line feature layer from a file or URL 167 166 map layer add text <url> <layerName> … … 218 217 nv>image -type image -bytes <nbytes> 219 218 <binary RGB data> 219 nv>legend <colormapName> <rmin> <rmax> <nbytes> 220 <binary RGB data> 220 221 nv>map coords <token> <mapCoordList> <?srs?> <?verticalDatum?> 221 222 Reply to query of map coordinates from screen coordinates. The mapCoordList
Note: See TracChangeset
for help on using the changeset viewer.