Skip to content

Commit

Permalink
add PartIndexRange to octree nodes (range is no longer stored in Poin…
Browse files Browse the repository at this point in the history
…tSet, but just forwarded from root node)
  • Loading branch information
stefanmaierhofer committed Oct 10, 2023
1 parent 5efeaa0 commit 7fb98c9
Show file tree
Hide file tree
Showing 15 changed files with 320 additions and 186 deletions.
11 changes: 9 additions & 2 deletions src/Aardvark.Algodat.Tests/ImportTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,18 @@ public void CanImport_Empty()


var pointcloud = PointCloud.Chunks(Array.Empty<Chunk>(), config);
Assert.IsTrue(pointcloud.Root != null);
Assert.IsTrue(pointcloud.Root.Id == Guid.Empty.ToString());
Assert.IsTrue(pointcloud.Root.Value.IsEmpty);
Assert.IsTrue(pointcloud.Id == "test");
Assert.IsTrue(pointcloud.PointCount == 0);

var reloaded = config.Storage.GetPointSet("test");
Assert.IsTrue(reloaded.Id == "test");
Assert.IsTrue(reloaded.PointCount == 0);
Assert.IsTrue(reloaded.HasPartIndexRange == false);
Assert.IsFalse(reloaded.HasPartIndices);
Assert.IsFalse(reloaded.HasPartIndexRange);
Assert.IsNull(reloaded.PartIndexRange);
}

#endregion
Expand Down Expand Up @@ -410,7 +415,9 @@ public void CanImportPtsFile()
var pointset = PointCloud.Import(filename, config);
Assert.IsTrue(pointset != null);
Assert.IsTrue(pointset.PointCount == 3);
Assert.IsTrue(pointset.PartIndexRange == Range1i.Invalid);
Assert.IsFalse(pointset.HasPartIndices);
Assert.IsFalse(pointset.HasPartIndexRange);
Assert.IsNull(pointset.PartIndexRange);
}

[Test]
Expand Down
33 changes: 32 additions & 1 deletion src/Aardvark.Algodat.Tests/LodTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void LodCreationSetsLodPointCountCell()
var cs = ps.Map(_ => C4b.White);

var pointset = PointSet.Create(
storage, "test", ps.ToList(), cs.ToList(), null, null, null, partIndices: 42u, 5000,
storage, "test", ps.ToList(), cs.ToList(), null, null, null, null, 5000,
generateLod: false, isTemporaryImportNode: true, ct: default
);
pointset.Root.Value.ForEachNode(true, cell =>
Expand All @@ -54,6 +54,37 @@ public void LodCreationSetsLodPointCountCell()
});
}

[Test]
public void LodCreationSetsPartIndices()
{
var r = new Random();
var storage = PointSetTests.CreateStorage();

var ps = new V3d[42000].SetByIndex(_ => new V3d(r.NextDouble(), r.NextDouble(), r.NextDouble()));
var cs = ps.Map(_ => C4b.White);

var pointset = PointSet.Create(
storage, "test", ps.ToList(), cs.ToList(), null, null, null, partIndices: 42, 5000,
generateLod: false, isTemporaryImportNode: true, ct: default
);
pointset.Root.Value.ForEachNode(true, cell =>
{
Assert.IsTrue(cell.IsNotLeaf() || cell.Positions != null);
});

var config = ImportConfig.Default
.WithKey("Test")
.WithOctreeSplitLimit(1)
;
var lodded = pointset.GenerateLod(config);
lodded.Root.Value.ForEachNode(true, cell =>
{
Assert.IsTrue(cell.HasPartIndices);
Assert.IsTrue(cell.HasPartIndexRange);
Assert.IsTrue(cell.PartIndexRange == new Range1i(42, 42));
});
}

[Test]
public void LodPositions()
{
Expand Down
4 changes: 2 additions & 2 deletions src/Aardvark.Algodat.Tests/PartIndicesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ public void ExtendRangeBy()
}

[Test]
public void ExtendRangeBy_Fail()
public void ExtendRangeBy_null()
{
Assert.Catch(() => PartIndexUtils.ExtendRangeBy(new Range1i(7, 11), null!));
Assert.True(PartIndexUtils.ExtendRangeBy(new Range1i(7, 11), null) == new Range1i(7, 11));
}
}
70 changes: 35 additions & 35 deletions src/Aardvark.Algodat.Tests/PointSetTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public void PointSetAttributes_All()
var ks = new List<byte> { 42 };
var qs = new List<byte> { 17 };
var storage = PointCloud.CreateInMemoryStore(cache: default);
var pointset = PointSet.Create(storage, "test", ps, cs, ns, js, ks, qs, 1, generateLod: true, isTemporaryImportNode: false, default);
var pointset = PointSet.Create(storage, "test", ps, cs, ns, js, ks, qs, octreeSplitLimit: 1, generateLod: true, isTemporaryImportNode: false, default);
Assert.IsTrue(pointset.HasColors == true);
Assert.IsTrue(pointset.HasClassifications == true);
Assert.IsTrue(pointset.HasIntensities == true);
Expand All @@ -203,7 +203,7 @@ public void PointSetAttributes_NoLod()
var ks = new List<byte> { 42 };
var qs = new List<byte> { 17 };
var storage = PointCloud.CreateInMemoryStore(cache: default);
var pointset = PointSet.Create(storage, "test", ps, cs, ns, js, ks, qs, 1, generateLod: false, isTemporaryImportNode: true, default);
var pointset = PointSet.Create(storage, "test", ps, cs, ns, js, ks, qs, octreeSplitLimit: 1, generateLod: false, isTemporaryImportNode: true, default);
Assert.IsTrue(pointset.HasColors == true);
Assert.IsTrue(pointset.HasClassifications == true);
Assert.IsTrue(pointset.HasIntensities == true);
Expand Down Expand Up @@ -233,45 +233,45 @@ public void PointSet_PartIndexRange_No()
{
var ps = new List<V3d> { new(0.5, 0.5, 0.5) };
var storage = PointCloud.CreateInMemoryStore(cache: default);
var pointset = PointSet.Create(storage, "test", ps, null, null, null, null, null, 1, generateLod: false, isTemporaryImportNode: true, default);
Assert.IsTrue(pointset.PartIndexRange == Range1i.Invalid);
var pointset = PointSet.Create(storage, "test", ps, null, null, null, null, partIndices: null, 1, generateLod: false, isTemporaryImportNode: true, default);
Assert.IsTrue(pointset.HasPartIndexRange == false);
Assert.IsTrue(pointset.PartIndexRange == null);
}

[Test]
public void PointSet_PartIndexRange()
{
var ps = new List<V3d> { new(0.5, 0.5, 0.5) };
var storage = PointCloud.CreateInMemoryStore(cache: default);
var pointset = PointSet.Create(
storage, "test", ps, null, null, null, null, null, 1, generateLod: false, isTemporaryImportNode: true
)
.WithPartIndexRange(new(7, 11))
;
Assert.IsTrue(pointset.PartIndexRange == new Range1i(7, 11));
Assert.IsTrue(pointset.HasPartIndexRange == true);
}
//[Test]
//public void PointSet_PartIndexRange()
//{
// var ps = new List<V3d> { new(0.5, 0.5, 0.5) };
// var storage = PointCloud.CreateInMemoryStore(cache: default);
// var pointset = PointSet.Create(
// storage, "test", ps, null, null, null, null, null, 1, generateLod: false, isTemporaryImportNode: true
// )
// .WithPartIndexRange(new(7, 11))
// ;
// Assert.IsTrue(pointset.PartIndexRange == new Range1i(7, 11));
// Assert.IsTrue(pointset.HasPartIndexRange == true);
//}

[Test]
public void PointSet_PartIndexRange_Serialization()
{
var ps = new List<V3d> { new(0.5, 0.5, 0.5) };
var storage = PointCloud.CreateInMemoryStore(cache: default);
//[Test]
//public void PointSet_PartIndexRange_Serialization()
//{
// var ps = new List<V3d> { new(0.5, 0.5, 0.5) };
// var storage = PointCloud.CreateInMemoryStore(cache: default);

var pointset = PointSet.Create(
storage, "test", ps, null, null, null, null, null, 1, generateLod: false, isTemporaryImportNode: true
)
.WithPartIndexRange(new(7, 11))
;
// var pointset = PointSet.Create(
// storage, "test", ps, null, null, null, null, null, 1, generateLod: false, isTemporaryImportNode: true
// )
// .WithPartIndexRange(new(7, 11))
// ;

var json = pointset.ToJson();
var reloaded = PointSet.Parse(json, storage);
// var json = pointset.ToJson();
// var reloaded = PointSet.Parse(json, storage);

Assert.IsTrue(pointset.Id == reloaded.Id );
Assert.IsTrue(pointset.SplitLimit == reloaded.SplitLimit );
Assert.IsTrue(pointset.Root.Value.Id == reloaded.Root.Value.Id );
Assert.IsTrue(pointset.PartIndexRange == reloaded.PartIndexRange);
}
// Assert.IsTrue(pointset.Id == reloaded.Id);
// Assert.IsTrue(pointset.SplitLimit == reloaded.SplitLimit);
// Assert.IsTrue(pointset.Root.Value.Id == reloaded.Root.Value.Id);
// Assert.IsTrue(pointset.PartIndexRange == reloaded.PartIndexRange);
//}

[Test]
public void PointSet_PartIndexRange_Serialization_NoRange()
Expand All @@ -290,7 +290,7 @@ public void PointSet_PartIndexRange_Serialization_NoRange()
Assert.IsTrue(pointset.SplitLimit == reloaded.SplitLimit );
Assert.IsTrue(pointset.Root.Value.Id == reloaded.Root.Value.Id );
Assert.IsTrue(pointset.PartIndexRange == reloaded.PartIndexRange);
Assert.IsTrue(reloaded.PartIndexRange.IsInvalid);
Assert.IsTrue(reloaded.PartIndexRange == null);
}
}
}
26 changes: 19 additions & 7 deletions src/Aardvark.Data.Points.Base/PartIndexUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,19 +262,31 @@ object createArray4<T>(IReadOnlyList<T> first, IReadOnlyList<T> second) where T
return resultIndices;
}

public static Range1i ExtendRangeBy(in Range1i range, object partIndices)
public static Range1i? GetRange(object? qs) => qs switch
{
if (partIndices == null) throw new Exception("Invariant d781e171-41c3-4272-88a7-261cea302c18.");
null => null,
int x => new Range1i(x),
uint x => new Range1i((int)x),
byte[] xs => new Range1i(xs.Select(x => (int)x)),
short[] xs => new Range1i(xs.Select(x => (int)x)),
int[] xs => new Range1i(xs),
_ => throw new Exception($"Unexpected type {qs.GetType().FullName}. Error 8a975735-bb10-42bf-9f7f-4d570e5223e3.")
};

public static Range1i? ExtendRangeBy(in Range1i? range, object? partIndices)
{
if (range == null) return GetRange(partIndices);
if (partIndices == null) return range;

checked
{
return partIndices switch
{
int x => range.ExtendedBy(x),
uint x => range.ExtendedBy((int)x),
IList<byte> xs => range.ExtendedBy((Range1i)new Range1b(xs)),
IList<short> xs => range.ExtendedBy((Range1i)new Range1s(xs)),
IList<int> xs => range.ExtendedBy(new Range1i(xs)),
int x => range.Value.ExtendedBy(x),
uint x => range.Value.ExtendedBy((int)x),
IList<byte> xs => range.Value.ExtendedBy((Range1i)new Range1b(xs)),
IList<short> xs => range.Value.ExtendedBy((Range1i)new Range1s(xs)),
IList<int> xs => range.Value.ExtendedBy(new Range1i(xs)),

_ => throw new Exception(
$"Unexpected part indices type {partIndices.GetType().FullName}. " +
Expand Down
12 changes: 4 additions & 8 deletions src/Aardvark.Geometry.PointSet/Import/ImportChunks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static PointSet Chunks(IEnumerable<Chunk> chunks, ImportConfig config)
{
config.ProgressCallback(0.0);

var partIndicesRange = Range1i.Invalid;
var partIndicesRange = (Range1i?)null;
var chunkCount = 0;
chunks = chunks.Do(chunk =>
{
Expand Down Expand Up @@ -183,16 +183,12 @@ Chunk map(Chunk x, CancellationToken ct)
// create final point set with specified key (or random key when no key is specified)
var key = config.Key ?? Guid.NewGuid().ToString();
final = new PointSet(
storage : config.Storage ?? throw new Exception($"No storage specified. Error 5b4ebfec-d418-4ddc-9c2f-646d270cf78c."),
storage: config.Storage ?? throw new Exception($"No storage specified. Error 5b4ebfec-d418-4ddc-9c2f-646d270cf78c."),
pointSetId: key,
rootCellId: final.Root?.Value?.Id ?? Guid.Empty,
rootCellId: final.Root.Value!.Id,
splitLimit: config.OctreeSplitLimit
)
{
PartIndexRange = partIndicesRange
};
);
config.Storage.Add(key, final);

return final;
}

Expand Down
4 changes: 1 addition & 3 deletions src/Aardvark.Geometry.PointSet/Import/MapReduce.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ public static PointSet MapReduce(this IEnumerable<Chunk> chunks, ImportConfig co
var totalPointSetsCount = pointsets.Count;
if (totalPointSetsCount == 0)
{
var empty = new PointSet(config.Storage, key);
config.Storage.Add(key, empty);
return empty;
return PointSet.Empty;
}

var doneCount = 0;
Expand Down
20 changes: 20 additions & 0 deletions src/Aardvark.Geometry.PointSet/Octrees/IPointCloudNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public interface IPointCloudNode
/// </summary>
bool IsMaterialized { get; }

/// <summary>
/// True, if this is Node.Empty.
/// </summary>
bool IsEmpty { get; }

/// <summary>
/// Returns materialized version of this node.
/// E.g. a non-materialized filtered node is converted into a PointSetNode (which is stored in Storage).
Expand Down Expand Up @@ -146,6 +151,7 @@ public interface IPointCloudNode
/// <summary>
/// Durable definition aadbb622-1cf6-42e0-86df-be79d28d6757.
/// </summary>
[MemberNotNullWhen(true, nameof(BoundingBoxExactLocal))]
bool HasBoundingBoxExactLocal { get; }

/// <summary>
Expand All @@ -161,6 +167,7 @@ public interface IPointCloudNode
/// <summary>
/// Durable definition 7912c862-74b4-4f44-a8cd-d11ea1da9304.
/// </summary>
[MemberNotNullWhen(true, nameof(BoundingBoxExactGlobal))]
bool HasBoundingBoxExactGlobal { get; }

/// <summary>
Expand Down Expand Up @@ -244,14 +251,27 @@ public interface IPointCloudNode

#region PartIndices

/// <summary>
/// True if this node has a PartIndexRange.
/// </summary>
[MemberNotNullWhen(true, nameof(PartIndexRange))]
bool HasPartIndexRange { get; }

/// <summary>
/// Octree. Min and max part index in octree.
/// </summary>
Range1i? PartIndexRange { get; }

/// <summary>
/// True if this node has part indices.
/// </summary>
[MemberNotNullWhen(true, nameof(PartIndices))]
bool HasPartIndices { get; }

/// <summary>
/// Octree. Per-point or per-cell part indices.
/// </summary>

object? PartIndices { get; }

/// <summary>
Expand Down
Loading

0 comments on commit 7fb98c9

Please sign in to comment.