/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
using Spatial4n.Core.Context;
using Spatial4n.Core.Exceptions;
using Spatial4n.Core.Shapes;
namespace Spatial4n.Core.Exceptions
{
[Serializable]
public class InvalidSpatialArgument : ArgumentException
{
public InvalidSpatialArgument(String reason)
: base(reason)
{
}
}
}
namespace Lucene.Net.Spatial.Queries
{
public class SpatialArgs
{
public static readonly double DEFAULT_DISTERRPCT = 0.025d;
public SpatialOperation Operation { get; set; }
public SpatialArgs(SpatialOperation operation, Shape shape)
{
if (operation == null || shape == null)
throw new ArgumentException("operation and shape are required");
this.Operation = operation;
this.Shape = shape;
}
///
/// Computes the distance given a shape and the {@code distErrPct}. The
/// algorithm is the fraction of the distance from the center of the query
/// shape to its furthest bounding box corner.
///
/// Mandatory.
/// 0 to 0.5
/// Mandatory
/// A distance (in degrees).
public static double CalcDistanceFromErrPct(Shape shape, double distErrPct, SpatialContext ctx)
{
if (distErrPct < 0 || distErrPct > 0.5)
{
throw new ArgumentException("distErrPct " + distErrPct + " must be between [0 to 0.5]", "distErrPct");
}
if (distErrPct == 0 || shape is Point)
{
return 0;
}
Rectangle bbox = shape.GetBoundingBox();
//The diagonal distance should be the same computed from any opposite corner,
// and this is the longest distance that might be occurring within the shape.
double diagonalDist = ctx.GetDistCalc().Distance(
ctx.MakePoint(bbox.GetMinX(), bbox.GetMinY()), bbox.GetMaxX(), bbox.GetMaxY());
return diagonalDist*0.5*distErrPct;
}
///
/// Gets the error distance that specifies how precise the query shape is. This
/// looks at {@link #getDistErr()}, {@link #getDistErrPct()}, and {@code
/// defaultDistErrPct}.
///
///
/// 0 to 0.5
/// >= 0
public double ResolveDistErr(SpatialContext ctx, double defaultDistErrPct)
{
if (DistErr != null)
return DistErr.Value;
double? distErrPct = (this.distErrPct ?? defaultDistErrPct);
return CalcDistanceFromErrPct(Shape, distErrPct.Value, ctx);
}
///
/// Check if the arguments make sense -- throw an exception if not
///
public void Validate()
{
if (Operation.IsTargetNeedsArea() && !Shape.HasArea())
{
throw new ArgumentException(Operation + " only supports geometry with area");
}
}
public override String ToString()
{
return SpatialArgsParser.WriteSpatialArgs(this);
}
//------------------------------------------------
// Getters & Setters
//------------------------------------------------
public Shape Shape { get; set; }
///
/// A measure of acceptable error of the shape as a fraction. This effectively
/// inflates the size of the shape but should not shrink it.
///
/// The default is {@link #DEFAULT_DIST_PRECISION}
///
/// 0 to 0.5
public double? DistErrPct
{
get { return distErrPct; }
set
{
if (value != null)
distErrPct = value.Value;
}
}
private double? distErrPct;
///
/// The acceptable error of the shape. This effectively inflates the
/// size of the shape but should not shrink it.
///
/// >= 0
public double? DistErr { get; set; }
}
}