LatLon ConventionalCoordinateSystem::coord2latlon(const Coordinate &crdSource) const
{
    LatLon pl = _projection->coord2latlon(crdSource);
    if (!pl.isValid())
        return llUNDEF;
    if (abs(pl.lon()) > 90)
        return llUNDEF;
    return pl;
}
Coordinate ConventionalCoordinateSystem::coord2coord(const ICoordinateSystem &sourceCs, const Coordinate &crdSource) const
{
    if (sourceCs->isEqual(*this))
        return crdSource;
    LatLon ll = sourceCs->coord2latlon(crdSource);
    if ( ll.isValid()) {
        return latlon2coord(ll);
    }
    return Coordinate();
}
Coordinate ConventionalCoordinateSystem::coord2coord(const ICoordinateSystem &sourceCs, const Coordinate &crdSource) const
{
    //TODO isLatLon guard doesn't consider latlon cs other than WGS84!
    if (sourceCs->id() == id()) //  the 'real'isEqual test is too expensive here, as this method can be called 100000's of times (resample)
        return crdSource;
    LatLon ll = sourceCs->isLatLon() ? LatLon(crdSource.y,crdSource.x) : sourceCs->coord2latlon(crdSource);
    if ( ll.isValid()) {
        return isLatLon() ? ll : latlon2coord(ll);
    }
    return Coordinate();
}
void SubGridLayer::calcEnvelope(Coordinate& cmin, Coordinate& cmax) const {
    cmin = layerManager()->rootLayer()->zoomEnvelope().min_corner();
    cmax = layerManager()->rootLayer()->zoomEnvelope().max_corner();
    if (!cmin.isValid() || !cmax.isValid())
        return;

    ICoordinateSystem screenCsy = layerManager()->rootLayer()->screenCsy();
    if (!screenCsy.isValid())
        return;

    if (screenCsy->isUnknown()) // cant do any extra calcs with unknown
        return;

    bool isLatLon = screenCsy->isLatLon();
    if (isLatLon) {
        if (cmin.y <= -89)
            cmin.y = -89;
        if (cmin.x < -180)
            cmin.x = -180;
        if (cmax.y >= 89)
            cmax.y = 89;
        if (cmax.x > 180)
            cmax.x = 180;
    }
    else {
        LatLon llmin = screenCsy->coord2latlon(cmin);
        LatLon llmax = screenCsy->coord2latlon(cmax);
        if (llmin.isValid() && llmax.isValid()) {
            if (llmin.Lat() <= -85)
                cmin.y = screenCsy->latlon2coord(LatLon(-85, llmin.Lon())).y;
            if (llmin.Lon() < -180)
                cmin.x = screenCsy->latlon2coord(LatLon(llmin.Lat(), -180)).x;
            if (llmax.Lat() > 85)
                cmax.y = screenCsy->latlon2coord(LatLon(85, llmax.Lon())).y;
            if (llmax.Lon() > 180)
                cmax.x = screenCsy->latlon2coord(LatLon(llmax.Lat(), 180)).x;
        }
    }
}
LatLon ProjectionImplementationInternal::coord2latlon(const Ilwis::Coordinate &crdSource) const
{
    if (_coordinateSystem->projection().isValid() && crdSource != crdUNDEF) {
        Coordinate xy((crdSource.x - _easting) / _maxis, (crdSource.y - _northing) / _maxis);

        LatLon pl = crd2ll(xy);
        if (!pl.isValid())
            return llUNDEF;
        if (abs(pl.lat()) > 90)
            return llUNDEF;
        pl.lon( pl.lon() + _centralMeridian);
        return pl;
    }
    else
        return llUNDEF;

}
Coordinate ConventionalCoordinateSystem::coord2coord(const ICoordinateSystem &sourceCs, const Coordinate &crdSource) const
{
    //TODO isLatLon guard doesn't consider latlon cs other than WGS84!
    if (sourceCs->id() == id()) //  the 'real'isEqual test is too expensive here, as this method can be called 100000's of times (resample)
        return crdSource;
    LatLon ll = sourceCs->isLatLon() ? LatLon(crdSource.y,crdSource.x) : sourceCs->coord2latlon(crdSource);
    if (ll.isValid()) {
        if (hasType(sourceCs->ilwisType(), itCONVENTIONALCOORDSYSTEM)) {
            const IConventionalCoordinateSystem & srcCs = sourceCs.as<ConventionalCoordinateSystem>();
            if (srcCs->datum().get() && datum().get() && !srcCs->datum()->equal(*datum().get())) { // different datums given, datum shift needed
                ll = srcCs->datum()->llToWGS84(ll, *srcCs->ellipsoid().ptr());
                ll = datum()->llFromWGS84(ll, *ellipsoid().ptr());
            }
        }
        return isLatLon() ? ll : latlon2coord(ll);
    }

    return Coordinate();
}
Coordinate ProjectionImplementationInternal::latlon2coord(const LatLon &ll) const
{
    if (_coordinateSystem->projection().isValid() && ll.isValid()) {
        LatLon pl(ll);
        if (pl.lat() > M_PI_2)
            pl.lat(Angle(M_PI_2, true));
        else if (pl.lat() < -M_PI_2)
            pl.lat(Angle(-M_PI_2, true));
        pl.lon( pl.lon()-_centralMeridian);
        Coordinate xy = ll2crd(pl);
        if (xy != crdUNDEF)
            return crdUNDEF;
        Coordinate crd;
        crd.x = xy.x * _maxis  + _easting;
        crd.y = xy.y * _maxis  + _northing;
        return crd;
    }
    else
        return crdUNDEF;

}