wiki:MapGuideRfc26

MapGuide RFC 26 - Stylize Elevation Layer

This page contains an change request (RFC) for the MapGuide Open Source project. More MapGuide RFCs can be found on the RFCs page.

Status

RFC Template Version1.0
Submission DateAug 2, 2007
Last ModifiedMaggie Yang Timestamp?
AuthorMaggie Yang
RFC Statusapproved
Implementation Statusunder development
Proposed Milestone2.0
Assigned PSC guide(s)(when determined)
Voting HistoryAug 27, 2007
+1Jason,Andy, Haris, Tom, Bruce and Paul
+0
-0
-1

Overview

The purpose of this RFC is to allow MapGuide to stylize the elevation data, which configured surface style in its layer definition.

Motivation

MapGuide cannot stylize the elevation layer, such as DEM and GeoTIFF file, configured by the following kind of layer definition with surface style:

<LayerDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="LayerDefinition-1.0.0.xsd" version="1.0.0">
<GridLayerDefinition>  <ResourceId>Library://Publish/Data/Raster_1.FeatureSource</ResourceId> 
  <FeatureName>rasters:davenport</FeatureName> 
  <Geometry>Image</Geometry> 
  <GridScaleRange>
    <SurfaceStyle>
      <Band>1</Band> 
      <DefaultColor>0000FF00</DefaultColor> 
    </SurfaceStyle>
    <ColorStyle>
      <HillShade>
        <Band>1</Band> 
        <Azimuth>45</Azimuth> 
        <Altitude>45</Altitude> 
      </HillShade>
      <ColorRule>
        <LegendLabel>-1.79e+308 to 1.79e+308</LegendLabel> 
        <Filter>(Height(1) > -1.7976931348623158e+308) AND (Height(1) < 1.7976931348623158e+308)</Filter> 
        <Color>
          <ExplicitColor>FF00FF00</ExplicitColor> 
        </Color>
      </ColorRule>
      <ColorRule>
        <LegendLabel>{DEFAULT}</LegendLabel> 
        <Color>
          <ExplicitColor>FF006423</ExplicitColor> 
        </Color>
      </ColorRule>
    </ColorStyle>
    <RebuildFactor>1</RebuildFactor> 
  </GridScaleRange>
</GridLayerDefinition>

Currently, MapGuide do not have the stylization mechanism for grid surface data. So, in this release, we will make MapGuide has the ability to stylize the elevation layer. The user would see the stylized elevation data, like Figure 1 in MapGuide in the future, not the Figure 2, which is the current status for elevation data in MapGuide.

instead of
Figure1 Figure2

Proposed Solution

Modify Stylization project to support the stylization of the elevation data with surface style. Here, introduce some key classes for stylizing elevation data, also called grid data. They are GridStylizer, GridData, GridStyleHandler, GridColorHandler and GridApplyStatusReporter.

GridStylizer

This class only for stylization with grid data and grid styles. GridStylizer takes a grid, a grid color style, and a grid surface style. Then it applies the color style on the grid and writes the result into the color band of the grid. Moreover, it also applies the surface style on the grid and writes the result into the elevation band of the grid.

class GridStylizer
{
public:
    ///<summary>
    /// Stylizes a grid base on the given surface style and color style.
    /// It applies the surface style to generate a new elevation band to show
    /// 3d surface. And it also applies the color style to generate a new
    /// color band to show the texture of the 3d surface.
    ///</summary>
    ///<param name="pGrid">
    /// A grid is a set of bands. The stylizer read band data from the grid
    /// and write the result into the color band and elevation band.
    ///</param>
    ///<param name="pSurfaceStyle">
    /// The pointer of GridSurfaceStyle, which specifies how to calculate the elevation.
    ///</param>
    ///<param name="pColorStyle">
    /// The pointer of GridColorStyle, which specifies how to stylize each pixel.
    ///</param>
    ///</param>
    ///<param name="fOpacity">
    /// Opacity of this Grid Layer
    ///</param>
    ///<returns>
    /// Returns true to indicate the stylization transaction completes successfully.
    /// Returns false to indicate the stylization transaction encouters some errors and
    /// has been interruptted.
    ///</returns>
    STYLIZATION_API bool ApplyStyles(
                                     GridData *pGrid,
                                     const MdfModel::GridSurfaceStyle *pSurfaceStyle,
                                     const MdfModel::GridColorStyle *pColorStyle,
 				     double fOpacity = 1.0);
 
    ///<summary>
    /// Stylizes a grid base on the given color style and default color.
    /// It applies the color style to generate a new color band to show 
    /// the texture of the 3d surface. And also it will set the transparent
    /// pixel to the default color.
    ///</summary>
    ///<param name="pGrid">
    /// A grid is a set of bands. The stylizer read band data from the grid
    /// and write the result into the color band.
    ///</param>
    ///<param name="pColorStyle">
    /// The pointer of GridColorStyle, which specifies how to stylize each pixel.
    ///</param>
    ///<param name="sDefaultColor">
    /// The default color for the tansparent pixel.
    ///</param>
    ///<returns>
    /// Returns true to indicate the stylization transaction completes successfully.
    /// Returns false to indicate the stylization transaction encouters some errors and
    /// has been interruptted.
    ///</returns>
    STYLIZATION_API bool ApplyColorStyle(
                                         GridData *pGrid,
                                         const MdfModel::GridColorStyle *pStyle,
                                         const MdfModel::MdfString &sDefaultColor);

    ///<summary>
    /// Stylizes a grid base on the given surface style.
    /// It applies the surface style to generate a new elevation band to show
    /// 3d surface.
    ///</summary>
    ///<param name="pGrid">
    /// A grid is a set of bands. The stylizer read band data from the grid
    /// and write the result into the color band and elevation band.
    ///</param>
    ///<param name="pSurfaceStyle">
    /// The pointer of GridSurfaceStyle, which specifies how to calculate the elevation.
    ///</param>
    ///<returns>
    /// Returns true to indicate the stylization transaction completes successfully.
    /// Returns false to indicate the stylization transaction encouters some errors and
    /// has been interruptted.
    ///</returns>
    STYLIZATION_API bool ApplySurfaceStyle(
                                           GridData *pGrid,
                                           const MdfModel::GridSurfaceStyle *pStyle);

    ///<summary>
    /// Applied the hillshade effect to a gis band
    ///</summary>
    ///<param name="pColorBand">
    /// It is the input and ouput, we read color from it, and apply hillshade, then write
    /// back to it.
    ///</param>
    ///<param name="pHS">
    /// It describes how to apply hillshade to the gis band.
    ///</param>
    ///<returns>
    /// Returns true to indicate the stylization transaction completes successfully.
    /// Returns false to indicate the stylization transaction encouters some errors and
    /// has been interruptted.
    ///</returns>
    STYLIZATION_API static bool ApplyHillShade(
                                               Band* pColorBand,
                                               const MdfModel::HillShade *pHS);

}

GridData

This class is a collection of all kinds of information from elevation data, such as bands, hillshade, bounding box and etc. Those grid data are populated from FdoIRaster.

class GridData
{
public:    
    typedef std::vector<Band*>        GISGRIDVECTOR;    

public:    
    ///<summary>
    /// Because all the bands in the same grid have the same original point extent and count,
    /// so this information is kept in the GridData class.    
    ///</summary>
    STYLIZATION_API                     GridData(   const Point2D&  point, 
                                                    double          xExtent, 
                                                    double          yExtent, 
                                                    unsigned int    nXCount, 
                                                    unsigned int    nYCount);
    /// <summary>
    ///   Populates the GridData from an FdoIRaster
    /// </summary>
    STYLIZATION_API void                     ReadRaster(RS_Raster*       pRaster,
                                                        FdoString*       pBandName,
                                                        unsigned long    cols,
                                                        unsigned long    rows,
                                                        double           xMin,
                                                        double           yMin,
                                                        double           xMax,
                                                        double           yMax,
                                                        bool             bAlignment);



    ///<summary>
    /// Get the Band with band name. If it is not in the grid, return NULL.
    ///</summary>    
    STYLIZATION_API Band*            GetBand(const MdfModel::MdfString& name) const;        

    ///<summary>
    /// Get the Band with the band index. If it is not in the grid, return NULL.
    /// The index of the Band maybe will changed after some insert operation, 
    /// so please don't keep the band index to get the band next time.
    /// In the most case, please you'd better get the Band with the band name.
    /// You can use this method and GetBandCount method to iterator the grid get all
    /// the bands.
    ///</summary>
    STYLIZATION_API Band*            GetBand(unsigned int index) const;
    STYLIZATION_API inline size_t       GetBandCount() const;                                            

    ///<summary>
    /// This method is used to create a new band in the grid, the band name 
    /// will be set as the name parament. And this band will be insert to the grid.
    /// If the name is duplicated, this method will return NULL.
    ///</summary>
    STYLIZATION_API Band*            CreateBand(Band::BandDataType dataType, const MdfModel::MdfString& name);

    ///<summary>
    /// Insert a band into the grid. Because a band is identity with it's name in the grid,
    /// so please make sure the name of band is not empty before insert it to the grid,
    /// or this method will return false. And if there is a band in the grid has the same name
    /// with the insert band, it will return false too.
    ///</summary>
    STYLIZATION_API bool                InsertBand( Band* pBand);

    ///<summary>
    /// If the elevation band is a band in the grid, set the elevation band
    /// with the band name and index of the band in the grid.
    ///</summary>
    STYLIZATION_API bool                SetElevationBand(const MdfModel::MdfString& name);
    STYLIZATION_API bool                SetElevationBand(unsigned int index);
    
    ///<summary>
    /// If the elevation band is not a band in the grid, use this method to set the 
    /// elevation band for the grid.
    ///</summary>
    STYLIZATION_API inline void         SetElevationBand(Band* pBand);

    ///<summary>
    /// Get the elevation band in this grid.
    ///</summary>
    STYLIZATION_API inline Band*     GetElevationBand() const;

    ///<summary>
    /// Get a band for stylization use. If it is empty, we will create one band (double type).    
    ///</summary>
    STYLIZATION_API Band*            GetElevationBandDataForStylization();

    ///<summary>
    /// Get the draped color band in this grid.
    ///</summary>
    STYLIZATION_API  Band*            GetDrapedColorBand() const;

    ///<summary>
    /// Create a draped color band in this grid.
    /// In some cases, the draped color band is not required for the grid.
    /// So we just offer this method to create the drpaed color band when it is required.
    ///</summary>
    STYLIZATION_API  void                CreateDrapedColorBand();

    ///<summary>
    /// Get the color band in this grid.
    ///</summary>
    STYLIZATION_API Band*            GetColorBand() const; 
                                            
    ///<summary>
    /// Function to retrieve the band that stores the hillshade values. It is in float format. 
    ///</summary>
    STYLIZATION_API const Band*      GetCacheHillShadeBand(const MdfModel::HillShade *pHS) const;

    ///<summary>
    /// Function to set the band that stores the hillshade values. It is in float format. 
    ///</summary>
    STYLIZATION_API bool                SetCacheHillShadeBand(
                                                              const MdfModel::HillShade *pHS,
                                                              Band                   *pHSBand);

    ///<summary>
    /// Set the raw color band without hillshade effect if the color band includes effect.
    ///</summary>
    STYLIZATION_API bool                SetNoHillShadeColorBand(Band *pNoHillShadeColorBand);

    ///<summary>
    /// Get the raw color band without hillshade effect if the color band includes effect.
    ///</summary>
    STYLIZATION_API const Band*      GetNoHillShadeColorBand() const;

    ///<summary>
    /// Get the raw color band without hillshade effect if the color band includes effect.
    ///</summary>
    STYLIZATION_API Band*            GetNoHillShadeColorBand();

    ///<summary>
    /// Get the geometry information for the bands in this grid.    
    ///</summary>
    STYLIZATION_API inline double       GetXUnitDistance() const;

    STYLIZATION_API inline double       GetYUnitDistance() const;

    STYLIZATION_API inline double       GetInvScaledDX() const;

    STYLIZATION_API inline double       GetInvScaledDY() const;

    STYLIZATION_API inline unsigned int GetXCount() const;
                                    
    STYLIZATION_API inline unsigned int GetYCount() const; 

    STYLIZATION_API inline double       GetXExtent () const;
                                 
    STYLIZATION_API inline double       GetYExtent () const;
                                            

    STYLIZATION_API inline const Point2D&            GetOriginalPoint2D() const;                                            

    STYLIZATION_API inline MdfModel::Box2D            GetBoundingBox() const;

    STYLIZATION_API inline void         SetCoordSysUnitLength(double dUnitLength);

    STYLIZATION_API inline double       GetCoordSysUnitLength() const;

    STYLIZATION_API Band::BandDataType  GetGridDataType(RS_Raster* pRaster, 
                                                        bool bBandDataType = true) const;
}

GridStyleHandler

Class GridStyleHandler is the base class of all the grid style handlers. This class provides the common interface to visit each pixel of the band and do the different operations, such as to stylize the band.

class GridStyleHandler
{
public:
    ///<summary>
    /// Function to clear the data info of the handler.
    ///</summary>
    virtual void Clear() = 0;

    ///<summary>
    /// Function to visit each pixel. 
    ///</summary>
    virtual void Visit(unsigned int x, unsigned int y) = 0;

    ///<summary>
    /// Finished visiting all the pixels
    ///</summary>
    virtual void Finished(bool bSuccessful) {bSuccessful;}

    ///<summary>
    /// Set GridStatusReporter
    ///</summary>
    virtual void SetStatusReporter(GridStatusReporter *pReporter) = 0;

    ///<summary>
    /// Function to visit all pixels. 
    ///</summary>
    virtual bool Visit() = 0;
};

There are several derived classes of GridStyleHandler:
GridStyleColorHandler is used to handle the MdfModel::GridColorStyle.
GridStyleSurfaceColorHandler is used to set the transparent color to the default color. And it also set the invalid pixel to the default color.
GridStyleSurfaceHandler is used to handle the MdfModel::GridSurfaceStyle.

GridColorHandler

This base class provides the uniform interface for getting the color on each pixel when stylizing the band

class GridColorHandler
{
public:
    ///<summary>
    /// Function to initialize the GridColorHandler object.
    ///</summary>
    ///<param name = "pRules">
    /// The rules includes the detail info.
    ///</param>
    ///<param name = "pGrid">
    /// The grid that the styles are applied on.
    ///</param>
    ///<returns>
    /// Returns true if it is intialized successfully.
    /// Othrewise, returns false.
    ///</returns>
    virtual bool Initialize(const MdfModel::RuleCollection *pRules, const GridData *pGrid) = 0;

    ///<summary>
    /// Function to get the color on the pixel. 
    ///</summary>
    ///<param name = "color">
    /// [Out] Stores the result color.
    ///</param>
    ///<param name = "x">
    /// The X axis position of the pixel
    ///</param>
    ///<param name = "y">
    /// The Y axis position of the pixel
    ///</param>
    ///<returns>
    /// Returns true if it gets the corresponding color.
    /// Othrewise, returns false.
    ///</returns>
    virtual bool GetColor(Color &color, unsigned int x, unsigned int y) = 0;

    ///<summary>
    /// Function to clear the data info of the handler.
    ///</summary>
    virtual void Clear() = 0;

    ///<summary>
    /// Function to create the corresponding color handler according to the different pRules.
    ///</summary>
    ///<param name = "pRules">
    /// The rules includes the detail info.
    ///</param>
    ///<param name = "pGrid">
    /// The grid that the styles are applied on.
    ///</param>
    ///<returns>
    /// Returns the pointer to the new created GridColorHandler.
    /// Caller must be responsible to release it.
    /// Returns NULL if the handlers fail to initialize.
    ///</returns>
    static GridColorHandler* Create(const MdfModel::RuleCollection *pRules, const GridData *pGrid);

    ///<summary>
    /// Function to create the GridColorBandHandler.
    ///</summary>
    ///<param name = "pRules">
    /// The rules includes the detail info.
    ///</param>
    ///<param name = "pGrid">
    /// The grid that the styles are applied on.
    ///</param>
    ///<returns>
    /// Returns the pointer to the new created GridColorBandHandler.
    /// Caller must be responsible to release it.
    /// Returns NULL if the handlers fail to initialize.
    ///</returns>
    static GridColorBandHandler* CreateBandHandler(const MdfModel::RuleCollection *pRules, const GridData *pGrid);

    ///<summary>
    /// Function to create the GridColorBandsHandler.
    ///</summary>
    ///<param name = "pRules">
    /// The rules includes the detail info.
    ///</param>
    ///<param name = "pGrid">
    /// The grid that the styles are applied on.
    ///</param>
    ///<returns>
    /// Returns the pointer to the new created GridColorBandsHandler.
    /// Caller must be responsible to release it.
    /// Returns NULL if the handlers fail to initialize.
    ///</returns>
    static GridColorBandsHandler* CreateBandsHandler(const MdfModel::RuleCollection *pRules, const GridData *pGrid);

    ///<summary>
    /// Function to create the GridColorThemeHandler.
    ///</summary>
    ///<param name = "pRules">
    /// The rules includes the theme info.
    ///</param>
    ///<param name = "pGrid">
    /// The grid that the styles are applied on.
    ///</param>
    ///<returns>
    /// Returns the pointer to the new created GridColorThemeHandler.
    /// Caller must be responsible to release it.
    /// Returns NULL if the handlers fail to initialize.
    ///</returns>
    static GridColorThemeHandler* CreateThemeHandler(const MdfModel::RuleCollection *pRules, const GridData *pGrid);

    ///<summary>
    /// Function to create the GridColorNullHandler.
    ///</summary>
    ///<param name = "pRules">
    /// The rules includes the detail info.
    ///</param>
    ///<param name = "pGrid">
    /// The grid that the styles are applied on.
    ///</param>
    ///<returns>
    /// Returns the pointer to the new created GridColorNullHandler.
    /// Caller must be responsible to release it.
    /// Returns NULL if the handlers fail to initialize.
    ///</returns>
    static GridColorNullHandler* CreateNullHandler(const MdfModel::RuleCollection *pRules, const GridData *pGrid);
};

There are several derived classes of GridColorHandler:
GridColorBandsHandler is used to handle the situation when the GridColor's type is Bands. It gets the channel data from the three ChannelBands and merge them to a color value.
GridColorBandHandler is used to handle the situation when the GridColor's type is Band. It gets the band's value and return it as the color value.
GridColorNullHandler is used to handle the situation when there is no rule.
GridColorThemeHandler is used to handle the situtation when stylizer themes a band according to the aspect, slope, or height value.It calculates the geometry value and searchs the corresponding color in its generated hash table.

GridApplyStatusReporter

An implementation of GridStatusReporter. This class will delegate all the status change events to the stylizer's reactors.

class GridApplyStatusReporter : public GridStatusReporter
{
public:
    ///<summary>
    /// Initializes this class by the three arguments.
    ///</summary>
    ///<param name="stylizer">The the stylizer which is applying style.</param>
    ///<param name="pixelCount">The count of the total pixels of the grid.</param>
    void            Init(GridStylizer *stylizer, double pixelCount);

    ///<summary>
    /// Indicates the transaction has been started.
    /// This class will notify the stylizer's reactors that
    /// the stylizer begins to apply the styles.
    ///</summary>
    virtual void     Begin();

    ///<summary>
    /// Indicates the transaction has been finished successfully.
    /// This class will notify the stylizer's reactors that
    /// the stylizer has finished applying styles.
    ///</summary>
    virtual void     Commit();

    ///<summary>
    /// Indicates the transaction encountered some error and has been terminated.
    /// This class will notify the stylizer's reactors that
    /// the stylizer failed to apply styles for some unknown reasons.
    ///</summary>
    virtual void     Rollback();

    ///<summary>
    /// Call this function when finishing a step.
    /// And check the returned value.
    /// If the returned value is true, that means the Step() function has been handled successfully.
    /// Otherwise, false means encountering some exceptions.
    ///</summary>
    virtual bool     Step(int stepSize = 1);

    ///<summary>
    /// If isTerminate is TRUE, then Step() will return FALSE to let the stylizer stop applying.
    /// It just sets a flag. And the flag will show its influence when 
    /// calling Step() next time.
    ///</summary>
    void             SetTerminate(bool isTerminate);

    ///<summary>
    /// Returns m_isTerminate.
    ///</summary>
    bool             IsTerminate() const;
}

Some new classes will be introduced to handle Band, Color, ChannelBand, Theme and etc individually.

Implications

This RFC does not describe any GUI modifications and does not affect the existed published API.

Test Plan

Add some elevation data,such as DEM/TIFF file and layer definition with surface style,like

<LayerDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:noNamespaceSchemaLocation="LayerDefinition-1.0.0.xsd" version="1.0.0">
<GridLayerDefinition>  
  <ResourceId>Library://Publish/Data/Raster_1.FeatureSource</ResourceId> 
  <FeatureName>rasters:davenport</FeatureName> 
  <Geometry>Image</Geometry> 
  <GridScaleRange>
    <SurfaceStyle>
      <Band>1</Band> 
      <DefaultColor>0000FF00</DefaultColor> 
    </SurfaceStyle>
    <ColorStyle>
      <HillShade>
        <Band>1</Band> 
        <Azimuth>45</Azimuth> 
        <Altitude>45</Altitude> 
      </HillShade>
      <ColorRule>
        <LegendLabel>-1.79e+308 to 1.79e+308</LegendLabel> 
        <Filter>(Height(1) > -1.7976931348623158e+308) AND (Height(1) < 1.7976931348623158e+308)</Filter> 
        <Color>
          <ExplicitColor>FF00FF00</ExplicitColor> 
        </Color>
      </ColorRule>
      <ColorRule>
        <LegendLabel>{DEFAULT}</LegendLabel> 
        <Color>
          <ExplicitColor>FF006423</ExplicitColor> 
        </Color>
      </ColorRule>
    </ColorStyle>
    <RebuildFactor>1</RebuildFactor> 
  </GridScaleRange>
</GridLayerDefinition>

to a MapGuide server, the elevation layer should display, like Figure1 in MapGuide studio.

Funding/Resources?

Supplied by Autodesk.

Last modified 10 years ago Last modified on Sep 6, 2007 10:47:19 AM

Attachments (2)

Download all attachments as: .zip