bool FeatureConnector::storeBinaryDataPolygon(FeatureCoverage *fcov, const QString& baseName) {
    QString filename = baseName + ".mpz#";

    std::ofstream output_file(filename.toLatin1(),ios_base::out | ios_base::binary | ios_base::trunc);
    if ( !output_file.is_open())
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,filename);
    IFeatureCoverage cov;
    cov.set(fcov);
    FeatureIterator iter(cov);
    double raw = 1;
    for_each(iter, iter.end(), [&](SPFeatureI feature){
        const Geometry& geom = feature->geometry();
        for(int i=0; i < feature->trackSize(); ++i) {
            if ( geom.ilwisType() == itPOLYGON) {
                Polygon pol = geom.toType<Polygon>();
                writeCoords(output_file, pol.outer());
                output_file.write((char *)&raw,8);
                quint32 holeCount = pol.inners().size();
                output_file.write((char *)&holeCount,4);
                for(const std::vector<Coordinate2d>& coords : pol.inners() ) {
                    writeCoords(output_file, coords);
                }
                ++raw;
            }
        }

    });

    output_file.close();

    return true;
}
QString IlwisObjectModel::valuetype() const
{
    try{
        if ( !_ilwisobject.isValid())
            return "";

        IlwisTypes objectype = _ilwisobject->ilwisType();
        IlwisTypes valueType = itUNKNOWN;
        if ( hasType( objectype, itCOVERAGE|itDOMAIN)){
            if ( objectype == itRASTER){
                IRasterCoverage raster = _ilwisobject.as<RasterCoverage>();
                valueType = raster->datadef().domain()->valueType();
            } else if ( hasType( objectype , itFEATURE)){
                IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
                ColumnDefinition coldef = features->attributeDefinitions().columndefinition(COVERAGEKEYCOLUMN);
                if ( coldef.isValid()){
                    valueType = coldef.datadef().domain()->valueType();
                }

            } else if ( hasType( objectype , itDOMAIN)){
                IDomain dom = _ilwisobject.as<Domain>();
                valueType = dom->valueType();

            }
        }
        QString typeName =  TypeHelper::type2HumanReadable(valueType);

        return typeName == sUNDEF ? "" : typeName;
    }catch(const ErrorObject& ){
        // no exceptions may escape here
    }
    return "";
}
bool FeatureConnector::storeBinaryDataPoints(FeatureCoverage *fcov, const QString& baseName) {
    std::ofstream output_file;
    QString filename = baseName + ".pt#";
    output_file.open(filename.toLatin1(),ios_base::out | ios_base::binary | ios_base::trunc);
    if ( !output_file.is_open())
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,baseName);
    char header[128];
    memset(header, 0, 128);
    output_file.write(header,128);

    IFeatureCoverage cov;
    cov.set(fcov);
    FeatureIterator iter(cov);
    double raw = 1;

    for_each(iter, iter.end(), [&](SPFeatureI feature){
        storePoint(feature->geometry(), fcov,output_file,raw);
        auto indexes = fcov->attributeDefinitions().indexes();
        for(auto index : indexes) {
            auto subfeature = feature[index];
            if (!subfeature.get()) {
                continue;
            }
            storePoint(subfeature->geometry(), fcov,output_file,raw);

        }
        return true;
    });

    output_file.close();

    return true;
}
void IlwisObjectModel::resetAttributeModel(const QString& attributeName){

    auto setAttributeModel = [&](int i, const ColumnDefinition& coldef, const QString& attributeName){
        if ( coldef.name() == attributeName){
            AttributeModel *attribute = new AttributeModel(coldef, this, _ilwisobject);
            _attributes[i] = attribute;
        }
    };

    IlwisTypes objecttype = _ilwisobject->ilwisType();
    if ( objecttype == itRASTER){
        IRasterCoverage raster = _ilwisobject.as<RasterCoverage>();
        if ( raster->hasAttributes()){
            for(int i = 0; i < raster->attributeTable()->columnCount(); ++i){
                setAttributeModel(i,raster->attributeTable()->columndefinition(i), attributeName);
            }
        }
    } else if ( hasType(objecttype,itFEATURE)){
        IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
        for(int i = 0; i < features->attributeDefinitions().definitionCount(); ++i){
            setAttributeModel(i,features->attributeTable()->columndefinition(i), attributeName);
        }
    } else if ( hasType(objecttype,itTABLE)){
        ITable tbl = _ilwisobject.as<Table>();
        for(int i = 0; i < tbl->columnCount(); ++i){
            setAttributeModel(i,tbl->columndefinition(i),attributeName);
        }
    }

}
bool Assignment::assignFeatureCoverage(ExecutionContext *ctx) {

    IFeatureCoverage outputFC = _outputObj.get<FeatureCoverage>();
    IFeatureCoverage inputFC = _inputObj.get<FeatureCoverage>();
    FeatureIterator iterIn(inputFC);
    for_each(iterIn, iterIn.end(), [&](SPFeatureI feature) {
        outputFC->newFeatureFrom(feature);
    });

    return true;
}
QString IlwisObjectModel::rangeDefinition(bool defaultRange, bool calc, const QString& columnName) {
    try {
        IlwisTypes objectype = _ilwisobject->ilwisType();
        QString rangeString;
        if ( hasType( objectype, itCOVERAGE|itDOMAIN)){
            if ( objectype == itRASTER){
                IRasterCoverage raster = _ilwisobject.as<RasterCoverage>();
                if ( defaultRange){
                  rangeString = raster->datadef().domain()->range()->toString();
                }else{
                    if ( calc){
                        raster->loadData();
                        raster->statistics(NumericStatistics::pBASIC);
                    }
                  rangeString = raster->datadef().range()->toString();
                }
            } else if ( hasType( objectype , itFEATURE)){
                IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
                ColumnDefinition coldef = features->attributeDefinitions().columndefinition(COVERAGEKEYCOLUMN);
                if ( coldef.isValid()){
                    if ( defaultRange)
                      rangeString =  coldef.datadef().domain()->range()->toString();
                    else{
                        if ( calc){
                            features->loadData();
                            std::vector<QVariant> data = features->attributeTable()->column(columnName);
                            if ( data.size() != 0){
                                std::vector<double> values(data.size());
                                int  i=0;
                                for(auto v : data)
                                    values[i++] = v.toDouble();
                                NumericStatistics stats; // realy like to do this with a template specialization of the proper calculate function, but the syntax was unclear to me
                                stats.calculate(values.begin(), values.end());
                                NumericRange *rng = new NumericRange(stats.prop(NumericStatistics::pMIN),stats.prop(NumericStatistics::pMAX));
                                features->attributeDefinitionsRef().columndefinitionRef(columnName).datadef().range(rng);
                            }
                        }
                        rangeString = coldef.datadef().range()->toString();
                    }
                }

            } else if ( hasType( objectype , itDOMAIN)){
                rangeString = _ilwisobject.as<Domain>()->range()->toString();
            }
        }
        return rangeString;
    }catch(const ErrorObject& ){
        // no exceptions may escape here
    }
    return "";

}
void FeatureLayerDrawer::setActiveVisualAttribute(const QString &attr)
{
    IFeatureCoverage features = coverage().as<FeatureCoverage>();
    if ( features.isValid())    {
        if ( features->attributeDefinitions().columnIndex(attr) != iUNDEF){

            IRepresentation newrpr = Representation::defaultRepresentation(features->attributeDefinitions().columndefinition(attr).datadef().domain());
            if ( newrpr.isValid()){
                LayerDrawer::setActiveVisualAttribute(attr);
            }
        }
    }
}
void FeatureLayerDrawer::resetVisualProperty(const QString& propertyName, const IRepresentation& rpr){
   IFeatureCoverage features = coverage().as<FeatureCoverage>();
    for(int i = 0; i < features->attributeDefinitions().definitionCount(); ++i){
        const ColumnDefinition& coldef = features->attributeDefinitions().columndefinitionRef(i);
        if ( coldef.name() == propertyName){
            IlwisTypes attrType = coldef.datadef().domain()->ilwisType();
            if ( hasType(attrType, itNUMERICDOMAIN | itITEMDOMAIN | itTEXTDOMAIN)){
                VisualAttribute props = createVisualProperty(coldef, i, rpr);
                visualProperty(coldef.name(), props);
                break;
            }
        }
    }
}
bool GdalFeatureConnector::store(IlwisObject *obj, const IOOptions&   )
{

    if (!loadDriver())
        return false;

    IFeatureCoverage coverage;
    coverage.set(static_cast<FeatureCoverage *>(obj));

    std::vector<SourceHandles> datasources(3);
    std::vector<bool> validAttributes;
    if(!setDataSourceAndLayers(coverage, datasources, validAttributes))
        return false;

    std::vector<ColumnDefinition> defs;
    for(int i=0; i < coverage->attributeTable()->columnCount(); ++i){
        defs.push_back(coverage->attributeTable()->columndefinition(i));
    }

    FeatureIterator fiter(coverage);
    FeatureIterator endIter = end(coverage);
    for(; fiter != endIter; ++fiter) {
        SPFeatureI feature = *fiter;
        IlwisTypes geomType = feature->geometryType();
        if ( geomType != 0){
            OGRLayerH lyr = datasources[ilwisType2Index(geomType)]._layers[0];
            OGRFeatureH hfeature = gdal()->createFeature(gdal()->getLayerDef(lyr));
            if (hfeature) {
                setAttributes(hfeature, feature, validAttributes, defs);
                const geos::geom::Geometry* geometry = feature->geometry().get();
                if (gdal()->setGeometryDirectly(hfeature,createFeature(geometry)) != OGRERR_NONE)
                    ERROR2(ERR_COULD_NOT_ALLOCATE_2, TR("geometry"), _filename.toString());
                if (gdal()->addFeature2Layer(lyr, hfeature) != OGRERR_NONE) {
                    ERROR2(ERR_COULD_NOT_ALLOCATE_2, TR("feature"), _filename.toString());
                }
                gdal()->destroyFeature(hfeature);
            };
        }
    }
    for(auto& datasource : datasources){
        if ( datasource._source != 0)
            gdal()->destroyDataSource(datasource._source);
    }

    return true;

}
SPFeatureI &FeatureCoverage::newFeature(const Geometry& geom) {
    Locker lock(_mutex);
    _featureTypes |= geom.ilwisType();
    if ( _featureFactory == 0) {
        _featureFactory = kernel()->factory<FeatureFactory>("FeatureFactory","ilwis");
    }
    _record.reset(new AttributeRecord(attributeTable(),FEATUREIDCOLUMN ));

    CreateFeature create = _featureFactory->getCreator("feature");
    IFeatureCoverage fcoverage;
    fcoverage.set(this);
    FeatureInterface *f = create(this);
    f->set(geom);
    SPFeatureI p(f);
    _features.push_back(p);
    return _features.back();
}
void FeatureLayerDrawer::coverage(const ICoverage &cov)
{
    LayerDrawer::coverage(cov);
    setActiveVisualAttribute(sUNDEF);
    IFeatureCoverage features = coverage().as<FeatureCoverage>();

    for(int i = 0; i < features->attributeDefinitions().definitionCount(); ++i){
        const ColumnDefinition& coldef = features->attributeDefinitions().columndefinitionRef(i);
        IlwisTypes attrType = coldef.datadef().domain()->ilwisType();
        if ( hasType(attrType, itNUMERICDOMAIN | itITEMDOMAIN | itTEXTDOMAIN)){
            VisualAttribute props = createVisualProperty(coldef, i);
            visualProperty(coldef.name(), props);
        }
    }
    // try to find a reasonable default for the activeattribute
    for(int i = 0; i < features->attributeDefinitions().definitionCount(); ++i){
        if ( activeAttribute() == sUNDEF){
            const ColumnDefinition& coldef = features->attributeDefinitions().columndefinitionRef(i);
            if ( features->attributeDefinitions().columnIndex(FEATUREVALUECOLUMN) != iUNDEF){
                setActiveVisualAttribute(FEATUREVALUECOLUMN);
            }else if ( features->attributeDefinitions().columnIndex(COVERAGEKEYCOLUMN) != iUNDEF){
                setActiveVisualAttribute(COVERAGEKEYCOLUMN);
            }
            else if ( hasType(coldef.datadef().domain()->ilwisType(), itNUMERICDOMAIN)){
                setActiveVisualAttribute(coldef.name());
            }
        }else
            break;
    }
}
bool FeatureConnector::storeBinaryDataLine(FeatureCoverage *fcov, const QString& baseName) {
    std::ofstream output_file;
    QFileInfo inf(baseName);
    QString dir = context()->workingCatalog()->location().toLocalFile();
    QString filename = dir + "/" + inf.baseName() + ".mps#";
    output_file.open(filename.toLatin1(),ios_base::out | ios_base::binary | ios_base::trunc);
    if ( !output_file.is_open())
        return ERROR1(ERR_COULD_NOT_OPEN_WRITING_1,filename);
    char header[128];
    memset(header, 0, 128);
    output_file.write(header,128);

    IFeatureCoverage cov;
    cov.set(fcov);
    FeatureIterator iter(cov);
    quint32 raw = 1;

    for_each(iter, iter.end(), [&](SPFeatureI feature){
        const Geometry& geom = feature->geometry();
        for(int i=0; i < feature->trackSize(); ++i) {
            if ( geom.ilwisType() == itLINE) {
                Line2D<Coordinate2d> line = geom.toType<Line2D<Coordinate2d>>();
                const Coordinate2d& crdmin = geom.envelope().min_corner();
                const Coordinate2d& crdmax = geom.envelope().max_corner();
                writeCoord(output_file, crdmin);
                writeCoord(output_file, crdmax);
                int noOfCoordsBytes = line.size() * 16;
                output_file.write((char *)&noOfCoordsBytes, 4);
                for(const Coordinate2d& crd: line) {
                    writeCoord(output_file, crd);
                }
                long deleted=1;
                output_file.write((char *)&deleted, 4);
                output_file.write((char *)&raw, 4);
                ++raw;
            }
        }

    });

    output_file.close();

    return true;
}
QQmlListProperty<AttributeModel> IlwisObjectModel::attributes()
{
    try {
        if ( _attributes.size() == 0){
            if ( _ilwisobject.isValid())    {
                IlwisTypes objecttype = _ilwisobject->ilwisType();
                if ( objecttype == itRASTER){
                    IRasterCoverage raster = _ilwisobject.as<RasterCoverage>();

                    if ( raster->hasAttributes()){
                        for(int i = 0; i < raster->attributeTable()->columnCount(); ++i){
                            AttributeModel *attribute = new AttributeModel(raster->attributeTable()->columndefinition(i), this, _ilwisobject);
                            _attributes.push_back(attribute);
                        }
                    }else {
                        AttributeModel *attribute = new AttributeModel(ColumnDefinition(PIXELVALUE, raster->datadef(),i64UNDEF), this, _ilwisobject);
                        _attributes.push_back(attribute);
                    }
                } else if ( hasType(objecttype,itFEATURE)){
                    IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
                    for(int i = 0; i < features->attributeDefinitions().definitionCount(); ++i){
                        AttributeModel *attribute = new AttributeModel(features->attributeDefinitions().columndefinition(i), this, _ilwisobject);
                        _attributes.push_back(attribute);
                    }
                } else if ( hasType(objecttype,itTABLE)){
                    ITable tbl = _ilwisobject.as<Table>();
                    for(int i = 0; i < tbl->columnCount(); ++i){
                        AttributeModel *attribute = new AttributeModel(tbl->columndefinition(i), this, _ilwisobject);
                        _attributes.push_back(attribute);
                    }
                }
            }
        }
        if ( _attributes.size() > 0){
            return QQmlListProperty<AttributeModel>(this, _attributes) ;
        }
    }
    catch(const ErrorObject& ){
        // no exceptions may escape here
    }
    return QQmlListProperty<AttributeModel>();

}
bool GdalFeatureConnector::createDataSourceAndLayers(IlwisTypes types,
                                                     const QString& postfix,
                                                     const IFeatureCoverage& features,
                                                     OGRSpatialReferenceH srs,
                                                     const std::vector<OGRFieldDefnH>& fielddefs,
                                                     std::vector<SourceHandles>& datasources,
                                                     std::vector<bool>& validAttributes ){

    QFileInfo fileinfo = sourceRef().toLocalFile();
    int typeIndex  = ilwisType2Index(types);
    ITable tbl = features->attributeTable();
    datasources[typeIndex]._source =  createFileBasedDataSource(postfix, fileinfo);
    if ( datasources[typeIndex]._source == 0)
        return false;
    datasources[typeIndex]._layers.push_back(createLayer(features->name(), ilwisType2GdalFeatureType(types), srs,datasources[typeIndex]._source));
    if (  datasources[typeIndex]._layers.back() == 0)
        return false;

    return createAttributes(tbl, datasources[typeIndex]._layers[0], fielddefs,validAttributes);
}
void createAttributeSetter(const IFeatureCoverage& features, std::vector<std::shared_ptr<BaseSpatialAttributeSetter>>& setters, RootDrawer *rootdrawer)
{
    QVariant v = qVariantFromValue((void *) rootdrawer);
    IOOptions opt("rootdrawer", v);
    setters[itPOINT].reset( DrawerAttributeSetterFactory::create<BaseSpatialAttributeSetter>("simplepointsetter",opt));
    setters[itLINE].reset( DrawerAttributeSetterFactory::create<BaseSpatialAttributeSetter>("simplelinesetter",  opt));
    setters[itPOLYGON].reset( DrawerAttributeSetterFactory::create<BaseSpatialAttributeSetter>("simplepolygonsetter", opt));
    for(int i=0; i < setters.size(); ++i){
        if(setters[i]){
            setters[i]->sourceCsySystem(features->coordinateSystem());
        }
    }
}
QString IlwisObjectModel::value2string(const QVariant &value, const QString &attrName)
{
    auto v2s = [](const ColumnDefinition& coldef, const QVariant& value)->QString {
            if ( coldef.isValid()){
                if ( coldef.datadef().domain()->ilwisType() == itTEXTDOMAIN)
                    return value.toString();
                return coldef.datadef().domain()->impliedValue(value).toString();
            }
            if ( value.toDouble() == rUNDEF)
                return sUNDEF;
            return value.toString();
    };
    if ( attrName != "") {
        IlwisTypes objectype = _ilwisobject->ilwisType();
        if ( hasType(objectype, itFEATURE)){
            IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
            ColumnDefinition coldef = features->attributeDefinitions().columndefinition(attrName);
            return v2s(coldef, value);

        }else if (hasType(objectype, itRASTER)){
             IRasterCoverage raster = _ilwisobject.as<RasterCoverage>();
             if ( raster->hasAttributes()){
                ColumnDefinition coldef = raster->attributeTable()->columndefinition(attrName);
                return v2s(coldef, value);
             }
             if ( raster->datadef().domain()->ilwisType() == itCOLORDOMAIN){
                 auto clr = ColorRangeBase::toColor(value, ColorRangeBase::cmRGBA);
                return ColorRangeBase::toString(clr,ColorRangeBase::cmRGBA)    ;
             }
        }
    }
    if ( value.toDouble() == rUNDEF)
        return sUNDEF;
    return value.toString();

}
bool GdalFeatureConnector::setDataSourceAndLayers(const IFeatureCoverage& features, std::vector<SourceHandles>& datasources,std::vector<bool>& validAttributes) {


    ITable tbl = features->attributeTable();
    validAttributes.resize(tbl->columnCount(), false);
    std::vector<OGRFieldDefnH> fielddefs(tbl->columnCount());

    int index = 0;
    for(int i=0; i < tbl->columnCount(); ++i){
        OGRFieldType ogrtype = ilwisType2GdalFieldType(tbl->columndefinition(i).datadef().domain<>()->valueType());
        OGRFieldDefnH fieldef = gdal()->createAttributeDefintion(tbl->columndefinition(i).name().toLocal8Bit(),ogrtype);
        if ( fieldef == 0){
            WARN2(ERR_INVALID_INIT_FOR_2, TR("data-type"), tbl->columndefinition(i).name());
        }else
            validAttributes[i] = true;

        fielddefs[index++] = fieldef;
    }
    bool ok = false;
    OGRSpatialReferenceH srs = createSRS(features->coordinateSystem());
    IlwisTypes types = features->featureTypes();
    bool multipleoutputs = (types == (itPOINT | itLINE)) || (types == (itPOINT | itPOLYGON)) || (types == (itLINE | itPOLYGON)) || (types == (itFEATURE));
    if ( multipleoutputs){
        if ((features->featureTypes() & itPOINT) != 0) {
            ok = createDataSourceAndLayers(itPOINT, "point", features, srs,fielddefs,datasources,validAttributes);
        }
        if ((features->featureTypes() & itLINE) != 0) {
            ok = createDataSourceAndLayers(itLINE, "line", features, srs,fielddefs,datasources,validAttributes);
        }
        if ((features->featureTypes() & itPOLYGON) != 0) {
            ok = createDataSourceAndLayers(itPOLYGON, "polygon", features, srs,fielddefs,datasources,validAttributes);
        }
    }else {
        ok = createDataSourceAndLayers(types, "", features, srs,fielddefs,datasources,validAttributes);
    }

    for(OGRFieldDefnH fieldef : fielddefs) {
        gdal()->destroyAttributeDefintion(fieldef);
    }
    return ok;
}
QString IlwisObjectModel::getProperty(const QString &propertyname)
{
    try{
        QString property = ResourceModel::getProperty(propertyname);
        if ( property != sUNDEF)
            return property;
        if ( !_ilwisobject.isValid())
            return "";
        if ( propertyname == "latlonenvelope" || propertyname == "envelope"){
            if (hasType(_ilwisobject->ilwisType(), itCOVERAGE)){
                return _ilwisobject.as<Coverage>()->envelope(propertyname == "latlonenvelope").toString();
            } if ( hasType(_ilwisobject->ilwisType(), itCOORDSYSTEM)){
                return _ilwisobject.as<CoordinateSystem>()->envelope(propertyname == "latlonenvelope").toString();
            }
        }
        if ( propertyname == "pixelsize"){
            return pixSizeString();
        }
        if ( propertyname == "centerpixelboundingbox"){
            return centerPixelLocation();
        }
        if ( propertyname == "parentdomain"){
            return parentDomain();
        }
        if ( propertyname == "valuetype"){
            return valueType();
        }
        if ( propertyname == "recordcount"){
            if ( hasType(_ilwisobject->ilwisType(), itTABLE)){
                return QString::number(_ilwisobject.as<Table>()->recordCount());
            }
        }
        if ( propertyname == "columncount"){
            if ( hasType(_ilwisobject->ilwisType(), itTABLE)){
                return QString::number(_ilwisobject.as<Table>()->columnCount());
            }
        }
        if ( propertyname == "polygoncount"){
             if ( hasType(_ilwisobject->ilwisType(), itFEATURE)){
                IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
                return QString::number(features->featureCount(itPOLYGON));
             }
        }
        if ( propertyname == "linecount"){
             if ( hasType(_ilwisobject->ilwisType(), itFEATURE)){
                IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
                return QString::number(features->featureCount(itLINE));
             }
        }
        if ( propertyname == "pointcount"){
             if ( hasType(_ilwisobject->ilwisType(), itFEATURE)){
                IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
                return QString::number(features->featureCount(itPOINT));
             }
        }
        if ( propertyname == "featurecount"){
             if ( hasType(_ilwisobject->ilwisType(), itFEATURE)){
                IFeatureCoverage features = _ilwisobject.as<FeatureCoverage>();
                return QString::number(features->featureCount());
             }
        }
        if ( propertyname == "majoraxis"){
             if ( hasType(_ilwisobject->ilwisType(), itELLIPSOID)){
                IEllipsoid ellipsoid = _ilwisobject.as<Ellipsoid>();
                return QString::number(ellipsoid->majorAxis());
             }
        }
        if ( propertyname == "minoraxis"){
             if ( hasType(_ilwisobject->ilwisType(), itELLIPSOID)){
                IEllipsoid ellipsoid = _ilwisobject.as<Ellipsoid>();
                return QString::number(ellipsoid->minorAxis());
             }
        }
        if ( propertyname == "flattening"){
             if ( hasType(_ilwisobject->ilwisType(), itELLIPSOID)){
                IEllipsoid ellipsoid = _ilwisobject.as<Ellipsoid>();
                return QString::number(ellipsoid->flattening());
             }
        }
        if ( propertyname == "excentricity"){
             if ( hasType(_ilwisobject->ilwisType(), itELLIPSOID)){
                IEllipsoid ellipsoid = _ilwisobject.as<Ellipsoid>();
                return QString::number(ellipsoid->excentricity());
             }
        }
        if (propertyname == "proj4def"){
            IlwisTypes objectype = _ilwisobject->ilwisType();
            if ( hasType( objectype, itPROJECTION | itCONVENTIONALCOORDSYSTEM)){
                IProjection proj;
                if ( hasType(objectype, itCONVENTIONALCOORDSYSTEM)){
                    IConventionalCoordinateSystem csyProj = _ilwisobject.as<ConventionalCoordinateSystem>();
                    if ( csyProj.isValid()){
                        proj = csyProj->projection();
                    }
                }else
                    proj = _ilwisobject.as<Projection>();
                if ( proj.isValid()){
                    return proj->toProj4();
                }
            }

        }

        return "";
    } catch(const ErrorObject& ){
        // no exceptions may escape here
    }
    return "";
}
bool FeatureLayerDrawer::prepare(DrawerInterface::PreparationType prepType, const IOOptions &options)
{
    if(!LayerDrawer::prepare(prepType, options))
        return false;

    if ( hasType(prepType, ptSHADERS) && !isPrepared(ptSHADERS)){
        _vboColor = _shaders.attributeLocation("vertexColor");
        _scaleCenter = _shaders.uniformLocation("scalecenter");
        _scaleFactor = _shaders.uniformLocation("scalefactor");

        _prepared |= DrawerInterface::ptSHADERS;
    }
    if ( hasType(prepType, DrawerInterface::ptGEOMETRY) && !isPrepared(DrawerInterface::ptGEOMETRY)){



        IFeatureCoverage features = coverage().as<FeatureCoverage>();
        if ( !features.isValid()){
            return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"FeatureCoverage", TR("Visualization"));
        }
        // set all to 0
        //_indices = std::vector<VertexIndex>();
        _vertices = QVector<QVector3D>();
        _normals = QVector<QVector3D>();
        _colors = std::vector<VertexColor>();
        // get a description of how to render
        VisualAttribute attr = visualProperty(activeAttribute());


        std::vector<std::shared_ptr<BaseSpatialAttributeSetter>> setters(5); // types are 1 2 4, for performance a vector is used thoug not all elements are used
        // for the moment I use the simple setters, in the future this will be representation dependent
        createAttributeSetter(features, setters, rootDrawer());

        _featureDrawings.resize(features->featureCount());
        int featureIndex = 0;
        for(const SPFeatureI& feature : features){
            QVariant value =  attr.columnIndex() != iUNDEF ? feature(attr.columnIndex()) : featureIndex;
            IlwisTypes geomtype = feature->geometryType();
             _featureDrawings[featureIndex] = setters[geomtype]->setSpatialAttributes(feature,_vertices,_normals);
            const QColor& clr = geomtype == itPOLYGON ? _boundaryColor : _lineColor;
            setters[geomtype]->setColorAttributes(attr,value,clr,_featureDrawings[featureIndex],_colors) ;
            ++featureIndex;
        }
        // implicity the redoing of the geometry is also redoing the representation stuff(a.o. colors)
        _prepared |= ( DrawerInterface::ptGEOMETRY | DrawerInterface::ptRENDER);

    }
    if ( hasType(prepType, DrawerInterface::ptRENDER) && !isPrepared(DrawerInterface::ptRENDER)){
        IFeatureCoverage features = coverage().as<FeatureCoverage>();
        int featureIndex = 0;
        std::vector<std::shared_ptr<BaseSpatialAttributeSetter>> setters(5); // types are 1 2 4, for performance a vector is used thoug not all elements are used
        // for the moment I use the simple setters, in the future this will be representation dependent
        createAttributeSetter(features, setters, rootDrawer());
        VisualAttribute attr = visualProperty(activeAttribute());
        if ( !features.isValid()){
            return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2,"FeatureCoverage", TR("Visualization"));
        }
        _colors.resize(0);
        bool polygononly = false;
        if ( options.contains("polygononly"))
            polygononly = options["polygononly"].toBool();

        for(const SPFeatureI& feature : features){
            if ( polygononly && feature->geometryType() != itPOLYGON){
                ++featureIndex;
                continue;
            }
            QVariant value =  attr.columnIndex() != iUNDEF ? feature(attr.columnIndex()) : featureIndex;
            IlwisTypes geomtype = feature->geometryType();
            const QColor& clr = geomtype == itPOLYGON ? _boundaryColor : _lineColor;
            setters[geomtype]->setColorAttributes(attr,value,clr,_featureDrawings[featureIndex],_colors) ;
            ++featureIndex;
        }
        _prepared |= DrawerInterface::ptRENDER;
    }

    //initialize();
    return true;
}