/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2015, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.index.tree.hilbert; import java.io.IOException; import java.nio.channels.SeekableByteChannel; import org.apache.sis.util.ArraysExt; import org.geotoolkit.index.tree.Node; import org.geotoolkit.internal.tree.ChannelTreeAccess; import static org.geotoolkit.internal.tree.TreeUtilities.intersects; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * {@link TreeAccess} implementation adapted for {@link HilbertRTree}.<br/> * Store all {@link Node} architecture use by {@link Tree} into a {@link SeekableByteChannel}. * * @author Remi Marechal (Geomatys). * @see #internalSearch(int) * @see #readNode(int) * @see #writeNode(org.geotoolkit.index.tree.Node) */ abstract strictfp class HilbertChannelTreeAccess extends ChannelTreeAccess { /** * Hilbert Node attributs Number.<br/> * parent ID<br/> * sibling ID <br/> * child ID<br/> * current Hilbert Order<br/> * children number<br/> * data number. */ private static final int HILBERT_INT_NUMBER = 6; //------------------------------ reading mode ------------------------------ /** * Build a {@link Tree} from a already filled {@link Channel}, in other words, open in reading mode. * * @param channel {@link SeekableByteChannel} to read already filled object. * @param magicNumber {@code Integer} single {@link Tree} code. * @param versionNumber tree version. * @param byteBufferLength length in Byte unit of the buffer which read and write on hard disk. * @throws IOException if problem during channel read / write action. */ public HilbertChannelTreeAccess(final SeekableByteChannel channel, final int magicNumber, final double versionNumber, final int byteBufferLength) throws IOException, ClassNotFoundException { super(channel, magicNumber, versionNumber, byteBufferLength, HILBERT_INT_NUMBER); } //-------------------------- Writing mode ---------------------------------- /** * Build an empty {@link TreeAccess} adapted for {@link HilbertRTree} and store {@link Node} architecture, * in other words, open in writing mode. * * @param channel {@link SeekableByteChannel} to read already filled object. * @param magicNumber {@code Integer} single {@link Tree} code. * @param versionNumber tree version. * @param maxElements element number per cell. * @param hilbertOrder * @param crs * @param byteBufferLength length in Byte unit of the buffer which read and write on hard disk. * @throws IOException */ public HilbertChannelTreeAccess(final SeekableByteChannel channel, final int magicNumber, final double versionNumber, final int maxElements, final int hilbertOrder, final CoordinateReferenceSystem crs, final int byteBufferLength) throws IOException { super(channel, magicNumber, versionNumber, maxElements, hilbertOrder, null, crs, byteBufferLength, HILBERT_INT_NUMBER); } /** * {@inheritDoc }. */ @Override public void internalSearch(int nodeID) throws IOException { adjustBuffer(nodeID); final double[] boundary = new double[boundLength]; for (int i = 0; i < boundLength; i++) { boundary[i] = byteBuffer.getDouble(); } byteBuffer.position(byteBuffer.position() + 5);// step properties (1 byte) and step parent ID (int : 4 bytes) final int sibling = byteBuffer.getInt(); final int child = byteBuffer.getInt(); byteBuffer.position(byteBuffer.position() + 12);// step hilbertOrder, step child count and step dataCount if (sibling != 0) { internalSearch(sibling); } // trouver a ameliorer avec les valeurs de hilbert qui aide en cas de feuille if (!ArraysExt.hasNaN(boundary) && intersects(boundary, regionSearch, true)) { if (child > 0) { internalSearch(child); } else { if (child == 0) throw new IllegalStateException("child index should never be 0."); if (currentPosition == currentLength) { currentLength = currentLength << 1; final int[] tabTemp = tabSearch; tabSearch = new int[currentLength]; System.arraycopy(tabTemp, 0, tabSearch, 0, currentPosition); } tabSearch[currentPosition++] = -child; } } } /** * {@inheritDoc }. */ @Override public synchronized Node readNode(final int indexNode) throws IOException { adjustBuffer(indexNode); final double[] boundary = new double[boundLength]; for (int i = 0; i < boundLength; i++) { boundary[i] = byteBuffer.getDouble(); } final byte properties = byteBuffer.get(); final int parentId = byteBuffer.getInt(); final int siblingId = byteBuffer.getInt(); final int childId = byteBuffer.getInt(); final int currentHilbertOrder = byteBuffer.getInt(); final int childCount = byteBuffer.getInt(); final int dataCount = byteBuffer.getInt(); final HilbertNode redNode = new HilbertNode(this, indexNode, boundary, properties, parentId, siblingId, childId); redNode.setCurrentHilbertOrder(currentHilbertOrder); redNode.setChildCount(childCount); redNode.setDataCount(dataCount); return redNode; } /** * {@inheritDoc }. */ @Override public synchronized void writeNode(final Node candidate) throws IOException { final int indexNode = candidate.getNodeId(); adjustBuffer(indexNode); double[] candidateBound = candidate.getBoundary(); if (candidateBound == null) candidateBound = nanBound; for (int i = 0; i < boundLength; i++) { byteBuffer.putDouble(candidateBound[i]); } byteBuffer.put(candidate.getProperties()); byteBuffer.putInt(candidate.getParentId()); byteBuffer.putInt(candidate.getSiblingId()); byteBuffer.putInt(candidate.getChildId()); byteBuffer.putInt(((HilbertNode)candidate).getCurrentHilbertOrder()); byteBuffer.putInt(candidate.getChildCount()); byteBuffer.putInt(((HilbertNode)candidate).getDataCount()); writeBufferLimit = Math.max(writeBufferLimit, byteBuffer.limit()); } /** * {@inheritDoc }. */ @Override public synchronized Node createNode(double[] boundary, byte properties, int parentId, int siblingId, int childId) { final int currentID = (!recycleID.isEmpty()) ? recycleID.remove(0) : nodeId++; return new HilbertNode(this, currentID, (boundary == null) ? nanBound : boundary, properties, parentId, siblingId, childId); } }