You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by nk...@apache.org on 2020/03/03 03:25:12 UTC

[lucene-solr] branch branch_8x updated: LUCENE-9150: Restore support for dynamic PlanetModel in spatial3d

This is an automated email from the ASF dual-hosted git repository.

nknize pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8x by this push:
     new ab6fb77  LUCENE-9150: Restore support for dynamic PlanetModel in spatial3d
ab6fb77 is described below

commit ab6fb77c63df5a8d347c0d67335e8919df683f64
Author: Nicholas Knize <nk...@gmail.com>
AuthorDate: Fri Feb 7 11:56:31 2020 -0600

    LUCENE-9150: Restore support for dynamic PlanetModel in spatial3d
---
 lucene/CHANGES.txt                                 |   2 +
 .../org/apache/lucene/spatial/SpatialStrategy.java |   2 +-
 .../lucene/spatial/query/SpatialArgsParser.java    |   2 +-
 .../spatial4j/Geo3dSpatialContextFactory.java      |   2 +
 .../org/apache/lucene/spatial/PortedSolr3Test.java |   2 +-
 .../Geo3dShapeWGS84ModelRectRelationTest.java      |   7 +-
 .../lucene/spatial3d/Geo3DDocValuesField.java      | 252 ++---------
 .../org/apache/lucene/spatial3d/Geo3DPoint.java    |  99 +++--
 .../spatial3d/Geo3DPointDistanceComparator.java    |  18 +-
 .../Geo3DPointOutsideDistanceComparator.java       |  18 +-
 .../spatial3d/Geo3DPointOutsideSortField.java      |   7 +-
 .../lucene/spatial3d/Geo3DPointSortField.java      |   7 +-
 .../org/apache/lucene/spatial3d/Geo3DUtil.java     | 126 ++----
 .../lucene/spatial3d/PointInGeo3DShapeQuery.java   |   9 -
 .../spatial3d/PointInShapeIntersectVisitor.java    |  35 +-
 .../lucene/spatial3d/geom/GeoComplexPolygon.java   |  26 +-
 .../lucene/spatial3d/geom/GeoExactCircle.java      |   2 +-
 .../org/apache/lucene/spatial3d/geom/GeoWorld.java |   2 +-
 .../org/apache/lucene/spatial3d/geom/Plane.java    | 332 +++++++-------
 .../apache/lucene/spatial3d/geom/PlanetModel.java  | 491 +++++++++++++++++----
 .../org/apache/lucene/spatial3d/geom/Vector.java   |   4 +-
 .../lucene/spatial3d/TestGeo3DDocValues.java       |  20 +-
 .../apache/lucene/spatial3d/TestGeo3DPoint.java    | 270 +++++------
 .../apache/lucene/spatial3d/geom/Geo3DUtil.java    | 245 ----------
 .../lucene/spatial3d/geom/GeoCircleTest.java       |   6 +-
 .../lucene/spatial3d/geom/GeoExactCircleTest.java  |   6 +-
 .../apache/lucene/spatial3d/geom/GeoPathTest.java  |   2 +-
 .../lucene/spatial3d/geom/GeoPolygonTest.java      |  22 +-
 28 files changed, 957 insertions(+), 1059 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 3582960..b14e8bf 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -27,6 +27,8 @@ API Changes
 * LUCENE-9212: Intervals.multiterm() takes CompiledAutomaton rather than plain Automaton
   (Alan Woodward)
 
+* LUCENE-9150: Restore support for dynamic PlanetModel in spatial3d. (Nick Knize)
+
 New Features
 ---------------------
 
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/SpatialStrategy.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/SpatialStrategy.java
index 215fa1d..bd23a36 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/SpatialStrategy.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/SpatialStrategy.java
@@ -128,7 +128,7 @@ public abstract class SpatialStrategy {
   /**
    * Returns a ValueSource with values ranging from 1 to 0, depending inversely
    * on the distance from {@link #makeDistanceValueSource(org.locationtech.spatial4j.shape.Point,double)}.
-   * The formula is {@code c/(d + c)} where 'd' is the distance and 'c' is
+   * The formula is {@code zScaling/(d + zScaling)} where 'd' is the distance and 'zScaling' is
    * one tenth the distance to the farthest edge from the center. Thus the
    * scores will be 1 for indexed points at the center of the query shape and as
    * low as ~0.1 at its furthest edges.
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/query/SpatialArgsParser.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/query/SpatialArgsParser.java
index 79ad7a9..bd3916c 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/query/SpatialArgsParser.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/query/SpatialArgsParser.java
@@ -125,7 +125,7 @@ public class SpatialArgsParser {
     return v == null ? defaultValue : Boolean.parseBoolean(v);
   }
 
-  /** Parses "a=b c=d f" (whitespace separated) into name-value pairs. If there
+  /** Parses "a=b zScaling=d f" (whitespace separated) into name-value pairs. If there
    * is no '=' as in 'f' above then it's short for f=f. */
   protected static Map<String, String> parseMap(String body) {
     Map<String, String> map = new HashMap<>();
diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dSpatialContextFactory.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dSpatialContextFactory.java
index 1ce4ebc..6124b90 100644
--- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dSpatialContextFactory.java
+++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/spatial4j/Geo3dSpatialContextFactory.java
@@ -72,6 +72,8 @@ public class Geo3dSpatialContextFactory extends SpatialContextFactory {
         this.planetModel = PlanetModel.SPHERE;
       } else if (planetModel.equalsIgnoreCase("wgs84")) {
         this.planetModel = PlanetModel.WGS84;
+      } else if (planetModel.equalsIgnoreCase("clarke1866")) {
+        this.planetModel = PlanetModel.CLARKE_1866;
       } else {
         throw new RuntimeException("Unknown planet model: " + planetModel);
       }
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/PortedSolr3Test.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/PortedSolr3Test.java
index f55daf6..e9cd63d 100644
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/PortedSolr3Test.java
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/PortedSolr3Test.java
@@ -110,7 +110,7 @@ public class PortedSolr3Test extends StrategyTestCase {
     checkHitsCircle(ctx.makePoint(1, 1), 5000, 3, 5, 6, 7);
     //Because we are generating a box based on the west/east longitudes and the south/north latitudes, which then
     //translates to a range query, which is slightly more inclusive.  Thus, even though 0.0 is 15.725 kms away,
-    //it will be included, b/c of the box calculation.
+    //it will be included, b/zScaling of the box calculation.
     checkHitsBBox(ctx.makePoint(0.1, 0.1), 15, 2, 5, 6);
     //try some more
     deleteAll();
diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
index 8d5f307..341d4f9 100644
--- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
+++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/spatial4j/Geo3dShapeWGS84ModelRectRelationTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.lucene.spatial.spatial4j;
 
+import com.carrotsearch.randomizedtesting.generators.RandomPicks;
 import org.apache.lucene.spatial3d.geom.GeoArea;
 import org.apache.lucene.spatial3d.geom.GeoBBox;
 import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
@@ -32,7 +33,7 @@ import org.locationtech.spatial4j.shape.SpatialRelation;
 
 public class Geo3dShapeWGS84ModelRectRelationTest extends ShapeRectRelationTestCase {
 
-  PlanetModel planetModel = PlanetModel.WGS84;
+  PlanetModel planetModel = RandomPicks.randomFrom(random(), new PlanetModel[] {PlanetModel.WGS84, PlanetModel.CLARKE_1866});
 
   public Geo3dShapeWGS84ModelRectRelationTest() {
     Geo3dSpatialContextFactory factory = new Geo3dSpatialContextFactory();
@@ -71,11 +72,11 @@ public class Geo3dShapeWGS84ModelRectRelationTest extends ShapeRectRelationTestC
   @Test
   public void testFailure3() {
     /*
-   [junit4]   1> S-R Rel: {}, Shape {}, Rectangle {}    lap# {} [CONTAINS, Geo3dShape{planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, shape=GeoPath: {planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, width=1.53588974175501(87.99999999999999),
+   [junit4]   1> S-R Rel: {}, Shape {}, Rectangle {}    lap# {} [CONTAINS, Geo3dShape{planetmodel=PlanetModel: {xyScaling=1.0011188180710464, zScaling=0.9977622539852008}, shape=GeoPath: {planetmodel=PlanetModel: {xyScaling=1.0011188180710464, zScaling=0.9977622539852008}, width=1.53588974175501(87.99999999999999),
     points={[[X=0.12097657665150223, Y=-0.6754177666095532, Z=0.7265376136709238], [X=-0.3837892785614207, Y=0.4258049113530899, Z=0.8180007850434892]]}}},
     Rect(minX=4.0,maxX=36.0,minY=16.0,maxY=16.0), 6981](no slf4j subst; sorry)
    [junit4] FAILURE 0.59s | Geo3dWGS84ShapeRectRelationTest.testGeoPathRect <<<
-   [junit4]    > Throwable #1: java.lang.AssertionError: Geo3dShape{planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, shape=GeoPath: {planetmodel=PlanetModel: {ab=1.0011188180710464, c=0.9977622539852008}, width=1.53588974175501(87.99999999999999),
+   [junit4]    > Throwable #1: java.lang.AssertionError: Geo3dShape{planetmodel=PlanetModel: {xyScaling=1.0011188180710464, zScaling=0.9977622539852008}, shape=GeoPath: {planetmodel=PlanetModel: {xyScaling=1.0011188180710464, zScaling=0.9977622539852008}, width=1.53588974175501(87.99999999999999),
     points={[[X=0.12097657665150223, Y=-0.6754177666095532, Z=0.7265376136709238], [X=-0.3837892785614207, Y=0.4258049113530899, Z=0.8180007850434892]]}}} intersect Pt(x=23.81626064835212,y=16.0)
    [junit4]    >  at __randomizedtesting.SeedInfo.seed([2595268DA3F13FEA:6CC30D8C83453E5D]:0)
    [junit4]    >  at org.apache.lucene.spatial.spatial4j.RandomizedShapeTestCase._assertIntersect(RandomizedShapeTestCase.java:168)
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
index dc9df35..e2d2733 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DDocValuesField.java
@@ -48,43 +48,14 @@ import org.apache.lucene.spatial3d.geom.GeoOutsideDistance;
  * @see Geo3DPoint
  */
 public class Geo3DDocValuesField extends Field {
-
-  // These are the multiplicative constants we need to use to arrive at values that fit in 21 bits.
-  // The formula we use to go from double to encoded value is:  Math.floor((value - minimum) * factor + 0.5)
-  // If we plug in maximum for value, we should get 0x1FFFFF.
-  // So, 0x1FFFFF = Math.floor((maximum - minimum) * factor + 0.5)
-  // We factor out the 0.5 and Math.floor by stating instead:
-  // 0x1FFFFF = (maximum - minimum) * factor
-  // So, factor = 0x1FFFFF / (maximum - minimum)
-
-  private final static double inverseMaximumValue = 1.0 / (double)(0x1FFFFF);
-  
-  private final static double inverseXFactor = (PlanetModel.WGS84.getMaximumXValue() - PlanetModel.WGS84.getMinimumXValue()) * inverseMaximumValue;
-  private final static double inverseYFactor = (PlanetModel.WGS84.getMaximumYValue() - PlanetModel.WGS84.getMinimumYValue()) * inverseMaximumValue;
-  private final static double inverseZFactor = (PlanetModel.WGS84.getMaximumZValue() - PlanetModel.WGS84.getMinimumZValue()) * inverseMaximumValue;
-  
-  private final static double xFactor = 1.0 / inverseXFactor;
-  private final static double yFactor = 1.0 / inverseYFactor;
-  private final static double zFactor = 1.0 / inverseZFactor;
-  
-  // Fudge factor for step adjustments.  This is here solely to handle inaccuracies in bounding boxes
-  // that occur because of quantization.  For unknown reasons, the fudge factor needs to be
-  // 10.0 rather than 1.0.  See LUCENE-7430.
-  
-  private final static double STEP_FUDGE = 10.0;
-  
-  // These values are the delta between a value and the next value in each specific dimension
-  
-  private final static double xStep = inverseXFactor * STEP_FUDGE;
-  private final static double yStep = inverseYFactor * STEP_FUDGE;
-  private final static double zStep = inverseZFactor * STEP_FUDGE;
+  private final PlanetModel planetModel;
   
   /**
    * Type for a Geo3DDocValuesField
    * <p>
    * Each value stores a 64-bit long where the three values (x, y, and z) are given
    * 21 bits each.  Each 21-bit value represents the maximum extent in that dimension
-   * for the WGS84 planet model.
+   * for the defined planet model.
    */
   public static final FieldType TYPE = new FieldType();
   static {
@@ -98,8 +69,8 @@ public class Geo3DDocValuesField extends Field {
    * @param point is the point.
    * @throws IllegalArgumentException if the field name is null or the point is out of bounds
    */
-  public Geo3DDocValuesField(final String name, final GeoPoint point) {
-    super(name, TYPE);
+  public Geo3DDocValuesField(final String name, final GeoPoint point, final PlanetModel planetModel) {
+    this(name, TYPE, planetModel);
     setLocationValue(point);
   }
 
@@ -111,18 +82,23 @@ public class Geo3DDocValuesField extends Field {
    * @param z is the z value for the point.
    * @throws IllegalArgumentException if the field name is null or x, y, or z are out of bounds
    */
-  public Geo3DDocValuesField(final String name, final double x, final double y, final double z) {
-    super(name, TYPE);
+  public Geo3DDocValuesField(final String name, final double x, final double y, final double z, final PlanetModel planetModel) {
+    this(name, TYPE, planetModel);
     setLocationValue(x, y, z);
   }
-  
+
+  private Geo3DDocValuesField(final String name, final FieldType type, final PlanetModel planetModel) {
+    super(name, TYPE);
+    this.planetModel = planetModel;
+  }
+
   /**
    * Change the values of this field
    * @param point is the point.
    * @throws IllegalArgumentException if the point is out of bounds
    */
   public void setLocationValue(final GeoPoint point) {
-    fieldsData = Long.valueOf(encodePoint(point));
+    fieldsData = Long.valueOf(planetModel.getDocValueEncoder().encodePoint(point));
   }
 
   /**
@@ -133,158 +109,7 @@ public class Geo3DDocValuesField extends Field {
    * @throws IllegalArgumentException if x, y, or z are out of bounds
    */
   public void setLocationValue(final double x, final double y, final double z) {
-    fieldsData = Long.valueOf(encodePoint(x, y, z));
-  }
-  
-  /** Encode a point.
-   * @param point is the point
-   * @return the encoded long
-   */
-  public static long encodePoint(final GeoPoint point) {
-    return encodePoint(point.x, point.y, point.z);
-  }
-
-  /** Encode a point.
-   * @param x is the x value
-   * @param y is the y value
-   * @param z is the z value
-   * @return the encoded long
-   */
-  public static long encodePoint(final double x, final double y, final double z) {
-    int XEncoded = encodeX(x);
-    int YEncoded = encodeY(y);
-    int ZEncoded = encodeZ(z);
-    return
-      (((long)(XEncoded & 0x1FFFFF)) << 42) |
-      (((long)(YEncoded & 0x1FFFFF)) << 21) |
-      ((long)(ZEncoded & 0x1FFFFF));
-  }
-
-  /** Decode GeoPoint value from long docvalues value.
-   * @param docValue is the doc values value.
-   * @return the GeoPoint.
-   */
-  public static GeoPoint decodePoint(final long docValue) {
-    return new GeoPoint(decodeX(((int)(docValue >> 42)) & 0x1FFFFF),
-      decodeY(((int)(docValue >> 21)) & 0x1FFFFF),
-      decodeZ(((int)(docValue)) & 0x1FFFFF));
-  }
-  
-  /** Decode X value from long docvalues value.
-   * @param docValue is the doc values value.
-   * @return the x value.
-   */
-  public static double decodeXValue(final long docValue) {
-    return decodeX(((int)(docValue >> 42)) & 0x1FFFFF);
-  }
-  
-  /** Decode Y value from long docvalues value.
-   * @param docValue is the doc values value.
-   * @return the y value.
-   */
-  public static double decodeYValue(final long docValue) {
-    return decodeY(((int)(docValue >> 21)) & 0x1FFFFF);
-  }
-  
-  /** Decode Z value from long docvalues value.
-   * @param docValue is the doc values value.
-   * @return the z value.
-   */
-  public static double decodeZValue(final long docValue) {
-    return decodeZ(((int)(docValue)) & 0x1FFFFF);
-  }
-
-  /** Round the provided X value down, by encoding it, decrementing it, and unencoding it.
-   * @param startValue is the starting value.
-   * @return the rounded value.
-   */
-  public static double roundDownX(final double startValue) {
-    return startValue - xStep;
-  }
-
-  /** Round the provided X value up, by encoding it, incrementing it, and unencoding it.
-   * @param startValue is the starting value.
-   * @return the rounded value.
-   */
-  public static double roundUpX(final double startValue) {
-    return startValue + xStep;
-  }
-
-  /** Round the provided Y value down, by encoding it, decrementing it, and unencoding it.
-   * @param startValue is the starting value.
-   * @return the rounded value.
-   */
-  public static double roundDownY(final double startValue) {
-    return startValue - yStep;
-  }
-
-  /** Round the provided Y value up, by encoding it, incrementing it, and unencoding it.
-   * @param startValue is the starting value.
-   * @return the rounded value.
-   */
-  public static double roundUpY(final double startValue) {
-    return startValue + yStep;
-  }
-  
-  /** Round the provided Z value down, by encoding it, decrementing it, and unencoding it.
-   * @param startValue is the starting value.
-   * @return the rounded value.
-   */
-  public static double roundDownZ(final double startValue) {
-    return startValue - zStep;
-  }
-
-  /** Round the provided Z value up, by encoding it, incrementing it, and unencoding it.
-   * @param startValue is the starting value.
-   * @return the rounded value.
-   */
-  public static double roundUpZ(final double startValue) {
-    return startValue + zStep;
-  }
-
-  // For encoding/decoding, we generally want the following behavior:
-  // (1) If you encode the maximum value or the minimum value, the resulting int fits in 21 bits.
-  // (2) If you decode an encoded value, you get back the original value for both the minimum and maximum planet model values.
-  // (3) Rounding occurs such that a small delta from the minimum and maximum planet model values still returns the same
-  // values -- that is, these are in the center of the range of input values that should return the minimum or maximum when decoded
-  
-  private static int encodeX(final double x) {
-    if (x > PlanetModel.WGS84.getMaximumXValue()) {
-      throw new IllegalArgumentException("x value exceeds WGS84 maximum");
-    } else if (x < PlanetModel.WGS84.getMinimumXValue()) {
-      throw new IllegalArgumentException("x value less than WGS84 minimum");
-    }
-    return (int)Math.floor((x - PlanetModel.WGS84.getMinimumXValue()) * xFactor + 0.5);
-  }
-  
-  private static double decodeX(final int x) {
-    return x * inverseXFactor + PlanetModel.WGS84.getMinimumXValue();
-  }
-
-  private static int encodeY(final double y) {
-    if (y > PlanetModel.WGS84.getMaximumYValue()) {
-      throw new IllegalArgumentException("y value exceeds WGS84 maximum");
-    } else if (y < PlanetModel.WGS84.getMinimumYValue()) {
-      throw new IllegalArgumentException("y value less than WGS84 minimum");
-    }
-    return (int)Math.floor((y - PlanetModel.WGS84.getMinimumYValue()) * yFactor + 0.5);
-  }
-
-  private static double decodeY(final int y) {
-    return y * inverseYFactor + PlanetModel.WGS84.getMinimumYValue();
-  }
-
-  private static int encodeZ(final double z) {
-    if (z > PlanetModel.WGS84.getMaximumZValue()) {
-      throw new IllegalArgumentException("z value exceeds WGS84 maximum");
-    } else if (z < PlanetModel.WGS84.getMinimumZValue()) {
-      throw new IllegalArgumentException("z value less than WGS84 minimum");
-    }
-    return (int)Math.floor((z - PlanetModel.WGS84.getMinimumZValue()) * zFactor + 0.5);
-  }
-
-  private static double decodeZ(final int z) {
-    return z * inverseZFactor + PlanetModel.WGS84.getMinimumZValue();
+    fieldsData = Long.valueOf(planetModel.getDocValueEncoder().encodePoint(x, y, z));
   }
 
   /** helper: checks a fieldinfo and throws exception if its definitely not a Geo3DDocValuesField */
@@ -307,11 +132,11 @@ public class Geo3DDocValuesField extends Field {
 
     long currentValue = (Long)fieldsData;
     
-    result.append(decodeXValue(currentValue));
+    result.append(planetModel.getDocValueEncoder().decodeXValue(currentValue));
     result.append(',');
-    result.append(decodeYValue(currentValue));
+    result.append(planetModel.getDocValueEncoder().decodeYValue(currentValue));
     result.append(',');
-    result.append(decodeZValue(currentValue));
+    result.append(planetModel.getDocValueEncoder().decodeZValue(currentValue));
 
     result.append('>');
     return result.toString();
@@ -335,9 +160,9 @@ public class Geo3DDocValuesField extends Field {
    * @return SortField ordering documents by distance
    * @throws IllegalArgumentException if {@code field} is null or circle has invalid coordinates.
    */
-  public static SortField newDistanceSort(final String field, final double latitude, final double longitude, final double maxRadiusMeters) {
-    final GeoDistanceShape shape = Geo3DUtil.fromDistance(latitude, longitude, maxRadiusMeters);
-    return new Geo3DPointSortField(field, shape);
+  public static SortField newDistanceSort(final String field, final double latitude, final double longitude, final double maxRadiusMeters, final PlanetModel planetModel) {
+    final GeoDistanceShape shape = Geo3DUtil.fromDistance(planetModel, latitude, longitude, maxRadiusMeters);
+    return new Geo3DPointSortField(field, planetModel, shape);
   }
 
   /**
@@ -358,9 +183,9 @@ public class Geo3DDocValuesField extends Field {
    * @return SortField ordering documents by distance
    * @throws IllegalArgumentException if {@code field} is null or path has invalid coordinates.
    */
-  public static SortField newPathSort(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) {
-    final GeoDistanceShape shape = Geo3DUtil.fromPath(pathLatitudes, pathLongitudes, pathWidthMeters);
-    return new Geo3DPointSortField(field, shape);
+  public static SortField newPathSort(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters, final PlanetModel planetModel) {
+    final GeoDistanceShape shape = Geo3DUtil.fromPath(planetModel, pathLatitudes, pathLongitudes, pathWidthMeters);
+    return new Geo3DPointSortField(field, planetModel, shape);
   }
 
   // Outside distances
@@ -384,9 +209,9 @@ public class Geo3DDocValuesField extends Field {
    * @return SortField ordering documents by distance
    * @throws IllegalArgumentException if {@code field} is null or location has invalid coordinates.
    */
-  public static SortField newOutsideDistanceSort(final String field, final double latitude, final double longitude, final double maxRadiusMeters) {
-    final GeoOutsideDistance shape = Geo3DUtil.fromDistance(latitude, longitude, maxRadiusMeters);
-    return new Geo3DPointOutsideSortField(field, shape);
+  public static SortField newOutsideDistanceSort(final String field, final double latitude, final double longitude, final double maxRadiusMeters, final PlanetModel planetModel) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromDistance(planetModel, latitude, longitude, maxRadiusMeters);
+    return new Geo3DPointOutsideSortField(field, planetModel, shape);
   }
 
   /**
@@ -409,9 +234,9 @@ public class Geo3DDocValuesField extends Field {
    * @return SortField ordering documents by distance
    * @throws IllegalArgumentException if {@code field} is null or box has invalid coordinates.
    */
-  public static SortField newOutsideBoxSort(final String field, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
-    final GeoOutsideDistance shape = Geo3DUtil.fromBox(minLatitude, maxLatitude, minLongitude, maxLongitude);
-    return new Geo3DPointOutsideSortField(field, shape);
+  public static SortField newOutsideBoxSort(final String field, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude, final PlanetModel planetModel) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromBox(planetModel, minLatitude, maxLatitude, minLongitude, maxLongitude);
+    return new Geo3DPointOutsideSortField(field, planetModel, shape);
   }
 
   /**
@@ -431,9 +256,9 @@ public class Geo3DDocValuesField extends Field {
    * @return SortField ordering documents by distance
    * @throws IllegalArgumentException if {@code field} is null or polygon has invalid coordinates.
    */
-  public static SortField newOutsidePolygonSort(final String field, final Polygon... polygons) {
-    final GeoOutsideDistance shape = Geo3DUtil.fromPolygon(polygons);
-    return new Geo3DPointOutsideSortField(field, shape);
+  public static SortField newOutsidePolygonSort(final String field, final PlanetModel planetModel, final Polygon... polygons) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromPolygon(planetModel, polygons);
+    return new Geo3DPointOutsideSortField(field, planetModel, shape);
   }
 
   /**
@@ -454,9 +279,9 @@ public class Geo3DDocValuesField extends Field {
    * @return SortField ordering documents by distance
    * @throws IllegalArgumentException if {@code field} is null or polygon has invalid coordinates.
    */
-  public static SortField newOutsideLargePolygonSort(final String field, final Polygon... polygons) {
-    final GeoOutsideDistance shape = Geo3DUtil.fromLargePolygon(polygons);
-    return new Geo3DPointOutsideSortField(field, shape);
+  public static SortField newOutsideLargePolygonSort(final String field, final PlanetModel planetModel, final Polygon... polygons) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromLargePolygon(planetModel, polygons);
+    return new Geo3DPointOutsideSortField(field, planetModel, shape);
   }
 
   /**
@@ -478,9 +303,8 @@ public class Geo3DDocValuesField extends Field {
    * @return SortField ordering documents by distance
    * @throws IllegalArgumentException if {@code field} is null or path has invalid coordinates.
    */
-  public static SortField newOutsidePathSort(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) {
-    final GeoOutsideDistance shape = Geo3DUtil.fromPath(pathLatitudes, pathLongitudes, pathWidthMeters);
-    return new Geo3DPointOutsideSortField(field, shape);
+  public static SortField newOutsidePathSort(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters, final PlanetModel planetModel) {
+    final GeoOutsideDistance shape = Geo3DUtil.fromPath(planetModel, pathLatitudes, pathLongitudes, pathWidthMeters);
+    return new Geo3DPointOutsideSortField(field, planetModel, shape);
   }
-
 }
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
index 748d11c..eba72d5 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
@@ -41,6 +41,9 @@ import org.apache.lucene.util.NumericUtils;
  *  @lucene.experimental */
 public final class Geo3DPoint extends Field {
 
+  /** Planet Model for this Geo3DPoint */
+  protected final PlanetModel planetModel;
+
   /** Indexing {@link FieldType}. */
   public static final FieldType TYPE = new FieldType();
   static {
@@ -48,24 +51,54 @@ public final class Geo3DPoint extends Field {
     TYPE.freeze();
   }
 
-  /** 
-   * Creates a new Geo3DPoint field with the specified latitude, longitude (in degrees).
+  /**
+   * Creates a new Geo3DPoint field with the specified latitude, longitude (in degrees), with default WGS84 PlanetModel.
+   *
+   * @throws IllegalArgumentException if the field name is null or latitude or longitude are out of bounds
+   */
+  public Geo3DPoint(String name, double lat, double lon) {
+    this(name, PlanetModel.WGS84, lat, lon);
+  }
+
+  /**
+   * Creates a new Geo3DPoint field with the specified x,y,z, using default WGS84 planet model.
+   *
+   * @throws IllegalArgumentException if the field name is null or latitude or longitude are out of bounds
+   */
+  public Geo3DPoint(String name, double x, double y, double z) {
+    this(name, PlanetModel.WGS84, x, y, z);
+  }
+
+  /**
+   * Creates a new Geo3DPoint field with the specified x,y,z, and given planet model.
    *
    * @throws IllegalArgumentException if the field name is null or latitude or longitude are out of bounds
    */
-  public Geo3DPoint(String name, double latitude, double longitude) {
+  public Geo3DPoint(String name, PlanetModel planetModel, double x, double y, double z) {
+    super(name, TYPE);
+    this.planetModel = planetModel;
+    fillFieldsData(planetModel, x, y, z);
+  }
+
+  /**
+   * Creates a new Geo3DPoint field with the specified latitude, longitude (in degrees), given a planet model.
+   *
+   * @throws IllegalArgumentException if the field name is null or latitude or longitude are out of bounds
+   */
+  public Geo3DPoint(String name, PlanetModel planetModel, double latitude, double longitude) {
     super(name, TYPE);
     GeoUtils.checkLatitude(latitude);
     GeoUtils.checkLongitude(longitude);
+    this.planetModel = planetModel;
     // Translate latitude/longitude to x,y,z:
-    final GeoPoint point = new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(latitude), Geo3DUtil.fromDegrees(longitude));
-    fillFieldsData(point.x, point.y, point.z);
+    final GeoPoint point = new GeoPoint(planetModel, Geo3DUtil.fromDegrees(latitude), Geo3DUtil.fromDegrees(longitude));
+    fillFieldsData(planetModel, point.x, point.y, point.z);
   }
 
   /**
    * Create a query for matching points within the specified distance of the supplied location.
-   * @param field field name. must not be null.  Note that because
-   * {@link PlanetModel#WGS84} is used, this query is approximate and may have up
+   * @param field field name. must not be null.  Note that if
+   * {@link PlanetModel#WGS84} is used, the query is approximate and may have up
    * to 0.5% error.
    *
    * @param latitude latitude at the center: must be within standard +/-90 coordinate bounds.
@@ -74,8 +107,8 @@ public final class Geo3DPoint extends Field {
    * @return query matching points within this distance
    * @throws IllegalArgumentException if {@code field} is null, location has invalid coordinates, or radius is invalid.
    */
-  public static Query newDistanceQuery(final String field, final double latitude, final double longitude, final double radiusMeters) {
-    final GeoShape shape = Geo3DUtil.fromDistance(latitude, longitude, radiusMeters);
+  public static Query newDistanceQuery(final String field, final PlanetModel planetModel, final double latitude, final double longitude, final double radiusMeters) {
+    final GeoShape shape = Geo3DUtil.fromDistance(planetModel, latitude, longitude, radiusMeters);
     return newShapeQuery(field, shape);
   }
 
@@ -91,8 +124,8 @@ public final class Geo3DPoint extends Field {
    * @return query matching points within this box
    * @throws IllegalArgumentException if {@code field} is null, or the box has invalid coordinates.
    */
-  public static Query newBoxQuery(final String field, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
-    final GeoShape shape = Geo3DUtil.fromBox(minLatitude, maxLatitude, minLongitude, maxLongitude);
+  public static Query newBoxQuery(final String field, final PlanetModel planetModel, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
+    final GeoShape shape = Geo3DUtil.fromBox(planetModel, minLatitude, maxLatitude, minLongitude, maxLongitude);
     return newShapeQuery(field, shape);
   }
 
@@ -105,8 +138,8 @@ public final class Geo3DPoint extends Field {
    * @param polygons is the list of polygons to use to construct the query; must be at least one.
    * @return query matching points within this polygon
    */
-  public static Query newPolygonQuery(final String field, final Polygon... polygons) {
-    final GeoShape shape = Geo3DUtil.fromPolygon(polygons);
+  public static Query newPolygonQuery(final String field, final PlanetModel planetModel, final Polygon... polygons) {
+    final GeoShape shape = Geo3DUtil.fromPolygon(planetModel, polygons);
     return newShapeQuery(field, shape);
   }
 
@@ -119,8 +152,8 @@ public final class Geo3DPoint extends Field {
    * @param polygons is the list of polygons to use to construct the query; must be at least one.
    * @return query matching points within this polygon
    */
-  public static Query newLargePolygonQuery(final String field, final Polygon... polygons) {
-    final GeoShape shape = Geo3DUtil.fromLargePolygon(polygons);
+  public static Query newLargePolygonQuery(final String field, PlanetModel planetModel, final Polygon... polygons) {
+    final GeoShape shape = Geo3DUtil.fromLargePolygon(planetModel, polygons);
     return newShapeQuery(field, shape);
   }
 
@@ -133,39 +166,29 @@ public final class Geo3DPoint extends Field {
    * @param pathWidthMeters width of the path in meters.
    * @return query matching points within this polygon
    */
-  public static Query newPathQuery(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) {
-    final GeoShape shape = Geo3DUtil.fromPath(pathLatitudes, pathLongitudes, pathWidthMeters);
+  public static Query newPathQuery(final String field, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters, PlanetModel planetModel) {
+    final GeoShape shape = Geo3DUtil.fromPath(planetModel, pathLatitudes, pathLongitudes, pathWidthMeters);
     return newShapeQuery(field, shape);
   }
 
-  /** 
-   * Creates a new Geo3DPoint field with the specified x,y,z.
-   *
-   * @throws IllegalArgumentException if the field name is null or latitude or longitude are out of bounds
-   */
-  public Geo3DPoint(String name, double x, double y, double z) {
-    super(name, TYPE);
-    fillFieldsData(x, y, z);
-  }
-
-  private void fillFieldsData(double x, double y, double z) {
+  private void fillFieldsData(PlanetModel planetModel, double x, double y, double z) {
     byte[] bytes = new byte[12];
-    encodeDimension(x, bytes, 0);
-    encodeDimension(y, bytes, Integer.BYTES);
-    encodeDimension(z, bytes, 2*Integer.BYTES);
+    encodeDimension(x, bytes, 0, planetModel);
+    encodeDimension(y, bytes, Integer.BYTES, planetModel);
+    encodeDimension(z, bytes, 2*Integer.BYTES, planetModel);
     fieldsData = new BytesRef(bytes);
   }
 
   // public helper methods (e.g. for queries)
   
   /** Encode single dimension */
-  public static void encodeDimension(double value, byte bytes[], int offset) {
-    NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(value), bytes, offset);
+  public static void encodeDimension(double value, byte bytes[], int offset, PlanetModel planetModel) {
+    NumericUtils.intToSortableBytes(planetModel.encodeValue(value), bytes, offset);
   }
   
   /** Decode single dimension */
-  public static double decodeDimension(byte value[], int offset) {
-    return Geo3DUtil.decodeValue(NumericUtils.sortableBytesToInt(value, offset));
+  public static double decodeDimension(byte value[], int offset, PlanetModel planetModel) {
+    return planetModel.decodeValue(NumericUtils.sortableBytesToInt(value, offset));
   }
 
   /** Returns a query matching all points inside the provided shape.
@@ -186,9 +209,9 @@ public final class Geo3DPoint extends Field {
     result.append(':');
 
     BytesRef bytes = (BytesRef) fieldsData;
-    result.append(" x=").append(decodeDimension(bytes.bytes, bytes.offset));
-    result.append(" y=").append(decodeDimension(bytes.bytes, bytes.offset + Integer.BYTES));
-    result.append(" z=").append(decodeDimension(bytes.bytes, bytes.offset + 2 * Integer.BYTES));
+    result.append(" x=").append(decodeDimension(bytes.bytes, bytes.offset, this.planetModel));
+    result.append(" y=").append(decodeDimension(bytes.bytes, bytes.offset + Integer.BYTES, this.planetModel));
+    result.append(" z=").append(decodeDimension(bytes.bytes, bytes.offset + 2 * Integer.BYTES, this.planetModel));
     result.append('>');
     return result.toString();
   }
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointDistanceComparator.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointDistanceComparator.java
index b2cd9c5..64ff42c 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointDistanceComparator.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointDistanceComparator.java
@@ -42,6 +42,7 @@ class Geo3DPointDistanceComparator extends FieldComparator<Double> implements Le
   final String field;
   
   final GeoDistanceShape distanceShape;
+  final private PlanetModel planetModel;
 
   final double[] values;
   double bottomDistance;
@@ -53,9 +54,10 @@ class Geo3DPointDistanceComparator extends FieldComparator<Double> implements Le
   // the number of times setBottom has been called (adversary protection)
   int setBottomCounter = 0;
 
-  public Geo3DPointDistanceComparator(String field, final GeoDistanceShape distanceShape, int numHits) {
+  public Geo3DPointDistanceComparator(String field, final PlanetModel planetModel, final GeoDistanceShape distanceShape, int numHits) {
     this.field = field;
     this.distanceShape = distanceShape;
+    this.planetModel = planetModel;
     this.values = new double[numHits];
   }
   
@@ -105,9 +107,9 @@ class Geo3DPointDistanceComparator extends FieldComparator<Double> implements Le
 
       // Test against bounds.
       // First we need to decode...
-      final double x = Geo3DDocValuesField.decodeXValue(encoded);
-      final double y = Geo3DDocValuesField.decodeYValue(encoded);
-      final double z = Geo3DDocValuesField.decodeZValue(encoded);
+      final double x = planetModel.getDocValueEncoder().decodeXValue(encoded);
+      final double y = planetModel.getDocValueEncoder().decodeYValue(encoded);
+      final double z = planetModel.getDocValueEncoder().decodeZValue(encoded);
       
       if (x > priorityQueueBounds.getMaximumX() ||
         x < priorityQueueBounds.getMinimumX() ||
@@ -142,7 +144,7 @@ class Geo3DPointDistanceComparator extends FieldComparator<Double> implements Le
   @Override
   public Double value(int slot) {
     // Return the arc distance
-    return Double.valueOf(values[slot] * PlanetModel.WGS84_MEAN);
+    return Double.valueOf(values[slot] * planetModel.getMeanRadiusMeters());
   }
   
   @Override
@@ -160,9 +162,9 @@ class Geo3DPointDistanceComparator extends FieldComparator<Double> implements Le
       for (int i = 0; i < numValues; i++) {
         final long encoded = currentDocs.nextValue();
         final double distance = distanceShape.computeDistance(DistanceStyle.ARC,
-                                                              Geo3DDocValuesField.decodeXValue(encoded),
-                                                              Geo3DDocValuesField.decodeYValue(encoded),
-                                                              Geo3DDocValuesField.decodeZValue(encoded));
+                                                              planetModel.getDocValueEncoder().decodeXValue(encoded),
+                                                              planetModel.getDocValueEncoder().decodeYValue(encoded),
+                                                              planetModel.getDocValueEncoder().decodeZValue(encoded));
         minValue = Math.min(minValue, distance);
       }
     }
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
index c45cbba..d771598 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideDistanceComparator.java
@@ -37,14 +37,16 @@ class Geo3DPointOutsideDistanceComparator extends FieldComparator<Double> implem
   final String field;
   
   final GeoOutsideDistance distanceShape;
+  final private PlanetModel planetModel;
 
   final double[] values;
   double bottomDistance;
   double topValue;
   SortedNumericDocValues currentDocs;
   
-  public Geo3DPointOutsideDistanceComparator(String field, final GeoOutsideDistance distanceShape, int numHits) {
+  public Geo3DPointOutsideDistanceComparator(String field, final PlanetModel planetModel, final GeoOutsideDistance distanceShape, int numHits) {
     this.field = field;
+    this.planetModel = planetModel;
     this.distanceShape = distanceShape;
     this.values = new double[numHits];
   }
@@ -85,9 +87,9 @@ class Geo3DPointOutsideDistanceComparator extends FieldComparator<Double> implem
 
       // Test against bounds.
       // First we need to decode...
-      final double x = Geo3DDocValuesField.decodeXValue(encoded);
-      final double y = Geo3DDocValuesField.decodeYValue(encoded);
-      final double z = Geo3DDocValuesField.decodeZValue(encoded);
+      final double x = planetModel.getDocValueEncoder().decodeXValue(encoded);
+      final double y = planetModel.getDocValueEncoder().decodeYValue(encoded);
+      final double z = planetModel.getDocValueEncoder().decodeZValue(encoded);
       
       cmp = Math.max(cmp, Double.compare(bottomDistance, distanceShape.computeOutsideDistance(DistanceStyle.ARC, x, y, z)));
     }
@@ -113,7 +115,7 @@ class Geo3DPointOutsideDistanceComparator extends FieldComparator<Double> implem
   @Override
   public Double value(int slot) {
     // Return the arc distance
-    return Double.valueOf(values[slot] * PlanetModel.WGS84_MEAN);
+    return Double.valueOf(values[slot] * planetModel.getMeanRadiusMeters());
   }
   
   @Override
@@ -131,9 +133,9 @@ class Geo3DPointOutsideDistanceComparator extends FieldComparator<Double> implem
       for (int i = 0; i < numValues; i++) {
         final long encoded = currentDocs.nextValue();
         final double distance = distanceShape.computeOutsideDistance(DistanceStyle.ARC,
-                                                                     Geo3DDocValuesField.decodeXValue(encoded),
-                                                                     Geo3DDocValuesField.decodeYValue(encoded),
-                                                                     Geo3DDocValuesField.decodeZValue(encoded));
+                                                                     planetModel.getDocValueEncoder().decodeXValue(encoded),
+                                                                     planetModel.getDocValueEncoder().decodeYValue(encoded),
+                                                                     planetModel.getDocValueEncoder().decodeZValue(encoded));
         minValue = Math.min(minValue, distance);
       }
     }
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java
index 55cd985..e7251ff 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointOutsideSortField.java
@@ -19,14 +19,16 @@ package org.apache.lucene.spatial3d;
 import org.apache.lucene.search.FieldComparator;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.spatial3d.geom.GeoOutsideDistance;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 
 /**
  * Sorts by outside distance from an origin location.
  */
 final class Geo3DPointOutsideSortField extends SortField {
   final GeoOutsideDistance distanceShape;
+  final private PlanetModel planetModel;
 
-  Geo3DPointOutsideSortField(final String field, final GeoOutsideDistance distanceShape) {
+  Geo3DPointOutsideSortField(final String field, final PlanetModel planetModel, final GeoOutsideDistance distanceShape) {
     super(field, SortField.Type.CUSTOM);
     if (field == null) {
       throw new IllegalArgumentException("field must not be null");
@@ -34,13 +36,14 @@ final class Geo3DPointOutsideSortField extends SortField {
     if (distanceShape == null) {
       throw new IllegalArgumentException("distanceShape must not be null");
     }
+    this.planetModel = planetModel;
     this.distanceShape = distanceShape;
     setMissingValue(Double.POSITIVE_INFINITY);
   }
   
   @Override
   public FieldComparator<?> getComparator(int numHits, int sortPos) {
-    return new Geo3DPointOutsideDistanceComparator(getField(), distanceShape, numHits);
+    return new Geo3DPointOutsideDistanceComparator(getField(), planetModel, distanceShape, numHits);
   }
 
   @Override
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointSortField.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointSortField.java
index 476ef94..d15eb25 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointSortField.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPointSortField.java
@@ -19,14 +19,16 @@ package org.apache.lucene.spatial3d;
 import org.apache.lucene.search.FieldComparator;
 import org.apache.lucene.search.SortField;
 import org.apache.lucene.spatial3d.geom.GeoDistanceShape;
+import org.apache.lucene.spatial3d.geom.PlanetModel;
 
 /**
  * Sorts by distance from an origin location.
  */
 final class Geo3DPointSortField extends SortField {
   final GeoDistanceShape distanceShape;
+  final PlanetModel planetModel;
 
-  Geo3DPointSortField(final String field, final GeoDistanceShape distanceShape) {
+  Geo3DPointSortField(final String field, final PlanetModel planetModel, final GeoDistanceShape distanceShape) {
     super(field, SortField.Type.CUSTOM);
     if (field == null) {
       throw new IllegalArgumentException("field must not be null");
@@ -35,12 +37,13 @@ final class Geo3DPointSortField extends SortField {
       throw new IllegalArgumentException("distanceShape must not be null");
     }
     this.distanceShape = distanceShape;
+    this.planetModel = planetModel;
     setMissingValue(Double.POSITIVE_INFINITY);
   }
   
   @Override
   public FieldComparator<?> getComparator(int numHits, int sortPos) {
-    return new Geo3DPointDistanceComparator(getField(), distanceShape, numHits);
+    return new Geo3DPointDistanceComparator(getField(), planetModel, distanceShape, numHits);
   }
 
   @Override
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
index 4e1ecb5..032fa2b 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DUtil.java
@@ -36,119 +36,57 @@ import java.util.ArrayList;
 
 class Geo3DUtil {
 
-  /** How many radians are in one earth surface meter */
-  final static double RADIANS_PER_METER = 1.0 / PlanetModel.WGS84_MEAN;
   /** How many radians are in one degree */
   final static double RADIANS_PER_DEGREE = Math.PI / 180.0;
-  
-  private static final double MAX_VALUE = PlanetModel.WGS84.getMaximumMagnitude();
-  private static final int BITS = 32;
-  private static final double MUL = (0x1L<<BITS)/(2*MAX_VALUE);
-  static final double DECODE = getNextSafeDouble(1/MUL);
-  static final int MIN_ENCODED_VALUE = encodeValue(-MAX_VALUE);
-  static final int MAX_ENCODED_VALUE = encodeValue(MAX_VALUE);
-
-  public static int encodeValue(double x) {
-    if (x > MAX_VALUE) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (greater than WGS84's planetMax=" + MAX_VALUE + ")");
-    }
-    if (x < -MAX_VALUE) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than WGS84's -planetMax=" + -MAX_VALUE + ")");
-    }
-    long result = (long) Math.floor(x / DECODE);
-    assert result >= Integer.MIN_VALUE;
-    assert result <= Integer.MAX_VALUE;
-    return (int) result;
-  }
-
-  public static double decodeValue(int x) {
-    double result;
-    if (x == MIN_ENCODED_VALUE) {
-      // We must special case this, because -MAX_VALUE is not guaranteed to land precisely at a floor value, and we don't ever want to
-      // return a value outside of the planet's range (I think?).  The max value is "safe" because we floor during encode:
-      result = -MAX_VALUE;
-    } else if (x == MAX_ENCODED_VALUE) {
-      result = MAX_VALUE;
-    } else {
-      // We decode to the center value; this keeps the encoding stable
-      result = (x+0.5) * DECODE;
-    }
-    assert result >= -MAX_VALUE && result <= MAX_VALUE;
-    return result;
-  }
 
   /** Returns smallest double that would encode to int x. */
-  // NOTE: keep this package private!!
-  static double decodeValueFloor(int x) {
-    assert x <= MAX_ENCODED_VALUE && x >= MIN_ENCODED_VALUE;
-    if (x == MIN_ENCODED_VALUE) {
-      return -MAX_VALUE;
+  // NOTE: remains in this class to keep method package private!!
+  static double decodeValueFloor(int x, PlanetModel planetModel) {
+    assert x <= planetModel.MAX_ENCODED_VALUE && x >= planetModel.MIN_ENCODED_VALUE;
+    if (x == planetModel.MIN_ENCODED_VALUE) {
+      return -planetModel.MAX_VALUE;
     }
-    return x * DECODE;
-  }
-  
-  /** Returns a double value >= x such that if you multiply that value by an int, and then
-   *  divide it by that int again, you get precisely the same value back */
-  private static double getNextSafeDouble(double x) {
-
-    // Move to double space:
-    long bits = Double.doubleToLongBits(x);
-
-    // Make sure we are beyond the actual maximum value:
-    bits += Integer.MAX_VALUE;
-
-    // Clear the bottom 32 bits:
-    bits &= ~((long) Integer.MAX_VALUE);
-
-    // Convert back to double:
-    double result = Double.longBitsToDouble(bits);
-    assert result > x;
-    return result;
+    return x * planetModel.DECODE;
   }
 
   /** Returns largest double that would encode to int x. */
   // NOTE: keep this package private!!
-  static double decodeValueCeil(int x) {
-    assert x <= MAX_ENCODED_VALUE && x >= MIN_ENCODED_VALUE;
-    if (x == MAX_ENCODED_VALUE) {
-      return MAX_VALUE;
+  static double decodeValueCeil(int x, PlanetModel planetModel) {
+    assert x <= planetModel.MAX_ENCODED_VALUE && x >= planetModel.MIN_ENCODED_VALUE;
+    if (x == planetModel.MAX_ENCODED_VALUE) {
+      return planetModel.MAX_VALUE;
     }
-    return Math.nextDown((x+1) * DECODE);
+    return Math.nextDown((x+1) * planetModel.DECODE);
   }
   
   /** Converts degress to radians */
   static double fromDegrees(final double degrees) {
     return degrees * RADIANS_PER_DEGREE;
   }
-  
-  /** Converts earth-surface meters to radians */
-  static double fromMeters(final double meters) {
-    return meters * RADIANS_PER_METER;
-  }
 
   /**
     * Convert a set of Polygon objects into a GeoPolygon.
     * @param polygons are the Polygon objects.
     * @return the GeoPolygon.
     */
-  static GeoPolygon fromPolygon(final Polygon... polygons) {
+  static GeoPolygon fromPolygon(final PlanetModel planetModel, final Polygon... polygons) {
     //System.err.println("Creating polygon...");
     if (polygons.length < 1) {
       throw new IllegalArgumentException("need at least one polygon");
     }
     final GeoPolygon shape;
     if (polygons.length == 1) {
-      final GeoPolygon component = fromPolygon(polygons[0]);
+      final GeoPolygon component = fromPolygon(planetModel, polygons[0]);
       if (component == null) {
         // Polygon is degenerate
-        shape = new GeoCompositePolygon(PlanetModel.WGS84);
+        shape = new GeoCompositePolygon(planetModel);
       } else {
         shape = component;
       }
     } else {
-      final GeoCompositePolygon poly = new GeoCompositePolygon(PlanetModel.WGS84);
+      final GeoCompositePolygon poly = new GeoCompositePolygon(planetModel);
       for (final Polygon p : polygons) {
-        final GeoPolygon component = fromPolygon(p);
+        final GeoPolygon component = fromPolygon(planetModel, p);
         if (component != null) {
           poly.addShape(component);
         }
@@ -165,11 +103,11 @@ class Geo3DUtil {
    * @param polygons is the list of polygons to convert.
    * @return the large GeoPolygon.
    */
-  static GeoPolygon fromLargePolygon(final Polygon... polygons) {
+  static GeoPolygon fromLargePolygon(final PlanetModel planetModel, final Polygon... polygons) {
     if (polygons.length < 1) {
       throw new IllegalArgumentException("need at least one polygon");
     }
-    return GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.WGS84, convertToDescription(polygons));
+    return GeoPolygonFactory.makeLargeGeoPolygon(planetModel, convertToDescription(planetModel, polygons));
   }
   
   /**
@@ -179,7 +117,7 @@ class Geo3DUtil {
    * @param pathWidthMeters width of the path in meters.
    * @return the path.
    */
-  static GeoPath fromPath(final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) {
+  static GeoPath fromPath(final PlanetModel planetModel, final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) {
     if (pathLatitudes.length != pathLongitudes.length) {
       throw new IllegalArgumentException("same number of latitudes and longitudes required");
     }
@@ -189,9 +127,9 @@ class Geo3DUtil {
       final double longitude = pathLongitudes[i];
       GeoUtils.checkLatitude(latitude);
       GeoUtils.checkLongitude(longitude);
-      points[i] = new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude));
+      points[i] = new GeoPoint(planetModel, fromDegrees(latitude), fromDegrees(longitude));
     }
-    return GeoPathFactory.makeGeoPath(PlanetModel.WGS84, fromMeters(pathWidthMeters), points);
+    return GeoPathFactory.makeGeoPath(planetModel, planetModel.fromMeters(pathWidthMeters), points);
   }
   
   /**
@@ -201,10 +139,10 @@ class Geo3DUtil {
    * @param radiusMeters maximum distance from the center in meters: must be non-negative and finite.
    * @return the circle.
    */
-  static GeoCircle fromDistance(final double latitude, final double longitude, final double radiusMeters) {
+  static GeoCircle fromDistance(final PlanetModel planetModel, final double latitude, final double longitude, final double radiusMeters) {
     GeoUtils.checkLatitude(latitude);
     GeoUtils.checkLongitude(longitude);
-    return GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude), fromMeters(radiusMeters));
+    return GeoCircleFactory.makeGeoCircle(planetModel, fromDegrees(latitude), fromDegrees(longitude), planetModel.fromMeters(radiusMeters));
   }
   
   /**
@@ -215,12 +153,12 @@ class Geo3DUtil {
    * @param maxLongitude longitude upper bound: must be within standard +/-180 coordinate bounds.
    * @return the box.
    */
-  static GeoBBox fromBox(final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
+  static GeoBBox fromBox(final PlanetModel planetModel, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
     GeoUtils.checkLatitude(minLatitude);
     GeoUtils.checkLongitude(minLongitude);
     GeoUtils.checkLatitude(maxLatitude);
     GeoUtils.checkLongitude(maxLongitude);
-    return GeoBBoxFactory.makeGeoBBox(PlanetModel.WGS84, 
+    return GeoBBoxFactory.makeGeoBBox(planetModel,
       Geo3DUtil.fromDegrees(maxLatitude), Geo3DUtil.fromDegrees(minLatitude), Geo3DUtil.fromDegrees(minLongitude), Geo3DUtil.fromDegrees(maxLongitude));
   }
 
@@ -230,14 +168,14 @@ class Geo3DUtil {
     * @param polygon is the Polygon object.
     * @return the GeoPolygon.
     */
-  private static GeoPolygon fromPolygon(final Polygon polygon) {
+  private static GeoPolygon fromPolygon(final PlanetModel planetModel, final Polygon polygon) {
     // First, assemble the "holes".  The geo3d convention is to use the same polygon sense on the inner ring as the
     // outer ring, so we process these recursively with reverseMe flipped.
     final Polygon[] theHoles = polygon.getHoles();
     final List<GeoPolygon> holeList = new ArrayList<>(theHoles.length);
     for (final Polygon hole : theHoles) {
       //System.out.println("Hole: "+hole);
-      final GeoPolygon component = fromPolygon(hole);
+      final GeoPolygon component = fromPolygon(planetModel, hole);
       if (component != null) {
         holeList.add(component);
       }
@@ -252,10 +190,10 @@ class Geo3DUtil {
     // We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
     for (int i = 0; i < polyLats.length - 1; i++) {
       final int index = polyLats.length - 2 - i;
-      points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
+      points.add(new GeoPoint(planetModel, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
     }
     //System.err.println(" building polygon with "+points.size()+" points...");
-    final GeoPolygon rval = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, holeList);
+    final GeoPolygon rval = GeoPolygonFactory.makeGeoPolygon(planetModel, points, holeList);
     //System.err.println(" ...done");
     return rval;
   }
@@ -265,11 +203,11 @@ class Geo3DUtil {
    * @param polygons is the list of polygons to convert.
    * @return the list of polygon descriptions.
    */
-  private static List<GeoPolygonFactory.PolygonDescription> convertToDescription(final Polygon... polygons) {
+  private static List<GeoPolygonFactory.PolygonDescription> convertToDescription(final PlanetModel planetModel, final Polygon... polygons) {
     final List<GeoPolygonFactory.PolygonDescription> descriptions = new ArrayList<>(polygons.length);
     for (final Polygon polygon : polygons) {
       final Polygon[] theHoles = polygon.getHoles();
-      final List<GeoPolygonFactory.PolygonDescription> holes = convertToDescription(theHoles);
+      final List<GeoPolygonFactory.PolygonDescription> holes = convertToDescription(planetModel, theHoles);
       
       // Now do the polygon itself
       final double[] polyLats = polygon.getPolyLats();
@@ -280,7 +218,7 @@ class Geo3DUtil {
       // We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
       for (int i = 0; i < polyLats.length - 1; i++) {
         final int index = polyLats.length - 2 - i;
-        points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
+        points.add(new GeoPoint(planetModel, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
       }
       
       descriptions.add(new GeoPolygonFactory.PolygonDescription(points, holes));
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
index f5ccaed..09450fc 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java
@@ -29,9 +29,7 @@ import org.apache.lucene.search.QueryVisitor;
 import org.apache.lucene.search.ScoreMode;
 import org.apache.lucene.search.Scorer;
 import org.apache.lucene.search.Weight;
-import org.apache.lucene.spatial3d.geom.BasePlanetObject;
 import org.apache.lucene.spatial3d.geom.GeoShape;
-import org.apache.lucene.spatial3d.geom.PlanetModel;
 import org.apache.lucene.spatial3d.geom.XYZBounds;
 import org.apache.lucene.util.Accountable;
 import org.apache.lucene.util.DocIdSetBuilder;
@@ -56,13 +54,6 @@ final class PointInGeo3DShapeQuery extends Query implements Accountable {
     this.shape = shape;
     this.shapeBounds = new XYZBounds();
     shape.getBounds(shapeBounds);
-
-    if (shape instanceof BasePlanetObject) {
-      BasePlanetObject planetObject = (BasePlanetObject) shape;
-      if (planetObject.getPlanetModel().equals(PlanetModel.WGS84) == false) {
-        throw new IllegalArgumentException("this qurey requires PlanetModel.WGS84, but got: " + planetObject.getPlanetModel());
-      }
-    }
   }
 
   @Override
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInShapeIntersectVisitor.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInShapeIntersectVisitor.java
index 422c40f..1aa0ec2 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInShapeIntersectVisitor.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInShapeIntersectVisitor.java
@@ -22,7 +22,7 @@ import org.apache.lucene.index.PointValues.Relation;
 import org.apache.lucene.spatial3d.geom.GeoArea;
 import org.apache.lucene.spatial3d.geom.GeoAreaFactory;
 import org.apache.lucene.spatial3d.geom.GeoShape;
-import org.apache.lucene.spatial3d.geom.PlanetModel;
+import org.apache.lucene.spatial3d.geom.PlanetModel.DocValueEncoder;
 import org.apache.lucene.spatial3d.geom.XYZBounds;
 import org.apache.lucene.util.DocIdSetBuilder;
 import org.apache.lucene.util.NumericUtils;
@@ -43,12 +43,13 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
     XYZBounds bounds) {
     this.hits = hits;
     this.shape = shape;
-    this.minimumX = Geo3DDocValuesField.roundDownX(bounds.getMinimumX());
-    this.maximumX = Geo3DDocValuesField.roundUpX(bounds.getMaximumX());
-    this.minimumY = Geo3DDocValuesField.roundDownY(bounds.getMinimumY());
-    this.maximumY = Geo3DDocValuesField.roundUpY(bounds.getMaximumY());
-    this.minimumZ = Geo3DDocValuesField.roundDownZ(bounds.getMinimumZ());
-    this.maximumZ = Geo3DDocValuesField.roundUpZ(bounds.getMaximumZ());
+    DocValueEncoder docValueEncoder = shape.getPlanetModel().getDocValueEncoder();
+    this.minimumX = docValueEncoder.roundDownX(bounds.getMinimumX());
+    this.maximumX = docValueEncoder.roundUpX(bounds.getMaximumX());
+    this.minimumY = docValueEncoder.roundDownY(bounds.getMinimumY());
+    this.maximumY = docValueEncoder.roundUpY(bounds.getMaximumY());
+    this.minimumZ = docValueEncoder.roundDownZ(bounds.getMinimumZ());
+    this.maximumZ = docValueEncoder.roundUpZ(bounds.getMaximumZ());
   }
 
   @Override
@@ -64,9 +65,9 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
   @Override
   public void visit(int docID, byte[] packedValue) {
     assert packedValue.length == 12;
-    double x = Geo3DPoint.decodeDimension(packedValue, 0);
-    double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
-    double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
+    double x = Geo3DPoint.decodeDimension(packedValue, 0, shape.getPlanetModel());
+    double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES, shape.getPlanetModel());
+    double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES, shape.getPlanetModel());
     if (x >= minimumX && x <= maximumX &&
       y >= minimumY && y <= maximumY &&
       z >= minimumZ && z <= maximumZ) {
@@ -82,12 +83,12 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
     // here are inclusive, we need to extend the bounds to the largest un-quantized values that
     // could quantize into these bounds.  The encoding (Geo3DUtil.encodeValue) does
     // a Math.round from double to long, so e.g. 1.4 -> 1, and -1.4 -> -1:
-    double xMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 0));
-    double xMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 0));
-    double yMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
-    double yMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
-    double zMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
-    double zMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
+    double xMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 0), shape.getPlanetModel());
+    double xMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 0), shape.getPlanetModel());
+    double yMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES), shape.getPlanetModel());
+    double yMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES), shape.getPlanetModel());
+    double zMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES), shape.getPlanetModel());
+    double zMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES), shape.getPlanetModel());
 
     //System.out.println("  compare: x=" + cellXMin + "-" + cellXMax + " y=" + cellYMin + "-" + cellYMax + " z=" + cellZMin + "-" + cellZMax);
     assert xMin <= xMax;
@@ -102,7 +103,7 @@ class PointInShapeIntersectVisitor implements IntersectVisitor {
     }
 
     // Quick test failed so do slower one...
-    GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
+    GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(shape.getPlanetModel(), xMin, xMax, yMin, yMax, zMin, zMax);
 
     switch(xyzSolid.getRelationship(shape)) {
     case GeoArea.CONTAINS:
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
index 4b9ce10..af6e785 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoComplexPolygon.java
@@ -300,8 +300,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       
       if (testPointFixedYAbovePlane != null && testPointFixedYBelowPlane != null && fixedXAbovePlane != null && fixedXBelowPlane != null) {
         //check if planes intersects  inside world
-        final double checkAbove = 4.0 * (fixedXAbovePlane.D * fixedXAbovePlane.D * planetModel.inverseAbSquared + testPointFixedYAbovePlane.D * testPointFixedYAbovePlane.D * planetModel.inverseAbSquared - 1.0);
-        final double checkBelow = 4.0 * (fixedXBelowPlane.D * fixedXBelowPlane.D * planetModel.inverseAbSquared + testPointFixedYBelowPlane.D * testPointFixedYBelowPlane.D * planetModel.inverseAbSquared - 1.0);
+        final double checkAbove = 4.0 * (fixedXAbovePlane.D * fixedXAbovePlane.D * planetModel.inverseXYScalingSquared + testPointFixedYAbovePlane.D * testPointFixedYAbovePlane.D * planetModel.inverseXYScalingSquared - 1.0);
+        final double checkBelow = 4.0 * (fixedXBelowPlane.D * fixedXBelowPlane.D * planetModel.inverseXYScalingSquared + testPointFixedYBelowPlane.D * testPointFixedYBelowPlane.D * planetModel.inverseXYScalingSquared - 1.0);
         if (checkAbove < Vector.MINIMUM_RESOLUTION_SQUARED && checkBelow < Vector.MINIMUM_RESOLUTION_SQUARED) {
           //System.out.println("  Looking for intersections between travel and test point planes...");
           final GeoPoint[] XIntersectionsY = travelPlaneFixedX.findIntersections(planetModel, testPointFixedYPlane);
@@ -325,8 +325,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       if (testPointFixedZAbovePlane != null && testPointFixedZBelowPlane != null && fixedXAbovePlane != null && fixedXBelowPlane != null) {
         //check if planes intersects  inside world
-        final double checkAbove = 4.0 * (fixedXAbovePlane.D * fixedXAbovePlane.D * planetModel.inverseAbSquared + testPointFixedZAbovePlane.D * testPointFixedZAbovePlane.D * planetModel.inverseCSquared - 1.0);
-        final double checkBelow = 4.0 * (fixedXBelowPlane.D * fixedXBelowPlane.D * planetModel.inverseAbSquared + testPointFixedZBelowPlane.D * testPointFixedZBelowPlane.D * planetModel.inverseCSquared - 1.0);
+        final double checkAbove = 4.0 * (fixedXAbovePlane.D * fixedXAbovePlane.D * planetModel.inverseXYScalingSquared + testPointFixedZAbovePlane.D * testPointFixedZAbovePlane.D * planetModel.inverseZScalingSquared - 1.0);
+        final double checkBelow = 4.0 * (fixedXBelowPlane.D * fixedXBelowPlane.D * planetModel.inverseXYScalingSquared + testPointFixedZBelowPlane.D * testPointFixedZBelowPlane.D * planetModel.inverseZScalingSquared - 1.0);
         if (checkAbove < Vector.MINIMUM_RESOLUTION_SQUARED && checkBelow < Vector.MINIMUM_RESOLUTION_SQUARED) {
           //System.out.println("  Looking for intersections between travel and test point planes...");
           final GeoPoint[] XIntersectionsZ = travelPlaneFixedX.findIntersections(planetModel, testPointFixedZPlane);
@@ -349,8 +349,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       if (testPointFixedXAbovePlane != null && testPointFixedXBelowPlane != null && fixedYAbovePlane != null && fixedYBelowPlane != null) {
         //check if planes intersects inside world
-        final double checkAbove = 4.0 * (testPointFixedXAbovePlane.D * testPointFixedXAbovePlane.D * planetModel.inverseAbSquared + fixedYAbovePlane.D * fixedYAbovePlane.D * planetModel.inverseAbSquared - 1.0);
-        final double checkBelow = 4.0 * (testPointFixedXBelowPlane.D * testPointFixedXBelowPlane.D * planetModel.inverseAbSquared + fixedYBelowPlane.D * fixedYBelowPlane.D * planetModel.inverseAbSquared - 1.0);
+        final double checkAbove = 4.0 * (testPointFixedXAbovePlane.D * testPointFixedXAbovePlane.D * planetModel.inverseXYScalingSquared + fixedYAbovePlane.D * fixedYAbovePlane.D * planetModel.inverseXYScalingSquared - 1.0);
+        final double checkBelow = 4.0 * (testPointFixedXBelowPlane.D * testPointFixedXBelowPlane.D * planetModel.inverseXYScalingSquared + fixedYBelowPlane.D * fixedYBelowPlane.D * planetModel.inverseXYScalingSquared - 1.0);
         if (checkAbove < Vector.MINIMUM_RESOLUTION_SQUARED && checkBelow < Vector.MINIMUM_RESOLUTION_SQUARED) {
           //System.out.println("  Looking for intersections between travel and test point planes...");
           final GeoPoint[] YIntersectionsX = travelPlaneFixedY.findIntersections(planetModel, testPointFixedXPlane);
@@ -373,8 +373,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       if (testPointFixedZAbovePlane != null && testPointFixedZBelowPlane != null && fixedYAbovePlane != null && fixedYBelowPlane != null) {
         //check if planes intersects inside world
-        final double checkAbove = 4.0 * (testPointFixedZAbovePlane.D * testPointFixedZAbovePlane.D * planetModel.inverseCSquared + fixedYAbovePlane.D * fixedYAbovePlane.D * planetModel.inverseAbSquared - 1.0);
-        final double checkBelow = 4.0 * (testPointFixedZBelowPlane.D * testPointFixedZBelowPlane.D * planetModel.inverseCSquared + fixedYBelowPlane.D * fixedYBelowPlane.D * planetModel.inverseAbSquared - 1.0);
+        final double checkAbove = 4.0 * (testPointFixedZAbovePlane.D * testPointFixedZAbovePlane.D * planetModel.inverseZScalingSquared + fixedYAbovePlane.D * fixedYAbovePlane.D * planetModel.inverseXYScalingSquared - 1.0);
+        final double checkBelow = 4.0 * (testPointFixedZBelowPlane.D * testPointFixedZBelowPlane.D * planetModel.inverseZScalingSquared + fixedYBelowPlane.D * fixedYBelowPlane.D * planetModel.inverseXYScalingSquared - 1.0);
         if (checkAbove < Vector.MINIMUM_RESOLUTION_SQUARED && checkBelow < Vector.MINIMUM_RESOLUTION_SQUARED) {
           //System.out.println("  Looking for intersections between travel and test point planes...");
           final GeoPoint[] YIntersectionsZ = travelPlaneFixedY.findIntersections(planetModel, testPointFixedZPlane);
@@ -397,8 +397,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       if (testPointFixedXAbovePlane != null && testPointFixedXBelowPlane != null && fixedZAbovePlane != null && fixedZBelowPlane != null) {
         //check if planes intersects inside world
-        final double checkAbove = 4.0 * (testPointFixedXAbovePlane.D * testPointFixedXAbovePlane.D * planetModel.inverseAbSquared + fixedZAbovePlane.D * fixedZAbovePlane.D * planetModel.inverseCSquared - 1.0);
-        final double checkBelow = 4.0 * (testPointFixedXBelowPlane.D * testPointFixedXBelowPlane.D * planetModel.inverseAbSquared + fixedZBelowPlane.D * fixedZBelowPlane.D * planetModel.inverseCSquared - 1.0);
+        final double checkAbove = 4.0 * (testPointFixedXAbovePlane.D * testPointFixedXAbovePlane.D * planetModel.inverseXYScalingSquared + fixedZAbovePlane.D * fixedZAbovePlane.D * planetModel.inverseZScalingSquared - 1.0);
+        final double checkBelow = 4.0 * (testPointFixedXBelowPlane.D * testPointFixedXBelowPlane.D * planetModel.inverseXYScalingSquared + fixedZBelowPlane.D * fixedZBelowPlane.D * planetModel.inverseZScalingSquared - 1.0);
         if (checkAbove < Vector.MINIMUM_RESOLUTION_SQUARED && checkBelow < Vector.MINIMUM_RESOLUTION_SQUARED) {
           //System.out.println("  Looking for intersections between travel and test point planes...");
           final GeoPoint[] ZIntersectionsX = travelPlaneFixedZ.findIntersections(planetModel, testPointFixedXPlane);
@@ -421,8 +421,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
       }
       if (testPointFixedYAbovePlane != null && testPointFixedYBelowPlane != null && fixedZAbovePlane != null && fixedZBelowPlane != null) {
         //check if planes intersects inside world
-        final double checkAbove = 4.0 * (testPointFixedYAbovePlane.D * testPointFixedYAbovePlane.D * planetModel.inverseAbSquared + fixedZAbovePlane.D * fixedZAbovePlane.D * planetModel.inverseCSquared - 1.0);
-        final double checkBelow = 4.0 * (testPointFixedYBelowPlane.D * testPointFixedYBelowPlane.D * planetModel.inverseAbSquared + fixedZBelowPlane.D * fixedZBelowPlane.D * planetModel.inverseCSquared - 1.0);
+        final double checkAbove = 4.0 * (testPointFixedYAbovePlane.D * testPointFixedYAbovePlane.D * planetModel.inverseXYScalingSquared + fixedZAbovePlane.D * fixedZAbovePlane.D * planetModel.inverseZScalingSquared - 1.0);
+        final double checkBelow = 4.0 * (testPointFixedYBelowPlane.D * testPointFixedYBelowPlane.D * planetModel.inverseXYScalingSquared + fixedZBelowPlane.D * fixedZBelowPlane.D * planetModel.inverseZScalingSquared - 1.0);
         if (checkAbove < Vector.MINIMUM_RESOLUTION_SQUARED && checkBelow < Vector.MINIMUM_RESOLUTION_SQUARED) {
           //System.out.println("  Looking for intersections between travel and test point planes...");
           final GeoPoint[] ZIntersectionsY = travelPlaneFixedZ.findIntersections(planetModel, testPointFixedYPlane);
@@ -1466,7 +1466,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
         final GeoPoint[] belowAbove = travelBelowPlane.findIntersections(planetModel, testPointAbovePlane, intersectionBound1, intersectionBound2);
         assert belowAbove != null : "Below + above should not be coplanar";
 
-        assert ((aboveAbove.length > 0)?1:0) + ((aboveBelow.length > 0)?1:0) + ((belowBelow.length > 0)?1:0) + ((belowAbove.length > 0)?1:0) == 1 : "Can be exactly one inside point, instead was: aa="+aboveAbove.length+" ab=" + aboveBelow.length+" bb="+ belowBelow.length+" ba=" + belowAbove.length;
+        assert ((aboveAbove.length > 0)?1:0) + ((aboveBelow.length > 0)?1:0) + ((belowBelow.length > 0)?1:0) + ((belowAbove.length > 0)?1:0) == 1 : "Can be exactly one inside point, instead was: aa="+aboveAbove.length+" xyScaling=" + aboveBelow.length+" bb="+ belowBelow.length+" ba=" + belowAbove.length;
         
         final GeoPoint[] insideInsidePoints;
         if (aboveAbove.length > 0) {
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java
index 845dd6a..cbcc5cb 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoExactCircle.java
@@ -81,7 +81,7 @@ class GeoExactCircle extends GeoBaseCircle {
     final GeoPoint westPoint = planetModel.surfacePointOnBearing(center, radius, Math.PI * 1.5);
 
     final GeoPoint edgePoint;
-    if (planetModel.c > planetModel.ab) {
+    if (planetModel.zScaling > planetModel.xyScaling) {
       // z can be greater than x or y, so ellipse is longer in height than width
       slices.add(new ApproximationSlice(center, eastPoint, Math.PI * 0.5, westPoint, Math.PI * -0.5, northPoint, 0.0, true));
       slices.add(new ApproximationSlice(center, westPoint, Math.PI * 1.5, eastPoint, Math.PI * 0.5, southPoint, Math.PI, true));
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
index 641f09d..4eef128 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoWorld.java
@@ -36,7 +36,7 @@ class GeoWorld extends GeoBaseBBox {
    */
   public GeoWorld(final PlanetModel planetModel) {
     super(planetModel);
-    originPoint = new GeoPoint(planetModel.ab, 1.0, 0.0, 0.0);
+    originPoint = new GeoPoint(planetModel.xyScaling, 1.0, 0.0, 0.0);
   }
 
   /** Constructor.
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
index 038dda0..836feca 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Plane.java
@@ -722,7 +722,7 @@ public class Plane extends Vector {
     // ... can be solved by Cramer's rule:
     // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
     // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
-    // ... where det( a b / c d ) = ad - bc, so:
+    // ... where det( a b / zScaling d ) = ad - bc, so:
     // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
     // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
     double x0;
@@ -766,16 +766,16 @@ public class Plane extends Vector {
 
     // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
     // will yield zero, one, or two points.
-    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
-    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
-    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
-    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/zScaling^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/zScaling^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / zScaling^2 + 2CC0t / zScaling^2 + C0^2 / zScaling^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / zScaling^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / zScaling^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / zScaling^2 - 1,0] = 0.0
     // Use the quadratic formula to determine t values and candidate point(s)
-    final double A = lineVectorX * lineVectorX * planetModel.inverseAbSquared +
-      lineVectorY * lineVectorY * planetModel.inverseAbSquared +
-      lineVectorZ * lineVectorZ * planetModel.inverseCSquared;
-    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseAbSquared + lineVectorY * y0 * planetModel.inverseAbSquared + lineVectorZ * z0 * planetModel.inverseCSquared);
-    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+    final double A = lineVectorX * lineVectorX * planetModel.inverseXYScalingSquared +
+      lineVectorY * lineVectorY * planetModel.inverseXYScalingSquared +
+      lineVectorZ * lineVectorZ * planetModel.inverseZScalingSquared;
+    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseXYScalingSquared + lineVectorY * y0 * planetModel.inverseXYScalingSquared + lineVectorZ * z0 * planetModel.inverseZScalingSquared);
+    final double C = x0 * x0 * planetModel.inverseXYScalingSquared + y0 * y0 * planetModel.inverseXYScalingSquared + z0 * z0 * planetModel.inverseZScalingSquared - 1.0;
 
     final double BsquaredMinus = B * B - 4.0 * A * C;
     if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
@@ -898,7 +898,7 @@ public class Plane extends Vector {
     // ... can be solved by Cramer's rule:
     // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
     // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
-    // ... where det( a b / c d ) = ad - bc, so:
+    // ... where det( a b / zScaling d ) = ad - bc, so:
     // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
     // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
     double x0;
@@ -939,16 +939,16 @@ public class Plane extends Vector {
 
     // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
     // will yield zero, one, or two points.
-    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
-    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
-    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
-    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/zScaling^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/zScaling^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / zScaling^2 + 2CC0t / zScaling^2 + C0^2 / zScaling^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / zScaling^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / zScaling^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / zScaling^2 - 1,0] = 0.0
     // Use the quadratic formula to determine t values and candidate point(s)
-    final double A = lineVectorX * lineVectorX * planetModel.inverseAbSquared +
-      lineVectorY * lineVectorY * planetModel.inverseAbSquared +
-      lineVectorZ * lineVectorZ * planetModel.inverseCSquared;
-    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseAbSquared + lineVectorY * y0 * planetModel.inverseAbSquared + lineVectorZ * z0 * planetModel.inverseCSquared);
-    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+    final double A = lineVectorX * lineVectorX * planetModel.inverseXYScalingSquared +
+      lineVectorY * lineVectorY * planetModel.inverseXYScalingSquared +
+      lineVectorZ * lineVectorZ * planetModel.inverseZScalingSquared;
+    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseXYScalingSquared + lineVectorY * y0 * planetModel.inverseXYScalingSquared + lineVectorZ * z0 * planetModel.inverseZScalingSquared);
+    final double C = x0 * x0 * planetModel.inverseXYScalingSquared + y0 * y0 * planetModel.inverseXYScalingSquared + z0 * z0 * planetModel.inverseZScalingSquared - 1.0;
 
     final double BsquaredMinus = B * B - 4.0 * A * C;
     if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
@@ -1048,7 +1048,7 @@ public class Plane extends Vector {
     // ... can be solved by Cramer's rule:
     // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
     // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
-    // ... where det( a b / c d ) = ad - bc, so:
+    // ... where det( a b / zScaling d ) = ad - bc, so:
     // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
     // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
     // We try to maximize the determinant in the denominator
@@ -1138,16 +1138,16 @@ public class Plane extends Vector {
     final Membership... bounds) {
     // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
     // will yield zero, one, or two points.
-    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
-    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
-    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
-    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/zScaling^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/zScaling^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / zScaling^2 + 2CC0t / zScaling^2 + C0^2 / zScaling^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / zScaling^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / zScaling^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / zScaling^2 - 1,0] = 0.0
     // Use the quadratic formula to determine t values and candidate point(s)
-    final double A = lineVectorX * lineVectorX * planetModel.inverseAbSquared +
-      lineVectorY * lineVectorY * planetModel.inverseAbSquared +
-      lineVectorZ * lineVectorZ * planetModel.inverseCSquared;
-    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseAbSquared + lineVectorY * y0 * planetModel.inverseAbSquared + lineVectorZ * z0 * planetModel.inverseCSquared);
-    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+    final double A = lineVectorX * lineVectorX * planetModel.inverseXYScalingSquared +
+      lineVectorY * lineVectorY * planetModel.inverseXYScalingSquared +
+      lineVectorZ * lineVectorZ * planetModel.inverseZScalingSquared;
+    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseXYScalingSquared + lineVectorY * y0 * planetModel.inverseXYScalingSquared + lineVectorZ * z0 * planetModel.inverseZScalingSquared);
+    final double C = x0 * x0 * planetModel.inverseXYScalingSquared + y0 * y0 * planetModel.inverseXYScalingSquared + z0 * z0 * planetModel.inverseZScalingSquared - 1.0;
 
     final double BsquaredMinus = B * B - 4.0 * A * C;
     if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
@@ -1213,7 +1213,7 @@ public class Plane extends Vector {
       throw new RuntimeException("Intersection point not on original plane; point="+point+", plane="+this);
     if (!q.evaluateIsZero(point))
       throw new RuntimeException("Intersection point not on intersected plane; point="+point+", plane="+q);
-    if (Math.abs(point.x * point.x * planetModel.inverseASquared + point.y * point.y * planetModel.inverseBSquared + point.z * point.z * planetModel.inverseCSquared - 1.0) >= MINIMUM_RESOLUTION) 
+    if (Math.abs(point.x * point.x * planetModel.inverseASquared + point.y * point.y * planetModel.inverseBSquared + point.z * point.z * planetModel.inverseZScalingSquared - 1.0) >= MINIMUM_RESOLUTION)
       throw new RuntimeException("Intersection point not on ellipsoid; point="+point);
   }
   */
@@ -1283,9 +1283,9 @@ public class Plane extends Vector {
     }
 
     // First, compute common subexpressions
-    final double k = 1.0 / ((x*x + y*y)*planetModel.ab*planetModel.ab + z*z*planetModel.c*planetModel.c);
-    final double abSquared = planetModel.ab * planetModel.ab;
-    final double cSquared = planetModel.c * planetModel.c;
+    final double k = 1.0 / ((x*x + y*y)*planetModel.xyScaling *planetModel.xyScaling + z*z*planetModel.zScaling *planetModel.zScaling);
+    final double abSquared = planetModel.xyScaling * planetModel.xyScaling;
+    final double cSquared = planetModel.zScaling * planetModel.zScaling;
     final double ASquared = A * A;
     final double BSquared = B * B;
     final double CSquared = C * C;
@@ -1298,11 +1298,11 @@ public class Plane extends Vector {
       //
       // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
       //
-      // Minimize and maximize f(x,y,z) = x, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
+      // Minimize and maximize f(x,y,z) = x, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/xyScaling^2 + y^2/xyScaling^2 + z^2/zScaling^2 - 1
       //
       // grad(f(x,y,z)) = (1,0,0)
       // grad(g(x,y,z)) = (A,B,C)
-      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
+      // grad(h(x,y,z)) = (2x/xyScaling^2,2y/xyScaling^2,2z/zScaling^2)
       //
       // Equations we need to simultaneously solve:
       // 
@@ -1311,49 +1311,49 @@ public class Plane extends Vector {
       // h(x,y,z) = 0
       // 
       // Equations:
-      // 1 = l*A + m*2x/ab^2
-      // 0 = l*B + m*2y/ab^2
-      // 0 = l*C + m*2z/c^2
+      // 1 = l*A + m*2x/xyScaling^2
+      // 0 = l*B + m*2y/xyScaling^2
+      // 0 = l*C + m*2z/zScaling^2
       // Ax + By + Cz + D = 0
-      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
+      // x^2/xyScaling^2 + y^2/xyScaling^2 + z^2/zScaling^2 - 1 = 0
       // 
       // Solve for x,y,z in terms of (l, m):
       // 
-      // x = ((1 - l*A) * ab^2 ) / (2 * m)
-      // y = (-l*B * ab^2) / ( 2 * m)
-      // z = (-l*C * c^2)/ (2 * m)
+      // x = ((1 - l*A) * xyScaling^2 ) / (2 * m)
+      // y = (-l*B * xyScaling^2) / ( 2 * m)
+      // z = (-l*C * zScaling^2)/ (2 * m)
       // 
       // Two equations, two unknowns:
       // 
-      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // A * (((1 - l*A) * xyScaling^2 ) / (2 * m)) + B * ((-l*B * xyScaling^2) / ( 2 * m)) + C * ((-l*C * zScaling^2)/ (2 * m)) + D = 0
       // 
       // and
       // 
-      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // (((1 - l*A) * xyScaling^2 ) / (2 * m))^2/xyScaling^2 + ((-l*B * xyScaling^2) / ( 2 * m))^2/xyScaling^2 + ((-l*C * zScaling^2)/ (2 * m))^2/zScaling^2 - 1 = 0
       // 
       // Simple: solve for l and m, then find x from it.
       // 
       // (a) Use first equation to find l in terms of m.
       // 
-      // A * (((1 - l*A) * ab^2 ) / (2 * m)) + B * ((-l*B * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // A * ((1 - l*A) * ab^2 ) + B * (-l*B * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
-      // A * ab^2 - l*A^2* ab^2 - B^2 * l * ab^2 - C^2 * l * c^2 + D * 2 * m = 0
-      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (A * ab^2 + D * 2 * m) = 0
-      // l = (A * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // l = A * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // A * (((1 - l*A) * xyScaling^2 ) / (2 * m)) + B * ((-l*B * xyScaling^2) / ( 2 * m)) + C * ((-l*C * zScaling^2)/ (2 * m)) + D = 0
+      // A * ((1 - l*A) * xyScaling^2 ) + B * (-l*B * xyScaling^2) + C * (-l*C * zScaling^2) + D * 2 * m = 0
+      // A * xyScaling^2 - l*A^2* xyScaling^2 - B^2 * l * xyScaling^2 - C^2 * l * zScaling^2 + D * 2 * m = 0
+      // - l *(A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2) + (A * xyScaling^2 + D * 2 * m) = 0
+      // l = (A * xyScaling^2 + D * 2 * m) / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2)
+      // l = A * xyScaling^2 / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2) + m * 2 * D / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2)
       // 
       // For convenience:
       // 
-      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // k = 1.0 / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2)
       // 
       // Then:
       // 
-      // l = A * ab^2 * k + m * 2 * D * k
-      // l = k * (A*ab^2 + m*2*D)
+      // l = A * xyScaling^2 * k + m * 2 * D * k
+      // l = k * (A*xyScaling^2 + m*2*D)
       //
       // For further convenience:
       //
-      // q = A*ab^2*k
+      // q = A*xyScaling^2*k
       // r = 2*D*k
       //
       // l = (r*m + q)
@@ -1361,23 +1361,23 @@ public class Plane extends Vector {
       // 
       // (b) Simplify the second equation before substitution
       // 
-      // (((1 - l*A) * ab^2 ) / (2 * m))^2/ab^2 + ((-l*B * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // ((1 - l*A) * ab^2 )^2/ab^2 + (-l*B * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
-      // (1 - l*A)^2 * ab^2 + (-l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
-      // (1 - 2*l*A + l^2*A^2) * ab^2 + l^2*B^2 * ab^2 + l^2*C^2 * c^2 = 4 * m^2
-      // ab^2 - 2*A*ab^2*l + A^2*ab^2*l^2 + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
+      // (((1 - l*A) * xyScaling^2 ) / (2 * m))^2/xyScaling^2 + ((-l*B * xyScaling^2) / ( 2 * m))^2/xyScaling^2 + ((-l*C * zScaling^2)/ (2 * m))^2/zScaling^2 - 1 = 0
+      // ((1 - l*A) * xyScaling^2 )^2/xyScaling^2 + (-l*B * xyScaling^2)^2/xyScaling^2 + (-l*C * zScaling^2)^2/zScaling^2 = 4 * m^2
+      // (1 - l*A)^2 * xyScaling^2 + (-l*B)^2 * xyScaling^2 + (-l*C)^2 * zScaling^2 = 4 * m^2
+      // (1 - 2*l*A + l^2*A^2) * xyScaling^2 + l^2*B^2 * xyScaling^2 + l^2*C^2 * zScaling^2 = 4 * m^2
+      // xyScaling^2 - 2*A*xyScaling^2*l + A^2*xyScaling^2*l^2 + B^2*xyScaling^2*l^2 + C^2*zScaling^2*l^2 - 4*m^2 = 0
       // 
-      // (c) Substitute for l, l^2
+      // (zScaling) Substitute for l, l^2
       //
-      // ab^2 - 2*A*ab^2*(r*m + q) + A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
-      // ab^2 - 2*A*ab^2*r*m - 2*A*ab^2*q + A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m +
-      //        A^2*ab^2*q^2 + B^2*ab^2*r^2*m^2 + 2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
+      // xyScaling^2 - 2*A*xyScaling^2*(r*m + q) + A^2*xyScaling^2*(r^2 * m^2 + 2*r*m*q + q^2) + B^2*xyScaling^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*zScaling^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
+      // xyScaling^2 - 2*A*xyScaling^2*r*m - 2*A*xyScaling^2*q + A^2*xyScaling^2*r^2*m^2 + 2*A^2*xyScaling^2*r*q*m +
+      //        A^2*xyScaling^2*q^2 + B^2*xyScaling^2*r^2*m^2 + 2*B^2*xyScaling^2*r*q*m + B^2*xyScaling^2*q^2 + C^2*zScaling^2*r^2*m^2 + 2*C^2*zScaling^2*r*q*m + C^2*zScaling^2*q^2 - 4*m^2 = 0
       //
       // (d) Group
       //
-      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
-      // m * [- 2*A*ab^2*r + 2*A^2*ab^2*r*q + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
-      // [ab^2 - 2*A*ab^2*q + A^2*ab^2*q^2 + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
+      // m^2 * [A^2*xyScaling^2*r^2 + B^2*xyScaling^2*r^2 + C^2*zScaling^2*r^2 - 4] +
+      // m * [- 2*A*xyScaling^2*r + 2*A^2*xyScaling^2*r*q + 2*B^2*xyScaling^2*r*q + 2*C^2*zScaling^2*r*q] +
+      // [xyScaling^2 - 2*A*xyScaling^2*q + A^2*xyScaling^2*q^2 + B^2*xyScaling^2*q^2 + C^2*zScaling^2*q^2]  =  0
       
       // Useful subexpressions for this bound
       final double q = A*abSquared*k;
@@ -1396,14 +1396,14 @@ public class Plane extends Vector {
           // Valid?
           if (Math.abs(m) >= MINIMUM_RESOLUTION) {
             final double l = r * m + q;
-            // x = ((1 - l*A) * ab^2 ) / (2 * m)
-            // y = (-l*B * ab^2) / ( 2 * m)
-            // z = (-l*C * c^2)/ (2 * m)
+            // x = ((1 - l*A) * xyScaling^2 ) / (2 * m)
+            // y = (-l*B * xyScaling^2) / ( 2 * m)
+            // z = (-l*C * zScaling^2)/ (2 * m)
             final double denom0 = 0.5 / m;
             final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
             //Math is not quite accurate enough for this
             //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-            //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+            //  (thePoint.x*thePoint.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.y*thePoint.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.z*thePoint.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
             //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
             addPoint(boundsInfo, bounds, thePoint);
           } else {
@@ -1421,18 +1421,18 @@ public class Plane extends Vector {
           if (Math.abs(m1) >= MINIMUM_RESOLUTION || Math.abs(m2) >= MINIMUM_RESOLUTION) {
             final double l1 = r * m1 + q;
             final double l2 = r * m2 + q;
-            // x = ((1 - l*A) * ab^2 ) / (2 * m)
-            // y = (-l*B * ab^2) / ( 2 * m)
-            // z = (-l*C * c^2)/ (2 * m)
+            // x = ((1 - l*A) * xyScaling^2 ) / (2 * m)
+            // y = (-l*B * xyScaling^2) / ( 2 * m)
+            // z = (-l*C * zScaling^2)/ (2 * m)
             final double denom1 = 0.5 / m1;
             final double denom2 = 0.5 / m2;
             final GeoPoint thePoint1 = new GeoPoint((1.0-l1*A) * abSquared * denom1, -l1*B * abSquared * denom1, -l1*C * cSquared * denom1);
             final GeoPoint thePoint2 = new GeoPoint((1.0-l2*A) * abSquared * denom2, -l2*B * abSquared * denom2, -l2*C * cSquared * denom2);
             //Math is not quite accurate enough for this
             //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-            //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
+            //  (thePoint1.x*thePoint1.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint1.y*thePoint1.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint1.z*thePoint1.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
             //assert planetModel.pointOnSurface(thePoint2): "Point1: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-            //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
+            //  (thePoint2.x*thePoint2.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint2.y*thePoint2.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint2.z*thePoint2.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
             //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
             //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
             addPoint(boundsInfo, bounds, thePoint1);
@@ -1445,17 +1445,17 @@ public class Plane extends Vector {
           // No solutions
         }
       } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
-        // a = 0, so m = - c / b
+        // a = 0, so m = - zScaling / b
         final double m = -c / b;
         final double l = r * m + q;
-        // x = ((1 - l*A) * ab^2 ) / (2 * m)
-        // y = (-l*B * ab^2) / ( 2 * m)
-        // z = (-l*C * c^2)/ (2 * m)
+        // x = ((1 - l*A) * xyScaling^2 ) / (2 * m)
+        // y = (-l*B * xyScaling^2) / ( 2 * m)
+        // z = (-l*C * zScaling^2)/ (2 * m)
         final double denom0 = 0.5 / m;
         final GeoPoint thePoint = new GeoPoint((1.0-l*A) * abSquared * denom0, -l*B * abSquared * denom0, -l*C * cSquared * denom0);
         //Math is not quite accurate enough for this
         //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+        //  (thePoint.x*thePoint.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.y*thePoint.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.z*thePoint.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
         //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
         addPoint(boundsInfo, bounds, thePoint);
       } else {
@@ -1469,11 +1469,11 @@ public class Plane extends Vector {
       //
       // For this, we need grad(F(x,y,z)) = (dF/dx, dF/dy, dF/dz).
       //
-      // Minimize and maximize f(x,y,z) = y, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1
+      // Minimize and maximize f(x,y,z) = y, with respect to g(x,y,z) = Ax + By + Cz - D and h(x,y,z) = x^2/xyScaling^2 + y^2/xyScaling^2 + z^2/zScaling^2 - 1
       //
       // grad(f(x,y,z)) = (0,1,0)
       // grad(g(x,y,z)) = (A,B,C)
-      // grad(h(x,y,z)) = (2x/ab^2,2y/ab^2,2z/c^2)
+      // grad(h(x,y,z)) = (2x/xyScaling^2,2y/xyScaling^2,2z/zScaling^2)
       //
       // Equations we need to simultaneously solve:
       // 
@@ -1482,49 +1482,49 @@ public class Plane extends Vector {
       // h(x,y,z) = 0
       // 
       // Equations:
-      // 0 = l*A + m*2x/ab^2
-      // 1 = l*B + m*2y/ab^2
-      // 0 = l*C + m*2z/c^2
+      // 0 = l*A + m*2x/xyScaling^2
+      // 1 = l*B + m*2y/xyScaling^2
+      // 0 = l*C + m*2z/zScaling^2
       // Ax + By + Cz + D = 0
-      // x^2/ab^2 + y^2/ab^2 + z^2/c^2 - 1 = 0
+      // x^2/xyScaling^2 + y^2/xyScaling^2 + z^2/zScaling^2 - 1 = 0
       // 
       // Solve for x,y,z in terms of (l, m):
       // 
-      // x = (-l*A * ab^2 ) / (2 * m)
-      // y = ((1 - l*B) * ab^2) / ( 2 * m)
-      // z = (-l*C * c^2)/ (2 * m)
+      // x = (-l*A * xyScaling^2 ) / (2 * m)
+      // y = ((1 - l*B) * xyScaling^2) / ( 2 * m)
+      // z = (-l*C * zScaling^2)/ (2 * m)
       // 
       // Two equations, two unknowns:
       // 
-      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
+      // A * ((-l*A * xyScaling^2 ) / (2 * m)) + B * (((1 - l*B) * xyScaling^2) / ( 2 * m)) + C * ((-l*C * zScaling^2)/ (2 * m)) + D = 0
       // 
       // and
       // 
-      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
+      // ((-l*A * xyScaling^2 ) / (2 * m))^2/xyScaling^2 + (((1 - l*B) * xyScaling^2) / ( 2 * m))^2/xyScaling^2 + ((-l*C * zScaling^2)/ (2 * m))^2/zScaling^2 - 1 = 0
       // 
       // Simple: solve for l and m, then find y from it.
       // 
       // (a) Use first equation to find l in terms of m.
       // 
-      // A * ((-l*A * ab^2 ) / (2 * m)) + B * (((1 - l*B) * ab^2) / ( 2 * m)) + C * ((-l*C * c^2)/ (2 * m)) + D = 0
-      // A * (-l*A * ab^2 ) + B * ((1-l*B) * ab^2) + C * (-l*C * c^2) + D * 2 * m = 0
-      // -A^2*l*ab^2 + B*ab^2 - l*B^2*ab^2 - C^2*l*c^2 + D*2*m = 0
-      // - l *(A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + (B * ab^2 + D * 2 * m) = 0
-      // l = (B * ab^2 + D * 2 * m) / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
-      // l = B * ab^2 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2) + m * 2 * D / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // A * ((-l*A * xyScaling^2 ) / (2 * m)) + B * (((1 - l*B) * xyScaling^2) / ( 2 * m)) + C * ((-l*C * zScaling^2)/ (2 * m)) + D = 0
+      // A * (-l*A * xyScaling^2 ) + B * ((1-l*B) * xyScaling^2) + C * (-l*C * zScaling^2) + D * 2 * m = 0
+      // -A^2*l*xyScaling^2 + B*xyScaling^2 - l*B^2*xyScaling^2 - C^2*l*zScaling^2 + D*2*m = 0
+      // - l *(A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2) + (B * xyScaling^2 + D * 2 * m) = 0
+      // l = (B * xyScaling^2 + D * 2 * m) / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2)
+      // l = B * xyScaling^2 / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2) + m * 2 * D / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2)
       // 
       // For convenience:
       // 
-      // k = 1.0 / (A^2* ab^2 + B^2 * ab^2 + C^2 * c^2)
+      // k = 1.0 / (A^2* xyScaling^2 + B^2 * xyScaling^2 + C^2 * zScaling^2)
       // 
       // Then:
       // 
-      // l = B * ab^2 * k + m * 2 * D * k
-      // l = k * (B*ab^2 + m*2*D)
+      // l = B * xyScaling^2 * k + m * 2 * D * k
+      // l = k * (B*xyScaling^2 + m*2*D)
       //
       // For further convenience:
       //
-      // q = B*ab^2*k
+      // q = B*xyScaling^2*k
       // r = 2*D*k
       //
       // l = (r*m + q)
@@ -1532,23 +1532,23 @@ public class Plane extends Vector {
       // 
       // (b) Simplify the second equation before substitution
       // 
-      // ((-l*A * ab^2 ) / (2 * m))^2/ab^2 + (((1 - l*B) * ab^2) / ( 2 * m))^2/ab^2 + ((-l*C * c^2)/ (2 * m))^2/c^2 - 1 = 0
-      // (-l*A * ab^2 )^2/ab^2 + ((1 - l*B) * ab^2)^2/ab^2 + (-l*C * c^2)^2/c^2 = 4 * m^2
-      // (-l*A)^2 * ab^2 + (1 - l*B)^2 * ab^2 + (-l*C)^2 * c^2 = 4 * m^2
-      // l^2*A^2 * ab^2 + (1 - 2*l*B + l^2*B^2) * ab^2 + l^2*C^2 * c^2 = 4 * m^2
-      // A^2*ab^2*l^2 + ab^2 - 2*B*ab^2*l + B^2*ab^2*l^2 + C^2*c^2*l^2 - 4*m^2 = 0
+      // ((-l*A * xyScaling^2 ) / (2 * m))^2/xyScaling^2 + (((1 - l*B) * xyScaling^2) / ( 2 * m))^2/xyScaling^2 + ((-l*C * zScaling^2)/ (2 * m))^2/zScaling^2 - 1 = 0
+      // (-l*A * xyScaling^2 )^2/xyScaling^2 + ((1 - l*B) * xyScaling^2)^2/xyScaling^2 + (-l*C * zScaling^2)^2/zScaling^2 = 4 * m^2
+      // (-l*A)^2 * xyScaling^2 + (1 - l*B)^2 * xyScaling^2 + (-l*C)^2 * zScaling^2 = 4 * m^2
+      // l^2*A^2 * xyScaling^2 + (1 - 2*l*B + l^2*B^2) * xyScaling^2 + l^2*C^2 * zScaling^2 = 4 * m^2
+      // A^2*xyScaling^2*l^2 + xyScaling^2 - 2*B*xyScaling^2*l + B^2*xyScaling^2*l^2 + C^2*zScaling^2*l^2 - 4*m^2 = 0
       // 
-      // (c) Substitute for l, l^2
+      // (zScaling) Substitute for l, l^2
       //
-      // A^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + ab^2 - 2*B*ab^2*(r*m + q) + B^2*ab^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*c^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
-      // A^2*ab^2*r^2*m^2 + 2*A^2*ab^2*r*q*m + A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*r*m - 2*B*ab^2*q + B^2*ab^2*r^2*m^2 +
-      //    2*B^2*ab^2*r*q*m + B^2*ab^2*q^2 + C^2*c^2*r^2*m^2 + 2*C^2*c^2*r*q*m + C^2*c^2*q^2 - 4*m^2 = 0
+      // A^2*xyScaling^2*(r^2 * m^2 + 2*r*m*q + q^2) + xyScaling^2 - 2*B*xyScaling^2*(r*m + q) + B^2*xyScaling^2*(r^2 * m^2 + 2*r*m*q + q^2) + C^2*zScaling^2*(r^2 * m^2 + 2*r*m*q + q^2) - 4*m^2 = 0
+      // A^2*xyScaling^2*r^2*m^2 + 2*A^2*xyScaling^2*r*q*m + A^2*xyScaling^2*q^2 + xyScaling^2 - 2*B*xyScaling^2*r*m - 2*B*xyScaling^2*q + B^2*xyScaling^2*r^2*m^2 +
+      //    2*B^2*xyScaling^2*r*q*m + B^2*xyScaling^2*q^2 + C^2*zScaling^2*r^2*m^2 + 2*C^2*zScaling^2*r*q*m + C^2*zScaling^2*q^2 - 4*m^2 = 0
       //
       // (d) Group
       //
-      // m^2 * [A^2*ab^2*r^2 + B^2*ab^2*r^2 + C^2*c^2*r^2 - 4] +
-      // m * [2*A^2*ab^2*r*q - 2*B*ab^2*r + 2*B^2*ab^2*r*q + 2*C^2*c^2*r*q] +
-      // [A^2*ab^2*q^2 + ab^2 - 2*B*ab^2*q + B^2*ab^2*q^2 + C^2*c^2*q^2]  =  0
+      // m^2 * [A^2*xyScaling^2*r^2 + B^2*xyScaling^2*r^2 + C^2*zScaling^2*r^2 - 4] +
+      // m * [2*A^2*xyScaling^2*r*q - 2*B*xyScaling^2*r + 2*B^2*xyScaling^2*r*q + 2*C^2*zScaling^2*r*q] +
+      // [A^2*xyScaling^2*q^2 + xyScaling^2 - 2*B*xyScaling^2*q + B^2*xyScaling^2*q^2 + C^2*zScaling^2*q^2]  =  0
 
       //System.err.println("    computing Y bound");
       
@@ -1569,14 +1569,14 @@ public class Plane extends Vector {
           // Valid?
           if (Math.abs(m) >= MINIMUM_RESOLUTION) {
             final double l = r * m + q;
-            // x = (-l*A * ab^2 ) / (2 * m)
-            // y = ((1.0-l*B) * ab^2) / ( 2 * m)
-            // z = (-l*C * c^2)/ (2 * m)
+            // x = (-l*A * xyScaling^2 ) / (2 * m)
+            // y = ((1.0-l*B) * xyScaling^2) / ( 2 * m)
+            // z = (-l*C * zScaling^2)/ (2 * m)
             final double denom0 = 0.5 / m;
             final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
             //Math is not quite accurate enough for this
             //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-            //  (thePoint1.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+            //  (thePoint1.x*thePoint.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.y*thePoint.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.z*thePoint.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
             //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
             addPoint(boundsInfo, bounds, thePoint);
           } else {
@@ -1594,18 +1594,18 @@ public class Plane extends Vector {
           if (Math.abs(m1) >= MINIMUM_RESOLUTION || Math.abs(m2) >= MINIMUM_RESOLUTION) {
             final double l1 = r * m1 + q;
             final double l2 = r * m2 + q;
-            // x = (-l*A * ab^2 ) / (2 * m)
-            // y = ((1.0-l*B) * ab^2) / ( 2 * m)
-            // z = (-l*C * c^2)/ (2 * m)
+            // x = (-l*A * xyScaling^2 ) / (2 * m)
+            // y = ((1.0-l*B) * xyScaling^2) / ( 2 * m)
+            // z = (-l*C * zScaling^2)/ (2 * m)
             final double denom1 = 0.5 / m1;
             final double denom2 = 0.5 / m2;
             final GeoPoint thePoint1 = new GeoPoint(-l1*A * abSquared * denom1, (1.0-l1*B) * abSquared * denom1, -l1*C * cSquared * denom1);
             final GeoPoint thePoint2 = new GeoPoint(-l2*A * abSquared * denom2, (1.0-l2*B) * abSquared * denom2, -l2*C * cSquared * denom2);
             //Math is not quite accurate enough for this
             //assert planetModel.pointOnSurface(thePoint1): "Point1: "+thePoint1+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-            //  (thePoint1.x*thePoint1.x*planetModel.inverseAb*planetModel.inverseAb + thePoint1.y*thePoint1.y*planetModel.inverseAb*planetModel.inverseAb + thePoint1.z*thePoint1.z*planetModel.inverseC*planetModel.inverseC);
+            //  (thePoint1.x*thePoint1.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint1.y*thePoint1.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint1.z*thePoint1.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
             //assert planetModel.pointOnSurface(thePoint2): "Point2: "+thePoint2+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-            //  (thePoint2.x*thePoint2.x*planetModel.inverseAb*planetModel.inverseAb + thePoint2.y*thePoint2.y*planetModel.inverseAb*planetModel.inverseAb + thePoint2.z*thePoint2.z*planetModel.inverseC*planetModel.inverseC);
+            //  (thePoint2.x*thePoint2.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint2.y*thePoint2.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint2.z*thePoint2.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
             //assert evaluateIsZero(thePoint1): "Evaluation of point1: "+evaluate(thePoint1);
             //assert evaluateIsZero(thePoint2): "Evaluation of point2: "+evaluate(thePoint2);
             addPoint(boundsInfo, bounds, thePoint1);
@@ -1618,17 +1618,17 @@ public class Plane extends Vector {
           // No solutions
         }
       } else if (Math.abs(b) > MINIMUM_RESOLUTION_SQUARED) {
-        // a = 0, so m = - c / b
+        // a = 0, so m = - zScaling / b
         final double m = -c / b;
         final double l = r * m + q;
-        // x = ( -l*A * ab^2 ) / (2 * m)
-        // y = ((1-l*B) * ab^2) / ( 2 * m)
-        // z = (-l*C * c^2)/ (2 * m)
+        // x = ( -l*A * xyScaling^2 ) / (2 * m)
+        // y = ((1-l*B) * xyScaling^2) / ( 2 * m)
+        // z = (-l*C * zScaling^2)/ (2 * m)
         final double denom0 = 0.5 / m;
         final GeoPoint thePoint = new GeoPoint(-l*A * abSquared * denom0, (1.0-l*B) * abSquared * denom0, -l*C * cSquared * denom0);
         //Math is not quite accurate enough for this
         //assert planetModel.pointOnSurface(thePoint): "Point: "+thePoint+"; Planetmodel="+planetModel+"; A="+A+" B="+B+" C="+C+" D="+D+" planetfcn="+
-        //  (thePoint.x*thePoint.x*planetModel.inverseAb*planetModel.inverseAb + thePoint.y*thePoint.y*planetModel.inverseAb*planetModel.inverseAb + thePoint.z*thePoint.z*planetModel.inverseC*planetModel.inverseC);
+        //  (thePoint.x*thePoint.x*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.y*thePoint.y*planetModel.inverseXYScaling*planetModel.inverseXYScaling + thePoint.z*thePoint.z*planetModel.inverseZScaling*planetModel.inverseZScaling);
         //assert evaluateIsZero(thePoint): "Evaluation of point: "+evaluate(thePoint);
         addPoint(boundsInfo, bounds, thePoint);
       } else {
@@ -1734,9 +1734,9 @@ public class Plane extends Vector {
             // Group:
             // y^2 * [B^2/a^2 + A^2/b^2] + y [2BD/a^2] + [D^2/a^2-A^2] = 0
 
-            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
-            b = 2.0 * B * D * planetModel.inverseAbSquared;
-            c = D * D * planetModel.inverseAbSquared - A * A;
+            a = B * B * planetModel.inverseXYScalingSquared + A * A * planetModel.inverseXYScalingSquared;
+            b = 2.0 * B * D * planetModel.inverseXYScalingSquared;
+            c = D * D * planetModel.inverseXYScalingSquared - A * A;
 
             double sqrtClause = b * b - 4.0 * a * c;
 
@@ -1767,9 +1767,9 @@ public class Plane extends Vector {
             // Use equation suitable for B != 0
             // Since I != 0, we rewrite:
             // y = (-Ax - D)/B
-            a = B * B * planetModel.inverseAbSquared + A * A * planetModel.inverseAbSquared;
-            b = 2.0 * A * D * planetModel.inverseAbSquared;
-            c = D * D * planetModel.inverseAbSquared - B * B;
+            a = B * B * planetModel.inverseXYScalingSquared + A * A * planetModel.inverseXYScalingSquared;
+            b = 2.0 * A * D * planetModel.inverseXYScalingSquared;
+            c = D * D * planetModel.inverseXYScalingSquared - B * B;
 
             double sqrtClause = b * b - 4.0 * a * c;
 
@@ -1807,21 +1807,21 @@ public class Plane extends Vector {
         // From plane:
         // z = (-Ax - By - D) / C
         // From ellipsoid:
-        // x^2/a^2 + y^2/b^2 + [(-Ax - By - D) / C]^2/c^2 = 1
+        // x^2/a^2 + y^2/b^2 + [(-Ax - By - D) / C]^2/zScaling^2 = 1
         // Simplify/expand:
-        // C^2*x^2/a^2 + C^2*y^2/b^2 + (-Ax - By - D)^2/c^2 = C^2
+        // C^2*x^2/a^2 + C^2*y^2/b^2 + (-Ax - By - D)^2/zScaling^2 = C^2
         //
-        // x^2 * C^2/a^2 + y^2 * C^2/b^2 + x^2 * A^2/c^2 + ABxy/c^2 + ADx/c^2 + ABxy/c^2 + y^2 * B^2/c^2 + BDy/c^2 + ADx/c^2 + BDy/c^2 + D^2/c^2 = C^2
+        // x^2 * C^2/a^2 + y^2 * C^2/b^2 + x^2 * A^2/zScaling^2 + ABxy/zScaling^2 + ADx/zScaling^2 + ABxy/zScaling^2 + y^2 * B^2/zScaling^2 + BDy/zScaling^2 + ADx/zScaling^2 + BDy/zScaling^2 + D^2/zScaling^2 = C^2
         // Group:
-        // [A^2/c^2 + C^2/a^2] x^2 + [B^2/c^2 + C^2/b^2] y^2 + [2AB/c^2]xy + [2AD/c^2]x + [2BD/c^2]y + [D^2/c^2-C^2] = 0
+        // [A^2/zScaling^2 + C^2/a^2] x^2 + [B^2/zScaling^2 + C^2/b^2] y^2 + [2AB/zScaling^2]xy + [2AD/zScaling^2]x + [2BD/zScaling^2]y + [D^2/zScaling^2-C^2] = 0
         // For convenience, introduce post-projection coefficient variables to make life easier.
         // E x^2 + F y^2 + G xy + H x + I y + J = 0
-        double E = A * A * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
-        double F = B * B * planetModel.inverseCSquared + C * C * planetModel.inverseAbSquared;
-        double G = 2.0 * A * B * planetModel.inverseCSquared;
-        double H = 2.0 * A * D * planetModel.inverseCSquared;
-        double I = 2.0 * B * D * planetModel.inverseCSquared;
-        double J = D * D * planetModel.inverseCSquared - C * C;
+        double E = A * A * planetModel.inverseZScalingSquared + C * C * planetModel.inverseXYScalingSquared;
+        double F = B * B * planetModel.inverseZScalingSquared + C * C * planetModel.inverseXYScalingSquared;
+        double G = 2.0 * A * B * planetModel.inverseZScalingSquared;
+        double H = 2.0 * A * D * planetModel.inverseZScalingSquared;
+        double I = 2.0 * B * D * planetModel.inverseZScalingSquared;
+        double J = D * D * planetModel.inverseZScalingSquared - C * C;
 
         //System.err.println("E = " + E + " F = " + F + " G = " + G + " H = "+ H + " I = " + I + " J = " + J);
 
@@ -1875,7 +1875,7 @@ public class Plane extends Vector {
             b = 4.0 * E * I * J - 2.0 * G * H * J;
             c = 4.0 * E * J * J - J * H * H;
 
-            //System.out.println("a="+a+" b="+b+" c="+c);
+            //System.out.println("a="+a+" b="+b+" zScaling="+zScaling);
             double sqrtClause = b * b - 4.0 * a * c;
             //System.out.println("sqrtClause="+sqrtClause);
 
@@ -1927,7 +1927,7 @@ public class Plane extends Vector {
             b = 4.0 * F * H * J - 2.0 * G * I * J;
             c = 4.0 * F * J * J - J * I * I;
 
-            //System.out.println("a="+a+" b="+b+" c="+c);
+            //System.out.println("a="+a+" b="+b+" zScaling="+zScaling);
             double sqrtClause = b * b - 4.0 * a * c;
             //System.out.println("sqrtClause="+sqrtClause);
             if (Math.abs(sqrtClause) < MINIMUM_RESOLUTION_CUBED) {
@@ -2044,7 +2044,7 @@ public class Plane extends Vector {
     // ... can be solved by Cramer's rule:
     // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
     // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
-    // ... where det( a b / c d ) = ad - bc, so:
+    // ... where det( a b / zScaling d ) = ad - bc, so:
     // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
     // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
     double x0;
@@ -2088,16 +2088,16 @@ public class Plane extends Vector {
 
     // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
     // will yield zero, one, or two points.
-    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
-    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
-    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
-    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/zScaling^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/zScaling^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / zScaling^2 + 2CC0t / zScaling^2 + C0^2 / zScaling^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / zScaling^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / zScaling^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / zScaling^2 - 1,0] = 0.0
     // Use the quadratic formula to determine t values and candidate point(s)
-    final double A = lineVectorX * lineVectorX * planetModel.inverseAbSquared +
-      lineVectorY * lineVectorY * planetModel.inverseAbSquared +
-      lineVectorZ * lineVectorZ * planetModel.inverseCSquared;
-    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseAbSquared + lineVectorY * y0 * planetModel.inverseAbSquared + lineVectorZ * z0 * planetModel.inverseCSquared);
-    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+    final double A = lineVectorX * lineVectorX * planetModel.inverseXYScalingSquared +
+      lineVectorY * lineVectorY * planetModel.inverseXYScalingSquared +
+      lineVectorZ * lineVectorZ * planetModel.inverseZScalingSquared;
+    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseXYScalingSquared + lineVectorY * y0 * planetModel.inverseXYScalingSquared + lineVectorZ * z0 * planetModel.inverseZScalingSquared);
+    final double C = x0 * x0 * planetModel.inverseXYScalingSquared + y0 * y0 * planetModel.inverseXYScalingSquared + z0 * z0 * planetModel.inverseZScalingSquared - 1.0;
 
     final double BsquaredMinus = B * B - 4.0 * A * C;
     if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
@@ -2236,7 +2236,7 @@ public class Plane extends Vector {
     // ... can be solved by Cramer's rule:
     // x = det(S0 R0 / S1 R1) / det(Q0 R0 / Q1 R1)
     // y = det(Q0 S0 / Q1 S1) / det(Q0 R0 / Q1 R1)
-    // ... where det( a b / c d ) = ad - bc, so:
+    // ... where det( a b / zScaling d ) = ad - bc, so:
     // x = (S0 * R1 - R0 * S1) / (Q0 * R1 - R0 * Q1)
     // y = (Q0 * S1 - S0 * Q1) / (Q0 * R1 - R0 * Q1)
     double x0;
@@ -2280,16 +2280,16 @@ public class Plane extends Vector {
 
     // Once an intersecting line is determined, the next step is to intersect that line with the ellipsoid, which
     // will yield zero, one, or two points.
-    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/c^2
-    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/c^2
-    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / c^2 + 2CC0t / c^2 + C0^2 / c^2  - 1,0 = 0.0
-    // [A^2 / a^2 + B^2 / b^2 + C^2 / c^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / c^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / c^2 - 1,0] = 0.0
+    // The ellipsoid equation: 1,0 = x^2/a^2 + y^2/b^2 + z^2/zScaling^2
+    // 1.0 = (At+A0)^2/a^2 + (Bt+B0)^2/b^2 + (Ct+C0)^2/zScaling^2
+    // A^2 t^2 / a^2 + 2AA0t / a^2 + A0^2 / a^2 + B^2 t^2 / b^2 + 2BB0t / b^2 + B0^2 / b^2 + C^2 t^2 / zScaling^2 + 2CC0t / zScaling^2 + C0^2 / zScaling^2  - 1,0 = 0.0
+    // [A^2 / a^2 + B^2 / b^2 + C^2 / zScaling^2] t^2 + [2AA0 / a^2 + 2BB0 / b^2 + 2CC0 / zScaling^2] t + [A0^2 / a^2 + B0^2 / b^2 + C0^2 / zScaling^2 - 1,0] = 0.0
     // Use the quadratic formula to determine t values and candidate point(s)
-    final double A = lineVectorX * lineVectorX * planetModel.inverseAbSquared +
-      lineVectorY * lineVectorY * planetModel.inverseAbSquared +
-      lineVectorZ * lineVectorZ * planetModel.inverseCSquared;
-    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseAbSquared + lineVectorY * y0 * planetModel.inverseAbSquared + lineVectorZ * z0 * planetModel.inverseCSquared);
-    final double C = x0 * x0 * planetModel.inverseAbSquared + y0 * y0 * planetModel.inverseAbSquared + z0 * z0 * planetModel.inverseCSquared - 1.0;
+    final double A = lineVectorX * lineVectorX * planetModel.inverseXYScalingSquared +
+      lineVectorY * lineVectorY * planetModel.inverseXYScalingSquared +
+      lineVectorZ * lineVectorZ * planetModel.inverseZScalingSquared;
+    final double B = 2.0 * (lineVectorX * x0 * planetModel.inverseXYScalingSquared + lineVectorY * y0 * planetModel.inverseXYScalingSquared + lineVectorZ * z0 * planetModel.inverseZScalingSquared);
+    final double C = x0 * x0 * planetModel.inverseXYScalingSquared + y0 * y0 * planetModel.inverseXYScalingSquared + z0 * z0 * planetModel.inverseZScalingSquared - 1.0;
 
     final double BsquaredMinus = B * B - 4.0 * A * C;
     if (Math.abs(BsquaredMinus) < MINIMUM_RESOLUTION_SQUARED) {
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
index 55b730d..9e19b3f 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/PlanetModel.java
@@ -29,41 +29,47 @@ public class PlanetModel implements SerializableObject {
   /** Planet model corresponding to sphere. */
   public static final PlanetModel SPHERE = new PlanetModel(1.0,1.0);
 
-  /** Mean radius */
+  /** Planet model corresponding to WGS84 ellipsoid*/
   // see http://earth-info.nga.mil/GandG/publications/tr8350.2/wgs84fin.pdf
-  public static final double WGS84_MEAN = 6371008.7714;
-  /** Polar radius */
-  public static final double WGS84_POLAR = 6356752.314245;
-  /** Equatorial radius */
-  public static final double WGS84_EQUATORIAL = 6378137.0;
-  /** Planet model corresponding to WGS84 */
-  public static final PlanetModel WGS84 = new PlanetModel(WGS84_EQUATORIAL/WGS84_MEAN,
-    WGS84_POLAR/WGS84_MEAN);
+  public static final PlanetModel WGS84 = new PlanetModel(6378137.0d, 6356752.314245d, 298.257223563d);
+
+  /** Planet model corresponding to Clarke 1866 ellipsoid*/
+  // see https://georepository.com/ellipsoid_7008/Clarke-1866.html
+  public static final PlanetModel CLARKE_1866 = new PlanetModel(6378206.4d, 6356583.8d, 294.9786982d);
 
   // Surface of the planet:
-  // x^2/a^2 + y^2/b^2 + z^2/c^2 = 1.0
-  // Scaling factors are a,b,c.  geo3d can only support models where a==b, so use ab instead.
-  
+  // x^2/a^2 + y^2/b^2 + z^2/zScaling^2 = 1.0
+  // Scaling factors are a,b,zScaling.  geo3d can only support models where a==b, so use xyScaling instead.
+  /** Semi-major axis */
+  public double a;
+  /** Semi-minor axis */
+  public double b;
+  /** Flattening factor */
+  public double f;
   /** The x/y scaling factor */
-  public final double ab;
+  public final double xyScaling;
   /** The z scaling factor */
-  public final double c;
-  /** The inverse of ab */
-  public final double inverseAb;
-  /** The inverse of c */
-  public final double inverseC;
-  /** The square of the inverse of ab */
-  public final double inverseAbSquared;
-  /** The square of the inverse of c */
-  public final double inverseCSquared;
-  /** The flattening value */
-  public final double flattening;
+  public final double zScaling;
+  /** The inverse of xyScaling */
+  public final double inverseXYScaling;
+  /** The inverse of zScaling */
+  public final double inverseZScaling;
+  /** The square of the inverse of xyScaling */
+  public final double inverseXYScalingSquared;
+  /** The square of the inverse of zScaling */
+  public final double inverseZScalingSquared;
+  /** The scaled flattening value */
+  public final double scaledFlattening;
   /** The square ratio */
   public final double squareRatio;
   /** The scale of the planet */
   public final double scale;
   /** The inverse of scale */
   public final double inverseScale;
+  /** The mean radius of the planet model */
+  // Computed as (2a + b) / 3 from: "Geodetic Reference System 1980" by H. Moritz
+  // ftp://athena.fsv.cvut.cz/ZFG/grs80-Moritz.pdf
+  public double r1;
 
 
   // We do NOT include radius, because all computations in geo3d are in radians, not meters.
@@ -84,29 +90,79 @@ public class PlanetModel implements SerializableObject {
   public final GeoPoint MAX_Y_POLE;
   /** Minimum surface distance between poles */
   public final double minimumPoleDistance;
-  
+
+  // ENCODING / DECODING CONSTANTS
+  /** bit space for integer encoding */
+  private static final int BITS = 32;
+  /** maximum magnitude value for *this* planet model */
+  public final double MAX_VALUE;
+  /** numeric space (buckets) for mapping double values into integer range */
+  private final double MUL;
+  /** scalar value used to decode from integer back into double space*/
+  public final double DECODE;
+  /** Max encoded value */
+  public final int MAX_ENCODED_VALUE;
+  /** Min encoded value */
+  public final int MIN_ENCODED_VALUE;
+  /** computed radians per meter for *this* planet model */
+  public final double RADIANS_PER_METER;
+  /** utility class used to encode/decode from lat/lon (decimal degrees) into doc value integers */
+  public final DocValueEncoder docValueEncoder;
+
+  /**
+   * Construct a Planet Model from the semi major axis, semi minor axis, and radius of curvature.
+   *
+   * NOTE: These parameters are only used to compute the scaling factors used in all computations. If
+   * scaling factors are already known, use {@code PlanetModel(final double xyScaling, final double zScaling)} instead
+   *
+   * @param semiMajorAxis is the semi major axis (in meters) defined as 'a' in projection formulae.
+   * @param semiMinorAxis is the semi minor axis (in meters) defined as 'b' in projection formulae.
+   * @param flattening is the flattening factor defined as a - b / a.
+   */
+  public PlanetModel(final double semiMajorAxis, final double semiMinorAxis, final double flattening) { // final double zScaling) {
+    this(semiMajorAxis, semiMinorAxis, flattening, ((2d * semiMajorAxis) + semiMinorAxis) / 3d);
+  }
+
+  private PlanetModel(final double a, final double b, final double f, final double r1) {
+    this(a / r1, b / r1);
+    this.a = a;
+    this.b = b;
+    this.f = f;
+    this.r1 = r1;
+  }
+
   /** Constructor.
-   * @param ab is the x/y scaling factor.
-   * @param c is the z scaling factor.
+   * @param xyScaling is the x/y scaling factor.
+   * @param zScaling is the z scaling factor.
    */
-  public PlanetModel(final double ab, final double c) {
-    this.ab = ab;
-    this.c = c;
-    this.inverseAb = 1.0 / ab;
-    this.inverseC = 1.0 / c;
-    this.flattening = (ab - c) * inverseAb;
-    this.squareRatio = (ab * ab - c * c) / (c * c);
-    this.inverseAbSquared = inverseAb * inverseAb;
-    this.inverseCSquared = inverseC * inverseC;
-    this.NORTH_POLE = new GeoPoint(c, 0.0, 0.0, 1.0, Math.PI * 0.5, 0.0);
-    this.SOUTH_POLE = new GeoPoint(c, 0.0, 0.0, -1.0, -Math.PI * 0.5, 0.0);
-    this.MIN_X_POLE = new GeoPoint(ab, -1.0, 0.0, 0.0, 0.0, -Math.PI);
-    this.MAX_X_POLE = new GeoPoint(ab, 1.0, 0.0, 0.0, 0.0, 0.0);
-    this.MIN_Y_POLE = new GeoPoint(ab, 0.0, -1.0, 0.0, 0.0, -Math.PI * 0.5);
-    this.MAX_Y_POLE = new GeoPoint(ab, 0.0, 1.0, 0.0, 0.0, Math.PI * 0.5);
-    this.scale = (2.0 * ab + c)/3.0;
+  public PlanetModel(final double xyScaling, final double zScaling) {
+    this.xyScaling = xyScaling;
+    this.zScaling = zScaling;
+    this.inverseXYScaling = 1.0 / xyScaling;
+    this.inverseZScaling = 1.0 / zScaling;
+    this.scaledFlattening = (xyScaling - zScaling) * inverseXYScaling;
+    this.squareRatio = (xyScaling * xyScaling - zScaling * zScaling) / (zScaling * zScaling);
+    this.inverseXYScalingSquared = inverseXYScaling * inverseXYScaling;
+    this.inverseZScalingSquared = inverseZScaling * inverseZScaling;
+    this.NORTH_POLE = new GeoPoint(zScaling, 0.0, 0.0, 1.0, Math.PI * 0.5, 0.0);
+    this.SOUTH_POLE = new GeoPoint(zScaling, 0.0, 0.0, -1.0, -Math.PI * 0.5, 0.0);
+    this.MIN_X_POLE = new GeoPoint(xyScaling, -1.0, 0.0, 0.0, 0.0, -Math.PI);
+    this.MAX_X_POLE = new GeoPoint(xyScaling, 1.0, 0.0, 0.0, 0.0, 0.0);
+    this.MIN_Y_POLE = new GeoPoint(xyScaling, 0.0, -1.0, 0.0, 0.0, -Math.PI * 0.5);
+    this.MAX_Y_POLE = new GeoPoint(xyScaling, 0.0, 1.0, 0.0, 0.0, Math.PI * 0.5);
+    this.scale = (2.0 * xyScaling + zScaling)/3.0;
     this.inverseScale = 1.0 / scale;
     this.minimumPoleDistance  = Math.min(surfaceDistance(NORTH_POLE, SOUTH_POLE), surfaceDistance(MIN_X_POLE, MAX_X_POLE));
+
+    this.MAX_VALUE = getMaximumMagnitude();
+    this.MUL = (0x1L << BITS) / (2 * this.MAX_VALUE);
+    this.DECODE = getNextSafeDouble(1/MUL);
+    this.MIN_ENCODED_VALUE = encodeValue(-MAX_VALUE);
+    this.MAX_ENCODED_VALUE = encodeValue(MAX_VALUE);
+
+    this.RADIANS_PER_METER = 1.0 / xyScaling;
+
+    this.docValueEncoder = new DocValueEncoder(this);
   }
 
   /** Deserialization constructor.
@@ -118,71 +174,141 @@ public class PlanetModel implements SerializableObject {
   
   @Override
   public void write(final OutputStream outputStream) throws IOException {
-    SerializableObject.writeDouble(outputStream, ab);
-    SerializableObject.writeDouble(outputStream, c);
+    SerializableObject.writeDouble(outputStream, xyScaling);
+    SerializableObject.writeDouble(outputStream, zScaling);
   }
   
   /** Does this planet model describe a sphere?
    *@return true if so.
    */
   public boolean isSphere() {
-    return this.ab == this.c;
+    return this.xyScaling == this.zScaling;
   }
   
   /** Find the minimum magnitude of all points on the ellipsoid.
    * @return the minimum magnitude for the planet.
    */
   public double getMinimumMagnitude() {
-    return Math.min(this.ab, this.c);
+    return Math.min(this.xyScaling, this.zScaling);
   }
 
   /** Find the maximum magnitude of all points on the ellipsoid.
    * @return the maximum magnitude for the planet.
    */
   public double getMaximumMagnitude() {
-    return Math.max(this.ab, this.c);
+    return Math.max(this.xyScaling, this.zScaling);
   }
   
   /** Find the minimum x value.
    *@return the minimum X value.
    */
   public double getMinimumXValue() {
-    return -this.ab;
+    return -this.xyScaling;
   }
   
   /** Find the maximum x value.
    *@return the maximum X value.
    */
   public double getMaximumXValue() {
-    return this.ab;
+    return this.xyScaling;
   }
 
   /** Find the minimum y value.
    *@return the minimum Y value.
    */
   public double getMinimumYValue() {
-    return -this.ab;
+    return -this.xyScaling;
   }
   
   /** Find the maximum y value.
    *@return the maximum Y value.
    */
   public double getMaximumYValue() {
-    return this.ab;
+    return this.xyScaling;
   }
   
   /** Find the minimum z value.
    *@return the minimum Z value.
    */
   public double getMinimumZValue() {
-    return -this.c;
+    return -this.zScaling;
   }
   
   /** Find the maximum z value.
    *@return the maximum Z value.
    */
   public double getMaximumZValue() {
-    return this.c;
+    return this.zScaling;
+  }
+
+  /** return the calculated mean radius (in meters) */
+  public double getMeanRadiusMeters() {
+    return this.r1;
+  }
+
+  /** encode the provided value from double to integer space */
+  public int encodeValue(double x) {
+    if (x > getMaximumMagnitude()) {
+      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (greater than planetMax=" + getMaximumMagnitude() + ")");
+    }
+    if (x == getMaximumMagnitude()) {
+      x = Math.nextDown(x);
+    }
+    if (x < -getMaximumMagnitude()) {
+      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than -planetMax=" + -getMaximumMagnitude() + ")");
+    }
+    long result = (long) Math.floor(x / DECODE);
+    assert result >= Integer.MIN_VALUE;
+    assert result <= Integer.MAX_VALUE;
+    return (int) result;
+  }
+
+  /**
+   * Decodes a given integer back into the radian value according to the defined planet model
+   */
+  public double decodeValue(int x) {
+    double result;
+    if (x == MIN_ENCODED_VALUE) {
+      // We must special case this, because -MAX_VALUE is not guaranteed to land precisely at a floor value, and we don't ever want to
+      // return a value outside of the planet's range (I think?).  The max value is "safe" because we floor during encode:
+      result = -MAX_VALUE;
+    } else if (x == MAX_ENCODED_VALUE) {
+      result = MAX_VALUE;
+    } else {
+      // We decode to the center value; this keeps the encoding stable
+      result = (x+0.5) * DECODE;
+    }
+    assert result >= -MAX_VALUE && result <= MAX_VALUE;
+    return result;
+  }
+
+  /** return reference to the DocValueEncoder used to encode/decode Geo3DDocValues */
+  public DocValueEncoder getDocValueEncoder() {
+    return this.docValueEncoder;
+  }
+
+  /** Returns a double value >= x such that if you multiply that value by an int, and then
+   *  divide it by that int again, you get precisely the same value back */
+  private static double getNextSafeDouble(double x) {
+
+    // Move to double space:
+    long bits = Double.doubleToLongBits(x);
+
+    // Make sure we are beyond the actual maximum value:
+    bits += Integer.MAX_VALUE;
+
+    // Clear the bottom 32 bits:
+    bits &= ~((long) Integer.MAX_VALUE);
+
+    // Convert back to double:
+    double result = Double.longBitsToDouble(bits);
+    assert result >= x;
+    return result;
+  }
+
+  /** Converts earth-surface meters to radians */
+  public double fromMeters(final double meters) {
+    return meters * RADIANS_PER_METER;
   }
 
   /** Check if point is on surface.
@@ -200,8 +326,8 @@ public class PlanetModel implements SerializableObject {
    */
   public boolean pointOnSurface(final double x, final double y, final double z) {
     // Equation of planet surface is:
-    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
-    return Math.abs(x * x * inverseAb * inverseAb + y * y * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0) < Vector.MINIMUM_RESOLUTION;
+    // x^2 / a^2 + y^2 / b^2 + z^2 / zScaling^2 - 1 = 0
+    return Math.abs(x * x * inverseXYScaling * inverseXYScaling + y * y * inverseXYScaling * inverseXYScaling + z * z * inverseZScaling * inverseZScaling - 1.0) < Vector.MINIMUM_RESOLUTION;
   }
 
   /** Check if point is outside surface.
@@ -219,8 +345,8 @@ public class PlanetModel implements SerializableObject {
    */
   public boolean pointOutside(final double x, final double y, final double z) {
     // Equation of planet surface is:
-    // x^2 / a^2 + y^2 / b^2 + z^2 / c^2 - 1 = 0
-    return (x * x + y * y) * inverseAb * inverseAb + z * z * inverseC * inverseC - 1.0 > Vector.MINIMUM_RESOLUTION;
+    // x^2 / a^2 + y^2 / b^2 + z^2 / zScaling^2 - 1 = 0
+    return (x * x + y * y) * inverseXYScaling * inverseXYScaling + z * z * inverseZScaling * inverseZScaling - 1.0 > Vector.MINIMUM_RESOLUTION;
   }
   
   /** Compute a GeoPoint that's scaled to actually be on the planet surface.
@@ -239,12 +365,12 @@ public class PlanetModel implements SerializableObject {
    */
   public GeoPoint createSurfacePoint(final double x, final double y, final double z) {
     // The equation of the surface is:
-    // (x^2 / a^2 + y^2 / b^2 + z^2 / c^2) = 1
+    // (x^2 / a^2 + y^2 / b^2 + z^2 / zScaling^2) = 1
     // We will need to scale the passed-in x, y, z values:
-    // ((tx)^2 / a^2 + (ty)^2 / b^2 + (tz)^2 / c^2) = 1
-    // t^2 * (x^2 / a^2 + y^2 / b^2 + z^2 / c^2)  = 1
-    // t = sqrt ( 1 / (x^2 / a^2 + y^2 / b^2 + z^2 / c^2))
-    final double t = Math.sqrt(1.0 / (x*x*inverseAbSquared + y*y*inverseAbSquared + z*z*inverseCSquared));
+    // ((tx)^2 / a^2 + (ty)^2 / b^2 + (tz)^2 / zScaling^2) = 1
+    // t^2 * (x^2 / a^2 + y^2 / b^2 + z^2 / zScaling^2)  = 1
+    // t = sqrt ( 1 / (x^2 / a^2 + y^2 / b^2 + z^2 / zScaling^2))
+    final double t = Math.sqrt(1.0 / (x*x* inverseXYScalingSquared + y*y* inverseXYScalingSquared + z*z* inverseZScalingSquared));
     return new GeoPoint(t*x, t*y, t*z);
   }
   
@@ -258,9 +384,9 @@ public class PlanetModel implements SerializableObject {
     final double B0 = (pt1.y + pt2.y) * 0.5;
     final double C0 = (pt1.z + pt2.z) * 0.5;
       
-    final double denom = inverseAbSquared * A0 * A0 +
-      inverseAbSquared * B0 * B0 +
-      inverseCSquared * C0 * C0;
+    final double denom = inverseXYScalingSquared * A0 * A0 +
+      inverseXYScalingSquared * B0 * B0 +
+      inverseZScalingSquared * C0 * C0;
           
     if(denom < Vector.MINIMUM_RESOLUTION) {
       // Bisection is undefined
@@ -280,8 +406,8 @@ public class PlanetModel implements SerializableObject {
    */
   public double surfaceDistance(final GeoPoint pt1, final GeoPoint pt2) {
     final double L = pt2.getLongitude() - pt1.getLongitude();
-    final double U1 = Math.atan((1.0-flattening) * Math.tan(pt1.getLatitude()));
-    final double U2 = Math.atan((1.0-flattening) * Math.tan(pt2.getLatitude()));
+    final double U1 = Math.atan((1.0- scaledFlattening) * Math.tan(pt1.getLatitude()));
+    final double U2 = Math.atan((1.0- scaledFlattening) * Math.tan(pt2.getLatitude()));
 
     final double sinU1 = Math.sin(U1);
     final double cosU1 = Math.cos(U1);
@@ -324,9 +450,9 @@ public class PlanetModel implements SerializableObject {
 
       if (Double.isNaN(cos2SigmaM))
         cos2SigmaM = 0.0;  // equatorial line: cosSqAlpha=0
-      C = flattening / 16.0 * cosSqAlpha * (4.0 + flattening * (4.0 - 3.0 * cosSqAlpha));
+      C = scaledFlattening / 16.0 * cosSqAlpha * (4.0 + scaledFlattening * (4.0 - 3.0 * cosSqAlpha));
       lambdaP = lambda;
-      lambda = L + (1.0 - C) * flattening * sinAlpha *
+      lambda = L + (1.0 - C) * scaledFlattening * sinAlpha *
         (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1.0 + 2.0 * cos2SigmaM *cos2SigmaM)));
     } while (Math.abs(lambda-lambdaP) >= Vector.MINIMUM_RESOLUTION && ++iterLimit < 100);
     final double uSq = cosSqAlpha * this.squareRatio;
@@ -335,7 +461,7 @@ public class PlanetModel implements SerializableObject {
     final double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4.0 * (cosSigma * (-1.0 + 2.0 * cos2SigmaM * cos2SigmaM)-
                                         B / 6.0 * cos2SigmaM * (-3.0 + 4.0 * sinSigma * sinSigma) * (-3.0 + 4.0 * cos2SigmaM * cos2SigmaM)));
 
-    return c * inverseScale * A * (sigma - deltaSigma);
+    return zScaling * inverseScale * A * (sigma - deltaSigma);
   }
 
   /** Compute new point given original point, a bearing direction, and an adjusted angle (as would be computed by
@@ -357,7 +483,7 @@ public class PlanetModel implements SerializableObject {
     double sinα1 = Math.sin(bearing);
     double cosα1 = Math.cos(bearing);
 
-    double tanU1 = (1.0 - flattening) * Math.tan(lat);
+    double tanU1 = (1.0 - scaledFlattening) * Math.tan(lat);
     double cosU1 = 1.0 / Math.sqrt((1.0 + tanU1 * tanU1));
     double sinU1 = tanU1 * cosU1;
 
@@ -373,7 +499,7 @@ public class PlanetModel implements SerializableObject {
     double cosσ;
     double Δσ;
 
-    double σ = dist / (c * inverseScale * A);
+    double σ = dist / (zScaling * inverseScale * A);
     double σʹ;
     double iterations = 0;
     do {
@@ -383,30 +509,233 @@ public class PlanetModel implements SerializableObject {
       Δσ = B * sinσ * (cos2σM + B / 4.0 * (cosσ * (-1.0 + 2.0 * cos2σM * cos2σM) -
           B / 6.0 * cos2σM * (-3.0 + 4.0 * sinσ * sinσ) * (-3.0 + 4.0 * cos2σM * cos2σM)));
       σʹ = σ;
-      σ = dist / (c * inverseScale * A) + Δσ;
+      σ = dist / (zScaling * inverseScale * A) + Δσ;
     } while (Math.abs(σ - σʹ) >= Vector.MINIMUM_RESOLUTION && ++iterations < 100);
     double x = sinU1 * sinσ - cosU1 * cosσ * cosα1;
-    double φ2 = Math.atan2(sinU1 * cosσ + cosU1 * sinσ * cosα1, (1.0 - flattening) * Math.sqrt(sinα * sinα + x * x));
+    double φ2 = Math.atan2(sinU1 * cosσ + cosU1 * sinσ * cosα1, (1.0 - scaledFlattening) * Math.sqrt(sinα * sinα + x * x));
     double λ = Math.atan2(sinσ * sinα1, cosU1 * cosσ - sinU1 * sinσ * cosα1);
-    double C = flattening / 16.0 * cosSqα * (4.0 + flattening * (4.0 - 3.0 * cosSqα));
-    double L = λ - (1.0 - C) * flattening * sinα *
+    double C = scaledFlattening / 16.0 * cosSqα * (4.0 + scaledFlattening * (4.0 - 3.0 * cosSqα));
+    double L = λ - (1.0 - C) * scaledFlattening * sinα *
         (σ + C * sinσ * (cos2σM + C * cosσ * (-1.0 + 2.0 * cos2σM * cos2σM)));
     double λ2 = (lon + L + 3.0 * Math.PI) % (2.0 * Math.PI) - Math.PI;  // normalise to -180..+180
 
     return new GeoPoint(this, φ2, λ2);
   }
 
+  /** Utility class for encoding / decoding from lat/lon (decimal degrees) into sortable doc value numerics (integers) */
+  public static class DocValueEncoder {
+    private final PlanetModel planetModel;
+
+    // These are the multiplicative constants we need to use to arrive at values that fit in 21 bits.
+    // The formula we use to go from double to encoded value is:  Math.floor((value - minimum) * factor + 0.5)
+    // If we plug in maximum for value, we should get 0x1FFFFF.
+    // So, 0x1FFFFF = Math.floor((maximum - minimum) * factor + 0.5)
+    // We factor out the 0.5 and Math.floor by stating instead:
+    // 0x1FFFFF = (maximum - minimum) * factor
+    // So, factor = 0x1FFFFF / (maximum - minimum)
+
+    private final static double inverseMaximumValue = 1.0 / (double)(0x1FFFFF);
+
+    private final double inverseXFactor;
+    private final double inverseYFactor;
+    private final double inverseZFactor;
+
+    private final double xFactor;
+    private final double yFactor;
+    private final double zFactor;
+
+    // Fudge factor for step adjustments.  This is here solely to handle inaccuracies in bounding boxes
+    // that occur because of quantization.  For unknown reasons, the fudge factor needs to be
+    // 10.0 rather than 1.0.  See LUCENE-7430.
+
+    private final static double STEP_FUDGE = 10.0;
+
+    // These values are the delta between a value and the next value in each specific dimension
+
+    private final double xStep;
+    private final double yStep;
+    private final double zStep;
+
+    /** construct an encoder/decoder instance from the provided PlanetModel definition */
+    private DocValueEncoder(final PlanetModel planetModel) {
+      this.planetModel = planetModel;
+
+      this.inverseXFactor = (planetModel.getMaximumXValue() - planetModel.getMinimumXValue()) * inverseMaximumValue;
+      this.inverseYFactor = (planetModel.getMaximumYValue() - planetModel.getMinimumYValue()) * inverseMaximumValue;
+      this.inverseZFactor = (planetModel.getMaximumZValue() - planetModel.getMinimumZValue()) * inverseMaximumValue;
+
+      this.xFactor = 1.0 / inverseXFactor;
+      this.yFactor = 1.0 / inverseYFactor;
+      this.zFactor = 1.0 / inverseZFactor;
+
+      this.xStep = inverseXFactor * STEP_FUDGE;
+      this.yStep = inverseYFactor * STEP_FUDGE;
+      this.zStep = inverseZFactor * STEP_FUDGE;
+    }
+
+    /** Encode a point.
+     * @param point is the point
+     * @return the encoded long
+     */
+    public long encodePoint(final GeoPoint point) {
+      return encodePoint(point.x, point.y, point.z);
+    }
+
+    /** Encode a point.
+     * @param x is the x value
+     * @param y is the y value
+     * @param z is the z value
+     * @return the encoded long
+     */
+    public long encodePoint(final double x, final double y, final double z) {
+      int XEncoded = encodeX(x);
+      int YEncoded = encodeY(y);
+      int ZEncoded = encodeZ(z);
+      return
+          (((long)(XEncoded & 0x1FFFFF)) << 42) |
+              (((long)(YEncoded & 0x1FFFFF)) << 21) |
+              ((long)(ZEncoded & 0x1FFFFF));
+    }
+
+    /** Decode GeoPoint value from long docvalues value.
+     * @param docValue is the doc values value.
+     * @return the GeoPoint.
+     */
+    public GeoPoint decodePoint(final long docValue) {
+      return new GeoPoint(decodeX(((int)(docValue >> 42)) & 0x1FFFFF),
+          decodeY(((int)(docValue >> 21)) & 0x1FFFFF),
+          decodeZ(((int)(docValue)) & 0x1FFFFF));
+    }
+
+    /** Decode X value from long docvalues value.
+     * @param docValue is the doc values value.
+     * @return the x value.
+     */
+    public double decodeXValue(final long docValue) {
+      return decodeX(((int)(docValue >> 42)) & 0x1FFFFF);
+    }
+
+    /** Decode Y value from long docvalues value.
+     * @param docValue is the doc values value.
+     * @return the y value.
+     */
+    public double decodeYValue(final long docValue) {
+      return decodeY(((int)(docValue >> 21)) & 0x1FFFFF);
+    }
+
+    /** Decode Z value from long docvalues value.
+     * @param docValue is the doc values value.
+     * @return the z value.
+     */
+    public double decodeZValue(final long docValue) {
+      return decodeZ(((int)(docValue)) & 0x1FFFFF);
+    }
+
+    /** Round the provided X value down, by encoding it, decrementing it, and unencoding it.
+     * @param startValue is the starting value.
+     * @return the rounded value.
+     */
+    public double roundDownX(final double startValue) {
+      return startValue - xStep;
+    }
+
+    /** Round the provided X value up, by encoding it, incrementing it, and unencoding it.
+     * @param startValue is the starting value.
+     * @return the rounded value.
+     */
+    public double roundUpX(final double startValue) {
+      return startValue + xStep;
+    }
+
+    /** Round the provided Y value down, by encoding it, decrementing it, and unencoding it.
+     * @param startValue is the starting value.
+     * @return the rounded value.
+     */
+    public double roundDownY(final double startValue) {
+      return startValue - yStep;
+    }
+
+    /** Round the provided Y value up, by encoding it, incrementing it, and unencoding it.
+     * @param startValue is the starting value.
+     * @return the rounded value.
+     */
+    public double roundUpY(final double startValue) {
+      return startValue + yStep;
+    }
+
+    /** Round the provided Z value down, by encoding it, decrementing it, and unencoding it.
+     * @param startValue is the starting value.
+     * @return the rounded value.
+     */
+    public double roundDownZ(final double startValue) {
+      return startValue - zStep;
+    }
+
+    /** Round the provided Z value up, by encoding it, incrementing it, and unencoding it.
+     * @param startValue is the starting value.
+     * @return the rounded value.
+     */
+    public double roundUpZ(final double startValue) {
+      return startValue + zStep;
+    }
+
+    // For encoding/decoding, we generally want the following behavior:
+    // (1) If you encode the maximum value or the minimum value, the resulting int fits in 21 bits.
+    // (2) If you decode an encoded value, you get back the original value for both the minimum and maximum planet model values.
+    // (3) Rounding occurs such that a small delta from the minimum and maximum planet model values still returns the same
+    // values -- that is, these are in the center of the range of input values that should return the minimum or maximum when decoded
+
+    private int encodeX(final double x) {
+      if (x > planetModel.getMaximumXValue()) {
+        throw new IllegalArgumentException("x value exceeds planet model maximum");
+      } else if (x < planetModel.getMinimumXValue()) {
+        throw new IllegalArgumentException("x value less than planet model minimum");
+      }
+      return (int)Math.floor((x - planetModel.getMinimumXValue()) * xFactor + 0.5);
+    }
+
+    private double decodeX(final int x) {
+      return x * inverseXFactor + planetModel.getMinimumXValue();
+    }
+
+    private int encodeY(final double y) {
+      if (y > planetModel.getMaximumYValue()) {
+        throw new IllegalArgumentException("y value exceeds planet model maximum");
+      } else if (y < planetModel.getMinimumYValue()) {
+        throw new IllegalArgumentException("y value less than planet model minimum");
+      }
+      return (int)Math.floor((y - planetModel.getMinimumYValue()) * yFactor + 0.5);
+    }
+
+    private double decodeY(final int y) {
+      return y * inverseYFactor + planetModel.getMinimumYValue();
+    }
+
+    private int encodeZ(final double z) {
+      if (z > planetModel.getMaximumZValue()) {
+        throw new IllegalArgumentException("z value exceeds planet model maximum");
+      } else if (z < planetModel.getMinimumZValue()) {
+        throw new IllegalArgumentException("z value less than planet model minimum");
+      }
+      return (int)Math.floor((z - planetModel.getMinimumZValue()) * zFactor + 0.5);
+    }
+
+    private double decodeZ(final int z) {
+      return z * inverseZFactor + planetModel.getMinimumZValue();
+    }
+  }
+
   @Override
   public boolean equals(final Object o) {
     if (!(o instanceof PlanetModel))
       return false;
     final PlanetModel other = (PlanetModel)o;
-    return ab == other.ab && c == other.c;
+    return xyScaling == other.xyScaling && zScaling == other.zScaling;
   }
   
   @Override
   public int hashCode() {
-    return Double.hashCode(ab) + Double.hashCode(c);
+    return Double.hashCode(xyScaling) + Double.hashCode(zScaling);
   }
   
   @Override
@@ -415,8 +744,10 @@ public class PlanetModel implements SerializableObject {
       return "PlanetModel.SPHERE";
     } else if (this.equals(WGS84)) {
       return "PlanetModel.WGS84";
+    } else if (this.equals(CLARKE_1866)) {
+      return "PlanetModel.CLARKE_1866";
     } else {
-      return "PlanetModel(ab="+ab+" c="+c+")";
+      return "PlanetModel(xyScaling="+ xyScaling +" zScaling="+ zScaling +")";
     }
   }
 }
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
index c91d6eb..46605c1 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/Vector.java
@@ -562,7 +562,7 @@ public class Vector {
    * @return a magnitude value for that (x,y,z) that projects the vector onto the specified ellipsoid.
    */
   static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double x, final double y, final double z) {
-    return 1.0 / Math.sqrt(x*x*planetModel.inverseAbSquared + y*y*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
+    return 1.0 / Math.sqrt(x*x*planetModel.inverseXYScalingSquared + y*y*planetModel.inverseXYScalingSquared + z*z*planetModel.inverseZScalingSquared);
   }
 
   /** Compute the desired magnitude of a unit vector projected to a given
@@ -572,7 +572,7 @@ public class Vector {
    * @return a magnitude value for that z value that projects the vector onto the specified ellipsoid.
    */
   static double computeDesiredEllipsoidMagnitude(final PlanetModel planetModel, final double z) {
-    return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseAbSquared + z*z*planetModel.inverseCSquared);
+    return 1.0 / Math.sqrt((1.0-z*z)*planetModel.inverseXYScalingSquared + z*z*planetModel.inverseZScalingSquared);
   }
 
   @Override
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DDocValues.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DDocValues.java
index a099c54..41471c8 100644
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DDocValues.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DDocValues.java
@@ -16,6 +16,7 @@
  */
 package org.apache.lucene.spatial3d;
 
+import com.carrotsearch.randomizedtesting.generators.RandomPicks;
 import org.apache.lucene.spatial3d.geom.GeoPoint;
 import org.apache.lucene.spatial3d.geom.PlanetModel;
 
@@ -35,17 +36,18 @@ public class TestGeo3DDocValues extends LuceneTestCase {
   }
     
   void checkPointEncoding(final double latitude, final double longitude) {
-    final GeoPoint point = new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(latitude), Geo3DUtil.fromDegrees(longitude));
-    long pointValue = Geo3DDocValuesField.encodePoint(point);
-    final double x = Geo3DDocValuesField.decodeXValue(pointValue);
-    final double y = Geo3DDocValuesField.decodeYValue(pointValue);
-    final double z = Geo3DDocValuesField.decodeZValue(pointValue);
+    PlanetModel planetModel = RandomPicks.randomFrom(random(), new PlanetModel[] {PlanetModel.WGS84, PlanetModel.CLARKE_1866});
+    final GeoPoint point = new GeoPoint(planetModel, Geo3DUtil.fromDegrees(latitude), Geo3DUtil.fromDegrees(longitude));
+    long pointValue = planetModel.getDocValueEncoder().encodePoint(point);
+    final double x = planetModel.getDocValueEncoder().decodeXValue(pointValue);
+    final double y = planetModel.getDocValueEncoder().decodeYValue(pointValue);
+    final double z = planetModel.getDocValueEncoder().decodeZValue(pointValue);
     final GeoPoint pointR = new GeoPoint(x,y,z);
     // Check whether stable
-    pointValue = Geo3DDocValuesField.encodePoint(x, y, z);
-    assertEquals(x, Geo3DDocValuesField.decodeXValue(pointValue), 0.0);
-    assertEquals(y, Geo3DDocValuesField.decodeYValue(pointValue), 0.0);
-    assertEquals(z, Geo3DDocValuesField.decodeZValue(pointValue), 0.0);
+    pointValue = planetModel.getDocValueEncoder().encodePoint(x, y, z);
+    assertEquals(x, planetModel.getDocValueEncoder().decodeXValue(pointValue), 0.0);
+    assertEquals(y, planetModel.getDocValueEncoder().decodeYValue(pointValue), 0.0);
+    assertEquals(z, planetModel.getDocValueEncoder().decodeZValue(pointValue), 0.0);
     // Check whether has some relationship with original point
     assertEquals(0.0, point.arcDistance(pointR), 0.02);
   }
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
index 01d152b..5c74ca2 100644
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Random;
 import java.util.Set;
 
+import com.carrotsearch.randomizedtesting.generators.RandomPicks;
 import org.apache.lucene.codecs.Codec;
 import org.apache.lucene.codecs.FilterCodec;
 import org.apache.lucene.codecs.PointsFormat;
@@ -85,6 +86,10 @@ import com.carrotsearch.randomizedtesting.generators.RandomNumbers;
 
 public class TestGeo3DPoint extends LuceneTestCase {
 
+  protected PlanetModel randomPlanetModel() {
+    return RandomPicks.randomFrom(random(), new PlanetModel[] {PlanetModel.WGS84, PlanetModel.CLARKE_1866, PlanetModel.SPHERE});
+  }
+
   private static Codec getCodec() {
     if (Codec.getDefault().getName().equals("Lucene84")) {
       int maxPointsInLeafNode = TestUtil.nextInt(random(), 16, 2048);
@@ -120,13 +125,14 @@ public class TestGeo3DPoint extends LuceneTestCase {
     iwc.setCodec(getCodec());
     IndexWriter w = new IndexWriter(dir, iwc);
     Document doc = new Document();
-    doc.add(new Geo3DPoint("field", 50.7345267, -97.5303555));
+    PlanetModel planetModel = randomPlanetModel();
+    doc.add(new Geo3DPoint("field", planetModel, 50.7345267, -97.5303555));
     w.addDocument(doc);
     IndexReader r = DirectoryReader.open(w);
     // We can't wrap with "exotic" readers because the query must see the BKD3DDVFormat:
     IndexSearcher s = newSearcher(r, false);
     assertEquals(1, s.search(Geo3DPoint.newShapeQuery("field",
-                                                      GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits.value);
+                                                      GeoCircleFactory.makeGeoCircle(planetModel, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits.value);
     w.close();
     r.close();
     dir.close();
@@ -145,11 +151,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
     final int yMinEnc, yMaxEnc;
     final int zMinEnc, zMaxEnc;
     final int splitCount;
+    final PlanetModel planetModel;
 
     public Cell(Cell parent,
                 int xMinEnc, int xMaxEnc,
                 int yMinEnc, int yMaxEnc,
                 int zMinEnc, int zMaxEnc,
+                final PlanetModel planetModel,
                 int splitCount) {
       this.parent = parent;
       this.xMinEnc = xMinEnc;
@@ -160,13 +168,14 @@ public class TestGeo3DPoint extends LuceneTestCase {
       this.zMaxEnc = zMaxEnc;
       this.cellID = nextCellID++;
       this.splitCount = splitCount;
+      this.planetModel = planetModel;
     }
 
     /** Returns true if the quantized point lies within this cell, inclusive on all bounds. */
     public boolean contains(GeoPoint point) {
-      int docX = Geo3DUtil.encodeValue(point.x);
-      int docY = Geo3DUtil.encodeValue(point.y);
-      int docZ = Geo3DUtil.encodeValue(point.z);
+      int docX = planetModel.encodeValue(point.x);
+      int docY = planetModel.encodeValue(point.y);
+      int docZ = planetModel.encodeValue(point.z);
 
       return docX >= xMinEnc && docX <= xMaxEnc &&
         docY >= yMinEnc && docY <= yMaxEnc && 
@@ -179,12 +188,12 @@ public class TestGeo3DPoint extends LuceneTestCase {
     }
   }
 
-  private static double quantize(double xyzValue) {
-    return Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(xyzValue));
+  private static double quantize(double xyzValue, final PlanetModel planetModel) {
+    return planetModel.decodeValue(planetModel.encodeValue(xyzValue));
   }
 
-  private static GeoPoint quantize(GeoPoint point) {
-    return new GeoPoint(quantize(point.x), quantize(point.y), quantize(point.z));
+  private static GeoPoint quantize(GeoPoint point, final PlanetModel planetModel) {
+    return new GeoPoint(quantize(point.x, planetModel), quantize(point.y, planetModel), quantize(point.z, planetModel));
   }
 
   /** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */
@@ -197,9 +206,10 @@ public class TestGeo3DPoint extends LuceneTestCase {
 
     GeoPoint[] docs = new GeoPoint[numDocs];
     GeoPoint[] unquantizedDocs = new GeoPoint[numDocs];
+    PlanetModel planetModel = PlanetModel.CLARKE_1866;
     for(int docID=0;docID<numDocs;docID++) {
-      unquantizedDocs[docID] = new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
-      docs[docID] = quantize(unquantizedDocs[docID]);
+      unquantizedDocs[docID] = new GeoPoint(planetModel, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
+      docs[docID] = quantize(unquantizedDocs[docID], planetModel);
       if (VERBOSE) {
         System.out.println("  doc=" + docID + ": " + docs[docID] + "; unquantized: "+unquantizedDocs[docID]);
       }
@@ -210,7 +220,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
     int recurseDepth = RandomNumbers.randomIntBetween(random(), 5, 15);
     
     for(int iter=0;iter<iters;iter++) {
-      GeoShape shape = randomShape();
+      GeoShape shape = randomShape(planetModel);
 
       StringWriter sw = new StringWriter();
       PrintWriter log = new PrintWriter(sw, true);
@@ -224,12 +234,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
 
       // Start with the root cell that fully contains the shape:
       Cell root = new Cell(null,
-                           encodeValueLenient(bounds.getMinimumX()),
-                           encodeValueLenient(bounds.getMaximumX()),
-                           encodeValueLenient(bounds.getMinimumY()),
-                           encodeValueLenient(bounds.getMaximumY()),
-                           encodeValueLenient(bounds.getMinimumZ()),
-                           encodeValueLenient(bounds.getMaximumZ()),
+                           encodeValueLenient(bounds.getMinimumX(), planetModel),
+                           encodeValueLenient(bounds.getMaximumX(), planetModel),
+                           encodeValueLenient(bounds.getMinimumY(), planetModel),
+                           encodeValueLenient(bounds.getMaximumY(), planetModel),
+                           encodeValueLenient(bounds.getMinimumZ(), planetModel),
+                           encodeValueLenient(bounds.getMaximumZ(), planetModel),
+                           planetModel,
                            0);
 
       if (VERBOSE) {
@@ -294,16 +305,15 @@ public class TestGeo3DPoint extends LuceneTestCase {
             }
           }
         } else {
-          
-          GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,
-                                                        Geo3DUtil.decodeValueFloor(cell.xMinEnc), Geo3DUtil.decodeValueCeil(cell.xMaxEnc),
-                                                        Geo3DUtil.decodeValueFloor(cell.yMinEnc), Geo3DUtil.decodeValueCeil(cell.yMaxEnc),
-                                                        Geo3DUtil.decodeValueFloor(cell.zMinEnc), Geo3DUtil.decodeValueCeil(cell.zMaxEnc));
+          GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel,
+                                                        Geo3DUtil.decodeValueFloor(cell.xMinEnc, planetModel), Geo3DUtil.decodeValueCeil(cell.xMaxEnc, planetModel),
+                                                        Geo3DUtil.decodeValueFloor(cell.yMinEnc, planetModel), Geo3DUtil.decodeValueCeil(cell.yMaxEnc, planetModel),
+                                                        Geo3DUtil.decodeValueFloor(cell.zMinEnc, planetModel), Geo3DUtil.decodeValueCeil(cell.zMaxEnc, planetModel));
 
           if (VERBOSE) {
-            log.println("    minx="+Geo3DUtil.decodeValueFloor(cell.xMinEnc)+" maxx="+Geo3DUtil.decodeValueCeil(cell.xMaxEnc)+
-              " miny="+Geo3DUtil.decodeValueFloor(cell.yMinEnc)+" maxy="+Geo3DUtil.decodeValueCeil(cell.yMaxEnc)+
-              " minz="+Geo3DUtil.decodeValueFloor(cell.zMinEnc)+" maxz="+Geo3DUtil.decodeValueCeil(cell.zMaxEnc));
+            log.println("    minx="+Geo3DUtil.decodeValueFloor(cell.xMinEnc, planetModel)+" maxx="+Geo3DUtil.decodeValueCeil(cell.xMaxEnc, planetModel)+
+              " miny="+Geo3DUtil.decodeValueFloor(cell.yMinEnc, planetModel)+" maxy="+Geo3DUtil.decodeValueCeil(cell.yMaxEnc, planetModel)+
+              " minz="+Geo3DUtil.decodeValueFloor(cell.zMinEnc, planetModel)+" maxz="+Geo3DUtil.decodeValueCeil(cell.zMaxEnc, planetModel));
           }
 
           switch (xyzSolid.getRelationship(shape)) {          
@@ -365,11 +375,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
                                  cell.xMinEnc, splitValue,
                                  cell.yMinEnc, cell.yMaxEnc,
                                  cell.zMinEnc, cell.zMaxEnc,
+                                 planetModel,
                                  cell.splitCount+1);
               Cell cell2 = new Cell(cell,
                                  splitValue, cell.xMaxEnc,
                                  cell.yMinEnc, cell.yMaxEnc,
                                  cell.zMinEnc, cell.zMaxEnc,
+                                 planetModel,
                                  cell.splitCount+1);
               if (VERBOSE) {
                 log.println("    split cell1: " + cell1);
@@ -391,11 +403,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
                                  cell.xMinEnc, cell.xMaxEnc,
                                  cell.yMinEnc, splitValue,
                                  cell.zMinEnc, cell.zMaxEnc,
+                                 planetModel,
                                  cell.splitCount+1);
               Cell cell2 = new Cell(cell,
                                  cell.xMinEnc, cell.xMaxEnc,
                                  splitValue, cell.yMaxEnc,
                                  cell.zMinEnc, cell.zMaxEnc,
+                                 planetModel,
                                  cell.splitCount+1);
               if (VERBOSE) {
                 log.println("    split cell1: " + cell1);
@@ -417,11 +431,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
                                  cell.xMinEnc, cell.xMaxEnc,
                                  cell.yMinEnc, cell.yMaxEnc,
                                  cell.zMinEnc, splitValue,
+                                 planetModel,
                                  cell.splitCount+1);
               Cell cell2 = new Cell(cell,
                                  cell.xMinEnc, cell.xMaxEnc,
                                  cell.yMinEnc, cell.yMaxEnc,
                                  splitValue, cell.zMaxEnc,
+                                 planetModel,
                                  cell.splitCount+1);
               if (VERBOSE) {
                 log.println("    split cell1: " + cell1);
@@ -544,7 +560,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
       }
     }
 
-    verify(lats, lons);
+    verify(lats, lons, randomPlanetModel());
   }
 
   public void testPolygonOrdering() {
@@ -552,14 +568,12 @@ public class TestGeo3DPoint extends LuceneTestCase {
       51.204382859999996, 50.89947531437482, 50.8093624806861,50.8093624806861, 50.89947531437482, 51.204382859999996, 51.51015366140113, 51.59953838204167, 51.59953838204167, 51.51015366140113, 51.204382859999996};
     final double[] lons = new double[] {
       0.8747711978759765, 0.6509219832137298, 0.35960265165247807, 0.10290284834752167, -0.18841648321373008, -0.41226569787597667, -0.18960465285650027, 0.10285893781346236, 0.35964656218653757, 0.6521101528565002, 0.8747711978759765};
-    final Query q = Geo3DPoint.newPolygonQuery("point", new Polygon(lats, lons));
+    final Query q = Geo3DPoint.newPolygonQuery("point", randomPlanetModel(), new Polygon(lats, lons));
     //System.out.println(q);
     assertTrue(!q.toString().contains("GeoConcavePolygon"));
   }
-  
-  private static final double MEAN_EARTH_RADIUS_METERS = PlanetModel.WGS84_MEAN;
-  
-  private static Query random3DQuery(final String field) {
+
+  private static Query random3DQuery(final String field, final PlanetModel planetModel) {
     while (true) {
       final int shapeType = random().nextInt(5);
       switch (shapeType) {
@@ -567,8 +581,8 @@ public class TestGeo3DPoint extends LuceneTestCase {
         // Large polygons
         final boolean isClockwise = random().nextDouble() < 0.5;
         try {
-          final Query q = Geo3DPoint.newLargePolygonQuery(field, makePoly(PlanetModel.WGS84,
-            new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude())),
+          final Query q = Geo3DPoint.newLargePolygonQuery(field, planetModel, makePoly(planetModel,
+            new GeoPoint(planetModel, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude())),
             isClockwise,
             true));
           //System.err.println("Generated: "+q);
@@ -583,8 +597,8 @@ public class TestGeo3DPoint extends LuceneTestCase {
         // Polygons
         final boolean isClockwise = random().nextDouble() < 0.5;
         try {
-          final Query q = Geo3DPoint.newPolygonQuery(field, makePoly(PlanetModel.WGS84,
-            new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude())),
+          final Query q = Geo3DPoint.newPolygonQuery(field, planetModel, makePoly(planetModel,
+            new GeoPoint(planetModel, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude())),
             isClockwise,
             true));
           //System.err.println("Generated: "+q);
@@ -597,9 +611,9 @@ public class TestGeo3DPoint extends LuceneTestCase {
 
       case 1: {
         // Circles
-        final double widthMeters = random().nextDouble() * Math.PI * MEAN_EARTH_RADIUS_METERS;
+        final double widthMeters = random().nextDouble() * Math.PI * planetModel.getMeanRadiusMeters() /*MEAN_EARTH_RADIUS_METERS*/;
         try {
-          return Geo3DPoint.newDistanceQuery(field, GeoTestUtil.nextLatitude(), GeoTestUtil.nextLongitude(), widthMeters);
+          return Geo3DPoint.newDistanceQuery(field, planetModel, GeoTestUtil.nextLatitude(), GeoTestUtil.nextLongitude(), widthMeters);
         } catch (IllegalArgumentException e) {
           continue;
         }
@@ -609,7 +623,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
         // Rectangles
         final Rectangle r = GeoTestUtil.nextBox();
         try {
-          return Geo3DPoint.newBoxQuery(field, r.minLat, r.maxLat, r.minLon, r.maxLon);
+          return Geo3DPoint.newBoxQuery(field, planetModel, r.minLat, r.maxLat, r.minLon, r.maxLon);
         } catch (IllegalArgumentException e) {
           continue;
         }
@@ -619,7 +633,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
         // Paths
         // TBD: Need to rework generation to be realistic
         final int pointCount = random().nextInt(5) + 1;
-        final double width = random().nextDouble() * Math.PI * 0.5 * MEAN_EARTH_RADIUS_METERS;
+        final double width = random().nextDouble() * Math.PI * 0.5 * planetModel.getMeanRadiusMeters(); /* MEAN_EARTH_RADIUS_METERS;*/
         final double[] latitudes = new double[pointCount];
         final double[] longitudes = new double[pointCount];
         for (int i = 0; i < pointCount; i++) {
@@ -627,7 +641,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
           longitudes[i] = GeoTestUtil.nextLongitude();
         }
         try {
-          return Geo3DPoint.newPathQuery(field, latitudes, longitudes, width);
+          return Geo3DPoint.newPathQuery(field, latitudes, longitudes, width, planetModel);
         } catch (IllegalArgumentException e) {
           // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
           // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
@@ -643,7 +657,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
   }
   
   // Poached from Geo3dRptTest.randomShape:
-  private static GeoShape randomShape() {
+  private static GeoShape randomShape(final PlanetModel planetModel) {
     while (true) {
       final int shapeType = random().nextInt(4);
       switch (shapeType) {
@@ -652,11 +666,11 @@ public class TestGeo3DPoint extends LuceneTestCase {
         final int vertexCount = random().nextInt(3) + 3;
         final List<GeoPoint> geoPoints = new ArrayList<>();
         while (geoPoints.size() < vertexCount) {
-          final GeoPoint gPt = new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
+          final GeoPoint gPt = new GeoPoint(planetModel, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
           geoPoints.add(gPt);
         }
         try {
-          final GeoShape rval = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, geoPoints);
+          final GeoShape rval = GeoPolygonFactory.makeGeoPolygon(planetModel, geoPoints);
           if (rval == null) {
             // Degenerate polygon
             continue;
@@ -678,7 +692,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
         double angle = random().nextDouble() * Math.PI/2.0;
 
         try {
-          return GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, lat, lon, angle);
+          return GeoCircleFactory.makeGeoCircle(planetModel, lat, lon, angle);
         } catch (IllegalArgumentException iae) {
           // angle is too small; try again:
           continue;
@@ -702,7 +716,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
           lon1 = x;
         }
 
-        return GeoBBoxFactory.makeGeoBBox(PlanetModel.WGS84, lat1, lat0, lon0, lon1);
+        return GeoBBoxFactory.makeGeoBBox(planetModel, lat1, lat0, lon0, lon1);
       }
 
       case 3: {
@@ -711,10 +725,10 @@ public class TestGeo3DPoint extends LuceneTestCase {
         final double width = toRadians(random().nextInt(89)+1);
         final GeoPoint[] points = new GeoPoint[pointCount];
         for (int i = 0; i < pointCount; i++) {
-          points[i] = new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
+          points[i] = new GeoPoint(planetModel, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
         }
         try {
-          return GeoPathFactory.makeGeoPath(PlanetModel.WGS84, width, points);
+          return GeoPathFactory.makeGeoPath(planetModel, width, points);
         } catch (IllegalArgumentException e) {
           // This is what happens when we create a shape that is invalid.  Although it is conceivable that there are cases where
           // the exception is thrown incorrectly, we aren't going to be able to do that in this random test.
@@ -728,7 +742,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
     }
   }
 
-  private static void verify(double[] lats, double[] lons) throws Exception {
+  private static void verify(double[] lats, double[] lons, final PlanetModel planetModel) throws Exception {
     IndexWriterConfig iwc = newIndexWriterConfig();
 
     GeoPoint[] points = new GeoPoint[lats.length];
@@ -738,8 +752,8 @@ public class TestGeo3DPoint extends LuceneTestCase {
     for(int i=0;i<lats.length;i++) {
       if (Double.isNaN(lats[i]) == false) {
         //System.out.println("lats[" + i + "] = " + lats[i]);
-        unquantizedPoints[i] = new GeoPoint(PlanetModel.WGS84, toRadians(lats[i]), toRadians(lons[i]));
-        points[i] = quantize(unquantizedPoints[i]);
+        unquantizedPoints[i] = new GeoPoint(planetModel, toRadians(lats[i]), toRadians(lons[i]));
+        points[i] = quantize(unquantizedPoints[i], planetModel);
       }
     }
 
@@ -764,7 +778,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
       doc.add(new NumericDocValuesField("id", id));
       GeoPoint point = points[id];
       if (point != null) {
-        doc.add(new Geo3DPoint("point", point.x, point.y, point.z));
+        doc.add(new Geo3DPoint("point", planetModel, point.x, point.y, point.z));
       }
       w.addDocument(doc);
       if (id > 0 && random().nextInt(100) == 42) {
@@ -800,7 +814,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
       }
       */
       
-      Query query = random3DQuery("point"); // Geo3DPoint.newShapeQuery("point", shape);
+      Query query = random3DQuery("point", planetModel); // Geo3DPoint.newShapeQuery("point", shape);
 
       if (VERBOSE) {
         System.err.println("  using query: " + query);
@@ -843,7 +857,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
           GeoShape shape = ((PointInGeo3DShapeQuery)query).getShape();
           XYZBounds bounds = new XYZBounds();
           shape.getBounds(bounds);
-          XYZSolid solid = XYZSolidFactory.makeXYZSolid(PlanetModel.WGS84, bounds.getMinimumX(), bounds.getMaximumX(), bounds.getMinimumY(), bounds.getMaximumY(), bounds.getMinimumZ(), bounds.getMaximumZ());
+          XYZSolid solid = XYZSolidFactory.makeXYZSolid(planetModel, bounds.getMinimumX(), bounds.getMaximumX(), bounds.getMinimumY(), bounds.getMaximumY(), bounds.getMinimumZ(), bounds.getMaximumZ());
 
           boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point));
           if (hits.get(docID) != expected) {
@@ -856,9 +870,9 @@ public class TestGeo3DPoint extends LuceneTestCase {
             b.append("  shape=" + shape + "\n");
             b.append("  bounds=" + bounds + "\n");
             b.append("  world bounds=(" +
-              " minX=" + PlanetModel.WGS84.getMinimumXValue() + " maxX=" + PlanetModel.WGS84.getMaximumXValue() +
-              " minY=" + PlanetModel.WGS84.getMinimumYValue() + " maxY=" + PlanetModel.WGS84.getMaximumYValue() +
-              " minZ=" + PlanetModel.WGS84.getMinimumZValue() + " maxZ=" + PlanetModel.WGS84.getMaximumZValue() + "\n");
+              " minX=" + planetModel.getMinimumXValue() + " maxX=" + planetModel.getMaximumXValue() +
+              " minY=" + planetModel.getMinimumYValue() + " maxY=" + planetModel.getMaximumYValue() +
+              " minZ=" + planetModel.getMinimumZValue() + " maxZ=" + planetModel.getMaximumZValue() + "\n");
             b.append("  quantized point=" + point + " within shape? "+shape.isWithin(point)+" within bounds? "+solid.isWithin(point)+"\n");
             b.append("  unquantized point=" + unquantizedPoint + " within shape? "+shape.isWithin(unquantizedPoint)+" within bounds? "+solid.isWithin(unquantizedPoint)+"\n");
             b.append("  docID=" + docID + " deleted?=" + deleted.contains(id) + "\n");
@@ -877,7 +891,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
 
   public void testToString() {
     // Don't compare entire strings because Java 9 and Java 8 have slightly different values
-    Geo3DPoint point = new Geo3DPoint("point", 44.244272, 7.769736);
+    Geo3DPoint point = new Geo3DPoint("point", randomPlanetModel(), 44.244272, 7.769736);
     final String stringToCompare = "Geo3DPoint <point: x=";
     assertEquals(stringToCompare, point.toString().substring(0,stringToCompare.length()));
   }
@@ -894,7 +908,8 @@ public class TestGeo3DPoint extends LuceneTestCase {
   }
 
   public void testEquals() {
-    GeoShape shape = randomShape();
+    PlanetModel planetModel = randomPlanetModel();
+    GeoShape shape = randomShape(planetModel);
     Query q = Geo3DPoint.newShapeQuery("point", shape);
     assertEquals(q, Geo3DPoint.newShapeQuery("point", shape));
     assertFalse(q.equals(Geo3DPoint.newShapeQuery("point2", shape)));
@@ -902,14 +917,14 @@ public class TestGeo3DPoint extends LuceneTestCase {
     // make a different random shape:
     GeoShape shape2;
     do {
-      shape2 = randomShape();
+      shape2 = randomShape(planetModel);
     } while (shape.equals(shape2));
 
     assertFalse(q.equals(Geo3DPoint.newShapeQuery("point", shape2)));
   }
   
   public void testComplexPolygons() {
-    final PlanetModel pm = PlanetModel.WGS84;
+    final PlanetModel pm = randomPlanetModel();
     // Pick a random pole
     final GeoPoint randomPole = new GeoPoint(pm, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
     int iters = atLeast(100);
@@ -1138,33 +1153,33 @@ public class TestGeo3DPoint extends LuceneTestCase {
   }
 
   public void testEncodeDecodeCeil() throws Exception {
-
+    PlanetModel planetModel = randomPlanetModel();
     // just for testing quantization error
-    final double ENCODING_TOLERANCE = Geo3DUtil.DECODE;
+    final double ENCODING_TOLERANCE = planetModel.DECODE;
 
     int iters = atLeast(10000);
     for(int iter=0;iter<iters;iter++) {
-      GeoPoint point = new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
-      double xEnc = Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(point.x));
+      GeoPoint point = new GeoPoint(planetModel, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
+      double xEnc = planetModel.decodeValue(planetModel.encodeValue(point.x));
       assertEquals("x=" + point.x + " xEnc=" + xEnc + " diff=" + (point.x - xEnc), point.x, xEnc, ENCODING_TOLERANCE);
 
-      double yEnc = Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(point.y));
+      double yEnc = planetModel.decodeValue(planetModel.encodeValue(point.y));
       assertEquals("y=" + point.y + " yEnc=" + yEnc + " diff=" + (point.y - yEnc), point.y, yEnc, ENCODING_TOLERANCE);
 
-      double zEnc = Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(point.z));
+      double zEnc = planetModel.decodeValue(planetModel.encodeValue(point.z));
       assertEquals("z=" + point.z + " zEnc=" + zEnc + " diff=" + (point.z - zEnc), point.z, zEnc, ENCODING_TOLERANCE);
     }
 
     // check edge/interesting cases explicitly
-    double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
+    double planetMax = planetModel.getMaximumMagnitude();
     for (double value : new double[] {0.0, -planetMax, planetMax}) {
-      assertEquals(value, Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(value)), ENCODING_TOLERANCE);
+      assertEquals(value, planetModel.decodeValue(planetModel.encodeValue(value)), ENCODING_TOLERANCE);
     }
   }
 
   /** make sure values always go down: this is important for edge case consistency */
   public void testEncodeDecodeRoundsDown() throws Exception {
-
+    PlanetModel planetModel = randomPlanetModel();
     int iters = atLeast(1000);
     for(int iter=0;iter<iters;iter++) {
       final double latBase = GeoTestUtil.nextLatitude();
@@ -1176,10 +1191,10 @@ public class TestGeo3DPoint extends LuceneTestCase {
       for (int i = 0; i < 1000; i++) {
         lat = Math.min(90, Math.nextUp(lat));
         lon = Math.min(180, Math.nextUp(lon));
-        GeoPoint point = new GeoPoint(PlanetModel.WGS84, toRadians(lat), toRadians(lon));
-        GeoPoint pointEnc = new GeoPoint(Geo3DUtil.decodeValueFloor(Geo3DUtil.encodeValue(point.x)),
-                                         Geo3DUtil.decodeValueFloor(Geo3DUtil.encodeValue(point.y)),
-                                         Geo3DUtil.decodeValueFloor(Geo3DUtil.encodeValue(point.z)));
+        GeoPoint point = new GeoPoint(planetModel, toRadians(lat), toRadians(lon));
+        GeoPoint pointEnc = new GeoPoint(Geo3DUtil.decodeValueFloor(planetModel.encodeValue(point.x), planetModel),
+                                         Geo3DUtil.decodeValueFloor(planetModel.encodeValue(point.y), planetModel),
+                                         Geo3DUtil.decodeValueFloor(planetModel.encodeValue(point.z), planetModel));
         assertTrue(pointEnc.x <= point.x);
         assertTrue(pointEnc.y <= point.y);
         assertTrue(pointEnc.z <= point.z);
@@ -1191,10 +1206,10 @@ public class TestGeo3DPoint extends LuceneTestCase {
       for (int i = 0; i < 1000; i++) {
         lat = Math.max(-90, Math.nextDown(lat));
         lon = Math.max(-180, Math.nextDown(lon));
-        GeoPoint point = new GeoPoint(PlanetModel.WGS84, toRadians(lat), toRadians(lon));
-        GeoPoint pointEnc = new GeoPoint(Geo3DUtil.decodeValueFloor(Geo3DUtil.encodeValue(point.x)),
-                                         Geo3DUtil.decodeValueFloor(Geo3DUtil.encodeValue(point.y)),
-                                         Geo3DUtil.decodeValueFloor(Geo3DUtil.encodeValue(point.z)));
+        GeoPoint point = new GeoPoint(planetModel, toRadians(lat), toRadians(lon));
+        GeoPoint pointEnc = new GeoPoint(Geo3DUtil.decodeValueFloor(planetModel.encodeValue(point.x), planetModel),
+                                         Geo3DUtil.decodeValueFloor(planetModel.encodeValue(point.y), planetModel),
+                                         Geo3DUtil.decodeValueFloor(planetModel.encodeValue(point.z), planetModel));
         assertTrue(pointEnc.x <= point.x);
         assertTrue(pointEnc.y <= point.y);
         assertTrue(pointEnc.z <= point.z);
@@ -1203,37 +1218,39 @@ public class TestGeo3DPoint extends LuceneTestCase {
   }
 
   public void testMinValueQuantization(){
-    int encoded = Geo3DUtil.MIN_ENCODED_VALUE;
-    double minValue= -PlanetModel.WGS84.getMaximumMagnitude();
+    PlanetModel planetModel = randomPlanetModel();
+    int encoded = planetModel.MIN_ENCODED_VALUE;
+    double minValue= -planetModel.getMaximumMagnitude();
     //Normal encoding
-    double decoded = Geo3DUtil.decodeValue(encoded);
+    double decoded = planetModel.decodeValue(encoded);
     assertEquals(minValue, decoded, 0d);
-    assertEquals(encoded, Geo3DUtil.encodeValue(decoded));
+    assertEquals(encoded, planetModel.encodeValue(decoded));
     //Encoding floor
-    double decodedFloor = Geo3DUtil.decodeValueFloor(encoded);
+    double decodedFloor = Geo3DUtil.decodeValueFloor(encoded, planetModel);
     assertEquals(minValue, decodedFloor, 0d);
-    assertEquals(encoded, Geo3DUtil.encodeValue(decodedFloor));
+    assertEquals(encoded, planetModel.encodeValue(decodedFloor));
     //Encoding ceiling
-    double decodedCeiling = Geo3DUtil.decodeValueCeil(encoded);
+    double decodedCeiling = Geo3DUtil.decodeValueCeil(encoded, planetModel);
     assertTrue(decodedCeiling > minValue);
-    assertEquals(encoded, Geo3DUtil.encodeValue(decodedCeiling));
+    assertEquals(encoded, planetModel.encodeValue(decodedCeiling));
   }
 
   public void testMaxValueQuantization(){
-    int encoded = Geo3DUtil.MAX_ENCODED_VALUE;
-    double maxValue= PlanetModel.WGS84.getMaximumMagnitude();
+    PlanetModel planetModel = randomPlanetModel();
+    int encoded = planetModel.MAX_ENCODED_VALUE;
+    double maxValue= planetModel.getMaximumMagnitude();
     //Normal encoding
-    double decoded = Geo3DUtil.decodeValue(encoded);
+    double decoded = planetModel.decodeValue(encoded);
     assertEquals(maxValue, decoded, 0d);
-    assertEquals(encoded, Geo3DUtil.encodeValue(decoded));
+    assertEquals(encoded, planetModel.encodeValue(decoded));
     //Encoding floor
-    double decodedFloor = Geo3DUtil.decodeValueFloor(encoded);
+    double decodedFloor = Geo3DUtil.decodeValueFloor(encoded, planetModel);
     assertTrue(decodedFloor <  maxValue);
-    assertEquals(encoded, Geo3DUtil.encodeValue(decodedFloor));
+    assertEquals(encoded, planetModel.encodeValue(decodedFloor));
     //Encoding ceiling
-    double decodedCeiling = Geo3DUtil.decodeValueCeil(encoded);
+    double decodedCeiling = Geo3DUtil.decodeValueCeil(encoded, planetModel);
     assertEquals(maxValue, decodedCeiling, 0d);
-    assertEquals(encoded, Geo3DUtil.encodeValue(decodedCeiling));
+    assertEquals(encoded, planetModel.encodeValue(decodedCeiling));
   }
 
   // poached from TestGeoEncodingUtils.testLatitudeQuantization:
@@ -1245,33 +1262,34 @@ public class TestGeo3DPoint extends LuceneTestCase {
    */
   public void testQuantization() throws Exception {
     Random random = random();
+    PlanetModel planetModel = randomPlanetModel();
     for (int i = 0; i < 10000; i++) {
       int encoded = random.nextInt();
-      if (encoded <= Geo3DUtil.MIN_ENCODED_VALUE) {
+      if (encoded <= planetModel.MIN_ENCODED_VALUE) {
         continue;
       }
-      if (encoded >= Geo3DUtil.MAX_ENCODED_VALUE) {
+      if (encoded >= planetModel.MAX_ENCODED_VALUE) {
         continue;
       }
-      double min = encoded * Geo3DUtil.DECODE;
-      double decoded = Geo3DUtil.decodeValueFloor(encoded);
+      double min = encoded * planetModel.DECODE;
+      double decoded = Geo3DUtil.decodeValueFloor(encoded, planetModel);
       // should exactly equal expected value
       assertEquals(min, decoded, 0.0D);
       // should round-trip
-      assertEquals(encoded, Geo3DUtil.encodeValue(decoded));
+      assertEquals(encoded, planetModel.encodeValue(decoded));
       // test within the range
       if (encoded != Integer.MAX_VALUE) {
         // this is the next representable value
         // all double values between [min .. max) should encode to the current integer
-        double max = min + Geo3DUtil.DECODE;
-        assertEquals(max, Geo3DUtil.decodeValueFloor(encoded+1), 0.0D);
-        assertEquals(encoded+1, Geo3DUtil.encodeValue(max));
+        double max = min + planetModel.DECODE;
+        assertEquals(max, Geo3DUtil.decodeValueFloor(encoded+1, planetModel), 0.0D);
+        assertEquals(encoded+1, planetModel.encodeValue(max));
 
         // first and last doubles in range that will be quantized
         double minEdge = Math.nextUp(min);
         double maxEdge = Math.nextDown(max);
-        assertEquals(encoded, Geo3DUtil.encodeValue(minEdge));
-        assertEquals(encoded, Geo3DUtil.encodeValue(maxEdge));
+        assertEquals(encoded, planetModel.encodeValue(minEdge));
+        assertEquals(encoded, planetModel.encodeValue(maxEdge));
 
         // check random values within the double range
         long minBits = NumericUtils.doubleToSortableLong(minEdge);
@@ -1279,30 +1297,30 @@ public class TestGeo3DPoint extends LuceneTestCase {
         for (int j = 0; j < 100; j++) {
           double value = NumericUtils.sortableLongToDouble(TestUtil.nextLong(random, minBits, maxBits));
           // round down
-          assertEquals(encoded,   Geo3DUtil.encodeValue(value));
+          assertEquals(encoded,   planetModel.encodeValue(value));
         }
       }
     }
   }
 
   public void testEncodeDecodeIsStable() throws Exception {
-
+    PlanetModel planetModel = randomPlanetModel();
     int iters = atLeast(1000);
     for(int iter=0;iter<iters;iter++) {
       double lat = GeoTestUtil.nextLatitude();
       double lon = GeoTestUtil.nextLongitude();
 
-      GeoPoint point = new GeoPoint(PlanetModel.WGS84, toRadians(lat), toRadians(lon));
+      GeoPoint point = new GeoPoint(planetModel, toRadians(lat), toRadians(lon));
 
       // encode point
-      GeoPoint pointEnc = new GeoPoint(Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(point.x)),
-                                       Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(point.y)),
-                                       Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(point.z)));
+      GeoPoint pointEnc = new GeoPoint(planetModel.decodeValue(planetModel.encodeValue(point.x)),
+                                       planetModel.decodeValue(planetModel.encodeValue(point.y)),
+                                       planetModel.decodeValue(planetModel.encodeValue(point.z)));
 
       // encode it again (double encode)
-      GeoPoint pointEnc2 = new GeoPoint(Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(pointEnc.x)),
-                                        Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(pointEnc.y)),
-                                        Geo3DUtil.decodeValue(Geo3DUtil.encodeValue(pointEnc.z)));
+      GeoPoint pointEnc2 = new GeoPoint(planetModel.decodeValue(planetModel.encodeValue(pointEnc.x)),
+                                        planetModel.decodeValue(planetModel.encodeValue(pointEnc.y)),
+                                        planetModel.decodeValue(planetModel.encodeValue(pointEnc.z)));
       //System.out.println("TEST " + iter + ":\n  point    =" + point + "\n  pointEnc =" + pointEnc + "\n  pointEnc2=" + pointEnc2);
     
       assertEquals(pointEnc.x, pointEnc2.x, 0.0);
@@ -1312,14 +1330,14 @@ public class TestGeo3DPoint extends LuceneTestCase {
   }
 
   /** Clips the incoming value to the allowed min/max range before encoding, instead of throwing an exception. */
-  private static int encodeValueLenient(double x) {
-    double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
+  private static int encodeValueLenient(double x, PlanetModel planetModel) {
+    double planetMax = planetModel.getMaximumMagnitude();
     if (x > planetMax) {
       x = planetMax;
     } else if (x < -planetMax) {
       x = -planetMax;
     }
-    return Geo3DUtil.encodeValue(x);
+    return planetModel.encodeValue(x);
   }
 
   private static class ExplainingVisitor implements IntersectVisitor {
@@ -1382,9 +1400,9 @@ public class TestGeo3DPoint extends LuceneTestCase {
         }
       } else {
         if (docID == targetDocID) {
-          double x = Geo3DPoint.decodeDimension(packedValue, 0);
-          double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
-          double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
+          double x = Geo3DPoint.decodeDimension(packedValue, 0, shape.getPlanetModel());
+          double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES, shape.getPlanetModel());
+          double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES, shape.getPlanetModel());
           b.append("leaf visit docID=" + docID + " x=" + x + " y=" + y + " z=" + z + "\n");
           in.visit(docID, packedValue);
         }
@@ -1449,13 +1467,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
 
       @Override
       public String toString() {
-        double xMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 0));
-        double xMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 0));
-        double yMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES));
-        double yMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES));
-        double zMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES));
-        double zMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES));
-        final XYZSolid xyzSolid = XYZSolidFactory.makeXYZSolid(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
+        double xMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 0), shape.getPlanetModel());
+        double xMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 0), shape.getPlanetModel());
+        double yMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 1 * Integer.BYTES), shape.getPlanetModel());
+        double yMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 1 * Integer.BYTES), shape.getPlanetModel());
+        double zMin = Geo3DUtil.decodeValueFloor(NumericUtils.sortableBytesToInt(minPackedValue, 2 * Integer.BYTES), shape.getPlanetModel());
+        double zMax = Geo3DUtil.decodeValueCeil(NumericUtils.sortableBytesToInt(maxPackedValue, 2 * Integer.BYTES), shape.getPlanetModel());
+        final XYZSolid xyzSolid = XYZSolidFactory.makeXYZSolid(shape.getPlanetModel(), xMin, xMax, yMin, yMax, zMin, zMax);
         final int relationship = xyzSolid.getRelationship(shape);
         final boolean pointWithinCell = xyzSolid.isWithin(targetDocPoint);
         final boolean scaledWithinCell = xyzSolid.isWithin(scaledDocPoint);
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/Geo3DUtil.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/Geo3DUtil.java
index 52115cf..a4b25d0 100644
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/Geo3DUtil.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/Geo3DUtil.java
@@ -16,89 +16,13 @@
  */
 package org.apache.lucene.spatial3d.geom;
 
-import org.apache.lucene.geo.Polygon;
-import org.apache.lucene.geo.GeoUtils;
-
-import java.util.List;
-import java.util.ArrayList;
-
 class Geo3DUtil {
 
-  /** How many radians are in one earth surface meter */
-  final static double RADIANS_PER_METER = 1.0 / PlanetModel.WGS84_MEAN;
   /** How many radians are in one degree */
   final static double RADIANS_PER_DEGREE = Math.PI / 180.0;
   /** How many degrees in a radian */
   final static double DEGREES_PER_RADIAN = 180.0 / Math.PI;
   
-  private static final double MAX_VALUE = PlanetModel.WGS84.getMaximumMagnitude();
-  private static final int BITS = 32;
-  private static final double MUL = (0x1L<<BITS)/(2*MAX_VALUE);
-  static final double DECODE = getNextSafeDouble(1/MUL);
-  static final int MIN_ENCODED_VALUE = encodeValue(-MAX_VALUE);
-  static final int MAX_ENCODED_VALUE = encodeValue(MAX_VALUE);
-
-  public static int encodeValue(double x) {
-    if (x > MAX_VALUE) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (greater than WGS84's planetMax=" + MAX_VALUE + ")");
-    }
-    if (x < -MAX_VALUE) {
-      throw new IllegalArgumentException("value=" + x + " is out-of-bounds (less than than WGS84's -planetMax=" + -MAX_VALUE + ")");
-    }
-    long result = (long) Math.floor(x / DECODE);
-    assert result >= Integer.MIN_VALUE;
-    assert result <= Integer.MAX_VALUE;
-    return (int) result;
-  }
-
-  public static double decodeValue(int x) {
-    double result;
-    if (x == MIN_ENCODED_VALUE) {
-      // We must special case this, because -MAX_VALUE is not guaranteed to land precisely at a floor value, and we don't ever want to
-      // return a value outside of the planet's range (I think?).  The max value is "safe" because we floor during encode:
-      result = -MAX_VALUE;
-    } else if (x == MAX_ENCODED_VALUE) {
-      result = MAX_VALUE;
-    } else {
-      // We decode to the center value; this keeps the encoding stable
-      result = (x+0.5) * DECODE;
-    }
-    assert result >= -MAX_VALUE && result <= MAX_VALUE;
-    return result;
-  }
-
-  /** Returns smallest double that would encode to int x. */
-  // NOTE: keep this package private!!
-  static double decodeValueFloor(int x) {
-    return x * DECODE;
-  }
-  
-  /** Returns a double value >= x such that if you multiply that value by an int, and then
-   *  divide it by that int again, you get precisely the same value back */
-  private static double getNextSafeDouble(double x) {
-
-    // Move to double space:
-    long bits = Double.doubleToLongBits(x);
-
-    // Make sure we are beyond the actual maximum value:
-    bits += Integer.MAX_VALUE;
-
-    // Clear the bottom 32 bits:
-    bits &= ~((long) Integer.MAX_VALUE);
-
-    // Convert back to double:
-    double result = Double.longBitsToDouble(bits);
-    assert result > x;
-    return result;
-  }
-
-  /** Returns largest double that would encode to int x. */
-  // NOTE: keep this package private!!
-  static double decodeValueCeil(int x) {
-    assert x < Integer.MAX_VALUE;
-    return Math.nextDown((x+1) * DECODE);
-  }
-  
   /** Converts degress to radians */
   static double fromDegrees(final double degrees) {
     return degrees * RADIANS_PER_DEGREE;
@@ -108,173 +32,4 @@ class Geo3DUtil {
   static double toDegrees(final double radians) {
     return radians * DEGREES_PER_RADIAN;
   }
-  
-  /** Converts earth-surface meters to radians */
-  static double fromMeters(final double meters) {
-    return meters * RADIANS_PER_METER;
-  }
-
-  /**
-    * Convert a set of Polygon objects into a GeoPolygon.
-    * @param polygons are the Polygon objects.
-    * @return the GeoPolygon.
-    */
-  static GeoPolygon fromPolygon(final Polygon... polygons) {
-    //System.err.println("Creating polygon...");
-    if (polygons.length < 1) {
-      throw new IllegalArgumentException("need at least one polygon");
-    }
-    final GeoPolygon shape;
-    if (polygons.length == 1) {
-      final GeoPolygon component = fromPolygon(polygons[0]);
-      if (component == null) {
-        // Polygon is degenerate
-        shape = new GeoCompositePolygon(PlanetModel.WGS84);
-      } else {
-        shape = component;
-      }
-    } else {
-      final GeoCompositePolygon poly = new GeoCompositePolygon(PlanetModel.WGS84);
-      for (final Polygon p : polygons) {
-        final GeoPolygon component = fromPolygon(p);
-        if (component != null) {
-          poly.addShape(component);
-        }
-      }
-      shape = poly;
-    }
-    return shape;
-    //System.err.println("...done");
-  }
-  
-  
-  /**
-   * Convert a Polygon object to a large GeoPolygon.
-   * @param polygons is the list of polygons to convert.
-   * @return the large GeoPolygon.
-   */
-  static GeoPolygon fromLargePolygon(final Polygon... polygons) {
-    if (polygons.length < 1) {
-      throw new IllegalArgumentException("need at least one polygon");
-    }
-    return GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.WGS84, convertToDescription(polygons));
-  }
-  
-  /**
-   * Convert input parameters to a path.
-   * @param pathLatitudes latitude values for points of the path: must be within standard +/-90 coordinate bounds.
-   * @param pathLongitudes longitude values for points of the path: must be within standard +/-180 coordinate bounds.
-   * @param pathWidthMeters width of the path in meters.
-   * @return the path.
-   */
-  static GeoPath fromPath(final double[] pathLatitudes, final double[] pathLongitudes, final double pathWidthMeters) {
-    if (pathLatitudes.length != pathLongitudes.length) {
-      throw new IllegalArgumentException("same number of latitudes and longitudes required");
-    }
-    final GeoPoint[] points = new GeoPoint[pathLatitudes.length];
-    for (int i = 0; i < pathLatitudes.length; i++) {
-      final double latitude = pathLatitudes[i];
-      final double longitude = pathLongitudes[i];
-      GeoUtils.checkLatitude(latitude);
-      GeoUtils.checkLongitude(longitude);
-      points[i] = new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude));
-    }
-    return GeoPathFactory.makeGeoPath(PlanetModel.WGS84, fromMeters(pathWidthMeters), points);
-  }
-  
-  /**
-   * Convert input parameters to a circle.
-   * @param latitude latitude at the center: must be within standard +/-90 coordinate bounds.
-   * @param longitude longitude at the center: must be within standard +/-180 coordinate bounds.
-   * @param radiusMeters maximum distance from the center in meters: must be non-negative and finite.
-   * @return the circle.
-   */
-  static GeoCircle fromDistance(final double latitude, final double longitude, final double radiusMeters) {
-    GeoUtils.checkLatitude(latitude);
-    GeoUtils.checkLongitude(longitude);
-    return GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude), fromMeters(radiusMeters));
-  }
-  
-  /**
-   * Convert input parameters to a box.
-   * @param minLatitude latitude lower bound: must be within standard +/-90 coordinate bounds.
-   * @param maxLatitude latitude upper bound: must be within standard +/-90 coordinate bounds.
-   * @param minLongitude longitude lower bound: must be within standard +/-180 coordinate bounds.
-   * @param maxLongitude longitude upper bound: must be within standard +/-180 coordinate bounds.
-   * @return the box.
-   */
-  static GeoBBox fromBox(final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
-    GeoUtils.checkLatitude(minLatitude);
-    GeoUtils.checkLongitude(minLongitude);
-    GeoUtils.checkLatitude(maxLatitude);
-    GeoUtils.checkLongitude(maxLongitude);
-    return GeoBBoxFactory.makeGeoBBox(PlanetModel.WGS84, 
-      Geo3DUtil.fromDegrees(maxLatitude), Geo3DUtil.fromDegrees(minLatitude), Geo3DUtil.fromDegrees(minLongitude), Geo3DUtil.fromDegrees(maxLongitude));
-  }
-
-  /**
-    * Convert a Polygon object into a GeoPolygon.
-    * This method uses
-    * @param polygon is the Polygon object.
-    * @return the GeoPolygon.
-    */
-  private static GeoPolygon fromPolygon(final Polygon polygon) {
-    // First, assemble the "holes".  The geo3d convention is to use the same polygon sense on the inner ring as the
-    // outer ring, so we process these recursively with reverseMe flipped.
-    final Polygon[] theHoles = polygon.getHoles();
-    final List<GeoPolygon> holeList = new ArrayList<>(theHoles.length);
-    for (final Polygon hole : theHoles) {
-      //System.out.println("Hole: "+hole);
-      final GeoPolygon component = fromPolygon(hole);
-      if (component != null) {
-        holeList.add(component);
-      }
-    }
-    
-    // Now do the polygon itself
-    final double[] polyLats = polygon.getPolyLats();
-    final double[] polyLons = polygon.getPolyLons();
-    
-    // I presume the arguments have already been checked
-    final List<GeoPoint> points = new ArrayList<>(polyLats.length-1);
-    // We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
-    for (int i = 0; i < polyLats.length - 1; i++) {
-      final int index = polyLats.length - 2 - i;
-      points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
-    }
-    //System.err.println(" building polygon with "+points.size()+" points...");
-    final GeoPolygon rval = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, holeList);
-    //System.err.println(" ...done");
-    return rval;
-  }
-
-  /**
-   * Convert a list of polygons to a list of polygon descriptions.
-   * @param polygons is the list of polygons to convert.
-   * @return the list of polygon descriptions.
-   */
-  private static List<GeoPolygonFactory.PolygonDescription> convertToDescription(final Polygon... polygons) {
-    final List<GeoPolygonFactory.PolygonDescription> descriptions = new ArrayList<>(polygons.length);
-    for (final Polygon polygon : polygons) {
-      final Polygon[] theHoles = polygon.getHoles();
-      final List<GeoPolygonFactory.PolygonDescription> holes = convertToDescription(theHoles);
-      
-      // Now do the polygon itself
-      final double[] polyLats = polygon.getPolyLats();
-      final double[] polyLons = polygon.getPolyLons();
-      
-      // I presume the arguments have already been checked
-      final List<GeoPoint> points = new ArrayList<>(polyLats.length-1);
-      // We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
-      for (int i = 0; i < polyLats.length - 1; i++) {
-        final int index = polyLats.length - 2 - i;
-        points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
-      }
-      
-      descriptions.add(new GeoPolygonFactory.PolygonDescription(points, holes));
-    }
-    return descriptions;
-  }
-  
-
 }
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
index 2e49022..5bc3a78 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoCircleTest.java
@@ -172,7 +172,7 @@ public class GeoCircleTest extends LuceneTestCase {
     // Sixth BKD discovered failure
     c = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84,-0.006450320645814321,0.004660694205115142,0.00489710732634323);
     //xyzb = new XYZBounds();
-    //c.getBounds(xyzb);
+    //zScaling.getBounds(xyzb);
     //System.err.println("xmin="+xyzb.getMinimumX()+", xmax="+xyzb.getMaximumX()+",ymin="+xyzb.getMinimumY()+", ymax="+xyzb.getMaximumY()+",zmin="+xyzb.getMinimumZ()+", zmax="+xyzb.getMaximumZ());
     //xmin=1.0010356621420726, xmax=1.0011141249179447,ymin=-2.5326643901354566E-4, ymax=0.009584741915757169,zmin=-0.011359874956269283, zmax=-0.0015549504447452225
     area = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84,1.0010822580620098,1.0010945779732867,0.007079167343247293,0.007541006774427837,-0.0021855011220022575,-0.001896122718181518);
@@ -183,9 +183,9 @@ public class GeoCircleTest extends LuceneTestCase {
     //p2 = new GeoPoint(PlanetModel.WGS84,-0.002164069780096702, 0.007505617500830066);
     p2 = new GeoPoint(PlanetModel.WGS84,p1.getLatitude(),p1.getLongitude());
     assertTrue(PlanetModel.WGS84.pointOnSurface(p2));
-    assertTrue(!c.isWithin(p2));
+    assertTrue(!zScaling.isWithin(p2));
     assertTrue(!area.isWithin(p2));
-    assertTrue(!c.isWithin(p1));
+    assertTrue(!zScaling.isWithin(p1));
     assertTrue(PlanetModel.WGS84.pointOnSurface(p1)); // This fails
     assertTrue(!area.isWithin(p1)); // This fails
     */
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoExactCircleTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoExactCircleTest.java
index 74a229e..9b718cc 100644
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoExactCircleTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoExactCircleTest.java
@@ -55,7 +55,7 @@ public class GeoExactCircleTest extends RandomGeo3dShapeGenerator{
   @Test
   public void testSurfacePointOnBearingScale(){
     PlanetModel p1 = PlanetModel.WGS84;
-    PlanetModel p2 = new PlanetModel(0.5 * PlanetModel.WGS84.ab, 0.5 * PlanetModel.WGS84.c );
+    PlanetModel p2 = new PlanetModel(0.5 * PlanetModel.WGS84.xyScaling, 0.5 * PlanetModel.WGS84.zScaling);
     GeoPoint point1P1 = new GeoPoint(p1, 0, 0);
     GeoPoint point2P1 =  new GeoPoint(p1, 1, 1);
     GeoPoint point1P2 = new GeoPoint(p2, point1P1.getLatitude(), point1P1.getLongitude());
@@ -92,7 +92,7 @@ public class GeoExactCircleTest extends RandomGeo3dShapeGenerator{
   @Repeat(iterations = 100)
   public void RandomPointBearingCardinalTest(){
     //surface distance calculations methods start not converging when
-    //planet flattening > 0.4
+    //planet scaledFlattening > 0.4
     PlanetModel planetModel;
     do {
       double ab = random().nextDouble() * 2;
@@ -102,7 +102,7 @@ public class GeoExactCircleTest extends RandomGeo3dShapeGenerator{
       } else {
         planetModel = new PlanetModel(c, ab);
       }
-    } while (Math.abs(planetModel.flattening) > 0.4);
+    } while (Math.abs(planetModel.scaledFlattening) > 0.4);
     GeoPoint center = randomGeoPoint(planetModel);
     double radius =  random().nextDouble() * 0.9 * planetModel.minimumPoleDistance;
     checkBearingPoint(planetModel, center, radius, 0);
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
index 05f5f3e..9913f83 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPathTest.java
@@ -206,7 +206,7 @@ public class GeoPathTest extends LuceneTestCase {
     assertTrue(relationship == GeoArea.WITHIN || relationship == GeoArea.OVERLAPS);
     assertTrue(area.isWithin(point));
     // No longer true due to fixed GeoStandardPath waypoints.
-    //assertTrue(c.isWithin(point));
+    //assertTrue(zScaling.isWithin(point));
     
     c = new GeoStandardPath(PlanetModel.WGS84, 0.6894050545377601);
     c.addPoint(-0.0788176065762948, 0.9431251741731624);
diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
index f2388a9..991c407 100755
--- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
+++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java
@@ -122,7 +122,7 @@ public class GeoPolygonTest extends LuceneTestCase {
 
     GeoPolygonFactory.PolygonDescription pd = new GeoPolygonFactory.PolygonDescription(points);
     c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, pd);
-    //System.out.println(c);
+    //System.out.println(zScaling);
     
     // Middle point should NOT be within!!
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
@@ -143,7 +143,7 @@ public class GeoPolygonTest extends LuceneTestCase {
 
     pd = new GeoPolygonFactory.PolygonDescription(points);
     c = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, pd);
-    //System.out.println(c);
+    //System.out.println(zScaling);
     
     // Middle point should be within!!
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.5);
@@ -251,7 +251,7 @@ public class GeoPolygonTest extends LuceneTestCase {
     shapes.add(pd);
     
     c = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.SPHERE, shapes);
-    //System.out.println("Large polygon = "+c);
+    //System.out.println("Large polygon = "+zScaling);
     
     // Sample some points within
     gp = new GeoPoint(PlanetModel.SPHERE, 0.0, -0.45);
@@ -452,10 +452,10 @@ public class GeoPolygonTest extends LuceneTestCase {
   
   @Test
   public void testGeoPolygonBoundsCase2() {
-    // [junit4]   1> TEST: iter=23 shape=GeoCompositeMembershipShape: {[GeoConvexPolygon: {planetmodel=PlanetModel(ab=0.7563871189161702 c=1.2436128810838298), points=
+    // [junit4]   1> TEST: iter=23 shape=GeoCompositeMembershipShape: {[GeoConvexPolygon: {planetmodel=PlanetModel(xyScaling=0.7563871189161702 zScaling=1.2436128810838298), points=
     // [[lat=0.014071770744627236, lon=0.011030818292803128],
     //  [lat=0.006772117088906782, lon=-0.0012531892445234592],
-    //  [lat=0.0022201615609504792, lon=0.005941293187389326]]}, GeoConcavePolygon: {planetmodel=PlanetModel(ab=0.7563871189161702 c=1.2436128810838298), points=
+    //  [lat=0.0022201615609504792, lon=0.005941293187389326]]}, GeoConcavePolygon: {planetmodel=PlanetModel(xyScaling=0.7563871189161702 zScaling=1.2436128810838298), points=
     // [[lat=-0.005507100238396111, lon=-0.008487706131259667],
     //  [lat=0.014071770744627236, lon=0.011030818292803128],
     //  [lat=0.0022201615609504792, lon=0.005941293187389326]]}]}
@@ -476,7 +476,7 @@ public class GeoPolygonTest extends LuceneTestCase {
     BitSet p2bits = new BitSet();
     p2bits.set(1, true);
     c.addShape(new GeoConcavePolygon(pm, points2, p2bits, false));
-    //System.out.println(c);
+    //System.out.println(zScaling);
     
     // [junit4]   1>   point=[lat=0.003540694517552105, lon=-9.99517927901697E-4]
     // [junit4]   1>   quantized=[X=0.7563849869428783, Y=-7.560204674780763E-4, Z=0.0026781405884151086]
@@ -511,10 +511,10 @@ doc=906 added here:
 
 shape:
    [junit4]   1> TEST: iter=18 shape=GeoCompositeMembershipShape: {[GeoConvexPolygon: {
-   planetmodel=PlanetModel(ab=0.8568069516722363 c=1.1431930483277637), points=
+   planetmodel=PlanetModel(xyScaling=0.8568069516722363 zScaling=1.1431930483277637), points=
    [[lat=1.1577814487635816, lon=1.6283601832010004],
    [lat=0.6664570999069251, lon=2.0855825542851574],
-   [lat=-0.23953537010974632, lon=1.8498724094352876]]}, GeoConcavePolygon: {planetmodel=PlanetModel(ab=0.8568069516722363 c=1.1431930483277637), points=
+   [lat=-0.23953537010974632, lon=1.8498724094352876]]}, GeoConcavePolygon: {planetmodel=PlanetModel(xyScaling=0.8568069516722363 zScaling=1.1431930483277637), points=
    [[lat=1.1577814487635816, lon=1.6283601832010004],
    [lat=-0.23953537010974632, lon=1.8498724094352876],
    [lat=-1.1766904875978805, lon=-2.1346828411344436]]}]}
@@ -535,14 +535,14 @@ shape:
     BitSet p2bits = new BitSet();
     p2bits.set(1, true);
     c.addShape(new GeoConcavePolygon(pm, points2, p2bits, false));
-    //System.out.println(c);
+    //System.out.println(zScaling);
     
     GeoPoint point = new GeoPoint(pm, -0.9825762558001477, 2.4832136904725273);
     GeoPoint quantizedPoint = new GeoPoint(-0.4505446160475436, 0.34850109186970535, -0.8539966368663765);
     
     GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(pm,
       -0.6107484000858642, -0.39518364125756916, -0.8568069517709872, 0.8568069517709872, -1.1431930485939341, 1.1431930485939341);
-    //System.out.println("relationship = "+xyzSolid.getRelationship(c));
+    //System.out.println("relationship = "+xyzSolid.getRelationship(zScaling));
     assertTrue(xyzSolid.getRelationship(c) == GeoArea.OVERLAPS);
   }
   
@@ -1272,7 +1272,7 @@ shape:
     final GeoPoint negativeX = new GeoPoint(PlanetModel.WGS84, 0.0, Math.PI);
     final GeoPoint negativeY = new GeoPoint(PlanetModel.WGS84, 0.0, -Math.PI * 0.5);
     final GeoPoint positiveY = new GeoPoint(PlanetModel.WGS84, 0.0, Math.PI * 0.5);
-    final GeoPoint testPoint = new GeoPoint(-0.07416172733314662, 0.5686488061136892, 0.8178445379402641);
+    final GeoPoint testPoint = new GeoPoint(-0.074161727332972, 0.5686488061123504, 0.8178445379383386);
 
     // Construct a standard polygon first to see what that does.  This winds up being a large polygon under the covers.
     GeoPolygon standard = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, pd);