Here's a patch. Notes:
- I chose the name RptWithGeometrySpatialField; feedback welcome. It inherits the same schema attribute options as the RPT field but strictly speaking doesn't subclass that field type.
- I overrode the default distErrPct at indexing time to be 0.15.
- Compatibility with heatmaps.
- Uses a SolrCache if you define one in solrconfig.xml.
- Includes some getters on Lucene spatial's CompositeSpatialStrategy.
I was tempted, and attempted to subclass the Rpt field type which would have made the initialization less error prone & simple, and would have made heatmap compatibility work without issue. But it started becoming an ugly hack. The approach in this patch is perhaps a hack in that it contains another fieldType and deals with some initialization quirks in init(); but there isn't much to it. Another option is to do like BBoxField's component numeric fields... though I don't love that it requires more definitions for the user to make in the schema. But maybe that's a better trade-off, all things considered (it wouldn't have required the modification to heatmap here).
The cache is very interesting. Typically, a SolrCache gets blown away on every commit. But using a NoOpRegenerator, it will effectively get re-instated. But that can only be used for caching certain types of things and may require the code using the cache to facilitate this working – so don't expect it to work on the FilterCache, for example. The trick I do here is a special key to the cache that is comprised of a weak reference to a LeafReader segment core key, plus the segment-local docId. Unfortunately these cache entries won't eagerly clean themselves up if the segment becomes unreachable; however, it shouldn't stick around long if an LRU cache is used, since those entries won't be used again. The cache should be configured similar to the following, assuming a hypothetical field named "geom":
The 2nd and subsequent successful cache lookups will be the fastest for polygons in particular, since on the 1st cache hit, JtsGeometry.index() is called on it (if it is of that type).