private void TaskLoad(QuadTreeNode node) { try { var featureData = new GSFeatureDataNode(); DataByNode[node] = featureData; featureData.Features = ReadFeatures(node); foreach (var feature in featureData.Features) { var geographicCoordinates = new GeographicCoordinates(feature.Geometry.Centroid.Y, feature.Geometry.Centroid.X); var cartesianCoordinates = geographicCoordinates.TransformedWith(Database.Projection); float elev = Database.TerrainElevationAtLocation(geographicCoordinates); Vector3 position = new Vector3((float)cartesianCoordinates.X, elev, (float)cartesianCoordinates.Y); featureData.PositionByFeature[feature] = position; } } catch (Exception e) { Debug.LogException(e); } node.IsLoaded = true; node.IsLoading = false; }
void AddFeature(NetTopologySuite.Features.Feature feature, Color color, float elev) { Vector3[] points = null; if (feature.Geometry is NetTopologySuite.Geometries.LineString) { var linear = (NetTopologySuite.Geometries.LineString)feature.Geometry; if (!linear.IsValid) { return; } points = new Vector3[linear.Count]; for (int i = 0; i < points.Length; ++i) { var geographicCoordinates = new GeographicCoordinates(linear[i].Y, linear[i].X); var cartesianCoordinates = geographicCoordinates.TransformedWith(Database.Projection); points[i] = new Vector3((float)cartesianCoordinates.X, elev, (float)cartesianCoordinates.Y); } } if (points == null) { return; } var featureGameObject = new GameObject(); featureGameObject.transform.SetParent(Database.gameObject.transform); LineRenderer lineRenderer = featureGameObject.AddComponent <LineRenderer>(); lineRenderer.positionCount = points.Length; lineRenderer.SetPositions(points); lineRenderer.startWidth = 0.1f; lineRenderer.endWidth = 0.1f; lineRenderer.startColor = color; lineRenderer.endColor = color; lineRenderer.sharedMaterial = LineMaterial; }
public void HandleGlobeClick(GameObject sender, double lat, double lon) { if (cdbDatabase == null) { return; } if (lat < cdbDatabase.GeographicBounds.MinimumCoordinates.Latitude) { return; } if (lat > cdbDatabase.GeographicBounds.MaximumCoordinates.Latitude) { return; } if (lon < cdbDatabase.GeographicBounds.MinimumCoordinates.Longitude) { return; } if (lon > cdbDatabase.GeographicBounds.MaximumCoordinates.Longitude) { return; } ModeButton.UpdateState(2); OnFileSelect2(path); var geographicCoordinates = new GeographicCoordinates(lat, lon); var cartesianCoordinates = geographicCoordinates.TransformedWith(cdbDatabase.Projection); UserObject.transform.position = new Vector3((float)cartesianCoordinates.X, 20f, (float)cartesianCoordinates.Y); cdbDatabase.SetLODBracketsForDetail(); SetDetailMode.Invoke(true); OptionsCanvas.GetComponent <Options>().uiControlsCanvas.SetActive(OptionsCanvas.GetComponent <Options>().uiControlsCheckmark.activeSelf); sender.SetActive(false); }
public float TerrainElevationAtLocation(GeographicCoordinates location) { foreach (var elem in ActiveTiles) { Tile tile = elem.Value; if (location.Latitude < tile.GeographicBounds.MinimumCoordinates.Latitude) { continue; } if (location.Longitude < tile.GeographicBounds.MinimumCoordinates.Longitude) { continue; } if (location.Latitude > tile.GeographicBounds.MaximumCoordinates.Latitude) { continue; } if (location.Longitude > tile.GeographicBounds.MaximumCoordinates.Longitude) { continue; } var point = location.TransformedWith(Projection); var cartesianBounds = tile.GeographicBounds.TransformedWith(Projection); double spcX = (cartesianBounds.MaximumCoordinates.X - cartesianBounds.MinimumCoordinates.X) / tile.MeshDimension; double spcZ = (cartesianBounds.MaximumCoordinates.Y - cartesianBounds.MinimumCoordinates.Y) / tile.MeshDimension; double orgX = cartesianBounds.MinimumCoordinates.X; double orgZ = cartesianBounds.MinimumCoordinates.Y; float xComponent = (float)point.X - (float)orgX; float zComponent = (float)point.Y - (float)orgZ; int xIndex = Math.Min(tile.MeshDimension - 2, (int)Math.Floor(xComponent / spcX)); int zIndex = Math.Min(tile.MeshDimension - 2, (int)Math.Floor(zComponent / spcZ)); int[] indices = new int[4]; Vector3[] vertices = new Vector3[4]; indices[0] = zIndex * tile.MeshDimension + xIndex; indices[1] = indices[0] + 1; indices[2] = indices[0] + tile.MeshDimension; indices[3] = indices[0] + tile.MeshDimension + 1; for (int i = 0; i < indices.Length; ++i) { vertices[i] = tile.vertices[indices[i]]; } ref Vector3 a = ref vertices[0]; ref Vector3 b = ref vertices[1];
// This is the old, faster version that gets elevation at SW corner of a triangle pair. // TODO: if we want to keep this around for quick but inaccurate lookups, we could rename it appropriately public float TerrainElevationAtLocation(GeographicCoordinates location) { var tiles = ActiveTiles(); foreach (var tile in tiles) { if (location.Latitude < tile.GeographicBounds.MinimumCoordinates.Latitude) { continue; } if (location.Longitude < tile.GeographicBounds.MinimumCoordinates.Longitude) { continue; } if (location.Latitude > tile.GeographicBounds.MaximumCoordinates.Latitude) { continue; } if (location.Longitude > tile.GeographicBounds.MaximumCoordinates.Longitude) { continue; } var point = location.TransformedWith(Projection); var bounds = tile.GeographicBounds.TransformedWith(Projection); var spacingX = (bounds.MaximumCoordinates.X - bounds.MinimumCoordinates.X) / tile.MeshDimension; var spacingY = (bounds.MaximumCoordinates.Y - bounds.MinimumCoordinates.Y) / tile.MeshDimension; int indexX = (int)((point.X - bounds.MinimumCoordinates.X) / spacingX); int indexY = (int)((point.Y - bounds.MinimumCoordinates.Y) / spacingY); int index = (indexY * tile.MeshDimension) + indexX; if (index >= tile.vertices.Length) { index = tile.vertices.Length - 1; } var vertex = tile.vertices[index]; return(vertex.y); } return(float.MaxValue); }
//////////////////////////////////////////////////////////////////////////////// public void QuadTreeDataUpdate(QuadTreeNode node) // QuadTreeDelegate { #if UNITY_EDITOR if (node.IsActive) { var sw = node.GeographicBounds.MinimumCoordinates; var ne = node.GeographicBounds.MaximumCoordinates; var se = new GeographicCoordinates(sw.Latitude, ne.Longitude); var nw = new GeographicCoordinates(ne.Latitude, sw.Longitude); var swc = sw.TransformedWith(Database.Projection); var sec = se.TransformedWith(Database.Projection); var nwc = nw.TransformedWith(Database.Projection); var nec = ne.TransformedWith(Database.Projection); var elev = 100.0f; var swv = new Vector3((float)swc.X, elev, (float)swc.Y); var sev = new Vector3((float)sec.X, elev, (float)sec.Y); var nwv = new Vector3((float)nwc.X, elev, (float)nwc.Y); var nev = new Vector3((float)nec.X, elev, (float)nec.Y); Debug.DrawLine(swv, sev); Debug.DrawLine(swv, nwv); Debug.DrawLine(nwv, nev); Debug.DrawLine(sev, nev); } #endif if (!node.IsActive) { return; } if (!node.IsLoaded) { return; } if (Database.SystemMemoryLimitExceeded) { return; } //if (HasLoadedDecendents(node)) // return; var maxdist = Database.LODSwitchByObject[this].MaxDistance * Database.Projection.Scale; GSFeatureDataNode featureData = null; if (!DataByNode.TryGetValue(node, out featureData)) { return; } for (int i = 0; i < 1; ++i) { if (featureData.Features.Count < 1) { return; } if (Time.frameCount % 10 != 0) { var tempList = new List <GameObject>(); foreach (var go in featureData.LoadingGameObjects) { if (!go.GetComponent <Model>().Loaded) { tempList.Add(go); } } featureData.LoadingGameObjects = tempList; } if (featureData.LoadingGameObjects.Count > 4) { return; } int index = featureData.Features.Count - 1; var feature = featureData.Features[index]; var dist2 = (featureData.PositionByFeature[feature] - featureData.CameraPosition).sqrMagnitude; if (dist2 > maxdist * maxdist) { return; } lock (featureData.Features) { featureData.Features.RemoveAt(index); } try { var modelGameObject = GenerateModel(node, feature); if (modelGameObject != null) { featureData.GameObjects.Add(modelGameObject); featureData.LoadingGameObjects.Add(modelGameObject); } } catch (Exception e) { Debug.LogException(e); } } }
protected void Start() { if (Feature.Geometry == null) { Debug.LogErrorFormat("feature {0} has no geometry!!!", name); gameObject.SetActive(false); return; } if (!Feature.Geometry.IsSimple) { Debug.LogWarningFormat("feature {0} geometry is not simple!!!", name); } transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); var attributeNames = new List <string>(Feature.Attributes.GetNames()); var attributeValues = new List <object>(Feature.Attributes.GetValues()); for (int i = 0; i < attributeNames.Count; i++) { Attributes[attributeNames[i]] = attributeValues[i]; } // Copy the attributes into a field viewable from the inspector (for easy copy/paste debugging) string str = ""; for (int i = 0; i < attributeNames.Count; i++) { str += string.Format("{0}: {1}\n", attributeNames[i], attributeValues[i].ToString()); } //var multiPolygon = Feature.Geometry as NetTopologySuite.Geometries.MultiPolygon; //if (multiPolygon != null) // str += "MP\n"; textAttributes = str; name = GetName(); int id = -1; GetId(out id); if (id == contiguousUSA_Id) // skip contiguous US airspace that seems to be in every airspace shapefile { gameObject.SetActive(false); return; } Rebuild(); if (textInfo != null) { textInfo.text = name; textInfo.color = new Color(0.5f, 0.5f, 0.5f, 1f); if (vertices != null && vertices.Length > 0) { var geographicCoordinates = new GeographicCoordinates(Feature.Geometry.Centroid.Y, Feature.Geometry.Centroid.X); var cartesianCoordinates = geographicCoordinates.TransformedWith(Database.Projection); Vector3 vec = new Vector3((float)cartesianCoordinates.X, vertices[0].y, (float)cartesianCoordinates.Y); textInfo.transform.position = vec; textInfo.transform.localScale = Vector3.one; } } }
private bool ProcessGeometry(GeoAPI.Geometries.IGeometry geometry, float top, float bottom, GameObject node) { int index = 0; vertices = new Vector3[geometry.Coordinates.Length]; if (vertices.Length < 3) { return(false); } Vector3 referenceVec = Vector3.zero; foreach (var coordinate in geometry.Coordinates) { var geographicCoordinates = new GeographicCoordinates(coordinate.Y, coordinate.X); var cartesianCoordinates = geographicCoordinates.TransformedWith(Database.Projection); Vector3 vec = new Vector3((float)cartesianCoordinates.X, top, (float)cartesianCoordinates.Y); if (index == 0) { referenceVec = vec; } else { float distSq = Vector3.SqrMagnitude(vec - referenceVec); if (distSq > 250f * LOD * LOD) { referenceVec = vec; } else { continue; } } vertices[index] = vec; index++; } Array.Resize(ref vertices, index); // We have a poly which needs triangulation var triangulatorInput = new List <Vector2>(); var scratch = new List <Vector3>(); for (int i = 0; i < vertices.Length; i++) { if (i != vertices.Length - 1) // skip the last vertex so that triangulator plays nicely { triangulatorInput.Add(new Vector2(vertices[i].x, vertices[i].z)); } } for (int i = 0; i < vertices.Length - 1; i++) { scratch.Add(new Vector3(vertices[i].x, top, vertices[i].z)); } for (int i = 0; i < vertices.Length - 1; i++) { scratch.Add(new Vector3(vertices[i].x, bottom, vertices[i].z)); } // Store off the side vertices sideTriangles = new int[3 * scratch.Count]; int j = 0; for (int i = 0; i < sideTriangles.Length; i += 6, j++) { sideTriangles[i + 0] = j; sideTriangles[i + 1] = j + scratch.Count / 2; if (j + 1 == scratch.Count / 2) { j = -1; } sideTriangles[i + 2] = j + 1; sideTriangles[i + 3] = sideTriangles[i + 2]; sideTriangles[i + 4] = sideTriangles[i + 1]; sideTriangles[i + 5] = j + scratch.Count / 2 + 1; } var triangulator = new Triangulator(); var result = new List <Vector2>(); triangulator.Process(triangulatorInput, ref result); if (result.Count == 0 || result.Count % 3 != 0) { Debug.LogError(string.Format("{0}: triangulation failed!", name)); return(false); } // Add vertices for top and bottom caps vertices = new Vector3[2 * result.Count]; int v = 0; for (int i = 0; i < result.Count; i++, v++) { vertices[v].Set(result[i].x, top, result[i].y); } for (int i = 0; i < result.Count; i++, v++) { vertices[v].Set(result[i].x, bottom, result[i].y); } // Correct the side triangles list to match the new array for (int i = 0; i < sideTriangles.Length; i++) { int sideTriIndex = sideTriangles[i]; if (sideTriIndex > scratch.Count) { sideTriIndex = sideTriIndex - scratch.Count; } Vector3 sideVec = scratch[sideTriIndex]; for (int verticesIndex = 0; verticesIndex < vertices.Length; verticesIndex++) { Vector3 verticesVec = vertices[verticesIndex]; if (Mathf.Approximately(sideVec.x, verticesVec.x) && Mathf.Approximately(sideVec.y, verticesVec.y) && Mathf.Approximately(sideVec.z, verticesVec.z)) { sideTriangles[i] = verticesIndex; break; } } } var mesh = node.GetComponent <MeshFilter>().mesh; mesh.vertices = vertices; int topCapTriangleCount = mesh.vertices.Length / 2 / 3; int bottomCapTriangleCount = topCapTriangleCount; int sideTriangleCount = sideTriangles.Length / 3; int totalTriangleCount = topCapTriangleCount + bottomCapTriangleCount + sideTriangleCount; triangles = new int[3 * totalTriangleCount]; // Top cap int start = 0; int end = 3 * topCapTriangleCount; for (int i = start; i < end; i++) { triangles[i] = end - 1 - i; // start at the back, for winding purposes } // Bottom cap start = end; end = start + 3 * bottomCapTriangleCount; for (int i = start; i < end; i++) { triangles[i] = i; } // Sides start = end; end = start + 3 * sideTriangleCount; j = 0; for (int i = start; i < end; i++, j++) { triangles[i] = sideTriangles[j]; } mesh.triangles = triangles; normals = new Vector3[vertices.Length]; for (int i = 0; i < normals.Length; ++i) { normals[i] = Vector3.up; } mesh.normals = normals; return(true); }