<commit_before>package org.apache.solr.schema;
/**
 * 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.
 */

import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.spatial.DistanceUtils;
import org.apache.lucene.spatial.tier.InvalidGeoException;
import org.apache.solr.common.SolrException;
import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.response.XMLWriter;
import org.apache.solr.search.QParser;
import org.apache.solr.search.SpatialOptions;
import org.apache.solr.search.function.ValueSource;
import org.apache.solr.search.function.VectorValueSource;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * Represents a Latitude/Longitude as a 2 dimensional point.  Latitude is <b>always</b> specified first.
 * Can also, optionally, integrate in Spatial Tile capabilities.  The default is for tile fields from 4 - 15,
 * just as in the SpatialTileField that we are extending.
 */
public class LatLonType extends AbstractSubTypeFieldType implements SpatialQueryable {
  protected static final int LAT = 0;
  protected static final int LONG = 1;

  @Override
  protected void init(IndexSchema schema, Map<String, String> args) {
    super.init(schema, args);
    //TODO: refactor this, as we are creating the suffix cache twice, since the super.init does it too
    createSuffixCache(3);//we need three extra fields: one for the storage field, two for the lat/lon
  }

  @Override
  public Fieldable[] createFields(SchemaField field, String externalVal, float boost) {
    //we could have tileDiff + 3 fields (two for the lat/lon, one for storage)
    Fieldable[] f = new Fieldable[(field.indexed() ? 2 : 0) + (field.stored() ? 1 : 0)];
    if (field.indexed()) {
      int i = 0;
      double[] latLon = new double[0];
      try {
        latLon = DistanceUtils.parseLatitudeLongitude(null, externalVal);
      } catch (InvalidGeoException e) {
        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
      }
      //latitude
      f[i] = subField(field, i).createField(String.valueOf(latLon[LAT]), boost);
      i++;
      //longitude
      f[i] = subField(field, i).createField(String.valueOf(latLon[LONG]), boost);

    }

    if (field.stored()) {
      f[f.length - 1] = createField(field.getName(), externalVal,
              getFieldStore(field, externalVal), Field.Index.NO, Field.TermVector.NO,
              false, false, boost);
    }
    return f;
  }

  @Override
  public Query createSpatialQuery(QParser parser, SpatialOptions options) {
    BooleanQuery result = new BooleanQuery();
    double[] point = new double[0];
    try {
      point = DistanceUtils.parseLatitudeLongitude(options.pointStr);
    } catch (InvalidGeoException e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
    }

    //Get the distance
    double[] ur;
    double[] ll;
    if (options.measStr == null || options.measStr.equals("hsin")) {
      ur = DistanceUtils.latLonCornerDegs(point[LAT], point[LONG], options.distance, null, true, options.radius);
      ll = DistanceUtils.latLonCornerDegs(point[LAT], point[LONG], options.distance, null, false, options.radius);
    } else {
      ur = DistanceUtils.vectorBoxCorner(point, null, options.distance, true);
      ll = DistanceUtils.vectorBoxCorner(point, null, options.distance, false);
    }

    SchemaField subSF;
    Query range;

    double angDistDegs = DistanceUtils.angularDistance(options.distance,
            DistanceUtils.EARTH_MEAN_RADIUS_MI) * DistanceUtils.RADIANS_TO_DEGREES;
    //for the poles, do something slightly different
    if (point[LAT] + angDistDegs > 90.0) { //we cross the north pole
      //we don't need a longitude boundary at all

      double minLat = Math.min(ll[LAT], ur[LAT]);
      subSF = subField(options.field, LAT);
      range = subSF.getType().getRangeQuery(parser, subSF,
              String.valueOf(minLat),
              "90", true, true);
      result.add(range, BooleanClause.Occur.MUST);
    } else if (point[LAT] - angDistDegs < -90.0) {//we cross the south pole
      subSF = subField(options.field, LAT);
      double maxLat = Math.max(ll[LAT], ur[LAT]);
      range = subSF.getType().getRangeQuery(parser, subSF,
              "-90", String.valueOf(maxLat), true, true);
      result.add(range, BooleanClause.Occur.MUST);
    } else{
        //Latitude
        //we may need to generate multiple queries depending on the range
        //Are we crossing the 180 deg. longitude, if so, we need to do some special things
        if (ll[LONG] > 0.0 && ur[LONG] < 0.0) {
          //TODO: refactor into common code, etc.
          //Now check other side of the Equator
          if (ll[LAT] < 0.0 && ur[LAT] > 0.0) {
            addEquatorialBoundary(parser, options, result, ur[LAT], ll[LAT]);
          } //check poles
          else {
            subSF = subField(options.field, LAT);
            //not crossing the equator<commit_msg>solr spatial: use the radius passed (including units) instead of hard-coding to miles<commit_after>package org.apache.solr.schema;
/**
 * 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.
 */

import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.spatial.DistanceUtils;
import org.apache.lucene.spatial.tier.InvalidGeoException;
import org.apache.solr.common.SolrException;
import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.response.XMLWriter;
import org.apache.solr.search.QParser;
import org.apache.solr.search.SpatialOptions;
import org.apache.solr.search.function.ValueSource;
import org.apache.solr.search.function.VectorValueSource;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * Represents a Latitude/Longitude as a 2 dimensional point.  Latitude is <b>always</b> specified first.
 * Can also, optionally, integrate in Spatial Tile capabilities.  The default is for tile fields from 4 - 15,
 * just as in the SpatialTileField that we are extending.
 */
public class LatLonType extends AbstractSubTypeFieldType implements SpatialQueryable {
  protected static final int LAT = 0;
  protected static final int LONG = 1;

  @Override
  protected void init(IndexSchema schema, Map<String, String> args) {
    super.init(schema, args);
    //TODO: refactor this, as we are creating the suffix cache twice, since the super.init does it too
    createSuffixCache(3);//we need three extra fields: one for the storage field, two for the lat/lon
  }

  @Override
  public Fieldable[] createFields(SchemaField field, String externalVal, float boost) {
    //we could have tileDiff + 3 fields (two for the lat/lon, one for storage)
    Fieldable[] f = new Fieldable[(field.indexed() ? 2 : 0) + (field.stored() ? 1 : 0)];
    if (field.indexed()) {
      int i = 0;
      double[] latLon = new double[0];
      try {
        latLon = DistanceUtils.parseLatitudeLongitude(null, externalVal);
      } catch (InvalidGeoException e) {
        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
      }
      //latitude
      f[i] = subField(field, i).createField(String.valueOf(latLon[LAT]), boost);
      i++;
      //longitude
      f[i] = subField(field, i).createField(String.valueOf(latLon[LONG]), boost);

    }

    if (field.stored()) {
      f[f.length - 1] = createField(field.getName(), externalVal,
              getFieldStore(field, externalVal), Field.Index.NO, Field.TermVector.NO,
              false, false, boost);
    }
    return f;
  }

  @Override
  public Query createSpatialQuery(QParser parser, SpatialOptions options) {
    BooleanQuery result = new BooleanQuery();
    double[] point = new double[0];
    try {
      point = DistanceUtils.parseLatitudeLongitude(options.pointStr);
    } catch (InvalidGeoException e) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
    }

    //Get the distance
    double[] ur;
    double[] ll;
    if (options.measStr == null || options.measStr.equals("hsin")) {
      ur = DistanceUtils.latLonCornerDegs(point[LAT], point[LONG], options.distance, null, true, options.radius);
      ll = DistanceUtils.latLonCornerDegs(point[LAT], point[LONG], options.distance, null, false, options.radius);
    } else {
      ur = DistanceUtils.vectorBoxCorner(point, null, options.distance, true);
      ll = DistanceUtils.vectorBoxCorner(point, null, options.distance, false);
    }

    SchemaField subSF;
    Query range;

    double angDistDegs = DistanceUtils.angularDistance(options.distance,
            options.radius) * DistanceUtils.RADIANS_TO_DEGREES;
    
    //for the poles, do something slightly different
    if (point[LAT] + angDistDegs > 90.0) { //we cross the north pole
      //we don't need a longitude boundary at all

      double minLat = Math.min(ll[LAT], ur[LAT]);
      subSF = subField(options.field, LAT);
      range = subSF.getType().getRangeQuery(parser, subSF,
              String.valueOf(minLat),
              "90", true, true);
      result.add(range, BooleanClause.Occur.MUST);
    } else if (point[LAT] - angDistDegs < -90.0) {//we cross the south pole
      subSF = subField(options.field, LAT);
      double maxLat = Math.max(ll[LAT], ur[LAT]);
      range = subSF.getType().getRangeQuery(parser, subSF,
              "-90", String.valueOf(maxLat), true, true);
      result.add(range, BooleanClause.Occur.MUST);
    } else{
        //Latitude
        //we may need to generate multiple queries depending on the range
        //Are we crossing the 180 deg. longitude, if so, we need to do some special things
        if (ll[LONG] > 0.0 && ur[LONG] < 0.0) {
          //TODO: refactor into common code, etc.
          //Now check other side of the Equator
          if (ll[LAT] < 0.0 && ur[LAT] > 0.0) {
            addEquatorialBoundary(parser, options, result, ur[LAT], ll[LAT]);
          } //check poles
          else {
            subSF = subField(options.field, LAT);
            //not crossing the equator
{'fraction_non_alphanumeric': 0.10748721388446382, 'fraction_numerical': 0.00687515720633856, 'mean_word_length': 3.3139240506329113, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '821844', 'n_tokens_mistral': 3653, 'n_tokens_neox': 3494, 'n_words': 1073}