/**
* 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.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jo.sm.logic.utils.ByteUtils;
import jo.vecmath.Point3i;
import jo.vecmath.Point3s;
/**
* @Auther Jo Jaquinta for SMEdit Classic - version 1.0
**/
public final class SparseMatrix<T> {
public static long toHashCode(int x, int y, int z) {
byte[] buffer = new byte[8];
buffer[0] = 0;
ByteUtils.toBytes((short) x, buffer, 1);
ByteUtils.toBytes((short) y, buffer, 3);
ByteUtils.toBytes((short) z, buffer, 5);
buffer[7] = 1;
return ByteUtils.toLong(buffer);
}
public static Point3i fromHashCode(long hash) {
byte[] buffer = new byte[8];
ByteUtils.toBytes(hash, buffer);
short x = ByteUtils.toShort(buffer, 1);
short y = ByteUtils.toShort(buffer, 3);
short z = ByteUtils.toShort(buffer, 5);
Point3i p = new Point3i(x, y, z);
return p;
}
private Map<Long, T> mMatrix;
private Point3i mLower;
private Point3i mUpper;
public SparseMatrix() {
mMatrix = new HashMap<>();
mLower = null;
mUpper = null;
}
public SparseMatrix(SparseMatrix<T> original) {
this();
set(original);
mLower = new Point3i();
mUpper = new Point3i();
original.getBounds(mLower, mUpper);
}
public void addAll(SparseMatrix<T> original) {
for (Iterator<Point3i> i = original.iteratorNonNull(); i.hasNext();) {
Point3i p = i.next();
set(p, original.get(p));
}
}
public void set(SparseMatrix<T> original) {
mMatrix.clear();
addAll(original);
}
public void set(int x, int y, int z, T val) {
long idx = toHashCode(x, y, z);
if (val == null) {
mMatrix.remove(idx);
} else {
mMatrix.put(idx, val);
}
if (val != null) {
if (mLower == null) {
mLower = new Point3i(x, y, z);
} else {
mLower.x = Math.min(mLower.x, x);
mLower.y = Math.min(mLower.y, y);
mLower.z = Math.min(mLower.z, z);
}
if (mUpper == null) {
mUpper = new Point3i(x, y, z);
} else {
mUpper.x = Math.max(mUpper.x, x);
mUpper.y = Math.max(mUpper.y, y);
mUpper.z = Math.max(mUpper.z, z);
}
}
}
public T get(int x, int y, int z) {
long idx = toHashCode(x, y, z);
return mMatrix.get(idx);
}
public boolean contains(int x, int y, int z) {
return get(x, y, z) != null;
}
public void set(Point3i v, T val) {
set(v.x, v.y, v.z, val);
}
public T get(Point3i v) {
return get(v.x, v.y, v.z);
}
public T 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) {
if (mLower != null) {
lower.set(mLower);
}
if (mUpper != null) {
upper.set(mUpper);
}
}
public Iterator<Point3i> iterator() {
return new CubeIterator(mLower, mUpper);
}
public Iterator<Point3i> iteratorNonNull() {
List<Point3i> points = new ArrayList<>();
for (Long l : mMatrix.keySet()) {
Point3i p = fromHashCode(l);
points.add(p);
}
return points.iterator();
}
public int size() {
return mMatrix.size();
}
}