public void LoadPreview3D() { PointCloudTileSource tileSource = CurrentTileSource; Jacere.Core.Geometry.Extent3D extent = tileSource.Extent; Model3DGroup modelGroup = new Model3DGroup(); Model3DGroup modelSubGroup = new Model3DGroup(); modelGroup.Children.Add(modelSubGroup); Model3DGroup modelStitchingGroup = new Model3DGroup(); modelGroup.Children.Add(modelStitchingGroup); DirectionalLight lightSource = new DirectionalLight(System.Windows.Media.Colors.White, new Vector3D(-1, -1, -1)); modelGroup.Children.Add(lightSource); ModelVisual3D model = new ModelVisual3D(); model.Content = modelGroup; Jacere.Core.Geometry.Point3D centerOfMass = tileSource.CenterOfMass; Point3D lookatPoint = new Point3D(0, 0, 0); Point3D cameraPoint = new Point3D(0, extent.MinY - centerOfMass.Y, centerOfMass.Z - extent.MinZ + extent.RangeX); Vector3D lookDirection = lookatPoint - cameraPoint; lookDirection.Normalize(); PerspectiveCamera camera = new PerspectiveCamera(); camera.Position = cameraPoint; camera.LookDirection = lookDirection; camera.UpDirection = new Vector3D(0, 0, 1); camera.FieldOfView = 70; RenderOptions.SetEdgeMode(viewport, EdgeMode.Aliased); //viewport.ClipToBounds = false; //viewport.IsHitTestVisible = false; viewport.Camera = camera; viewport.Children.Add(model); m_tileModelCollection = modelSubGroup.Children; m_stitchingModelCollection = modelStitchingGroup.Children; m_backgroundWorker.RunWorkerAsync(CurrentTileSource); }
private void UpdateCurrentTile(PointCloudTile tile) { if (tile == null) { return; } List <PointCloudTile> tilesToLoad = new List <PointCloudTile>(); int pointsToLoad = 0; Model3DGroup emptyModelGroup = new Model3DGroup(); emptyModelGroup.Freeze(); bool isDirty = false; int radius = 2; int xMin = Math.Max(0, tile.Col - radius); int xMax = Math.Min(tile.Col + radius + 1, CurrentTileSource.TileSet.Cols); int yMin = Math.Max(0, tile.Row - radius); int yMax = Math.Min(tile.Row + radius + 1, CurrentTileSource.TileSet.Rows); for (int x = xMin; x < xMax; x++) { for (int y = yMin; y < yMax; y++) { PointCloudTile currentTile = CurrentTileSource.TileSet.GetTile(y, x); if (currentTile != null) { if (!m_loadedTiles.ContainsKey(currentTile)) { tilesToLoad.Add(currentTile); pointsToLoad += currentTile.PointCount; isDirty = true; } } } } PointCloudTile[] loadedTiles = m_loadedTiles.Keys.ToArray(); SortByDistanceFromTile(loadedTiles, tile); Array.Reverse(loadedTiles); // drop loaded tiles that are the farthest from the center int totalAllowedPoints = MAX_BUFFER_SIZE_BYTES / CurrentTileSource.PointSizeBytes; int loadedPoints = loadedTiles.Sum(t => t.PointCount); int potentialTotalPoints = loadedPoints + pointsToLoad; Dictionary <PointCloudTile, TileInfo3D> alteredTiles = new Dictionary <PointCloudTile, TileInfo3D>(); if (potentialTotalPoints > totalAllowedPoints) { int pointsToDrop = potentialTotalPoints - totalAllowedPoints; int i = 0; while (pointsToDrop > 0) { PointCloudTile currentTile = loadedTiles[i]; TileInfo3D tileInfo = m_tileInfo[currentTile]; GeometryModel3D model = m_loadedTiles[currentTile]; m_meshTileMap.Remove(model); m_loadedTiles.Remove(currentTile); //m_loadedTileBuffers.Remove(currentTile); // replace high-res tile with low-res geometry int modelIndex = tileInfo.Tile.ValidIndex; m_tileModelCollection[modelIndex] = tileInfo.LowResGeometry; // clear stitching m_stitchingModelCollection[modelIndex] = emptyModelGroup; tileInfo.ClearGeometry(); alteredTiles.Add(currentTile, tileInfo); pointsToDrop -= currentTile.PointCount; ++i; } } Jacere.Core.Geometry.Point3D centerOfMass = CurrentTileSource.CenterOfMass; PointCloudTile[] tilesToLoadArray = tilesToLoad.ToArray(); #warning sort so that disk reads are in order? or make a tile cache SortByDistanceFromTile(tilesToLoadArray, tile); foreach (PointCloudTile currentTile in tilesToLoadArray) { TileInfo3D tileInfo = m_tileInfo[currentTile]; CurrentTileSource.LoadTileGrid(currentTile, m_buffer, m_gridHighRes, m_quantizedGridHighRes); if (ENABLE_HEIGHT_EXAGGERATION) { m_gridHighRes.Multiply(m_heightExaggerationFactor, (float)centerOfMass.Z); } Jacere.Core.Geometry.Extent3D tileExtent = currentTile.Extent; MeshGeometry3D mesh = CurrentTileSource.GenerateMesh(m_gridHighRes, tileExtent); DiffuseMaterial material = new DiffuseMaterial(); if (USE_HIGH_RES_TEXTURE) { material.Brush = m_overviewTextureBrush; mesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(mesh, m_overallCenteredExtent, MathUtils.ZAxis); } else { material.Brush = m_solidBrush; } material.Freeze(); GeometryModel3D geometryModel = new GeometryModel3D(mesh, material); geometryModel.Freeze(); // replace low-res tile with high-res geometry int modelIndex = tileInfo.Tile.ValidIndex; m_tileModelCollection[modelIndex] = geometryModel; // clear stitching m_stitchingModelCollection[modelIndex] = emptyModelGroup; tileInfo.UpdateGeometry(geometryModel, m_gridHighRes); alteredTiles.Add(currentTile, tileInfo); m_meshTileMap.Add(geometryModel, currentTile); m_loadedTiles.Add(currentTile, geometryModel); //m_loadedTileBuffers.Add(currentTile, inputBuffer); } // in the future, I could have a list of which tiles need to be checked for stitching updates // go through the stitching groups and replace any empty ones with the appropriate stitching if (ENABLE_STITCHING && isDirty) { PointCloudTile[] alteredTileArray = alteredTiles.Keys.ToArray(); foreach (PointCloudTile currentTile in alteredTileArray) { // this amount of clearing is excessive. I only want to clear one of the edges if (currentTile.Col < CurrentTileSource.TileSet.Cols - 1) { PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row, currentTile.Col + 1); if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile)) { TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile]; if (!alteredTiles.ContainsKey(adjacentTile)) { alteredTiles.Add(adjacentTile, adjacentTileInfo); } m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup; adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.Left); } } if (currentTile.Row < CurrentTileSource.TileSet.Rows - 1) { PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row + 1, currentTile.Col); if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile)) { TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile]; if (!alteredTiles.ContainsKey(adjacentTile)) { alteredTiles.Add(adjacentTile, adjacentTileInfo); } m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup; adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.Top); } } if (currentTile.Col < CurrentTileSource.TileSet.Cols - 1 && currentTile.Row < CurrentTileSource.TileSet.Rows - 1) { PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row + 1, currentTile.Col + 1); if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile)) { TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile]; if (!alteredTiles.ContainsKey(adjacentTile)) { alteredTiles.Add(adjacentTile, adjacentTileInfo); } m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup; adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.TopLeft); } } } foreach (KeyValuePair <PointCloudTile, TileInfo3D> kvp in alteredTiles) { int i = kvp.Value.Tile.ValidIndex; Model3DGroup stitchingGroup = m_stitchingModelCollection[i] as Model3DGroup; if (stitchingGroup.Children.Count == 0) { GeometryModel3D geometryModel = m_tileModelCollection[i] as GeometryModel3D; Model3DGroup newStitchingGroup = GenerateTileStitching(CurrentTileSource, kvp.Value); if (newStitchingGroup.Children.Count > 0) { m_stitchingModelCollection[i] = newStitchingGroup; } } } //for (int i = 0; i < m_stitchingModelCollection.Count; i++) //{ // Model3DGroup stitchingGroup = m_stitchingModelCollection[i] as Model3DGroup; // // this is an incorrect condition, but it won't be apparent until I get multi-res stitching // if (stitchingGroup.Children.Count < 3) // { // GeometryModel3D geometryModel = m_tileModelCollection[i] as GeometryModel3D; // PointCloudTile currentTile = m_meshTileMap[geometryModel]; // TileInfo3D currentTileInfo = m_tileInfo[currentTile]; // Model3DGroup newStitchingGroup = GenerateTileStitching(CurrentTileSource, currentTileInfo); // if (newStitchingGroup.Children.Count > 0) // m_stitchingModelCollection[i] = newStitchingGroup; // } //} } }
private void OnBackgroundDoWork(object sender, DoWorkEventArgs e) { PointCloudTileSource tileSource = e.Argument as PointCloudTileSource; Jacere.Core.Geometry.Extent3D extent = tileSource.Extent; m_overviewTextureBrush = new ImageBrush(tileSource.Preview.Image); m_overviewTextureBrush.ViewportUnits = BrushMappingMode.Absolute; m_overviewTextureBrush.Freeze(); m_overviewMaterial = new DiffuseMaterial(m_overviewTextureBrush); m_overviewMaterial.Freeze(); if (tileSource != null) { previewImageGrid.MouseMove -= OnViewportGridMouseMove; Action <string> logAction = value => Context.WriteLine(value); m_progressManager = new BackgroundWorkerProgressManager(m_backgroundWorker, e, logAction, null); m_gridDimensionLowRes = (ushort)Math.Sqrt(VERTEX_COUNT_FAST / tileSource.TileSet.ValidTileCount); //m_gridDimensionHighRes = (ushort)Math.Sqrt(VERTEX_COUNT_LARGE / tileSource.TileSet.ValidTileCount); m_gridDimensionHighRes = (ushort)(Math.Sqrt(tileSource.TileSet.Density.MedianTileCount) / 3); //m_gridDimensionLowRes = (ushort)20; //m_gridDimensionHighRes = (ushort)40; Jacere.Core.Geometry.Point3D centerOfMass = tileSource.CenterOfMass; m_overallCenteredExtent = new Rect3D(extent.MinX - extent.MidpointX, extent.MinY - extent.MidpointY, extent.MinZ - centerOfMass.Z, extent.RangeX, extent.RangeY, extent.RangeZ); // load tiles KeyValuePair <Grid <int>, Grid <float> > gridsLowRes = tileSource.GenerateGrid(m_gridDimensionLowRes); m_gridLowRes = gridsLowRes.Value; m_quantizedGridLowRes = gridsLowRes.Key; KeyValuePair <Grid <int>, Grid <float> > gridsHighRes = tileSource.GenerateGrid(m_gridDimensionHighRes); m_gridHighRes = gridsHighRes.Value; m_quantizedGridHighRes = gridsHighRes.Key; foreach (PointCloudTile tile in tileSource.TileSet) { tileSource.LoadTileGrid(tile, m_buffer, m_gridLowRes, m_quantizedGridLowRes); if (ENABLE_HEIGHT_EXAGGERATION) { m_gridLowRes.Multiply(m_heightExaggerationFactor, (float)centerOfMass.Z); } Jacere.Core.Geometry.Extent3D tileExtent = tile.Extent; MeshGeometry3D mesh = tileSource.GenerateMesh(m_gridLowRes, tileExtent); DiffuseMaterial material = new DiffuseMaterial(); if (USE_LOW_RES_TEXTURE) { material.Brush = m_overviewTextureBrush; mesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(mesh, m_overallCenteredExtent, MathUtils.ZAxis); } else { material.Brush = m_solidBrush; } material.Freeze(); GeometryModel3D geometryModel = new GeometryModel3D(mesh, material); geometryModel.Freeze(); TileInfo3D tileInfo = new TileInfo3D(tile, geometryModel, m_gridLowRes); m_tileInfo.Add(tile, tileInfo); // add mappings m_meshTileMap.Add(geometryModel, tile); //m_lowResMap.Add(tile, geometryModel); if (!m_progressManager.Update(tile, geometryModel)) { break; } } //// test //foreach (double level in new double[] { centerOfMass.Z }) //{ // Grid<float> grid0 = new Grid<float>(20, 20, extent, false); // grid0.FillVal = (float)level; // grid0.Reset(); // grid0.FillVal = float.MinValue; // MeshGeometry3D mesh0 = tileSource.GenerateMesh(grid0, extent); // DiffuseMaterial material0 = new DiffuseMaterial(m_solidBrush); // material0.Freeze(); // GeometryModel3D geometryModel0 = new GeometryModel3D(mesh0, material0); // geometryModel0.Freeze(); // m_progressManager.Update(1.0f, geometryModel0); //} if (ENABLE_STITCHING) { int validStitchingIndex = 0; foreach (PointCloudTile tile in tileSource.TileSet) { TileInfo3D tileInfo = m_tileInfo[tile]; Model3DGroup stitchingGroup = GenerateTileStitching(tileSource, tileInfo); if (stitchingGroup != null) { ++validStitchingIndex; } if (!m_progressManager.Update(1.0f, stitchingGroup)) { break; } } } } }