Move all data sampling logic into IIncompleteFullDataSource

This commit is contained in:
James Seibel
2023-09-24 20:37:41 -05:00
parent c46e12fb7a
commit a4b7e3e021
5 changed files with 97 additions and 296 deletions
@@ -294,6 +294,8 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
@Override
public SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ) { return this.get(relativeX, relativeZ); }
@Override
public SingleColumnFullDataAccessor getOrCreate(int relativeX, int relativeZ) { return this.get(relativeX, relativeZ); }
@Override
public void update(ChunkSizedFullDataAccessor chunkDataView)
@@ -434,6 +436,7 @@ public class CompleteFullDataSource extends FullDataArrayAccessor implements IFu
@Override
public boolean isEmpty() { return this.isEmpty; }
@Override
public void markNotEmpty() { this.isEmpty = false; }
@Override
@@ -409,18 +409,31 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
// data //
//======//
public SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ)
@Override
public SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ) { return this.tryGetOrCreate(relativeX, relativeZ, false); }
@Override
public SingleColumnFullDataAccessor getOrCreate(int relativeX, int relativeZ) { return this.tryGetOrCreate(relativeX, relativeZ, true); }
private SingleColumnFullDataAccessor tryGetOrCreate(int relativeX, int relativeZ, boolean createIfMissing)
{
LodUtil.assertTrue(relativeX >= 0 && relativeX < SECTION_SIZE && relativeZ >= 0 && relativeZ < SECTION_SIZE);
int chunkX = relativeX / this.dataPointsPerSection;
int chunkZ = relativeZ / this.dataPointsPerSection;
FullDataArrayAccessor chunk = this.sparseData[chunkX * this.sectionCount + chunkZ];
if (chunk == null)
FullDataArrayAccessor accessor = this.sparseData[chunkX * this.sectionCount + chunkZ];
if (accessor == null)
{
return null;
if (createIfMissing)
{
// create the missing data so the following get() will succeed
accessor = new FullDataArrayAccessor(this.mapping, new long[this.dataPointsPerSection * this.dataPointsPerSection][], this.dataPointsPerSection);
this.sparseData[chunkX * this.sectionCount + chunkZ] = accessor;
}
else
{
return null;
}
}
return chunk.get(relativeX % this.dataPointsPerSection, relativeZ % this.dataPointsPerSection);
return accessor.get(relativeX % this.dataPointsPerSection, relativeZ % this.dataPointsPerSection);
}
@@ -466,6 +479,8 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
@Override
public boolean isEmpty() { return this.isEmpty; }
@Override
public void markNotEmpty() { this.isEmpty = false; }
@Override
public int getWidthInDataPoints() { return SECTION_SIZE; }
@@ -516,121 +531,6 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
// data sampling //
@Override
public void sampleFrom(IFullDataSource fullDataSource)
{
DhSectionPos pos = fullDataSource.getSectionPos();
LodUtil.assertTrue(pos.getDetailLevel() < this.sectionPos.getDetailLevel());
LodUtil.assertTrue(pos.overlapsExactly(this.sectionPos));
if (fullDataSource.isEmpty())
{
return;
}
if (fullDataSource instanceof CompleteFullDataSource)
{
this.sampleFrom((CompleteFullDataSource) fullDataSource);
}
else if (fullDataSource instanceof HighDetailIncompleteFullDataSource)
{
this.sampleFrom((HighDetailIncompleteFullDataSource) fullDataSource);
}
else if (fullDataSource instanceof LowDetailIncompleteFullDataSource)
{
// this.sampleFrom((LowDetailIncompleteFullDataSource) fullDataSource);
LodUtil.assertNotReach("SampleFrom not implemented for [" + IFullDataSource.class.getSimpleName() + "] with class [" + fullDataSource.getClass().getSimpleName() + "].");
}
else
{
LodUtil.assertNotReach("SampleFrom not implemented for [" + IFullDataSource.class.getSimpleName() + "] with class [" + fullDataSource.getClass().getSimpleName() + "].");
}
}
private void sampleFrom(CompleteFullDataSource completeDataSource)
{
DhSectionPos pos = completeDataSource.getSectionPos();
this.isEmpty = false;
DhLodPos basePos = this.sectionPos.getMinCornerLodPos(SPARSE_UNIT_DETAIL);
DhLodPos dataPos = pos.getMinCornerLodPos(SPARSE_UNIT_DETAIL);
int coveredChunks = pos.getWidthCountForLowerDetailedSection(SPARSE_UNIT_DETAIL);
int sourceDataPerChunk = SPARSE_UNIT_SIZE >>> completeDataSource.getDataDetailLevel();
LodUtil.assertTrue((coveredChunks * sourceDataPerChunk) == CompleteFullDataSource.WIDTH);
int xDataOffset = dataPos.x - basePos.x;
int zDataOffset = dataPos.z - basePos.z;
LodUtil.assertTrue(xDataOffset >= 0 && xDataOffset < this.sectionCount && zDataOffset >= 0 && zDataOffset < this.sectionCount);
for (int xOffset = 0; xOffset < coveredChunks; xOffset++)
{
for (int zOffset = 0; zOffset < coveredChunks; zOffset++)
{
FullDataArrayAccessor sourceChunk = completeDataSource.subView(sourceDataPerChunk, xOffset * sourceDataPerChunk, zOffset * sourceDataPerChunk);
FullDataArrayAccessor newFullDataAccessor = new FullDataArrayAccessor(this.mapping, new long[this.dataPointsPerSection * this.dataPointsPerSection][], this.dataPointsPerSection);
newFullDataAccessor.downsampleFrom(sourceChunk);
this.sparseData[(xOffset + xDataOffset) * this.sectionCount + (zOffset + zDataOffset)] = newFullDataAccessor;
}
}
}
private void sampleFrom(HighDetailIncompleteFullDataSource sparseDataSource)
{
DhSectionPos pos = sparseDataSource.getSectionPos();
this.isEmpty = false;
DhLodPos basePos = this.sectionPos.getMinCornerLodPos(SPARSE_UNIT_DETAIL);
DhLodPos dataPos = pos.getMinCornerLodPos(SPARSE_UNIT_DETAIL);
int offsetX = dataPos.x - basePos.x;
int offsetZ = dataPos.z - basePos.z;
LodUtil.assertTrue(offsetX >= 0 && offsetX < this.sectionCount && offsetZ >= 0 && offsetZ < this.sectionCount);
for (int xOffset = 0; xOffset < sparseDataSource.sectionCount; xOffset++)
{
for (int zOffset = 0; zOffset < sparseDataSource.sectionCount; zOffset++)
{
FullDataArrayAccessor sourceChunk = sparseDataSource.sparseData[xOffset * sparseDataSource.sectionCount + zOffset];
if (sourceChunk != null)
{
FullDataArrayAccessor newFullDataAccessor = new FullDataArrayAccessor(this.mapping, new long[this.dataPointsPerSection * this.dataPointsPerSection][], this.dataPointsPerSection);
newFullDataAccessor.downsampleFrom(sourceChunk);
this.sparseData[(xOffset + offsetX) * this.sectionCount + (zOffset + offsetZ)] = newFullDataAccessor;
}
}
}
}
private void sampleFrom(LowDetailIncompleteFullDataSource spottyDataSource)
{
// TODO implement
// DhSectionPos pos = spottyDataSource.getSectionPos();
// this.isEmpty = false;
//
// DhLodPos basePos = this.sectionPos.getCorner(SPARSE_UNIT_DETAIL);
// DhLodPos dataPos = pos.getCorner(SPARSE_UNIT_DETAIL);
//
// int coveredChunks = pos.getWidth(SPARSE_UNIT_DETAIL).numberOfLodSectionsWide;
// int sourceDataPerChunk = SPARSE_UNIT_SIZE >>> spottyDataSource.getDataDetailLevel();
// LodUtil.assertTrue((coveredChunks * sourceDataPerChunk) == CompleteFullDataSource.WIDTH);
//
// int xDataOffset = dataPos.x - basePos.x;
// int zDataOffset = dataPos.z - basePos.z;
// LodUtil.assertTrue(xDataOffset >= 0 && xDataOffset < this.sectionCount && zDataOffset >= 0 && zDataOffset < this.sectionCount);
//
// for (int xOffset = 0; xOffset < coveredChunks; xOffset++)
// {
// for (int zOffset = 0; zOffset < coveredChunks; zOffset++)
// {
// FullDataArrayAccessor sourceChunk = spottyDataSource.subView(sourceDataPerChunk, xOffset * sourceDataPerChunk, zOffset * sourceDataPerChunk);
// FullDataArrayAccessor newFullDataAccessor = new FullDataArrayAccessor(this.mapping, new long[this.dataPointsPerSection * this.dataPointsPerSection][], this.dataPointsPerSection);
// newFullDataAccessor.downsampleFrom(sourceChunk);
// this.sparseData[(xOffset + xDataOffset) * this.sectionCount + (zOffset + zDataOffset)] = newFullDataAccessor;
// }
// }
}
private void applyToFullDataSource(CompleteFullDataSource dataSource)
{
LodUtil.assertTrue(dataSource.getSectionPos().equals(this.sectionPos));
@@ -666,16 +566,13 @@ public class HighDetailIncompleteFullDataSource implements IIncompleteFullDataSo
return this;
}
}
isPromoted = true;
this.isPromoted = true;
CompleteFullDataSource fullDataSource = CompleteFullDataSource.createEmpty(this.sectionPos);
this.applyToFullDataSource(fullDataSource);
return fullDataSource;
}
@Override
public boolean hasBeenPromoted()
{
return isPromoted;
}
public boolean hasBeenPromoted() { return this.isPromoted; }
}
@@ -284,7 +284,23 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
//======//
@Override
public SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ) { return this.isColumnNotEmpty.get(relativeX * WIDTH + relativeZ) ? this.get(relativeX, relativeZ) : null; }
public SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ) { return this.tryGetOrCreate(relativeX, relativeZ, false); }
@Override
public SingleColumnFullDataAccessor getOrCreate(int relativeX, int relativeZ) { return this.tryGetOrCreate(relativeX, relativeZ, true); }
private SingleColumnFullDataAccessor tryGetOrCreate(int relativeX, int relativeZ, boolean createIfMissing)
{
int notEmptyIndex = relativeX * WIDTH + relativeZ;
boolean columnEmpty = this.isColumnNotEmpty.get(notEmptyIndex);
// "create" the missing column if necessary
if (columnEmpty && createIfMissing)
{
this.isColumnNotEmpty.set(notEmptyIndex, true);
columnEmpty = false;
}
return !columnEmpty ? this.get(relativeX, relativeZ) : null;
}
@@ -312,6 +328,7 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
@Override
public boolean isEmpty() { return this.isEmpty; }
@Override
public void markNotEmpty() { this.isEmpty = false; }
@Override
@@ -357,170 +374,6 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
}
@Override
public void sampleFrom(IFullDataSource fullDataSource)
{
DhSectionPos pos = fullDataSource.getSectionPos();
LodUtil.assertTrue(pos.getDetailLevel() < this.sectionPos.getDetailLevel());
LodUtil.assertTrue(pos.overlapsExactly(this.sectionPos));
if (fullDataSource.isEmpty())
{
return;
}
if (fullDataSource instanceof CompleteFullDataSource)
{
this.sampleFrom((CompleteFullDataSource) fullDataSource);
}
else if (fullDataSource instanceof HighDetailIncompleteFullDataSource)
{
this.sampleFrom((HighDetailIncompleteFullDataSource) fullDataSource);
}
else if (fullDataSource instanceof LowDetailIncompleteFullDataSource)
{
this.sampleFrom((LowDetailIncompleteFullDataSource) fullDataSource);
// LodUtil.assertNotReach("SampleFrom not implemented for ["+IFullDataSource.class.getSimpleName()+"] with class ["+fullDataSource.getClass().getSimpleName()+"].");
}
else
{
// TODO implement
LodUtil.assertNotReach("SampleFrom not implemented for [" + this.getClass().getSimpleName() + "] with class [" + fullDataSource.getClass().getSimpleName() + "].");
}
}
private void sampleFrom(HighDetailIncompleteFullDataSource sparseSource)
{
DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel());
DhSectionPos pos = sparseSource.getSectionPos();
this.isEmpty = false;
if (this.getDataDetailLevel() > this.sectionPos.getDetailLevel())
{
DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel());
int offsetX = dataLodPos.x - thisLodPos.x;
int offsetZ = dataLodPos.z - thisLodPos.z;
LodUtil.assertTrue(offsetX >= 0 && offsetX < WIDTH && offsetZ >= 0 && offsetZ < WIDTH);
int chunksPerData = 1 << (this.getDataDetailLevel() - HighDetailIncompleteFullDataSource.SPARSE_UNIT_DETAIL);
int dataSpan = this.sectionPos.getWidthCountForLowerDetailedSection(this.getDataDetailLevel());
for (int xOffset = 0; xOffset < dataSpan; xOffset++)
{
for (int zOffset = 0; zOffset < dataSpan; zOffset++)
{
SingleColumnFullDataAccessor column = sparseSource.tryGet(
xOffset * chunksPerData * sparseSource.dataPointsPerSection,
zOffset * chunksPerData * sparseSource.dataPointsPerSection);
if (column != null)
{
column.deepCopyTo(this.get(offsetX + xOffset, offsetZ + zOffset));
this.isColumnNotEmpty.set((offsetX + xOffset) * WIDTH + offsetZ + zOffset, true);
}
}
}
}
else
{
DhLodPos dataLodPos = pos.getSectionBBoxPos();
int lowerSectionsPerData = this.sectionPos.getWidthCountForLowerDetailedSection(dataLodPos.detailLevel);
if (dataLodPos.x % lowerSectionsPerData != 0 || dataLodPos.z % lowerSectionsPerData != 0)
{
return;
}
dataLodPos = dataLodPos.convertToDetailLevel(this.getDataDetailLevel());
int offsetX = dataLodPos.x - thisLodPos.x;
int offsetZ = dataLodPos.z - thisLodPos.z;
SingleColumnFullDataAccessor column = sparseSource.tryGet(0, 0);
if (column != null)
{
column.deepCopyTo(this.get(offsetX, offsetZ));
this.isColumnNotEmpty.set(offsetX * WIDTH + offsetZ, true);
}
}
}
private void sampleFrom(CompleteFullDataSource inputSource)
{
DhSectionPos inputPos = inputSource.getSectionPos();
this.isEmpty = false;
DhLodPos baseOffset = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel());
DhSectionPos inputOffset = inputPos.convertNewToDetailLevel(this.getDataDetailLevel());
int offsetX = inputOffset.getX() - baseOffset.x;
int offsetZ = inputOffset.getZ() - baseOffset.z;
int numberOfDataPointsToUpdate = WIDTH / this.sectionPos.getWidthCountForLowerDetailedSection(inputSource.getSectionPos().getDetailLevel()); // can be 0 if the input source is significantly smaller than this data source
// should be 1 at minimum, to prevent divide by zero errors (and because trying to get 0 data points doesn't make any sense)
numberOfDataPointsToUpdate = Math.max(1, numberOfDataPointsToUpdate);
int inputFractionWidth = inputSource.width() / numberOfDataPointsToUpdate;
for (int x = 0; x < numberOfDataPointsToUpdate; x++)
{
for (int z = 0; z < numberOfDataPointsToUpdate; z++)
{
SingleColumnFullDataAccessor thisDataColumn = this.get(offsetX + x, offsetZ + z);
SingleColumnFullDataAccessor inputDataColumn = inputSource.get(inputFractionWidth * x, inputFractionWidth * z);
inputDataColumn.deepCopyTo(thisDataColumn);
int notEmptyIndex = (offsetX + x) * WIDTH + (offsetZ + z);
this.isColumnNotEmpty.set(notEmptyIndex, true);
}
}
}
private void sampleFrom(LowDetailIncompleteFullDataSource spottySource)
{
DhSectionPos pos = spottySource.getSectionPos();
this.isEmpty = false;
this.downsampleFrom(spottySource);
if (this.getDataDetailLevel() > this.sectionPos.getDetailLevel())
{
DhLodPos thisLodPos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel());
DhLodPos dataLodPos = pos.getMinCornerLodPos(this.getDataDetailLevel());
int offsetX = dataLodPos.x - thisLodPos.x;
int offsetZ = dataLodPos.z - thisLodPos.z;
int dataWidth = this.sectionPos.getWidthCountForLowerDetailedSection(this.getDataDetailLevel());
for (int xOffset = 0; xOffset < dataWidth; xOffset++)
{
for (int zOffset = 0; zOffset < dataWidth; zOffset++)
{
this.isColumnNotEmpty.set((offsetX + xOffset) * WIDTH + offsetZ + zOffset, true);
}
}
}
else
{
DhLodPos dataPos = pos.getSectionBBoxPos();
int lowerSectionsPerData = this.sectionPos.getWidthCountForLowerDetailedSection(dataPos.detailLevel);
if (dataPos.x % lowerSectionsPerData != 0 || dataPos.z % lowerSectionsPerData != 0)
{
return;
}
DhLodPos basePos = this.sectionPos.getMinCornerLodPos(this.getDataDetailLevel());
dataPos = dataPos.convertToDetailLevel(this.getDataDetailLevel());
int offsetX = dataPos.x - basePos.x;
int offsetZ = dataPos.z - basePos.z;
this.isColumnNotEmpty.set(offsetX * WIDTH + offsetZ, true);
}
}
@Override
public IFullDataSource tryPromotingToCompleteDataSource()
{
@@ -533,15 +386,13 @@ public class LowDetailIncompleteFullDataSource extends FullDataArrayAccessor imp
{
return this;
}
isPromoted = true;
this.isPromoted = true;
return new CompleteFullDataSource(this.sectionPos, this.mapping, this.dataArrays);
}
@Override
public boolean hasBeenPromoted()
{
return isPromoted;
}
public boolean hasBeenPromoted() { return this.isPromoted; }
//================//
@@ -68,6 +68,7 @@ public interface IFullDataSource
void update(ChunkSizedFullDataAccessor data);
boolean isEmpty();
void markNotEmpty();
/** AKA; the max relative position that {@link IFullDataSource#tryGet(int, int)} can accept for either X or Z */
int getWidthInDataPoints();
@@ -84,6 +85,11 @@ public interface IFullDataSource
* @return null if the data doesn't exist
*/
SingleColumnFullDataAccessor tryGet(int relativeX, int relativeZ);
/**
* Attempts to get the data column for the given relative x and z position. <br>
* If no data exists yet an empty data column will be created.
*/
SingleColumnFullDataAccessor getOrCreate(int relativeX, int relativeZ);
FullDataPointIdMap getMapping();
@@ -19,7 +19,11 @@
package com.seibel.distanthorizons.core.dataObjects.fullData.sources.interfaces;
import com.seibel.distanthorizons.core.dataObjects.fullData.accessor.SingleColumnFullDataAccessor;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.CompleteFullDataSource;
import com.seibel.distanthorizons.core.pos.DhLodPos;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.util.LodUtil;
public interface IIncompleteFullDataSource extends IFullDataSource
{
@@ -28,7 +32,47 @@ public interface IIncompleteFullDataSource extends IFullDataSource
*
* This can be used to either merge same sized data sources or downsample to
*/
void sampleFrom(IFullDataSource fullDataSource);
default void sampleFrom(IFullDataSource inputSource)
{
DhSectionPos inputPos = inputSource.getSectionPos();
DhSectionPos thisPos = this.getSectionPos();
LodUtil.assertTrue(inputPos.getDetailLevel() < thisPos.getDetailLevel());
LodUtil.assertTrue(inputPos.overlapsExactly(this.getSectionPos()));
if (inputSource.isEmpty())
{
return;
}
this.markNotEmpty();
DhLodPos baseOffset = thisPos.getMinCornerLodPos(this.getDataDetailLevel());
DhSectionPos inputOffset = inputPos.convertNewToDetailLevel(this.getDataDetailLevel());
int offsetX = inputOffset.getX() - baseOffset.x;
int offsetZ = inputOffset.getZ() - baseOffset.z;
int numberOfDataPointsToUpdate = this.getWidthInDataPoints() / thisPos.getWidthCountForLowerDetailedSection(inputSource.getSectionPos().getDetailLevel()); // can be 0 if the input source is significantly smaller than this data source
// should be 1 at minimum, to prevent divide by zero errors (and because trying to get 0 or a fractional data point doesn't make any sense)
numberOfDataPointsToUpdate = Math.max(1, numberOfDataPointsToUpdate);
int inputFractionWidth = inputSource.getWidthInDataPoints() / numberOfDataPointsToUpdate;
for (int x = 0; x < numberOfDataPointsToUpdate; x++)
{
for (int z = 0; z < numberOfDataPointsToUpdate; z++)
{
SingleColumnFullDataAccessor thisDataColumn = this.getOrCreate(offsetX + x, offsetZ + z);
SingleColumnFullDataAccessor inputDataColumn = inputSource.tryGet(inputFractionWidth * x, inputFractionWidth * z);
if (inputDataColumn != null)
{
inputDataColumn.deepCopyTo(thisDataColumn);
}
}
}
}
/**
* Attempts to convert this {@link IIncompleteFullDataSource} into a {@link CompleteFullDataSource}.