/** * Copyright 2014 * SMEdit https://github.com/StarMade/SMEdit * SMTools https://github.com/StarMade/SMTools * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. **/ package jo.sm.data; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Objects; import jo.vecmath.Point3i; import jo.vecmath.Point3s; /** * @Auther Jo Jaquinta for SMEdit Classic - version 1.0 **/ public final class SparseBooleanMatrix { private Map<Integer, Map<Integer, Map<Integer, Long>>> mMatrix; public SparseBooleanMatrix() { mMatrix = new HashMap<>(); } public SparseBooleanMatrix(SparseBooleanMatrix original) { this(); set(original); } public void addAll(SparseBooleanMatrix original) { for (Iterator<Point3i> i = original.iteratorNonNull(); i.hasNext();) { Point3i p = i.next(); set(p, original.get(p)); } } public void set(SparseBooleanMatrix original) { mMatrix.clear(); addAll(original); } public void set(int x, int y, int z, Boolean val) { Map<Integer, Map<Integer, Long>> xrow = mMatrix.get(x); if (xrow == null) { xrow = new HashMap<>(); mMatrix.put(x, xrow); } Map<Integer, Long> yrow = xrow.get(y); if (yrow == null) { yrow = new HashMap<>(); xrow.put(y, yrow); } Long raster = yrow.get(z / 64); if (raster == null) { raster = 0L; } long mask = 1 << (Math.abs(z % 64)); if (Objects.equals(val, Boolean.TRUE)) { raster |= mask; } else if (Objects.equals(val, Boolean.FALSE)) { raster &= ~mask; } if (raster == 0L) { yrow.remove(z / 64); } else { yrow.put(z / 64, raster); } } public Boolean get(int x, int y, int z) { Map<Integer, Map<Integer, Long>> xrow = mMatrix.get(x); if (xrow == null) { return null; } Map<Integer, Long> yrow = xrow.get(y); if (yrow == null) { return null; } Long raster = yrow.get(z / 64); if (raster == null) { return null; } long mask = 1 << (Math.abs(z % 64)); if ((raster & mask) != 0) { return Boolean.TRUE; } else { return Boolean.FALSE; } } public boolean contains(int x, int y, int z) { return get(x, y, z) != null; } public void set(Point3i v, Boolean val) { set(v.x, v.y, v.z, val); } public Boolean get(Point3i v) { return get(v.x, v.y, v.z); } public Boolean get(Point3s v) { return get(v.x, v.y, v.z); } public boolean contains(Point3i v) { return get(v.x, v.y, v.z) != null; } public void getBounds(Point3i lower, Point3i upper) { boolean first = true; for (Integer x : mMatrix.keySet()) { Map<Integer, Map<Integer, Long>> xrow = mMatrix.get(x); for (Integer y : xrow.keySet()) { Map<Integer, Long> yrow = xrow.get(y); for (Integer z : yrow.keySet()) { if (contains(x, y, z)) { if (first) { lower.x = x; upper.x = x; lower.y = y; upper.y = y; lower.z = z * 64; upper.z = z * 64 + 63; first = false; } else { lower.x = Math.min(lower.x, x); upper.x = Math.max(upper.x, x); lower.y = Math.min(lower.y, y); upper.y = Math.max(upper.y, y); lower.z = Math.min(lower.z, z * 64); upper.z = Math.max(upper.z, z * 64 + 63); } } } } } } public Iterator<Point3i> iterator() { Point3i lower = new Point3i(); Point3i upper = new Point3i(); getBounds(lower, upper); return new CubeIterator(lower, upper); } public Iterator<Point3i> iteratorNonNull() { return new NonNullIterator(); } public int size() { int size = 0; for (Iterator<Point3i> i = iteratorNonNull(); i.hasNext(); i.next()) { size++; } return size; } public int sizeLongs() { int size = 0; for (Map<Integer, Map<Integer, Long>> xrows : mMatrix.values()) { for (Map<Integer, Long> yrow : xrows.values()) { size += yrow.size(); } } return size; } class NonNullIterator implements Iterator<Point3i> { private Iterator<Point3i> mRootIterator; private Point3i mNext; public NonNullIterator() { mRootIterator = iterator(); advance(); } private void advance() { while (mRootIterator.hasNext()) { Point3i n = mRootIterator.next(); if (contains(n)) { mNext = n; return; } } mNext = null; } @Override public boolean hasNext() { return mNext != null; } @Override public Point3i next() { Point3i next = mNext; advance(); return next; } @Override public void remove() { } } }