private SpheroidProjectionBase CreateObliqueStereographic(ProjectionCompilationParams opData)
        {
            Contract.Requires(opData != null);
            var originLatParam = new LatitudeOfNaturalOriginParameterSelector();
            var originLonParam = new LongitudeOfNaturalOriginParameterSelector();
            var offsetXParam = new FalseEastingParameterSelector();
            var offsetYParam = new FalseNorthingParameterSelector();
            var scaleFactorParam = new ScaleFactorParameterSelector();
            opData.ParameterLookup.Assign(originLatParam, originLonParam, offsetXParam, offsetYParam, scaleFactorParam);

            var spheroid = opData.StepParams.ConvertRelatedOutputSpheroidUnit(opData.StepParams.RelatedOutputCrsUnit);
            if (null == spheroid)
                return null;

            GeographicCoordinate origin;
            if (!(originLatParam.IsSelected || originLonParam.IsSelected) || !TryCreateGeographicCoordinate(originLatParam.Selection, originLonParam.Selection, out origin))
                origin = GeographicCoordinate.Zero;

            Vector2 offset;
            if (!(offsetXParam.IsSelected || offsetYParam.IsSelected) || !TryCreateVector2(offsetXParam.Selection, offsetYParam.Selection, opData.StepParams.RelatedOutputCrsUnit, out offset))
                offset = Vector2.Zero;

            double scaleFactor;
            if (scaleFactorParam.IsSelected && TryGetDouble(scaleFactorParam.Selection, ScaleUnitUnity.Value, out scaleFactor))
                return new ObliqueStereographic(origin, scaleFactor, offset, spheroid);

            return null;
        }
        private SpheroidProjectionBase CreateLambertAzimuthalEqualArea(ProjectionCompilationParams opData)
        {
            Contract.Requires(opData != null);
            var originLatParam = new LatitudeOfNaturalOriginParameterSelector();
            var originLonParam = new LongitudeOfNaturalOriginParameterSelector();
            var offsetXParam = new FalseEastingParameterSelector();
            var offsetYParam = new FalseNorthingParameterSelector();
            opData.ParameterLookup.Assign(originLatParam, originLonParam, offsetXParam, offsetYParam);

            var spheroid = opData.StepParams.ConvertRelatedOutputSpheroidUnit(opData.StepParams.RelatedOutputCrsUnit);
            if (null == spheroid)
                return null;

            GeographicCoordinate origin;
            if (!originLatParam.IsSelected || !originLonParam.IsSelected || !TryCreateGeographicCoordinate(originLatParam.Selection, originLonParam.Selection, out origin))
                origin = GeographicCoordinate.Zero;

            Vector2 offset;
            if (!offsetXParam.IsSelected || !offsetYParam.IsSelected || !TryCreateVector2(offsetXParam.Selection, offsetYParam.Selection, out offset))
                offset = Vector2.Zero;

            var spherical = _coordinateOperationNameComparer.Normalize(opData.OperationName).EndsWith("SPHERICAL");
            if (spherical)
                return new LambertAzimuthalEqualAreaSpherical(origin, offset, spheroid);

            if (Math.Abs(origin.Latitude - (Math.PI / 2.0)) < 0.00000001)
                return new LambertAzimuthalEqualAreaPolar(origin, offset, spheroid); // N
            if (Math.Abs(origin.Latitude - (Math.PI / -2.0)) < 0.00000001)
                return new LambertAzimuthalEqualAreaPolar(origin, offset, spheroid); // S

            return new LambertAzimuthalEqualAreaOblique(origin, offset, spheroid);
        }
        private SpheroidProjectionBase CreateEquidistantCylindrical(ProjectionCompilationParams opData)
        {
            Contract.Requires(opData != null);
            var originLatParam = new KeywordNamedParameterSelector("LAT", "PARALLEL");
            var originLonParam = new LongitudeOfNaturalOriginParameterSelector();
            var offsetXParam = new FalseEastingParameterSelector();
            var offsetYParam = new FalseNorthingParameterSelector();
            opData.ParameterLookup.Assign(originLatParam, originLonParam, offsetXParam, offsetYParam);

            var spheroid = opData.StepParams.ConvertRelatedOutputSpheroidUnit(opData.StepParams.RelatedOutputCrsUnit);
            if (null == spheroid)
                return null;

            GeographicCoordinate origin;
            if (!originLatParam.IsSelected || !originLonParam.IsSelected || !TryCreateGeographicCoordinate(originLatParam.Selection, originLonParam.Selection, out origin))
                origin = GeographicCoordinate.Zero;

            Vector2 offset;
            if (!offsetXParam.IsSelected || !offsetYParam.IsSelected || !TryCreateVector2(offsetXParam.Selection, offsetYParam.Selection, out offset))
                offset = Vector2.Zero;

            // ReSharper disable CompareOfFloatsByEqualityOperator
            var spherical = _coordinateOperationNameComparer.Normalize(opData.OperationName).EndsWith("SPHERICAL")
                || spheroid.E == 0;
            // ReSharper restore CompareOfFloatsByEqualityOperator

            return spherical
                ? (SpheroidProjectionBase)new EquidistantCylindricalSpherical(origin, offset, spheroid)
                : new EquidistantCylindrical(origin, offset, spheroid);
        }
        private ITransformation<GeographicCoordinate, Point2> CreateCassiniSoldner(ProjectionCompilationParams opData)
        {
            Contract.Requires(opData != null);
            var originLatParam = new LatitudeOfNaturalOriginParameterSelector();
            var originLonParam = new LongitudeOfNaturalOriginParameterSelector();
            var offsetXParam = new FalseEastingParameterSelector();
            var offsetYParam = new FalseNorthingParameterSelector();
            opData.ParameterLookup.Assign(originLatParam, originLonParam, offsetXParam, offsetYParam);

            var spheroid = opData.StepParams.ConvertRelatedOutputSpheroidUnit(opData.StepParams.RelatedOutputCrsUnit);
            if (null == spheroid)
                return null;

            GeographicCoordinate origin;
            if (!(originLatParam.IsSelected || originLonParam.IsSelected) || !TryCreateGeographicCoordinate(originLatParam.Selection, originLonParam.Selection, out origin))
                origin = GeographicCoordinate.Zero;

            Vector2 offset;
            if (!(offsetXParam.IsSelected || offsetYParam.IsSelected) || !TryCreateVector2(offsetXParam.Selection, offsetYParam.Selection, opData.StepParams.RelatedOutputCrsUnit, out offset))
                offset = Vector2.Zero;

            return new CassiniSoldner(origin, offset, spheroid);
        }
        private static PopularVisualizationPseudoMercator CreatePopularVisualisationPseudoMercator(ProjectionCompilationParams opData)
        {
            Contract.Requires(opData != null);
            var originLatParam = new LatitudeOfNaturalOriginParameterSelector();
            var originLonParam = new LongitudeOfNaturalOriginParameterSelector();
            var offsetXParam = new FalseEastingParameterSelector();
            var offsetYParam = new FalseNorthingParameterSelector();
            if (!opData.ParameterLookup.Assign(originLatParam, originLonParam, offsetXParam, offsetYParam))
                return null;

            var spheroid = opData.StepParams.ConvertRelatedOutputSpheroidUnit(opData.StepParams.RelatedOutputCrsUnit);
            if (null == spheroid)
                return null;

            GeographicCoordinate origin;
            Vector2 offset;

            TryCreateGeographicCoordinate(originLatParam.Selection, originLonParam.Selection, out origin);
            TryCreateVector2(offsetXParam.Selection, offsetYParam.Selection, out offset);
            return new PopularVisualizationPseudoMercator(origin, offset, spheroid);
        }
        private static SpheroidProjectionBase CreateLambertCylindricalEqualAreaSpherical(ProjectionCompilationParams opData)
        {
            Contract.Requires(opData != null);
            var originLatParam = new MultiParameterSelector(
                new LatitudeOfNaturalOriginParameterSelector(),
                new StandardParallelParameterSelector());
            var originLonParam = new LongitudeOfNaturalOriginParameterSelector();
            var offsetXParam = new FalseEastingParameterSelector();
            var offsetYParam = new FalseNorthingParameterSelector();
            opData.ParameterLookup.Assign(originLatParam, originLonParam, offsetXParam, offsetYParam);

            var spheroid = opData.StepParams.ConvertRelatedOutputSpheroidUnit(opData.StepParams.RelatedOutputCrsUnit);
            if (null == spheroid)
                return null;

            GeographicCoordinate origin;
            if (!(originLatParam.IsSelected || originLonParam.IsSelected) || !TryCreateGeographicCoordinate(originLatParam.Selection, originLonParam.Selection, out origin))
                origin = GeographicCoordinate.Zero;

            Vector2 offset;
            if (!(offsetXParam.IsSelected || offsetYParam.IsSelected) || !TryCreateVector2(offsetXParam.Selection, offsetYParam.Selection, opData.StepParams.RelatedOutputCrsUnit, out offset))
                offset = Vector2.Zero;

            return new LambertCylindricalEqualAreaSpherical(origin, offset, spheroid);
        }