Jump to content

[SOLVED] Problem modifying Images with engine.filesystem


photo

Recommended Posts

Hi guys,

 

I have some problems to unterstand working with the engine.filesystem-functions and modifying images in realtime. What I want to do is to create an empty black image, draw a 2D-Polygon in white with Bresenham'S line algorithm, and flood-fill the polygon with white two.

Drawing the lines seems to be fine. Next, I checked every pixel in my polygon if it is black, and if so, I want to turn it into white.

 

Using image.set2D(x,y,vec4(1,1,1,1)) and checked the the color of the pixel right after that, I get a black one. If I saved the image in an extern file and opened it, the white lines were drawed as expected.

I remembered one of my old topic, and frustum wrote, I have to use the engine.filesystem.addBufferFile() to store my image into the memory. After some digging through the docs and trying a little bit, that solution won't work for me. I tried the following lines:

	string MaskImageName = "BladeFieldMask.dds";
	
	if(engine.filesystem.addBufferFile("BladeFieldMask.dds"))
		log.message("Image successfully buffered!");

	Image MaskImageForObject = new Image();
	log.message("New image constructed!");

	if(MaskImageForObject.create2D(512,512,IMAGE_FORMAT_RGBA8,,,))
		log.message("Image successfully created!");
	if (MaskImageForObject.save("BladeFieldMask.dds"))
		log.message("Image from Buffer saved!");

	//do some modifications here

Can anybody help me with that, and maybe add some piece of code that will show me some basics about how modifying images at runtime worked.

 

PS: I only want to change the image once a time (at the beginning of creating a custom ObjectGrass-mask).

Link to comment
  • 1 month later...

Maybe your code for floodfilling is wrong (as you can see the white lines fter file save, but not the the filled area, as far as I understand). The following code example is working for me

 

 

    Image renderCountryColorTexture( string textureFile, Image imageIndex )
    {
        // render country texture
        Image image = new Image();

        int width  = imageIndex.getWidth();
        int height = imageIndex.getHeight();
        
        image.create2D( width, height, IMAGE_FORMAT_RGBA8, 1, 0 );
        image.set( 0, 0 );
        image.set( 1, 0 );
        image.set( 2, 0 );
        image.set( 3, 0 );

        log.message( "Rendering country color texture '%s' (%dx%d)\n", textureFile, width, height );

        for( int y=0; y<height; y++ )
        {
            for( int x=0; x<width; x++ )
            {
                int indexCountry = getCountryIndex( imageIndex, x, y );
                
                if( indexCountry == -1 )    
                {
                    // transparent background
                    image.set2D( x, y, vec4(0.0f,0.0f,0.0f,0.0f) );
                }
                else
                {
                    // get country color
                    Country country = m_countries.get( indexCountry );
                
                    image.set2D( x, y, m_colorTable[ country.border.color ] );
                }
            }
        }
        
        image.compress();
        image.save( textureFile );
        
        return image;
    }
Link to comment

BTW using foodfill algorithm might be both slow and error prone (depending on you polygon geometry, if it contain e.g. hole or not). Find afterwards some working code for some more efficient 2D polygon rasterization (scan line algorithm). In my case the polygon vertex x/y coordiantes are actually geographic longitude/latitude values (because I am working with georeferenced data e.g. country polygons), but it should be quite easy to adopt it to your requirements.

 

Code for Region/Position not included, but these classes only define min/maxLongitiude/Latitiude (Region) and longitude/latitude (Position)

 

The core rasterization code is in class Polygon, while AreaPolygon uses Polygon for defining a list of polygon defining the outer edge of the polygon region and some inside holes. All edged polygons will be rendered first to the image with the foreground color, and than any hole polygon will be rendered "above" this image with the background color (0,0,0). 

 

Also some isInside() testing code is include which is often required. Maybe this code example is also helpful for your use case.

#ifndef __AREA_H__
#define __AREA_H__

#include <rde/scripts/base/globe.h>
#include <rde/scripts/base/region.h>


///////////////////////////////////////////////////////////////////////////////

// area types
enum {  AREA_REGION,
        AREA_RADIAL,
        AREA_POLYGON
     };

     
///////////////////////////////////////////////////////////////////////////////

/**
 *  Area base class
 */
class Area
{
    int     m_type;
    Region  m_region;
    
    
    /**
     *  Constrctur
     */
    Area( int type )
    {
        m_type   = type;
        m_region = new Region();
    }
    
    /**
     *  Get area type
     */
    int getType()
    {
        return m_type;
    }

    /**
     *  Get area type
     */
    string getTypeString()
    {
        switch( getType() )
        {
        case AREA_REGION:   return "AREA_REGION";
        case AREA_RADIAL:   return "AREA_RADIAL";
        case AREA_POLYGON:  return "AREA_POLYGON";
        default:            return "UNKNOWN";
        }
    }

    /**
     *  Get area maximum region
     */
    Region  getRegion()
    {
        return m_region;
    }
    
    /**
     *  Clear area data
     */
    void clear()
    {
        m_region.setNull();
    }
    
    /**
     *    check if position is inside region
     *
     *    Remark    right/upper region border is exclusive
     */
    int isInside( Position position )
    {
        if( position.isNull() ) return 0;
        else                    return isInside( position.getLongitude(), position.getLatitude() );
    }
    
    /**
     *    check if position is inside region
     *
     *    Remark    right/upper region border is exclusive
     */
    int isInside( float longitudeDegrees, float latitudeDegrees )
    {
        return m_region.isInside( longitudeDegrees, latitudeDegrees );
    }
    
    /**
     *  load area from XML
     *
     *  @param xmlArea      XML area node
     */
    int loadXML( Xml xmlArea )
    {
        throw("Area::loadXML() must be implemented by inherited class !");
    }

    /**
     *  Save area to XML
     *
     *  @param xmlArea      XML area node
     */
    void saveXML( Xml xmlArea )
    {
        throw("Area::saveXML() must be implemented by inherited class !");
    }

    /**
     *  Write area to stream
     *
     *  @param  stream     binary stream
     */
    void write( Stream stream )
    {
        throw("Area::write() must be implemented by inherited class !");
    }

    /**
     *  Read area from stream
     *
     *  @param  stream     binary stream
     */
    void read( Stream stream )
    {
        throw("Area::write() must be implemented by inherited class !");
    }
    
};
     
     
///////////////////////////////////////////////////////////////////////////////

class AreaRegion : Area
{
    /**
     *  Constructor
     */
    AreaRegion() : Area( AREA_REGION )
    {
    }
    
    /**
     *  Constructor
     */
    AreaRegion( Region region ) : Area( AREA_REGION )
    {
        m_region.set( region );
    }

    /**
     *  load area from XML
     *
     *  @param xmlArea      XML area node
     */
    int loadXML( Xml xmlArea )
    {
        float longitudeMin = xmlArea.getFloatArg("longitudeMin");
        float latitudeMin  = xmlArea.getFloatArg("latitudeMin");

        float longitudeMax = xmlArea.getFloatArg("longitudeMax");
        float latitudeMax  = xmlArea.getFloatArg("latitudeMax");
        
        m_region.set( longitudeMin, latitudeMin, longitudeMax, latitudeMax );
        
        return 1;
    }

    /**
     *  Save area to XML
     *
     *  @param xmlArea      XML area node
     */
    void saveXML( Xml xmlArea )
    {
        xmlArea.setFloatArg("longitudeMin", m_region.getLongitudeMinDegrees() );
        xmlArea.setFloatArg("latitudeMin",  m_region.getLatitudeMinDegrees() );

        xmlArea.setFloatArg("longitudeMax", m_region.getLongitudeMaxDegrees() );
        xmlArea.setFloatArg("latitudeMax",  m_region.getLatitudeMaxDegrees() );
    }
    
    /**
     *  Write area to stream
     *
     *  @param  stream     binary stream
     */
    void write( Stream stream )
    {
        m_region.write( stream );
    }

    /**
     *  Read area from stream
     *
     *  @param  stream     binary stream
     */
    void read( Stream stream )
    {
        m_region.read( stream );
    }
    
};

          
///////////////////////////////////////////////////////////////////////////////

class AreaRadial : Area
{
    float   m_centerLongitude;
    float   m_centerLatitude;
    float   m_radiusDegrees;
    
    vec3    m_vectorCenter;
    float   m_angleRadiusCosine;


    /**
     *  Constructor
     */
    AreaRadial() : Area( AREA_RADIAL )
    {
    }
    
    /**
     *  Constructor
     */
    AreaRadial( Position center, float radiusDegrees ) : Area( AREA_RADIAL )
    {
        // radial data
        m_centerLongitude = center.getLongitude();
        m_centerLatitude  = center.getLatitude();
        m_radiusDegrees   = abs( radiusDegrees );

        updateData();
    }

    /**
     *  Clear area data
     */
    void clear()
    {
        Area::clear();

        m_centerLongitude = 0.0f;
        m_centerLatitude  = 0.0f;
        m_radiusDegrees   = 0.0f;
    }
    
    /**
     *  Update pre-calculated data after center/radius change
     */
    void updateData()
    {
        m_radiusDegrees = abs( m_radiusDegrees );
        
        // radial bounding region
        float cosLatitude = cos( DEG2RAD * m_centerLatitude );
        
        m_region.set( m_centerLongitude - m_radiusDegrees / cosLatitude,
                      m_centerLatitude  - m_radiusDegrees,
                      m_centerLongitude + m_radiusDegrees / cosLatitude,
                      m_centerLatitude  + m_radiusDegrees );
                                              
        // pre-calculate constant data used for inside testing
        m_vectorCenter = Globe::getNormal( m_centerLongitude, m_centerLatitude );
                                           
        m_angleRadiusCosine = cos( DEG2RAD * m_radiusDegrees );
    }
    
    /**
     *    check if position is inside region
     *
     *    Remark    right/upper region border is exclusive
     */
    int isInside( float longitudeDegrees, float latitudeDegrees )
    {
        if( m_region.isInside( longitudeDegrees, latitudeDegrees ) == 0 )     return 0;

        // Get cosine of angle between center and position unit vectors by
        // calculating vector dot product. Compare this value to the cosinus
        // of the area radius angle. If larger or equal the position is
        // located within radial area.
        vec3 vectorPosition = Globe::getNormal( longitudeDegrees, latitudeDegrees );
        
        float angleCosine = dot( m_vectorCenter, vectorPosition );

        return angleCosine >= m_angleRadiusCosine;
    }


    /**
     *  load area from XML
     *
     *  @param xmlArea      XML area node
     */
    int loadXML( Xml xmlArea )
    {
        clear();
        
        m_centerLongitude = xmlArea.getFloatArg("longitudeCenter");
        m_centerLatitude  = xmlArea.getFloatArg("latitudeCenter");
        m_radiusDegrees   = xmlArea.getFloatArg("radiusDegrees");

        updateData();
        
        return 1;
    }
   
    /**
     *  Save area to XML
     *
     *  @param xmlArea      XML area node
     */
    void saveXML( Xml xmlArea )
    {
        xmlArea.setFloatArg("longitudeCenter", m_centerLongitude );
        xmlArea.setFloatArg("latitudeCenter",  m_centerLatitude  );
        xmlArea.setFloatArg("radiusDegrees",   m_radiusDegrees   );
    }
    
    /**
     *  Write area to stream
     *
     *  @param  stream     binary stream
     */
    void write( Stream stream )
    {
        stream.writeFloat( m_centerLongitude );
        stream.writeFloat( m_centerLatitude  );
        stream.writeFloat( m_radiusDegrees   );
    }

    /**
     *  Read area from stream
     *
     *  @param  stream     binary stream
     */
    void read( Stream stream )
    {
        m_centerLongitude = stream.readFloat();
        m_centerLatitude  = stream.readFloat();
        m_radiusDegrees   = stream.readFloat();

        updateData();
    }
   
};
     
     
///////////////////////////////////////////////////////////////////////////////

/**
 *    Simple polygon
 *  
 *    Geographic polygon region defined by closed loop of longitude/latitude coordinates.
 */
class Polygon
{
    float    m_longitude[0];
    float    m_latitude[0];

    Region   m_region;
    
    class Edge
    {
        float   x ;     
        float   dxdy;
        int     ymin;
        int     ymax;
    };
    
    
    /**
     *    Constructor
     */
    Polygon()
    {
        m_region = new Region();
    }

    /**
     *  Get polygon region
     */
    int getRegion()
    {
        return m_region;
    }
    
    /**
     *  Clear polygon data
     */
    void clear()
    {
        m_longitude.clear();
        m_latitude .clear();
        
        m_region.setNull();
    }
    
    /**
     *    Check if coordinate is inside polygon region
     *
     *    @param longitudeDegrees        longitude value [-180...180]
     *    @param latitudeDegrees        latitude  value [-90...90]
     *
     *  @return 1: coordinate inside 0: coordinate outside polygon
     */
    int isInside( float longitudeDegrees, float latitudeDegrees )
    {
        if( m_region.isInside( longitudeDegrees, latitudeDegrees ) == 0 )    return 0;
        
        int inside = false;
        
        int vertices = m_longitude.size();

        float x = longitudeDegrees;
        float y = latitudeDegrees;
        
        float x2 = m_longitude[ 0 ];
        float y2 = m_latitude [ 0 ];

        float x1, y1;
        
        for( int i=1; i<vertices; i++ )
        {
            x1 = m_longitude[i];
            y1 = m_latitude[i];
            
            if( ( (y1 <  y) && (y2 >= y) ) || ( (y1 >= y) && (y2 <  y) ) )
            {
                if( ( (y - y1) / (y2 - y1) * (x2 - x1) ) < (x - x1) )
                {
                    inside = !inside;
                }
            }
            
            x2 = x1;
            y2 = y1;
        }
        
        return inside;
    }

    /**
     *  Update polygon coordinates from float array. Coordinates are
     *  in lon1, lat1, lon2, lat2, ... sequence.
     *
     *  @param  values     coordinates array
     *
     *  @return 0:  failure     1: success
     */
    int updateData( float values[] )
    {
        if( ( values.size() % 2 ) != 0 )
        {
            log.error("Polygon::updateData(): odd coordinates count !\n");
            return 0;
        }
        
        m_region.setNull();
        
        int count = values.size() / 2;
        
        m_longitude.resize( count );
        m_latitude .resize( count );
        
        for( int i=0; i<values.size(); i+=2 )
        {
            float longitude = values[ i + 0 ];
            float latitude  = values[ i + 1 ];
            
            m_region.add( longitude, latitude );
            
            int index = i / 2;
            
            m_longitude[ index ] = longitude;
            m_latitude [ index ] = latitude;
        }

        // ensure closed polygon loop
        int index = m_longitude.size() - 1;
        
        if( m_longitude[ 0 ] != m_longitude[ index ] ||
            m_latitude [ 0 ] != m_latitude [ index ] )
        {
            m_longitude.append( m_longitude[0] );
            m_latitude .append( m_latitude [0] );
        }
        
        return 1;
    }
        
    
    /**
     *  Parse polygon coordinates from KML <LinearRing> xml node
     *
     *  @param  kmlLinearRing     KML <LinearRing> xml root node
     *
     *  @return 0:  failure     1: success
     */
    int parseKML( Xml kmlLinearRing )
    {
        clear();
        
        if( kmlLinearRing.getName() != "LinearRing" )    return 0;
                
        Xml kmlCoordinates = kmlLinearRing.find("coordinates");
        
        if( kmlCoordinates == NULL )
        {
            log.error("Polygon::parseKML(): missing 'coordinates' element !\n");
            return 0;
        }

        float    values[0];
        
        if( kmlCoordinates.getFloatArrayData( values ) == 0 )
        {
            log.error("Polygon::parseKML(): could not parse float data\n");
            return 0;
        }

        updateData( values );
        
        return m_longitude.size();
    }

    /**
     *  load area from XML
     *
     *  @param xmlPolygon      XML polygon node
     */
    int loadXML( Xml xmlPolygon )
    {
        clear();
        
        Xml xmlCoordinates = xmlPolygon.find("Coordinates");
        
        if( xmlCoordinates == NULL )
        {
            log.error("Polygon::loadXML(): missing 'Coordinates' element !\n");
            return 0;
        }
        
        float    values[0];
        
        if( xmlCoordinates.getFloatArrayData( values ) == 0 )
        {
            log.error("Polygon::loadXML(): could not parse float data\n");
            return 0;
        }

        return updateData( values );
    }

    /**
     *  Save area to XML
     *
     *  @param xmlArea      XML area node
     */
    void saveXML( Xml xmlPolygon )
    {
        Xml xmlCoordinates = xmlPolygon.addChild("Coordinates");
        
        float    values[0];

        for( int i=0; i<m_longitude.size(); i++ )
        {
            values.append( m_longitude[i] );
            values.append( m_latitude[i]  );
        }
        
        xmlCoordinates.setFloatArrayData( values );
    }
    
    /**
     *  Write polygon to stream
     *
     *  @param  stream     binary stream
     */
    void write( Stream stream )
    {
        m_region.write( stream );
        
        stream.writeInt( m_longitude.size() );
        
        for( int i=0; i<m_longitude.size(); i++ )
        {
            stream.writeFloat( m_longitude[i] );
            stream.writeFloat( m_latitude[i]  );
        }
    }

    /**
     *  Read polygon from stream
     *
     *  @param  stream     binary stream
     */
    void read( Stream stream )
    {
        m_region.read( stream );

        int count = stream.readInt();
        
        m_longitude.resize( count );
        m_latitude .resize( count );
        
        for( int i=0; i<count; i++ )
        {
            m_longitude[i] = stream.readFloat();
            m_latitude[i]  = stream.readFloat();
        }
    }

    /**
     *  Render polygon to texture image
     *
     *  @param  region  image region
     *  @param  image   image texture
     *  @paral  color   polygon color
     */
    void render( Region region, Image image, vec4 color )
    {
        int width  = image.getWidth();
        int height = image.getHeight();
        
        // transform coordinates
        int count = m_longitude.size();
        
        int x[ count ];
        int y[ count ];
        
        int index = 0;
        
        for( int i=0; i<count; i++ )
        {
            x[ index ] = int( width  * ( m_longitude[i] - region.getLongitudeMinDegrees() ) / region.getLongitudeDeltaDegrees() );
            y[ index ] = int( height * ( region.getLatitudeMaxDegrees() - m_latitude[i]   ) / region.getLatitudeDeltaDegrees()  );
            
            // skip points with same coordinate as previous point
            if( index > 0 )
            {
                if( x[ index ] != x[ index-1 ] || y[ index ] != y[ index-1 ] )
                {
                    // different coordinate, so keep it
                    index++;
                }
            }
            else
            {
                // always keep first coordinte
                index++;
            }
        }

        count = index;
        
        if( count < 3 ) return;
        
        // build edge table
        Edge    edges[0];

        for( int i=0; i<count-1; i++ )
        {
            if( y[i] == y[i+1] )    continue; // skip horizontal lines
            
            Edge edge = new Edge();
            
            if( y[i+1] > y[i] )
            {
                edge.x      = x[i];     
                edge.dxdy   = float( x[i+1] - x[i] ) / float( y[i+1] - y[i] );
                edge.ymin   = y[i];
                edge.ymax   = y[i+1];
            }
            else
            {
                edge.x      = x[i+1];     
                edge.dxdy   = float( x[i] - x[i+1] ) / float( y[i] - y[i+1] );
                edge.ymin   = y[i+1];
                edge.ymax   = y[i];
            }
            
            edges.append( edge );
        }
 
        count = edges.size();
        
        if( count < 2 ) return;
        
        // scanline rasterization
        int     activeEdgesX[0];
        Edge    activeEdges[0];
        
        for( int yp=0; yp<height; yp++ )
        {
            // add new active edges
            for( int i=0; i<count; i++ )
            {
                if( yp == edges[i].ymin )
                {
                    // add to active edge list
                    activeEdgesX.append( edges[i].x );
                    activeEdges .append( edges[i]   );
                }
            }

            // remove inactive edges
            int i = 0;
            
            while( i < activeEdges.size() )
            {
                if( yp >= activeEdges[i].ymax )
                {
                    activeEdgesX.remove(i);
                    activeEdges .remove(i);
                }
                else
                {
                    i++;
                }
            }
            
            activeEdgesX.sort( activeEdges );
            
            // scanline fill of active edges
            for( int i=0; i<activeEdges.size(); i+=2 )
            {
                int xl = int( activeEdges[i]  .x );
                int xr = int( activeEdges[i+1].x );
                
                for( int xp=xl; xp<xr; xp++ )
                {
                    image.set2D( xp, yp, color );
                }
                
                activeEdges[i  ].x += activeEdges[i  ].dxdy;
                activeEdges[i+1].x += activeEdges[i+1].dxdy;
            }
        }
    }
    
};


/*
 *  Polygon area
 *
 *  A polygonal area defined by multiple polygons defining one or more outer
 *  border polygons and optional polygon holes (e.g. exclusion of vatican
 *  area from italian main land polygon)  
 */
class AreaPolygon : Area
{
    Polygon     m_polygons_include[0];    // area outer borders
    Polygon     m_polygons_exclude[0];    // area inner holes


    /**
     *    Constructor
     */
    AreaPolygon() : Area( AREA_POLYGON )
    {
    }

    /**
     *  Clear area data
     */
    void clear()
    {
        Area::clear();
        
        m_polygons_include.clear();
        m_polygons_exclude.clear();
    }
    
    /**
     *    Check if coordinate is inside polygon region
     *
     *    @param longitudeDegrees        longitude value [-180...180]
     *    @param latitudeDegrees        latitude  value [-90...90]
     *
     *  @return 1: coordinate inside 0: coordinate outside polygon
     */
    int isInside( float longitudeDegrees, float latitudeDegrees )
    {
        if( m_region.isInside( longitudeDegrees, latitudeDegrees ) == 0 )    return 0;
        
        foreach( Polygon polygon; m_polygons_exclude )
        {
            if( polygon.isInside( longitudeDegrees, latitudeDegrees ) == 1 )    return 0;
        }
        
        int inside = 0;
        
        foreach( Polygon polygon; m_polygons_include )
        {
            if( polygon.isInside( longitudeDegrees, latitudeDegrees ) == 1 )
            {
                inside = 1; break;
            }
        }
        
        return inside;
    }
    
    /**
     *  Render polygon area to texture image
     */
    void renderPolygon( Region region, Image image, vec4 colorForeground, vec4 colorBackground )
    {
        foreach( Polygon polygon; m_polygons_include )
        {
            polygon.render( region, image, colorForeground );
        }

        foreach( Polygon polygon; m_polygons_exclude )
        {
            polygon.render( region, image, colorBackground );
        }
    }
    
    /**
     *  Parse one or more area polygons from KML <MultiGeometry> or <Polygon> node xml
     *
     *  @return 0:  failure     1: success
     */
    int parseKML( Xml kml )
    {
        Xml multigeometry = kml.find("MultiGeometry");
            
        if( multigeometry != NULL )
        {
            for( int j=0; j<multigeometry.getNumChilds(); j++ )
            {
                Xml kmlPolygon = multigeometry.getChild(j);
        
                if( kmlPolygon.getName() != "Polygon" )    continue;
                
                parsePolygonKML( kmlPolygon );
            }
        }
        else
        {
            Xml kmlPolygon = kml.find("Polygon");

            if( kmlPolygon != NULL )   
            {
                parsePolygonKML( kmlPolygon );
            }
        }

        return m_polygons_include.size() > 0;
    }


    /**
     *  Parse polygon data from KML <Polygon> node xml
     */
    void parsePolygonKML( Xml kmlPolygon )
    {
        if( kmlPolygon.getName() != "Polygon" )    return 0;
                
        for( int i=0; i<kmlPolygon.getNumChilds(); i++ )
        {
            Xml kmlChild = kmlPolygon.getChild(i);

            int outer = -1;
            
            if     ( kmlChild.getName() == "outerBoundaryIs" )    outer = 1;
            else if( kmlChild.getName() == "innerBoundaryIs" )    outer = 0;
            else                                                  continue;

            Xml kmlLinearRing = kmlChild.find("LinearRing");

            if( kmlLinearRing == NULL )
            {
                log.error("Could not find KML polygon linear ring element !\n");
                continue;
            }
            
            Polygon polygon = new Polygon();
            
            if( polygon.parseKML( kmlLinearRing ) != 0 )
            {
                if( outer )     m_polygons_include.append( polygon );
                else            m_polygons_exclude.append( polygon );
                
                Region region = polygon.getRegion();
                
                m_region.add( region.getLongitudeMinDegrees(), region.getLatitudeMinDegrees() );
                m_region.add( region.getLongitudeMaxDegrees(), region.getLatitudeMaxDegrees() );
            }
            else
            {
                log.error("Could not parse KML polygon linear ring data !\n");
            }
        }
    }

    /**
     *  load area from XML
     *
     *  @param xmlArea      XML area node
     */
    int loadXML( Xml xmlArea )
    {
        for( int i=0; i<xmlArea.getNumChilds(); i++ )
        {
            Xml xmlPolygon = xmlArea.getChild(i);
         
            if( xmlPolygon.getName() != "Polygon" )    continue;
            
            Polygon polygon = new Polygon();
            
            if( polygon.loadXML( xmlPolygon ) == 0 )
            {
                log.error("AreaPolygon::loadXML(): failed to load polygon %d !\n", i );
                return 0;
            }
            
            int hole;
            
            if( xmlPolygon.isArg("hole") )      hole = xmlPolygon.getBoolArg("hole");
            else                                hole = 0;
            
            if( hole == 0 )     m_polygons_include.append( polygon );
            else                m_polygons_exclude.append( polygon );    
        }    
        
        return 1;
    }
    
    /**
     *  Save area to XML
     *
     *  @param xmlArea      XML area node
     */
    void saveXML( Xml xmlArea )
    {
        for( int i=0; i<m_polygons_include.size(); i++ )
        {
            Xml xmlPolygon = xmlArea.addChild("Polygon");
            
            m_polygons_include[i].saveXML( xmlPolygon );
        }
        
        for( int i=0; i<m_polygons_exclude.size(); i++ )
        {
            Xml xmlPolygon = xmlArea.addChild("Polygon", "hole=true" );
            
            m_polygons_exclude[i].saveXML( xmlPolygon );
        }
    }
    
    /**
     *  Write area to stream
     *
     *  @param  stream     binary stream
     */
    void write( Stream stream )
    {
        m_region.write( stream );
        
        stream.writeInt( m_polygons_include.size() );
        
        foreach( Polygon polygon; m_polygons_include )
        {
            polygon.write( stream );
        }
        
        stream.writeInt( m_polygons_exclude.size() );
        
        foreach( Polygon polygon; m_polygons_exclude )
        {
            polygon.write( stream );
        }
    }

    /**
     *  Read area from stream
     *
     *  @param  stream     binary stream
     */
    void read( Stream stream )
    {
        clear();
        
        m_region.read( stream );

        int countInclude = stream.readInt();
        
        for( int i=0; i<countInclude; i++ )
        {
            Polygon polygon = new Polygon();
            
            polygon.read( stream );
            
            m_polygons_include.append( polygon );
        }

        int countExclude = stream.readInt();
        
        for( int i=0; i<countExclude; i++ )
        {
            Polygon polygon = new Polygon();
            
            polygon.read( stream );
            
            m_polygons_exclude.append( polygon );
        }
    }
    
};

///////////////////////////////////////////////////////////////////////////////

/**
 *  Global Arean singleton creation
 */
namespace Area
{
    // Area instance factory method
    Area create( string type )
    {
        if     ( type == "REGION"  )        return new AreaRegion();
        else if( type == "RADIAL"  )        return new AreaRadial();
        else if( type == "POLYGON" )        return new AreaPolygon();
        else                                return NULL;
    }
}


#endif /* __AREA_H__ */
 
Link to comment

Hi Ulf,

 

thanks for the quick and detailed reply. I used the floodfill-algorithm as an quick and dirty way to insert the function to see, if the idea worked or not.

The following function are used in my case:

void FloodFill(Image ℑ, int x, int y, vec4 oldColor, vec4 newColor)
	{
		//Start-Pixel have the new color. Abort!
		if (image.get2D(x,y) == newColor)
			return;

		Coordinate EmptyPixel[0];
		EmptyPixel.append(new Coordinate(x,y));

		while (EmptyPixel.size())
		{
			Coordinate curCor = EmptyPixel[0];
			image.set2D(curCor.GetX(),curCor.GetY(),newColor);
			log.message("Fill Pixel (%d;%d) with color: %s\n",curCor.GetX(),curCor.GetY(),typeinfo(image.get2D(curCor.GetX(),curCor.GetY())));
			
			if (image.get2D(curCor.GetX(),curCor.GetY() + 1) == oldColor)
				EmptyPixel.append(new Coordinate(curCor.GetX(),curCor.GetY() + 1));
			if (image.get2D(curCor.GetX(),curCor.GetY() - 1) == oldColor)
				EmptyPixel.append(new Coordinate(curCor.GetX(),curCor.GetY() - 1));
			if (image.get2D(curCor.GetX() + 1,curCor.GetY()) == oldColor)
				EmptyPixel.append(new Coordinate(curCor.GetX() + 1,curCor.GetY()));
			if (image.get2D(curCor.GetX() - 1,curCor.GetY()) == oldColor)
				EmptyPixel.append(new Coordinate(curCor.GetX() - 1,curCor.GetY()));

			EmptyPixel.remove(0);
			delete curCor;
		}
	}

Coordinate is a class that only stores the X and Y-values.

My problem is, that I set a pixel into my image with a new color and right after that I checked it with the message-function. The result is, that this pixel has the same color as before.

Link to comment
  • 1 month later...
×
×
  • Create New...