/// <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); }
/// <summary> /// Gets kdtree path for a certain patch according to name, level and postype. /// </summary> public string GetKdTreePath(string patchName, int level, PositionsType posType) { var fileName = GetKdTreeFileName(patchName, level, posType); var kdTreePath = Path.Combine(RootPatchPath, fileName); return(kdTreePath); }
/// <summary> /// Takes first OPC in opcDirectory and returns its root patch info. This /// is typically needed to retrieve rendering offsets to prevent rounding errors. /// </summary> public static PatchFileInfo GetFirstPatchFileInfo(string opcDirectory, PositionsType posType) { var paths = OpcFileUtils.OpcPathsFromFolder(opcDirectory); var rootPatchPath = OpcFileUtils.GetRootPatchPath(paths.First()); return(PatchFileInfo.FromFile(rootPatchPath)); }
public static string GetKdTreeFileName(string patchName, int level, PositionsType posType) { string levelSub = level > -1 ? "-" + level : string.Empty; string positionSub = posType == PositionsType.V3dPositions ? string.Empty : "-2d"; var fileName = string.Format("{0}{1}{2}.{3}", patchName, levelSub, positionSub, Identifiers.KdTreeExt); return(fileName); }
/// <summary> /// Loads VertexGeometry from aara files. Beware: add Local2Global node for global space. /// </summary> /// <returns>Vertex Geometry in local OPC space.</returns> public static VertexGeometry LoadPatch(PatchFileInfo info, string basePath, PositionsType posType, bool loadNormals = true, bool loadTexCoords = true, bool loadDiffTex = true, bool loadHueTex = true, float maxTriangleSize = float.PositiveInfinity, bool loadAsDoubles = false) { Array positions; Symbol dataType; return(LoadPatch(info, basePath, posType, out positions, out dataType, loadNormals, loadTexCoords, loadDiffTex, loadHueTex, maxTriangleSize, loadAsDoubles)); }
/// <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 M44d GetLocal2Global(PositionsType posType) { if (posType == PositionsType.V3dPositions) { return(Local2Global); } else { return(Local2Global2d); } }
public Box3d GetLocalBoundingBox(PositionsType posType) { if (posType == PositionsType.V3dPositions) { return(LocalBoundingBox); } else { return(LocalBoundingBox2d); } }
public VertexGeometry Load(PatchFileInfo info, string basePath, PositionsType posType, bool loadTextures = true, bool loadNormals = true, bool loadTexCoords = true, float maxTriangleSize = float.PositiveInfinity) { //Array positions; //Symbol dataType; bool loadDiffTex = loadTextures ? LoadDiffTex : false; bool loadHueTex = loadTextures ? LoadHueTex : false; return(LoadPatch(info, basePath, posType, //out positions, out dataType, loadNormals, loadTexCoords, loadDiffTex, loadHueTex, maxTriangleSize)); }
public string GetPositionPath(PositionsType posType) { if (posType == PositionsType.V3dPositions) { return(Path.Combine(PatchPath, Info.Positions)); } else { return(Path.Combine(PatchPath, Info.Positions2d)); } }
public string GetKdTreeZeroPath(PositionsType posType) { if (posType == PositionsType.V3dPositions) { return(m_kdTreeZeroPath); } else { return(m_kdTreeZero2dPath); } }
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)); }
//static volatile int patchCounter = 0; /// <summary> /// Represents a single patch of ordered positions including coords, textures, etc. /// </summary> public Patch(PatchFileInfo info, string patchPath, int level, int maxLevel, PositionsType posType, bool invertZ = false, float maxTriangleSize = float.PositiveInfinity) : base(Identifier) { PatchFilePath = patchPath; Level = level; PatchFileInfo = info; MaxLevel = maxLevel; PositionsType = posType; InvertZ = invertZ; MaxTriangleSize = maxTriangleSize; //patchCounter++; //Report.Line("++" + patchCounter); }
/// <summary> /// Loads level N kdtree. If level N kdtree does not exist it is built from rootpatch. /// </summary> public static KdIntersectionTree BuildOrLoadKdTreeN(OpcPaths opcPaths, PositionsType posType, PatchFileInfo patchFileInfo) { KdIntersectionTree kdiTree = null; var kdTreeNPatch = opcPaths.GetKdTreeNPath(posType); if (!StorageConfig.FileExists(kdTreeNPatch)) { kdiTree = KdTreeUtils.BuildKdTreeForPatch(opcPaths.RootPatchName, -1, patchFileInfo, opcPaths, posType, saveTriangles: true); kdiTree.Save(opcPaths.RootPatchName); } else { kdiTree = Load.As <KdIntersectionTree>(opcPaths.GetKdTreeNPath(posType)); } return(kdiTree); }
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); } }
private static LazyKdTreeSet BuildLazyKdTreeSet(IEnumerable <PatchTree> patches, OpcPaths opcPaths, int level, PositionsType posType, bool overrideExisting, IObserver <float> progressObserver, CancellationToken cancelToken = default(CancellationToken), float maxTriangleSize = float.PositiveInfinity) { var placeHolders = new List <LazyKdTreeSet.KdTreePlaceHolder>(); var progressInc = 1f / patches.Count(); foreach (var p in patches) { cancelToken.ThrowIfCancellationRequested(); var kdtreePath = opcPaths.GetKdTreePath(p.Id, level, posType); if (overrideExisting || !StorageConfig.FileExists(kdtreePath)) { BuildKdTreeForPatch(p.Id, level, p.Info, opcPaths, posType, saveTriangles: false, saveKdTree: true, maxTriangleSize: maxTriangleSize); } // Create place holders placeHolders.Add(new LazyKdTreeSet.KdTreePlaceHolder() { BoundingBox = p.Info.GetGlobalBoundingBox(posType), Affine = p.Info.GetLocal2Global(posType), Path = opcPaths.GetKdTreePath(p.Id, level, posType), ObjectSetPath = p.GetPositionPath(posType) }); if (progressObserver != null) { progressObserver.OnNext(progressInc); } } if (progressObserver != null) { progressObserver.OnCompleted(); } return(new LazyKdTreeSet(placeHolders)); }
/// <summary> /// Builds kdtree for specific patch. /// Kdtree is built according to specified positions type and hierarchy level. /// </summary> private static KdIntersectionTree BuildKdTreeForPatch( string patchName, int level, PatchFileInfo info, OpcPaths paths, PositionsType posType, bool saveTriangles = false, bool saveKdTree = true, float maxTriangleSize = float.PositiveInfinity) { var path = Path.Combine(paths.PatchesSubDir, patchName); var patchGeometry = new TriangleSet(); //var patchGeometryTest = new TriangleSet(); if ((maxTriangleSize < float.PositiveInfinity) && (maxTriangleSize > 0.000001f)) { patchGeometry = PatchLoadingStrategy.LoadPatchTriangleSetWithoutOversizedTriangles(info, path, posType, maxTriangleSize); //patchGeometryTest = PatchLoadingStrategy.LoadPatchTriangleSet(info, path, posType); } else { patchGeometry = PatchLoadingStrategy.LoadPatchTriangleSet(info, path, posType); } KdIntersectionTree kdIntTree = new KdIntersectionTree(patchGeometry, KdIntersectionTree.BuildFlags.MediumIntersection | KdIntersectionTree.BuildFlags.Hierarchical); if (!saveTriangles) { kdIntTree.ObjectSet = null; } if (saveKdTree) { var kdTreePath = paths.GetKdTreePath(patchName, level, posType); kdIntTree.Save(kdTreePath); } return(kdIntTree); }
/// <summary> /// NOT TESTED /// </summary> private static KdTreeSet BuildConcreteKdTreeSet(IEnumerable <PatchTree> patches, OpcPaths opcPaths, int level, PositionsType posType, bool overrideExisting, IObserver <float> progressObserver, CancellationToken cancelToken = default(CancellationToken), float maxTriangleSize = float.PositiveInfinity) { var kdTrees = new List <ConcreteKdIntersectionTree>(); var progressInc = 1f / patches.Count(); foreach (var p in patches) { cancelToken.ThrowIfCancellationRequested(); KdIntersectionTree tree; var kdtreePath = opcPaths.GetKdTreePath(p.Id, level, posType); if (overrideExisting || !StorageConfig.FileExists(kdtreePath)) { tree = BuildKdTreeForPatch(p.Id, level, p.Info, opcPaths, posType, saveTriangles: true, saveKdTree: false, maxTriangleSize: maxTriangleSize); } else { tree = Load.As <KdIntersectionTree>(kdtreePath); } kdTrees.Add(tree.ToConcreteKdIntersectionTree()); if (progressObserver != null) { progressObserver.OnNext(progressInc); } } if (progressObserver != null) { progressObserver.OnCompleted(); } return(new KdTreeSet(kdTrees)); }
//~Patch() //{ // patchCounter--; // Report.Line("--" + patchCounter); //} public static Patch FromFile(string patchXmlPath, int level, int maxLevel, PositionsType posType) { return(new Patch(PatchFileInfo.FromFile(patchXmlPath), patchXmlPath, level, maxLevel, posType)); }
/// <summary> /// Loads VertexGeometry from aara files. Beware: add Local2Global node for global space. /// </summary> /// <param name="positions">Raw positions, read from aara files for possible further processing.</param> /// <param name="dataType">DataType of positions.</param> /// <returns>Vertex Geometry in local OPC space.</returns> public static VertexGeometry LoadPatch(PatchFileInfo info, string basePath, PositionsType posType, out Array positions, out Symbol dataType, bool loadNormals = true, bool loadTexCoords = true, bool loadDiffTex = true, bool loadHueTex = true, float maxTriangleSize = float.PositiveInfinity, bool loadAsDoubles = false) { var vg = new VertexGeometry(GeometryMode.TriangleList); positions = null; // load metadata var aara3dPos = AaraData.FromFile( Path.Combine(basePath, posType == PositionsType.V3dPositions ? info.Positions : info.Positions2d)); dataType = aara3dPos.DataTypeAsSymbol; var resolution = new V2i(aara3dPos.Size); if (resolution.AnySmaller(2)) { Report.Warn("ignoring patch {0} due to invalid gridresolution {1}", basePath, resolution); return(null); } // load positions positions = aara3dPos.LoadElements(); var positions3d = loadAsDoubles ? positions : AaraData.ConvertArrayToV3fs[aara3dPos.DataTypeAsSymbol](positions); //var positionsV3 = loadAsDoubles ? // (Array)AaraData.ConvertArrayToV3ds[aara3dPos.DataTypeAsSymbol](positions) : // (Array); vg.Positions = positions3d; var p = AaraData.ConvertArrayToV3fs[aara3dPos.DataTypeAsSymbol](positions); // calculate indices var invalidPoints = OpcIndices.GetInvalidPositions(p); // limit triangle size if ((maxTriangleSize < float.PositiveInfinity) && (maxTriangleSize > 0.000001f)) { vg.Indices = OpcIndices.ComputeIndexArray(resolution, invalidPoints.ToList(), p, maxTriangleSize); } else { vg.Indices = OpcIndices.ComputeIndexArray(resolution, invalidPoints.ToList()); } // load normals if (loadNormals) { var normalPath = Path.Combine(basePath, "Normals.aara"); if (StorageConfig.FileExists(normalPath)) { var normals = AaraData.FromFile(normalPath); var normals3d = AaraData.ConvertArrayToV3fs[normals.DataTypeAsSymbol](normals.LoadElements()); vg.Normals = normals3d; } } // load coordinates vg.Coordinates = new CoordinatesMap(); if (loadTexCoords) { var coordPath = Path.Combine(basePath, info.Coordinates.First()); var coordinates = AaraData.FromFile(coordPath).LoadElements() as V2f[]; vg.Coordinates[VertexGeometry.Property.DiffuseColorCoordinates] = coordinates; } // load textures vg.Textures = new TexturesMap(); if (loadDiffTex) { var texFile = Path.ChangeExtension(info.Textures.First(), ".dds"); var texPath = Path.GetFullPath(Path.Combine(basePath, @"..\..\images", texFile)); if (StorageConfig.FileExists(texPath)) { var img = Convertible.FromFile(texPath); vg.Textures[VertexGeometry.Property.DiffuseColorTexture] = new Aardvark.Rendering.Texture(img) { ForceImmediateUpload = false }; } } if (loadHueTex) { vg.Textures[VertexGeometry.Property.LightMapTexture] = new Aardvark.Rendering.Texture(Resources.HueColorMap.Convertible()); } return(vg); }
/// <summary> /// Gets Triangle Set loaded from AaraData and transformed to global space. /// </summary> public static TriangleSet LoadPatchTriangleSet(PatchFileInfo info, string basePath, PositionsType posType) { var vg = LoadPatch(info, basePath, posType, false, false, false, false, loadAsDoubles: false); if (vg == null) { return(new TriangleSet()); } var trafo = posType == PositionsType.V3dPositions ? info.Local2Global : info.Local2Global2d; vg.TransformV3d(trafo); var triangles = vg.Triangles .Where(x => !x.Point0.Position.IsNaN && !x.Point1.Position.IsNaN && !x.Point2.Position.IsNaN) .Select(x => x.ToTriangle3d()); return(new TriangleSet(triangles)); }
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)); }
public static Subject <float> GetKdTreeProgressObserver(OpcPaths opcPaths, int level, PositionsType posType) { var opcName = Path.GetFileName(opcPaths.BasePath); float totalProgress = 0f; var progress = new Subject <float>(); progress.Sample(TimeSpan.FromSeconds(1.0)).Subscribe(inc => { totalProgress += inc; Report.Line("{0} - {1} - {2} - Progress {3:0.0}%", opcName, level, posType.ToString(), totalProgress * 100.0); //Report.ProgressDelta(tup.E1); }); return(progress); }
/// <summary> /// Gets Triangle Set loaded from AaraData and transformed to global space. /// Triangles side length < maxTriiangleSize /// </summary> public static TriangleSet LoadPatchTriangleSetWithoutOversizedTriangles(PatchFileInfo info, string basePath, PositionsType posType, float maxTriangleSize = float.PositiveInfinity) { var vg = LoadPatch(info, basePath, posType, false, false, false, false); if (vg == null) { return(new TriangleSet()); } vg.Transform( posType == PositionsType.V3dPositions ? info.Local2Global : info.Local2Global2d); var triangles = vg.Triangles .Where(x => !x.Point0.Position.IsNaN && !x.Point1.Position.IsNaN && !x.Point2.Position.IsNaN && (V3d.Distance(x.Point0.Position, x.Point1.Position) < maxTriangleSize) && (V3d.Distance(x.Point0.Position, x.Point2.Position) < maxTriangleSize) && (V3d.Distance(x.Point1.Position, x.Point2.Position) < maxTriangleSize)) .Select(x => x.ToTriangle3d()); return(new TriangleSet(triangles)); }
/// <summary> /// Gets the aggregate kdtree path according to the specified level and positions type. Level -1 indicates /// the path for a Level N kdtree /// </summary> public string GetAggKdTreePath(int level, PositionsType posType) { return(GetKdTreePath(RootPatchName, level, posType)); }