Z3Ordering编码及查询c++实现 (GeoMesa翻译)

news2024/11/16 8:32:01

网上搜了很多Z3-Ordering实现没搜到,通过 sfcurve-master和geomesa-geomesa-3.2.2 得scala代码改编而来, 环境为C++, vs2015, 理论上windows和Linux都可以用. 不依赖任何库, 这项自身理解和翻译断断续续进行, 最近终于有一点进展,     本次放出Z3,  待全部实现完毕将直接挂出

详细实现代码如下:

#include "stdafx.h"
#include <vector>
#include <list>
#include <queue>
#include <map>
#include <algorithm>
#include <iostream>
#include <deque>
#include <math.h>
#include <time.h>
#include <functional>  
#include <memory>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <memory>
#include <functional>
#include <math.h>
#include <array>
#include <tuple>
using namespace std;
typedef unsigned long long ull;
#pragma region baseinterface
struct IndexRange {
	ull lower;
	ull upper;
	bool contained;
	IndexRange()
	{

	}
	IndexRange(ull a, ull b, bool c = true)
		:lower(a), upper(b), contained(c)
	{

	}
	IndexRange(const IndexRange& o)
	{
		lower = o.lower;
		upper = o.upper;
		contained = o.contained;
	}

	int operator ()(const IndexRange& o)const
	{
		if (lower != o.lower) return lower > o.lower ? 1 : -1;
		if (upper != o.upper) return upper > o.upper ? 1 : -1;

		return 0;
	}
};
/// 用于 std::sort 对结构体按指定成员比较
struct {
	bool operator()(const IndexRange &a, const IndexRange &b) const
	{
		if (a.lower != b.lower) return a.lower > b.lower ? 1 : -1;
		if (a.upper != b.upper) return a.upper > b.upper ? 1 : -1;

		return false;
	}
}CompA;
//也不清楚scala的seq能对应std哪个容器,先用定义后面直接改这个定义即可
using SeqIndexRange = std::list<IndexRange>;
using dblbox = std::array<double, 4>;
using SeqBoxs = std::vector<std::array<double, 4>>;
using SeqTimes = std::vector<std::array<ull, 2>>;
struct XZSFC {
	short DefaultPrecision = 12;
	double LogPointFive = log(0.5);
};
struct ZRange {
	ull min = 0, max = 0, mid = 0, length = 0;

	ZRange(ull umin, ull umax)
	{
		min = umin;
		max = umax;
		mid = (max + min) >> 1;
		length = max - min + 1;
	}


	ZRange(const ZRange& o)
	{
		min = o.min;
		max = o.max;
		mid = o.mid;
		length = o.length;
	}
	bool contains(ull bits)
	{
		return   bits >= min && bits <= max;
	}
	bool contains(const ZRange& r)
	{
		return contains(r.min) && contains(r.max);
	}
	bool overlaps(const ZRange& r) {
		return  contains(r.min) || contains(r.max);
	}
};
using ArrayZRange = std::vector<ZRange>;
class SpaceTimeFillingCurve {
	int FullPrecision = 64;
	int maxRanges = -1;
public:
	virtual ull index(double x, double y, ull t, bool   lenient = false) = 0;
	virtual void invert(ull  z, double& x, double & y, ull&t) = 0;
	virtual  SeqIndexRange ranges(SeqBoxs seqboxs, SeqTimes seqtimes, int precision, int maxRanges) = 0;

	virtual SeqIndexRange ranges(double x1, double x2, double y1, double y2, ull t1, ull t2)
	{
		SeqBoxs d;
		d.resize(1);
		d[0][0] = x1; d[0][1] = y1; d[0][2] = x2; d[0][3] = y1;
		SeqTimes tseq;
		tseq.resize(1);
		tseq[0][0] = (t1);		tseq[0][1] = (t2);
		ranges(d, tseq, FullPrecision, maxRanges);
	}
	virtual SeqIndexRange ranges(double x1, double x2, double y1, double y2, ull t1, ull t2, int precision)
	{
		SeqBoxs d;
		d.resize(1);
		d[0][0] = x1; d[0][1] = y1; d[0][2] = x2; d[0][3] = y1;
		SeqTimes tseq;
		tseq.resize(1);
		tseq[0][0] = (t1);		tseq[0][1] = (t2);
		ranges(d, tseq, precision, maxRanges);
	}
	virtual SeqIndexRange ranges(double x1, double x2, double y1, double y2, ull t1, ull t2, int precision, int maxRanges)
	{
		SeqBoxs d;
		d.resize(1);
		d[0][0] = x1; d[0][1] = y1; d[0][2] = x2; d[0][3] = y1;
		SeqTimes tseq;
		tseq.resize(1);
		tseq[0][0] = (t1);		tseq[0][1] = (t2);
		ranges(d, tseq, precision, maxRanges);
	}

};
class SpaceFillingCurve {
	int FullPrecision = 64;
	int maxRanges = -1;

	virtual ull index(double x, double y, bool   lenient = false) = 0;
	virtual void invert(ull  z, double& x, double & y) = 0;
	virtual  SeqIndexRange ranges(SeqBoxs seqboxs, int precision, int maxRanges) = 0;

	virtual SeqIndexRange ranges(double x1, double x2, double y1, double y2)
	{
		SeqBoxs d;
		d.resize(1);
		d[0][0] = x1; d[0][1] = y1; d[0][2] = x2; d[0][3] = y1;
		ranges(d, FullPrecision, maxRanges);
	}
	virtual SeqIndexRange ranges(double x1, double x2, double y1, double y2, int precision)
	{
		SeqBoxs d;
		d.resize(1);
		d[0][0] = x1; d[0][1] = y1; d[0][2] = x2; d[0][3] = y1;
		ranges(d, precision, maxRanges);
	}
	virtual SeqIndexRange ranges(double x1, double x2, double y1, double y2, int precision, int maxRanges)
	{
		SeqBoxs d;
		d.resize(1);
		d[0][0] = x1; d[0][1] = y1; d[0][2] = x2; d[0][3] = y1;
		ranges(d, precision, maxRanges);
	}

};


struct QueryWindow
{
	double xmin; double xmax; double ymin; double ymax;
	QueryWindow()
	{

	}
	QueryWindow(double dxmin, double dymin, double dxmax, double dymax) :
		xmin(dxmin), xmax(dxmax), ymin(dymin), ymax(dymax)
	{

	}

	QueryWindow(const QueryWindow& o)
	{
		xmin = o.xmin;
		ymin = o.ymin;
		xmax = o.xmax;
		ymax = o.ymax;
	}
};
struct XElement
{
	double xmin; double xmax; double ymin; double ymax; double length;

	double xext = 0;
	double yext = 0;
	XElement() {}
	XElement(double dxmin, double dymin, double dxmax, double dymax, double dlength)
		:xmin(dxmin), xmax(dxmax), ymin(dymin), ymax(dymax), length(dlength)
	{
		xext = xmax + length;
		yext = ymax + length;
	}
	XElement(const XElement& o)
	{
		xmin = o.xmin;
		xmax = o.xmax;
		ymin = o.ymin;
		ymax = o.ymax;
		length = o.length;
		xext = o.xext;
		yext = o.yext;
	}
	XElement clone()
	{
		return XElement(xmin, ymin, xmax, ymax, length);
	}
	bool isContained(QueryWindow window)
	{
		return window.xmin <= xmin && window.ymin <= ymin && window.xmax >= xext && window.ymax >= yext;
	}
	bool overlaps(QueryWindow window)
	{
		return 	window.xmax >= xmin && window.ymax >= ymin && window.xmin <= xext && window.ymin <= yext;
	}
	std::vector<XElement*> children() {
		double xCenter = (xmin + xmax) / 2.0;
		double yCenter = (ymin + ymax) / 2.0;
		double len = length / 2.0;
		std::vector<XElement*> ret;
		XElement* c0 = new XElement(xmin, ymin, xmax, ymax, length);
		c0->xmax = xCenter;
		c0->ymax = yCenter;
		c0->length = len;
		XElement* c1 = new XElement(xmin, ymin, xmax, ymax, length);
		c1->xmin = xCenter; c1->ymax = yCenter; c1->length = len;
		XElement* c2 = new XElement(xmin, ymin, xmax, ymax, length);
		c2->xmax = xCenter; c2->ymin = yCenter; c2->length = len;
		XElement* c3 = new XElement(xmin, ymin, xmax, ymax, length);
		c3->xmin = xCenter; c3->ymin = yCenter; c3->length = len;
		ret.push_back(c0);
		ret.push_back(c1);
		ret.push_back(c2);
		ret.push_back(c3);
		return ret;
	}
};
struct BitNormalizedDimension {
	double min, max;
	int maxIndex;
	double normalizer;
	double denormalizer;
	BitNormalizedDimension()
	{

	}
	BitNormalizedDimension(const BitNormalizedDimension & o)
	{
		min = o.min;
		max = o.max;
		maxIndex = o.maxIndex;
		normalizer = o.denormalizer;
		denormalizer = o.denormalizer;
	}
	BitNormalizedDimension(double dmin, double dmax, int precision)
	{
		if (!(precision > 0 && precision < 32))
			return;
		min = dmin;
		max = dmax;
		ull bins = pow(2, precision);// .toLong1 << precision;
		normalizer = bins / (max - min);
		denormalizer = (max - min) / bins;
		maxIndex = (bins - 1);
	}


	//case class NormalizedLat(precision : Int) extends BitNormalizedDimension(-90d, 90d, precision)
	//case class NormalizedLon(precision : Int) extends BitNormalizedDimension(-180d, 180d, precision)
	//case class NormalizedTime(precision : Int, override val max : Double) extends BitNormalizedDimension(0d, max, precision)


	int normalize(double x) {
		if (x >= max)
			return maxIndex;
		else
			return  floor((x - min) * normalizer);
	}
	double denormalize(int x) {
		if (x >= maxIndex)
		{
			return min + (maxIndex + 0.5) * denormalizer;
		}
		else
		{
			return min + (x + 0.5) * denormalizer;
		}
	}
};
#pragma endregion

#pragma region ZNOrdering
struct ZPrefix
{
	ull prefix;
	int precision;
	ZPrefix()
	{
	}
	ZPrefix(ull llprefix, int iprecision)
	{
		prefix = llprefix;
		precision = iprecision;
	}
	ZPrefix(ZPrefix&o)
	{
		prefix = o.prefix;
		precision = o.precision;
	}
};
/**
  * N-dimensional z-curve base class
  */
struct ZN {

	// number of bits used to store each dimension
	int BitsPerDimension;

	// number of dimensions
	int Dimensions;

	// max value for this z object - can be used to mask another long using &
	ull MaxMask;

	// total bits used - usually bitsPerDim * dims
	int TotalBits;

	// number of quadrants in our quad/oct tree - has to be lazy to instantiate correctly
	double Quadrants;
	int DefaultRecurse = 7;
	ZN(int Dimensions)
	{
		Quadrants = pow(2, Dimensions);
	}
	/**
	  * Insert (Dimensions - 1) zeros between each bit to create a zvalue from a single dimension.
	  * Only the first BitsPerDimension can be considered.
	  *
	  * @param value value to split
	  * @return
	  */
	virtual ull split(ull value) = 0;

	/**
	  * Combine every (Dimensions - 1) bits to re-create a single dimension. Opposite of split.
	  *
	  * @param z value to combine
	  * @return
	  */
	virtual int combine(ull z) = 0;

	/**
	  * Is the value contained in the range. Considers user-space.
	  *
	  * @param range range
	  * @param value value to be tested
	  * @return
	  */
	virtual bool contains(ZRange &range, ull value) = 0;

	/**
	  * Is the value contained in the range. Considers user-space.
	  *
	  * @param range range
	  * @param value value to be tested
	  * @return
	  */
	bool contains(ZRange& range, ZRange value)
	{
		return contains(range, value.min) && contains(range, value.max);
	}

	/**
	  * Does the value overlap with the range. Considers user-space.
	  *
	  * @param range range
	  * @param value value to be tested
	  * @return
	  */
	virtual bool overlaps(ZRange& range, ZRange& value) = 0;

	/**
	  * Returns (litmax, bigmin) for the given range and point
	  *
	  * @param p point
	  * @param rmin minimum value
	  * @param rmax maximum value
	  * @return (litmax, bigmin)
	  */
	void zdivide(ull p, ull  rmin, ull rmax, ull& minz, ull&maxz)
	{
		//: (Long, Long) = ZN.zdiv(load, Dimensions)(p, rmin, rmax)
	}
	// virtual  SeqIndexRange ranges(SeqBoxs seqboxs, int precision, int maxRanges) = 0;
	virtual SeqIndexRange zranges(ArrayZRange & zbounds)
	{
		return  zranges(zbounds, 64, -1, DefaultRecurse);
	}
	virtual SeqIndexRange zranges(ArrayZRange & zbounds, int precision)
	{
		return  zranges(zbounds, precision, -1, DefaultRecurse);
	}
	virtual SeqIndexRange zranges(ArrayZRange & zbounds, int precision, int maxRanges)
	{
		return  zranges(zbounds, precision, maxRanges, DefaultRecurse);
	}
	/**
* Calculates ranges in index space that match any of the input bounds. Uses breadth-first searching to
* allow a limit on the number of ranges returned.
*
* To improve performance, the following decisions have been made:
*   uses loops instead of foreach/maps
*   uses java queues instead of scala queues
*   allocates initial sequences of decent size
*   sorts once at the end before merging
*
* @param zbounds search space
* @param precision precision to consider, in bits (max 64)
* @param maxRanges loose cap on the number of ranges to return. A higher number of ranges will have less
*                  false positives, but require more processing.
* @param maxRecurse max levels of recursion to apply before stopping
* @return ranges covering the search space
*/
	struct   ZPrefix
	{
		ull prefix;
		int precision;
	};
	virtual SeqIndexRange zranges(ArrayZRange & zbounds, int precision = 64, int maxRanges = -1, int maxRecurse = 7)
	{

		// stores our results - initial size of 100 in general saves us some re-allocation
		//val ranges = new java.util.ArrayList[IndexRange](100)
		std::list<IndexRange> ranges;
		ranges.resize(100);
		// values remaining to process - initial size of 100 in general saves us some re-allocation
		//val remaining = new java.util.ArrayDeque[(Long, Long)](100)
		std::deque<std::pair<ull, ull>> remaining;
		remaining.resize(100);
		// calculate the common prefix in the z-values - we start processing with the first diff
		ZPrefix tmpZPrefix = longestCommonPrefix(zbounds);
		ull commonPrefix = tmpZPrefix.prefix;
		int	commonBits = tmpZPrefix.precision;
		int offset = 64 - commonBits;

		// checks if a range is contained in the search space

		auto isContained = [&zbounds, this](ZRange& range)
		{
			int i = 0;
			while (i < zbounds.size())
			{
				if (contains(zbounds[i], range))
					return true;
				i++;
			}
			return false;

		};
		auto isOverlapped = [&zbounds, this](ZRange& range)
		{
			int i = 0;
			while (i < zbounds.size())
			{
				if (overlaps(zbounds[i], range))
					return true;
				i++;
			}
			return false;

		};

		auto  checkValue = [&offset, &isContained, &isOverlapped, &precision, &ranges, &remaining](ull prefix, ull  quadrant) ->unsigned int {
			ull min = prefix | (quadrant << offset);
			ull max = min | (1L << offset) - 1;
			ZRange quadrantRange = ZRange(min, max);

			if (isContained(quadrantRange) || offset < 64 - precision) {
				// whole range matches, happy day
				ranges.push_back(IndexRange(min, max, true));
			}
			else if (isOverlapped(quadrantRange)) {
				// some portion of this range is excluded
				// queue up each sub-range for processing
				remaining.push_back(std::make_pair(min, max));
			}
		};
		std::pair<ull, ull> LevelTerminator = std::make_pair(-1, -1);
		auto  bottomOut = [this, &remaining, &ranges, LevelTerminator]() ->unsigned int {
			do {
				std::pair<ull, ull> minMax = remaining.front();
				auto min2 = std::get<0>(LevelTerminator);
				auto max2 = std::get<1>(LevelTerminator);
				if (minMax.first == min2 && minMax.second == max2)
				{
					ranges.emplace_back(minMax.first, minMax.second, false);
				}
				remaining.pop_front();
			} while (!remaining.empty());
		};


		// initial level - we just check the single quadrant
		checkValue(commonPrefix, 0);
		remaining.push_back(LevelTerminator);
		offset -= Dimensions;

		// level of recursion
		int level = 0;

		int rangeStop = maxRanges == -1 ? INT_MAX : maxRanges;
		int recurseStop = (maxRecurse == 7) ? (DefaultRecurse) : maxRecurse;

		do {
			auto next = remaining.front();
			remaining.pop_front();
			if (next.first == LevelTerminator.first && next.second == LevelTerminator.second)
			{
				if (!remaining.empty()) {
					level += 1;
					offset -= Dimensions;
					if (level >= recurseStop || offset < 0) {
						bottomOut();
					}
					else {
						remaining.push_back(LevelTerminator);
					}
				}
			}
			else {
				auto prefix = next.first;
				ull quadrant = 0L;
				while (quadrant < Quadrants) {
					checkValue(prefix, quadrant);
					quadrant += 1;
				};
				// subtract one from remaining.size to account for the LevelTerminator
				if (ranges.size() + remaining.size() - 1 >= rangeStop) {
					bottomOut();
				}
			}
		} while (!remaining.empty());

		// we've got all our ranges - now reduce them down by merging overlapping values
		//std::sort(ranges.begin(), ranges.end());
		ranges.sort(CompA);

		auto current = ranges.front(); // note: should always be at least one range
		SeqIndexRange result;
		int i = 1;
		while (i < ranges.size()) {
			auto range = ranges.front();
			if (range.lower <= current.upper + 1) {
				// merge the two ranges
				current = IndexRange(current.lower, max(current.upper, range.upper), current.contained && range.contained);
			}
			else {
				// append the last range and set the current range for future merging
				result.push_back(current);
				current = range;
			}
			i += 1;
		}
		// append the last range - there will always be one left that wasn't added
		result.push_back(current);

		return		  result;
	}

	/**
	 * Cuts Z-Range in two and trims based on user space, can be used to perform augmented binary search
	 *
	 * @param xd: division point
	 * @param inRange: is xd in query range
	 */
	static SeqIndexRange g_empty;
	SeqIndexRange cut(ZRange &r, ull xd, bool inRange) {
		SeqIndexRange ret;
		if (r.min == r.max) {
			return g_empty;
		}
		else if (inRange) {
			if (xd == r.min) { // degenerate case, two nodes min has already been counted
				ret.emplace_back(r.max, r.max);
			}
			else if (xd == r.max) { // degenerate case, two nodes max has already been counted
				ret.emplace_back(r.min, r.min);
			}
			else {
				ret.emplace_back(r.min, xd - 1);
				ret.emplace_back(xd + 1, r.max);
			}
		}
		else {
			ull litmax0, bigmin = 0;
			std::tuple<ull, ull> tup = zdiv(Dimensions, xd, r.min, r.max);

			ret.emplace_back(r.min, std::get<0>(tup));
			ret.emplace_back(std::get<1>(tup), r.max);
		}
	}

	/**
	  * Calculates the longest common binary prefix between two z longs
	  *
	  * @return (common prefix, number of bits in common)
	  */
	  //这里不是指针是不确定参数大小
	ZPrefix longestCommonPrefix(ArrayZRange & values) {
		if (values.size() < 1)
			return ZPrefix();
		std::vector<ull> llu;
		for (auto& var : values)
		{
			llu.push_back(var.min);
			llu.push_back(var.max);
		}

		int bitShift = TotalBits - Dimensions;
		ull head = llu[0] >> bitShift;
		int tail = llu.size() - 1;
		for (int i = llu.size() - 1; i > 0; i--)
		{
			ull v = llu[i] >> bitShift;
			if ((v == head) && bitShift > -1)
			{
				bitShift -= Dimensions;
				head = llu[0] >> bitShift;
			}
		}

		bitShift += Dimensions; // increment back to the last valid value
		ZPrefix ret;
		ret.prefix = (llu[0] & (((ull)~((ull)0)) << bitShift));
		ret.precision = 64 - bitShift;
		return ret;
	}
	//	case class ZPrefix(prefix : Long, precision : Int) // precision in bits
		/** Loads either 1000... or 0111... into starting at given bit index of a given dimension */
	ull load(ull target, ull p, int bits, int dim)
	{
		auto mask = ~(split(MaxMask >> (BitsPerDimension - bits)) << dim);
		auto wiped = target & mask;
		return wiped | (split(p) << dim);
	}





	/**
	  * Implements the the algorithm defined in: Tropf paper to find:
	  * LITMAX: maximum z-index in query range smaller than current point, xd
	  * BIGMIN: minimum z-index in query range greater than current point, xd
	  *
	  * @param load: function that knows how to load bits into appropraite dimension of a z-index
	  * @param xd: z-index that is outside of the query range
	  * @param rmin: minimum z-index of the query range, inclusive
	  * @param rmax: maximum z-index of the query range, inclusive
	  * @return (LITMAX, BIGMIN)
	  */
private:
	//std::tuple<ull, ull> LevelTerminator = std::make_tuple(-1,-1);

	std::tuple<ull, ull> zdiv(int dims, ull xd, ull  rmin, ull rmax)
	{
		//require(rmin < rmax, "min ($rmin) must be less than max $(rmax)")
		ull zmin = rmin;
		ull zmax = rmax;
		ull bigmin = 0L;
		ull litmax = 0L;
		//int dims = 2;
		auto bit = [&](ull x, int idx) {	return (int)((x & (1ULL << idx)) >> idx);	};
		auto over = [&](ull bits) {return  1L << (bits - 1); };
		auto under = [&](ull bits) { return  (1L << (bits - 1)) - 1; };


		auto i = 64;
		while (i > 0) {
			i -= 1;

			auto bits = i / dims + 1;
			auto dim = i % dims;
			auto a = bit(xd, i);
			auto b = bit(zmin, i);
			auto c = bit(zmax, i);
			if (a == 0 && b == 0 && c == 1)
			{
				zmax = load(zmax, under(bits), bits, dim);
				bigmin = load(zmin, over(bits), bits, dim);
			}
			else if (a == 0 && b == 1 && c == 1)
			{
				bigmin = zmin;
				return std::make_tuple(litmax, bigmin);
			}

			else if (a == 1 && b == 0 && c == 0)
			{
				litmax = zmax;
				return std::make_tuple(litmax, bigmin);
			}
			else if (a == 1 && b == 0 && c == 1)
			{
				litmax = load(zmax, under(bits), bits, dim);
				zmin = load(zmin, over(bits), bits, dim);
			}
			else
			{
				continue;
			}
		};
		return std::make_tuple(litmax, bigmin);
	}
};



#pragma endregion




#pragma region Z3Ordering =Z3SFC.scala

enum class TimePeriod
{
	eDay,
	eWeek,
	eMonth,
	eYear,
};
struct BinnedTime
{

	//case TimePeriod.Day = > ChronoUnit.DAYS.getDuration.toMillis
	//case TimePeriod.Week = > ChronoUnit.WEEKS.getDuration.toMillis / 1000L
	//case TimePeriod.Month = > (ChronoUnit.DAYS.getDuration.toMillis / 1000L) * 31L
	// based on 365 days + 1 leap day, with a fudge factor of 10 minutes to account for leap seconds added each year
	//case TimePeriod.Year = > (ChronoUnit.DAYS.getDuration.toMinutes * 366L) + 10L
	//86400000
	//604800
	//2678400
	//527050
	static ull maxOffset(TimePeriod period)
	{
		switch (period)
		{
		case TimePeriod::eDay:
			return 86400000;

		case TimePeriod::eWeek:
			return 604800;

		case TimePeriod::eMonth:
			return	2678400;

		case TimePeriod::eYear:
			return 527050;
		default:
			break;
		}

	}
};


struct  Z3 :public ZN {
	int Dimensions = 2;
	int BitsPerDimension = 31;
	int TotalBits = 62;
	ull MaxMask = 0x1fffffL;
	ull z = 0;
	int d0 = 0, d1 = 0, d2 = 0;
	int DefaultRecurse = 7;
	Z3(int dim = 3) :ZN(dim)
	{
		Dimensions = dim;
	}
	Z3(ull z) :ZN(3)
	{
		d0 = combine(z);
		d1 = combine(z >> 1);
		d2 = combine(z >> 2);
	}
	Z3(int x, int y, int t) :ZN(3)
	{
		ull z = (split(x) | split(y) << 1 | split(t) << 2);
		d0 = combine(z);
		d1 = combine(z >> 1);
		d2 = combine(z >> 2);
	}
	//def < (other: Z3) = z < other.z
	//def >(other: Z3) = z > other.z
	//def >= (other: Z3) = z >= other.z
	//def <= (other: Z3) = z <= other.z
	//def + (offset: Long) = new Z3(z + offset)
	//def - (offset: Long) = new Z3(z - offset)
	//def == (other: Z3) = other.z == z
	//def decode : (Int, Int, Int) = (d0, d1, d2)

	int dim(int i)
	{
		if (i == 0)	return d0;
		else if (i == 1)return  d1;
		else if (i == 2)return   d2;
		else {
			return 0;//throw new IllegalArgumentException(s"Invalid dimension $i - valid dimensions are 0,1,2")
		}
	}

	bool inRange(Z3 &rmin, Z3 &rmax)
	{
		int x = d0; int  y = d1; int z = d2;
		return x >= rmin.d0 &&
			x <= rmax.d0 &&
			y >= rmin.d1 &&
			y <= rmax.d1 &&
			z >= rmin.d2 &&
			z <= rmax.d2;
	}

	Z3 mid(Z3 &p)
	{
		int x = d0; int  y = d1; int z = d2;
		int px = p.d0; int py = p.d1; int pz = p.d2;
		return  Z3((x + px) >> 1, (y + py) >> 1, (z + pz) >> 1);
	}
	//toString 方法未实现
	//def bitsToString = f"(${z.toBinaryString.toLong}%016d)(${d0.toBinaryString.toLong}%08d,${d1.toBinaryString.toLong}%08d,${d2.toBinaryString.toLong}%08d)"
	//override def toString = f"$z $decode"
	//def unapply(z : Z3) : Option[(Int, Int, Int)] = Some(z.decode)
	/** insert 00 between every bit in value. Only first 21 bits can be considered. */
	virtual ull split(ull  value)
	{
		auto x = value & MaxMask;
		x = (x | x << 32) & 0x1f00000000ffffL;
		x = (x | x << 16) & 0x1f0000ff0000ffL;
		x = (x | x << 8) & 0x100f00f00f00f00fL;
		x = (x | x << 4) & 0x10c30c30c30c30c3L;
		return (x | x << 2) & 0x1249249249249249L;
	}

	/** combine every third bit to form a value. Maximum value is 21 bits. */
	virtual int combine(ull  value)
	{
		auto x = z & 0x1249249249249249L;
		x = (x ^ (x >> 2)) & 0x10c30c30c30c30c3L;
		x = (x ^ (x >> 4)) & 0x100f00f00f00f00fL;
		x = (x ^ (x >> 8)) & 0x1f0000ff0000ffL;
		x = (x ^ (x >> 16)) & 0x1f00000000ffffL;
		x = (x ^ (x >> 32)) & MaxMask;
		return (int)x;// x.toInt
	}

	virtual bool contains(ZRange& range, ull value)
	{
		Z3 ztmp(value);
		int x = ztmp.d0, y = ztmp.d1, z = ztmp.d2;
		return x >= Z3(range.min).d0 && x <= Z3(range.max).d0 &&
			y >= Z3(range.min).d1 && y <= Z3(range.max).d1 &&
			z >= Z3(range.min).d2 && z <= Z3(range.max).d2;
	}
	virtual bool overlaps(int a1, int a2, int b1, int b2)
	{
		return  max(a1, b1) <= min(a2, b2);
	}
	virtual bool overlaps(ZRange &range, ZRange& value)
	{
		return overlaps(Z3(range.min).d0, Z3(range.max).d0, Z3(value.min).d0, Z3(value.max).d0) &&
			overlaps(Z3(range.min).d1, Z3(range.max).d1, Z3(value.min).d1, Z3(value.max).d1) &&
			overlaps(Z3(range.min).d2, Z3(range.max).d2, Z3(value.min).d2, Z3(value.max).d2);
	}
};


/**
  * Z3 space filling curve
  *
  * @param period time period used to bin results
  * @param precision bits used per dimension - note all precisions must sum to less than 64
  */
class Z3SpaceTimeFillingCurve :public  SpaceTimeFillingCurve {
	BitNormalizedDimension lat;// (-90, 90, precision);
	BitNormalizedDimension lon;// (-180, 180, precision);

	BitNormalizedDimension time;// (0, maxtime, precision);
public:
	Z3SpaceTimeFillingCurve(TimePeriod period, int precision = 21)
	{
		if (precision <= 0 || precision >= 22)
		{
			printf("error Z3SpaceTimeFillingCurve Precision (bits) per dimension must be in [1,21]");
			return;
		}
		lat = BitNormalizedDimension(-90, 90, precision);
		lon = BitNormalizedDimension(-180, 180, precision);
		double maxtime = BinnedTime::maxOffset(period);
		lon = BitNormalizedDimension(0, maxtime, precision);
		SeqTimes wholePeriod;
		wholePeriod.resize(1);
		wholePeriod[0][0] = time.min;
		wholePeriod[0][1] = time.max;

	}
	virtual ull index(double x, double y, ull t, bool   lenient = false)
	{

		if (x >= lon.min && x <= lon.max && y >= lat.min && y <= lat.max && t >= time.min && t <= time.max)
		{
			return Z3(lon.normalize(x), lat.normalize(y), time.normalize(t)).z;
		}
		else
		{
			return 0;
		}

		//catch {
		//case _: IllegalArgumentException if lenient = > lenientIndex(x, y, t)

	}
	ull lenientIndex(double x, double y, ull  t)
	{
		double bx = 0; if (x < lon.min) { bx = lon.min; }
		else if (x > lon.max) { bx = lon.max; }
		else { bx = x; }
		double by = 0; if (y < lat.min) { by = lat.min; }
		else if (y > lat.max) { by = lat.max; }
		else { by = y; }
		double bt = 0; if (t < time.min) { bt = time.min; }
		else if (t > time.max) { bt = time.max; }
		else { bt = t; }
		return Z3(lon.normalize(bx), lat.normalize(by), time.normalize(bt)).z;
	}
	virtual void invert(ull  z, double& x, double & y, ull&t)
	{
		x = lon.denormalize(Z3(z).d0);
		y = lat.denormalize(Z3(z).d1);
		t = time.denormalize(Z3(z).d2);
	}

	virtual  SeqIndexRange ranges(SeqBoxs seqboxs, SeqTimes seqtimes, int precision, int maxRanges)
	{
		ArrayZRange az;
		for (int i = 0; i < seqboxs.size(); i++)
		{
			ull min = index(seqboxs[i][0], seqboxs[i][1], seqtimes[i][0]);
			ull max = index(seqboxs[i][2], seqboxs[i][3], seqtimes[i][1]);
			az.emplace_back(min, max);
		}

		Z3 zn(3);
		return zn.zranges(az, precision, maxRanges, 7);
	}
};
#pragma endregion


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/697427.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

知识图谱实战

一、知识图谱简单介绍 二、知识图谱的构建 三、知识图谱问答方案 NL2SQL:自然语言转为SQL语句 bulid_graph.py """知识图谱""" #三元组&#xff1a;实体-关系-实体 实体-属性-属性值import re,json from py2neo import Graph from collectio…

shell脚本检测进程的CPU内存占用率

使用方法&#xff1a; 把xxx替换为自己进程的名字&#xff0c;然后直接运行该脚本即可在当前目录下产生一个叫做memory_info.txt的文件&#xff0c;记录进程的CPU内存占用率信息。可以用来查看自己进程对系统资源的消耗情况。 #!/bin/bashprocess"xxx" output_file…

C#,数值计算——算术编码压缩技术与方法(Compression by Arithmetic Coding)源代码

算术编码的数据压缩 算术编码是无损和有损数据压缩算法中常用的一种算法。 这是一种熵编码技术&#xff0c;其中常见符号比罕见符号用更少的比特进行编码。与诸如霍夫曼编码之类的众所周知的技术相比&#xff0c;它具有一些优势。本文将详细描述CACM87算术编码的实现&#xf…

Uniapp_分包

前言&#xff1a;由于微信小程序的包只限制压缩不能超过2M&#xff0c;当开发的页面过多就要进行分包操作,tabbar页面不能进行分包其他页面可以 最多5个分包 不超过20M 第一步、找到这个位置 然后把这个代码复制进去 开启分包 "optimization" : {"subPackages&…

Linux系统【VS】Windows系统

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

FPS(CF、CS GO、PUBG、APEX、瓦罗兰) AI YOLOV5 自瞄 模型 权重

YOLOV5的各种AI自瞄权重&#xff0c;有需要的联系 联系方式 如果对上面的资源有需要&#xff0c;私聊或者留言或者进入下面项目了解详细内容 联系方式 加我时&#xff0c;请备注所需要的权重 https://gitee.com/wcx895278175/cf-ai-yolov5-self-aiming

【Oracle】springboot连接Oracle 集成mybatis、druid

目录 项目结构与库表数据pom.xmlapplication.yml实体类Mappercontroller接口测试 基于spring-boot 2.7.11&#xff0c;连接Oracle 11g 仅做一个简单的示例 特别说明&#xff08;不一定正确&#xff0c;还请指正&#xff09;&#xff1a;我Oracle也不熟&#xff0c;但据我观察发…

【Java高级语法】(二十三)系统辅助工具类:解析System类,一个系统操作与资源管理工具类~

Java高级语法详解之系统辅助工具类 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 System类常用方法3.2 使用技巧 4️⃣ 应用场景&#x1f33e; 总结 1️⃣ 概念 Java的System类是Java标准库中一个重要且常用的类。它被设计用于提供与系统相关的操作和信息访问功能。System类的设计…

【算法系列之贪心算法III】leetcode135. 分发糖果

134. 加油站 力扣题目链接 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定…

创建临时文件mkstemp()和tmpfile()

有些程序需要创建一些临时文件&#xff0c;仅供其在运行期间使用&#xff0c;程序终止后即行删除。例如&#xff0c;很多编译器程序会在编译过程中创建临时文件。GNU C语言函数库为此而提供了一系列库函数。&#xff08;之所以有“一系列”的库函数&#xff0c;部分原因是由于这…

ASD光谱仪.asd格式光谱曲线文件转换为.txt格式的方法

本文介绍基于ViewSpec Pro软件&#xff0c;将ASD地物光谱仪获取到的.asd格式文件&#xff0c;批量转换为通用的.txt文本格式文件的方法。 ASD光谱仪是英国Malvern Panalytical公司研发的系列野外便携式全范围光谱辐射仪和光谱仪&#xff0c;可以获取地物的实时光谱信息。我们用…

Arch Linux 中的 AUR 是什么?您应该使用它吗?

Arch Linux AUR 存储库包含社区驱动的软件,如果您采取一些简单的预防措施,就可以安全使用。即使您不懂 shell 脚本,也可以使用一些指标来判断包是否安全。 AUR 是 Arch Linux 皇冠上的宝石之一,提供了数千个附加软件包。但是这个用户驱动的存储库使用起来安全吗,还是应该避…

你给企业创建百科了吗?5分钟带你看懂创建企业百度百科的实用技巧和注意事项

企业百度百科是一种企业在互联网上展示自身形象和产品的重要途径。通过在百度百科上创建企业页面&#xff0c;可以让更多的人了解企业的历史、文化、产品和服务等信息&#xff0c;提高企业知名度和品牌形象。分媒互动将介绍企业百度百科的创建方法和需要注意的事项。 一、企业百…

搭建IP代理池 - ProxyPool

前言 在爬虫开发中&#xff0c;我们经常会碰到ip封禁&#xff0c;访问限制的问题&#xff0c;今天主要分享个我在开发中用到过比较好用的ip代理池&#xff0c;希望有需要的小伙伴提供到帮助~ 简介 ProxyPool是一个简易高效的代理池&#xff0c;他可以在windows上搭配redis使…

【强化学习】常用算法之一 “SARSA”

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typeblog个…

飞控的安全性设计

针对安全性设计&#xff0c;就必须先考虑故障情况。一般来讲&#xff0c;飞控故障有以下几个方面&#xff1a; 1、通讯故障 飞行器与地面端&#xff08;遥控器或地面站等设备&#xff09;需要进行实时通信&#xff0c;如果通信发生故障&#xff0c;后果很严重&#xff0c;因此…

赛效:WPS文字(Word)中的页面背景如何删除

1&#xff1a;打开一个有背景颜色的文档。 2&#xff1a;在“页面布局”选项卡里点击“背景”&#xff0c;在下拉菜单里点击“删除页面背景”。 3&#xff1a;接下来我们看到&#xff0c;文档背景已经恢复了默认的颜色。 如果你想了解更多办公软件以及办公技巧&#xff0c;可以…

青大数据结构【2019】【五算法设计】

关键字: 简单选择排序、二叉树后序遍历 1) void Countsort(int A[],int B[],int n) {int i,j,count;for(i=0;i<n;i++){count=0;for(j=0;j<n;j++)if(A[j]<A[i])count++;B[count]=A[i];}} 2) 每个元素都要与n个元素(含自身)进行比较,故比较次数为n方 3) …

Redis之数据类型String、List、Hash、Set、Sorted Set(详细)

一、String数据类型 1、SET/GET/APPEND/STRLEN &#xff08;1&#xff09; APPEND &#xff08;2&#xff09; SET/STRLEN 2、 INCR/ DECR/INCRBY/DECRBY &#xff08;1&#xff09;INCR/ DECR &#xff08;2&#xff09; INCRBY/DECRBY INCRBY key increment&#xff1…

JavaWed第二章:HTML和CSS的知识制作静态网页

目录 前言 一.HTML和CSS的介绍 &#x1f496;HTML的基本框架 二.HTML常用标签大全 三.资源路径讲解 &#x1f496;路径 &#x1f496;图片 img标签讲解 &#x1f496;超链接标签讲解 四.CSS &#x1f496;CSS的引入方式 五.HTML页面布局 &#x1f496;盒子模型介绍 …