/// <param name="level">Selects hierarchy Level the kdtree is built of (-1 shouldn't be used, use BuildKdtreeN instead).</param> /// <param name="progressObserver">Reports progress in increments which sum up to 1.</param> public static void BuildKdTreeForLevel( OpcPaths opcPaths, int level, PositionsType posType, bool lazy = true, bool overrideExisting = false, IObserver <float> progressObserver = null, CancellationToken cancelToken = default(CancellationToken), PatchHierarchyInfo hierarchyInfo = null, float maxTriangleSize = float.PositiveInfinity) { #region Preconditions if (hierarchyInfo == null) { hierarchyInfo = PatchHierarchyInfo.BuildOrLoadCache(opcPaths); } if (posType == PositionsType.V2dPositions && !hierarchyInfo.PatchTree.Info.Has2dData) { Report.Warn("KdTreeUtils: 2d KdTree needs 2d data to be able to get built."); progressObserver.OnNext(1f); progressObserver.OnCompleted(); return; } opcPaths.SetRootPatchName(hierarchyInfo.RootPatch); var kdTreeSetPath = opcPaths.GetAggKdTreePath(level, posType); if (!overrideExisting && StorageConfig.FileExists(kdTreeSetPath)) { progressObserver.OnNext(1f); progressObserver.OnCompleted(); return; } #endregion hierarchyInfo.PatchTree.CreatePatchPaths(opcPaths.PatchesSubDir); // Get geometry patchinformations for certain level with a valid boundingbox var patchTrees = hierarchyInfo.RetrievePatchTreesOfLevel(level) .Where(x => !x.Info.GlobalBoundingBox.IsInvalid); IIntersectableObjectSet kdTree; var buildFlags = KdIntersectionTree.BuildFlags.Hierarchical | KdIntersectionTree.BuildFlags.EmptySpaceOptimization; // Decide lazy or eager if (lazy) { kdTree = BuildLazyKdTreeSet(patchTrees, opcPaths, level, posType, overrideExisting, progressObserver, cancelToken, maxTriangleSize); buildFlags |= KdIntersectionTree.BuildFlags.OptimalRaytracing; } else { kdTree = BuildConcreteKdTreeSet(patchTrees, opcPaths, level, posType, overrideExisting, progressObserver, cancelToken, maxTriangleSize); buildFlags |= KdIntersectionTree.BuildFlags.MediumIntersection; } // Save Kd-Tree var aggrTree = new KdIntersectionTree(kdTree, buildFlags); aggrTree.Save(kdTreeSetPath, waitMode: WaitMode.WaitUntilFinished); }
public static bool HasKdTreeForGeoResolution(OpcPaths opcPaths, double minGeometricResolution, PositionsType posType) { var hierarchyInfo = PatchHierarchyInfo.BuildOrLoadCache(opcPaths); var level = GetLevelFromResolution(hierarchyInfo.AvgGeometrySizes, minGeometricResolution); return(HasKdTreeForLevel(opcPaths, level, posType, hierarchyInfo)); }
/// <param name="minGeometricResolution">Used to select an appropriate level in the hierarchy to meet the specified minimum resolution criterion.</param> /// <param name="progressObserver">Reports progress in increments which sum up to 1.</param> public static void BuildKdTreeForGeoResolution( OpcPaths opcPaths, double minGeometricResolution, PositionsType posType, bool lazy = true, bool overrideExisting = false, IObserver <float> progressObserver = null, CancellationToken cancelToken = default(CancellationToken)) { var hierarchyInfo = PatchHierarchyInfo.BuildOrLoadCache(opcPaths); var level = GetLevelFromResolution(hierarchyInfo.AvgGeometrySizes, minGeometricResolution); BuildKdTreeForLevel(opcPaths, level, posType, lazy, overrideExisting, progressObserver, cancelToken, hierarchyInfo); }
public static bool HasKdTreeForLevel(OpcPaths opcPaths, int level, PositionsType posType, PatchHierarchyInfo hierarchyInfo = null) { if (hierarchyInfo == null) { hierarchyInfo = PatchHierarchyInfo.BuildOrLoadCache(opcPaths); } opcPaths.SetRootPatchName(hierarchyInfo.RootPatch); var kdTreeSetPath = opcPaths.GetAggKdTreePath(level, posType); return(StorageConfig.FileExists(kdTreeSetPath)); }
public static void BuildKdtreeN(OpcPaths opcPaths, PositionsType posType, bool overrideExisting = false, float maxTriangleSize = float.PositiveInfinity) { var hierarchyInfo = PatchHierarchyInfo.BuildOrLoadCache(opcPaths); var patchInfo = hierarchyInfo.PatchTree.Info; opcPaths.SetRootPatchName(hierarchyInfo.RootPatch); if (posType == PositionsType.V2dPositions && !patchInfo.Has2dData) { Report.Warn("KdTreeUtils: 2d KdTreeN needs 2d data to be able to get built."); return; } if (overrideExisting || !StorageConfig.FileExists(opcPaths.GetKdTreeNPath(posType))) { BuildKdTreeForPatch(opcPaths.RootPatchName, -1, patchInfo, opcPaths, posType, true, true, maxTriangleSize); } }
/// <summary> /// Builds look up table for profile "intersection" in 2d data. /// </summary> public static void BuildLookUpTable(OpcPaths opcPaths, bool overrideExisting = false, IObserver <Tup <float, string> > progress = null, CancellationToken cancelToken = default(CancellationToken)) { if (!overrideExisting && StorageConfig.FileExists(opcPaths.ProfileLutPath)) { if (progress != null) { progress.OnNext(Tup.Create(1f, "")); progress.OnCompleted(); } Report.Line("LookUpTable already exists at {0}", opcPaths.ProfileLutPath); } // PatchHierarchyInfo var info = PatchHierarchyInfo.BuildOrLoadCache(opcPaths); info.PatchTree.CreatePatchPaths(opcPaths.PatchesSubDir); // Level 0 Patches var lvl0Patches = info.RetrievePatchTreesOfLevel(0); if (progress != null) { progress.OnNext(Tup.Create(.1f, "")); } // group by BB-2d: Min-X, Max-X var patchesGroupedByBB = lvl0Patches .GroupBy(patchTree => Tup.Create(patchTree.Info.GlobalBoundingBox2d.Min.X, patchTree.Info.GlobalBoundingBox2d.Max.X)).ToArray(); var entries = new List <ProfileLookUpTableEntry>(); #region Create ProfileLookUpTableEntries for (int index = 0; index < patchesGroupedByBB.Count(); index++) { if (cancelToken.IsCancellationRequested) { if (progress != null) { progress.OnNext(Tup.Create(0f, "Building LookUpTabele cancelled.")); } cancelToken.ThrowIfCancellationRequested(); } //sort patches according to their b (sv_b_r) value var patchesGroupedBySvBR = patchesGroupedByBB[index] .OrderBy(k => k.Info.GlobalBoundingBox2d.Min.Y); var fileHandleList = new List <PatchFileHandle>(); #region build PatchFileHandles foreach (var patchTree in patchesGroupedBySvBR) { if (patchTree.Info.Positions2d.IsNullOrEmpty()) { Report.Warn("ProfileLutCreation: Skipping Patchtree {0}, because of missing 2d positions.", patchTree.Id); if (progress != null) { progress.OnNext(Tup.Create(0f, "ProfileLutCreation: Skipping Patchtree " + patchTree.Id + ", because of missing 2d positions.")); } continue; } var pos2dPath = patchTree.GetPositionPath(PositionsType.V2dPositions); //CAUTION absolute path needs to be repaired during loading var file = AaraData.FromFile(pos2dPath); file.SourceFileName = string.Empty; fileHandleList.Add(new PatchFileHandle() { PatchTree = patchTree, FileLoader = file, }); } #endregion // Create ProfileLookupTableEntries var firstPatchBB = patchesGroupedBySvBR.First().Info.GlobalBoundingBox2d; entries.Add(new ProfileLookUpTableEntry() { Index = index, SvRange = new Range1d(firstPatchBB.Min.X, firstPatchBB.Max.X), FileHandles = fileHandleList, }); var progressInc = 0.8f / patchesGroupedByBB.Count(); if (progress != null) { progress.OnNext(Tup.Create(progressInc, "")); } } entries.Reverse(); #endregion #region Save LUT var lut = new ProfileLookUpTable() { SvRange = new Range1d(info.PatchTree.Info.GlobalBoundingBox2d.Min.X, info.PatchTree.Info.GlobalBoundingBox2d.Max.X), Entries = entries, AvgGeomtrySize = info.AvgGeometrySizes.First() }; lut.Save(opcPaths.ProfileLutPath); #endregion if (progress != null) { progress.OnNext(Tup.Create(0.1f, "")); progress.OnCompleted(); } }