Пример #1
0
        public void GenerateTriangles()
        {
            GeometryUtility.CPoint2D[] polyVertices = new GeometryUtility.CPoint2D[PointVms.Count];

            int i = 0;

            foreach (LfDragablePointViewModel dpvm in PointVms)
            {
                // Before triangles are generated we must reorder the identities of the
                // vertices to make them consequtive
                dpvm.Id = (uint)(i + 1);

                polyVertices[i] = new GeometryUtility.CPoint2D(dpvm.PosX, dpvm.PosY, dpvm.Id);

                i++;
            }

            PolygonCuttingEar.CPolygonShape poly = new PolygonCuttingEar.CPolygonShape(polyVertices);

            poly.CutEar();

            if (LocalModelObject != null)
            {
                LocalModelObject.Triangles.Clear();
                _triangles.Clear();

                for (int n = 0; n < poly.NumberOfPolygons; n++)
                {
                    Triangle nt = new Triangle((uint)n + 1, poly.Polygons(n)[0].Id, poly.Polygons(n)[1].Id, poly.Polygons(n)[2].Id);
                    LocalModelObject.Triangles.Add(nt);

                    TriangleViewModel ntvm = new TriangleViewModel(this, nt);
                    _triangles.Add(ntvm);
                }
            }
        }
Пример #2
0
        static void MainParallel(string[] args, MapProperties properties , string exportPath)
        {
            int max = 25;
            int current = 0;

            GaPSlabsVersion version = new GaPSlabsVersion("GaPSLabs 3D City Generator 1.0", 1, 0);

            if (!System.IO.Directory.Exists(exportPath))
                System.IO.Directory.CreateDirectory(exportPath);

            Random rand = new Random((int)DateTime.Now.Ticks);
            MapProperties mapboundaries = new MapProperties();
            if (properties != null)
                mapboundaries = properties;
            else
            {
                //mapboundaries.minLat = 59.3457;
                //mapboundaries.maxLat = 59.3527;
                //mapboundaries.minLon = 18.0609;
                //mapboundaries.maxLon = 18.0765;
                //mapboundaries.Name = "KTH Area";
                mapboundaries.minLat = 59.2294;
                mapboundaries.maxLat = 59.4800;
                mapboundaries.minLon = 17.7649;
                mapboundaries.maxLon = 18.2977;
                mapboundaries.Name = "KTH Area";
                mapboundaries.BuildingLineThickness = 0.6f;
                mapboundaries.RoadLineThickness = 0.2f;
                mapboundaries.Scale = new Vector2(16, 16);
                mapboundaries.BuildingColor = new Color(0, 255, 0);
                mapboundaries.LineColorStart = new Color(255, 255, 0);
                mapboundaries.LineColorEnd = new Color(255, 255, 0);
                mapboundaries.BuildingMaterial = null;
                mapboundaries.RoadMaterial = new Material("Route");
                mapboundaries.CycleWayMaterial = new Material("RouteCycleway");
                mapboundaries.FootWayMaterial = new Material("RouteFootway");
                mapboundaries.RailWayMaterial = null;
                mapboundaries.StepsMaterial = new Material("RouteSteps");
                mapboundaries.RoadWidth = 1;// 0.05f;
                mapboundaries.CyclewayWidth = 0.05f;
                mapboundaries.FootwayWidth = 0.05f;
                mapboundaries.BuildingHeight = 7.5f;
                mapboundaries.CombinationOptimizationSize = new Vector2(100, 100);
            }

            bool GenerateBuildingShapes = true;
            bool GenerateRoads = true;
            bool GenerateBuildings = true;
            bool CorrectAspectRatio = false;
            
            OSMPostgresqlSource source = new OSMPostgresqlSource(connPostGreSql);
            var bounds = source.Bounds;

            float[] minmaxX;
            float[] minmaxY;

            minmaxX = new float[] { 0, 5000 };
            minmaxY = new float[] { 0, 5000 };

            Bounds SelectedArea = new Bounds();
            float LineWidth = 0.4f;
            float BuildingWidth = 0.6f;

            float height;
            height = 7.5f;

            SelectedArea.minlat = mapboundaries.minLat;
            SelectedArea.maxlat = mapboundaries.maxLat;
            SelectedArea.minlon = mapboundaries.minLon;
            SelectedArea.maxlon = mapboundaries.maxLon;
            minmaxX = mapboundaries.minMaxX;
            minmaxY = mapboundaries.minMaxY;
            if (CorrectAspectRatio)
            {
                var aspectRatio = System.Math.Abs(SelectedArea.maxlat - SelectedArea.minlat) / System.Math.Abs(SelectedArea.maxlon - SelectedArea.minlon);
                minmaxY[1] = (float)(minmaxX[1] * aspectRatio);
            }

            LineWidth = mapboundaries.RoadLineThickness;
            BuildingWidth = mapboundaries.BuildingLineThickness;
            height = mapboundaries.BuildingHeight;
            if (height < 4)
                height = 4;

            string[] ways = null;
            if (!GenerateRoads)
            {
                string[][] buildingtag = new string[1][];
                buildingtag[0] = new string[] { "building", "" }; // NOTE: building tag in OSM is in lower case.
                ways = source.GetWayIdsWithTags(SelectedArea, buildingtag);
            }
            else
                if (!GenerateBuildings)
                {
                    string[][] roadtag = new string[1][];
                    roadtag[0] = new string[] { "highway", "" }; // NOTE: highway tag in OSM is in lower case.
                    ways = source.GetWayIdsWithTags(SelectedArea, roadtag);
                }
                else
                    ways = source.GetWayIdsInBound(SelectedArea);
            
            float[] MinPointOnArea = CoordinateConvertor.SimpleInterpolation((float)SelectedArea.minlat, (float)SelectedArea.minlon, bounds, minmaxX, minmaxY);

            int direction = -1;
            Vector3 MinPointOnMap = new Vector3(direction * MinPointOnArea[0], 0, MinPointOnArea[1]);
            mapboundaries.MinPointOnMap = MinPointOnMap;

            int totalWays = ways.Length;
            int progress = 0;
            //List<OsmNode> WayNodes;
            //List<Tag> WayTags;
            //Vector3[] tempPoints;
            //PolygonCuttingEar.CPolygonShape shp;
            Console.WriteLine("Started at " + DateTime.Now + " for " + ways.Length + " objects.");
            var duration = Stopwatch.StartNew();
            Parallel.ForEach<string>(ways, (FirstWay, state) =>
            //foreach (var FirstWay in ways)
            {
                var w = new Way(FirstWay);
                List<OsmNode> WayNodes;
                List<Tag> WayTags;
                using (Npgsql.NpgsqlConnection con = new Npgsql.NpgsqlConnection(connPostGreSql))
                {
                    con.Open();
                    WayNodes = w.GetNodesPostgreSQL(FirstWay, con);
                    WayTags = w.GetTagsPostgreSQL(FirstWay, con);
                    con.Close();
                }
                if (WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "landuse" || i.KeyValueSQL[0].ToLower() == "building" || i.KeyValueSQL[0].ToLower() == "highway").Count() != 0)
                {
                    var tempPoints = new Vector3[WayNodes.Count];

                    int counter = 0;
                    foreach (var node in WayNodes)
                    {
                        var result = CoordinateConvertor.SimpleInterpolation((float)node.PositionSQL.Lat, (float)node.PositionSQL.Lon, bounds, minmaxX, minmaxY);
                        // Testing the correct direction
                        tempPoints[counter] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap;
                        counter++;
                    }
                    WayNodes = null;
                    var building = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "building");
                    var highwayType = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "highway");
                    WayTags = null;
                    if (building.Count() != 0)
                    {
                        if (GenerateBuildings)
                        {
                            //Debug.Log("Current building: "+FirstWay);
                            if (GenerateBuildingShapes)
                            {
                                // Check if it has overlapping start and ending points.
                                // NOTE: Replaced with the code to remove all the duplicates, not only the endpoints.							
                                // Checking for duplicates:
                                tempPoints = tempPoints.ToArray().RemoveDuplicates();
                                var Skip = false;
                                if (tempPoints.Length <= 2)
                                {
                                    // Buildings that are too small to show such as 76844368
                                    // http://www.openstreetmap.org/browse/way/76844368
                                    // "A weird building were found and ignored. FirstWay \nRelated url: http://www.openstreetmap.org/browse/way/{0}"
                                    Skip = true; // continue;
                                }
                                if (!Skip)
                                {
                                    var p2d = tempPoints.ToCPoint2D();
                                    // TODO bug in the cpolygon, probably duplicates
                                    var shp = new PolygonCuttingEar.CPolygonShape(p2d);
                                    shp.CutEar();
                                    p2d = null;
                                    GC.Collect();
                                    // TODO:
                                    var randHeight = CoordinateConvertor.linear((float)rand.NextDouble(), 0, 1, -3f, height);
                                    var randMaterial = (randHeight > height / 2f) ? "BuildingTall" : randHeight < height / 2f ? "Building2" : "Building";
                                    var resultedGameObject = shp.GenerateShapeUVedWithWalls_Balanced(
                                            CoordinateConvertor.OSMType.Polygon, FirstWay,
                                            "Building", "Building", randMaterial,
                                            height + randHeight, height + 7, true);
                                    //Console.WriteLine("Generating building..id=" + FirstWay);

                                    // To file:
                                    // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));
                                    
                                    // To PostGreSql LargeObjects:
                                    var objData = ObjFormat.GameObjectToString(resultedGameObject);
                                    var binaryData = System.Text.Encoding.ASCII.GetBytes(objData);
                                    AddToDatabase(binaryData, FirstWay, resultedGameObject.Name, resultedGameObject, version, connPostGreSql);
                                    // gc.id , gc is now set
                                }
                            }
                            else
                                Console.WriteLine("TODO");
                            // draw.Draw(tempPoints, buildingColor, buildingColor, BuildingWidth, BuildingWidth, LineDraw.OSMType.Line, FirstWay, "Building", "Building");
                        }
                    }
                    else
                    {
                        if (highwayType.Count() != 0)
                        {
                            if (GenerateRoads)
                            {
                                var hwtype = highwayType.First();
                                //Console.WriteLine("Generating roads..id=" + FirstWay);
                                switch (hwtype.KeyValueSQL[1])
                                {
                                    case "cycleway":
                                        {
                                            var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(2f), mapboundaries.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", mapboundaries.CycleWayMaterial.Name, -0.01f);
                                            // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));

                                            // To PostGreSql LargeObjects:
                                            var objData = ObjFormat.GameObjectToString(resultedGameObject);
                                            var binaryData = System.Text.Encoding.ASCII.GetBytes(objData);
                                            AddToDatabase(binaryData, FirstWay, resultedGameObject.Name, resultedGameObject, version, connPostGreSql);
                                            // gc.id , gc is now set
                                            break;
                                        }
                                    case "footway":
                                    case "path":
                                    case "pedestrian":
                                        {
                                            var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(4f), mapboundaries.FootwayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", mapboundaries.FootWayMaterial.Name, -0.01f);
                                            // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));

                                            // To PostGreSql LargeObjects:
                                            var objData = ObjFormat.GameObjectToString(resultedGameObject);
                                            var binaryData = System.Text.Encoding.ASCII.GetBytes(objData);
                                            AddToDatabase(binaryData, FirstWay, resultedGameObject.Name, resultedGameObject, version, connPostGreSql);
                                            // gc.id , gc is now set
                                            break;
                                        }
                                    case "steps":
                                        {
                                            var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(4f), mapboundaries.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", mapboundaries.StepsMaterial.Name, -0.01f);
                                            // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));

                                            // To PostGreSql LargeObjects:
                                            var objData = ObjFormat.GameObjectToString(resultedGameObject);
                                            var binaryData = System.Text.Encoding.ASCII.GetBytes(objData);
                                            AddToDatabase(binaryData, FirstWay, resultedGameObject.Name, resultedGameObject, version, connPostGreSql);
                                            // gc.id , gc is now set
                                            break;
                                        }
                                    case "motorway":
                                        {
                                            break;
                                        }
                                    default:
                                        {
                                            var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(0.5f), mapboundaries.RoadWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", mapboundaries.RoadMaterial.Name, 0f);
                                            // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));

                                            // To PostGreSql LargeObjects:
                                            var objData = ObjFormat.GameObjectToString(resultedGameObject);
                                            var binaryData = System.Text.Encoding.ASCII.GetBytes(objData);
                                            AddToDatabase(binaryData, FirstWay, resultedGameObject.Name, resultedGameObject, version, connPostGreSql);
                                            // gc.id , gc is now set
                                            break;
                                        }
                                }
                                //current++;
                                //if (current > max)
                                //    state.Break();
                            }
                        }
                    }
                }
            });
            duration.Stop();
            Console.WriteLine("Finished in " + duration.Elapsed.Minutes + " minutes, " + duration.Elapsed.Seconds + " seconds, " + duration.Elapsed.Milliseconds + " milliseconds.");
            Console.ReadLine();
        }
        public static GameObject GenerateShapeUVedWithWalls_Balanced(this PolygonCuttingEar.CPolygonShape shape, OSMType type, string Id, string other, string tag, string MaterialName = "Building", float WallHeight = 5, float MaximumHeight = 12, bool GenerateColliders = true)
        {
            GameObject gameObject = new GameObject(type + "|" + ((int)type) + "|" + Id + (!string.IsNullOrEmpty(other) ? "|" + other : ""));

            gameObject.tag = tag;

            List <Vector3> vertices = new List <Vector3>();

            for (int i = 0; i < shape.NumberOfPolygons; i++)
            {
                vertices.AddRange(shape.Polygons(i).ToVector3(WallHeight));
            }

            // This is the starting index in the vertex list that belongs to the walls.
            // We use this to distinguish between roof UVs and wall UVs.
            int            WallStartIndex = vertices.Count;
            List <Vector2> UVs            = new List <Vector2>();
            var            minXRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.x).Min();
            var            minZRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.z).Min();
            var            maxXRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.x).Max();
            var            maxZRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.z).Max();

            // for (int i = 0; i < UVs.Length; i++)
            for (int i = 0; i < WallStartIndex; i++)
            {
                UVs.Add(new Vector2(
                            linear(vertices[i].x, minXRoof, maxXRoof, 0, 1),
                            linear(vertices[i].z, minZRoof, maxZRoof, 0, 0.5f)
                            ));
            }


            Vector2[] UVRef = new Vector2[]
            {
                new Vector2(0, 0.5f),                                     // top left
                new Vector2(1, 0.5f),                                     // top right
                new Vector2(0, 0.5f + 0.5f * WallHeight / MaximumHeight), // bottom left
                new Vector2(1, 0.5f + 0.5f * WallHeight / MaximumHeight)  // bottom right
                // new Vector2(0,1), // bottom left
                // new Vector2(1,1) // bottom right
            };
            Vector3[] OriginalVertices = shape.InputVertices.ToVector3(WallHeight);
            Vector3   HeightVector     = new Vector3(0, WallHeight, 0);

            // Generating Walls - Total: (OriginalVertices.Length)*4*3
            for (int i = 0; i < OriginalVertices.Length - 1; i++)
            {
                Vector3 v1   = OriginalVertices[i];
                Vector3 v2   = OriginalVertices[i + 1];
                var     dist = Vector3.Distance(v1, v2);

                //Debug.Log("Distance: "+dist);
                dist = dist.Clamp(0, 5);
                var UVratioTopRight    = new Vector2(dist / 5, UVRef[1].y);
                var UVratioBottomRight = new Vector2(dist / 5, UVRef[3].y);

                Vector3 v3 = OriginalVertices[i] - HeightVector;
                Vector3 v4 = OriginalVertices[i + 1] - HeightVector;
                vertices.AddRange(new Vector3[] { v1, v2, v3 });
                UVs.Add(UVRef[0]);
                UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]);
                UVs.Add(UVRef[2]);
                vertices.AddRange(new Vector3[] { v3, v2, v4 });
                UVs.Add(UVRef[2]);
                UVs.Add(UVratioTopRight);    //UVs.Add(UVRef[1]);
                UVs.Add(UVratioBottomRight); //UVs.Add(UVRef[3]);
                // Reverse
                vertices.AddRange(new Vector3[] { v1, v3, v2 });
                UVs.Add(UVRef[0]);
                UVs.Add(UVRef[2]);
                UVs.Add(UVratioTopRight); //UVs.Add(UVRef[1]);
                vertices.AddRange(new Vector3[] { v3, v4, v2 });
                UVs.Add(UVRef[2]);
                UVs.Add(UVratioBottomRight); //UVs.Add(UVRef[3]);
                UVs.Add(UVratioTopRight);    //UVs.Add(UVRef[1]);
            }

            // Last Wall - Total: 4*3
            Vector3 lv1    = OriginalVertices[OriginalVertices.Length - 1];
            Vector3 lv2    = OriginalVertices[0];
            var     distlw = Vector3.Distance(lv1, lv2);

            //Debug.Log("Distance: "+distlw);
            distlw = distlw.Clamp(0, 5);
            var     UVratioTopRightlw    = new Vector2(distlw / 5, UVRef[1].y);
            var     UVratioBottomRightlw = new Vector2(distlw / 5, UVRef[3].y);
            Vector3 lv3 = OriginalVertices[OriginalVertices.Length - 1] - HeightVector;
            Vector3 lv4 = OriginalVertices[0] - HeightVector;

            vertices.AddRange(new Vector3[] { lv1, lv2, lv3 });
            UVs.Add(UVRef[0]);
            UVs.Add(UVratioTopRightlw); //UVs.Add(UVRef[1]);
            UVs.Add(UVRef[2]);
            vertices.AddRange(new Vector3[] { lv3, lv2, lv4 });
            UVs.Add(UVRef[2]);
            UVs.Add(UVratioTopRightlw);    //UVs.Add(UVRef[1]);
            UVs.Add(UVratioBottomRightlw); //UVs.Add(UVRef[3]);
            // Reverse
            vertices.AddRange(new Vector3[] { lv1, lv3, lv2 });
            UVs.Add(UVRef[0]);
            UVs.Add(UVRef[2]);
            UVs.Add(UVratioTopRightlw); //UVs.Add(UVRef[1]);
            vertices.AddRange(new Vector3[] { lv3, lv4, lv2 });
            UVs.Add(UVRef[2]);
            UVs.Add(UVratioBottomRightlw); //UVs.Add(UVRef[3]);
            UVs.Add(UVratioTopRightlw);    //UVs.Add(UVRef[1]);



            int[] tris = new int[shape.NumberOfPolygons * 3 + (OriginalVertices.Length - 1) * 4 * 3 + 4 * 3];
            for (int i = 0; i < tris.Length; i++)
            {
                tris[i] = i;
            }

            gameObject.position = CoordinateConvertor.ChangePivot(ref vertices, CoordinateConvertor.PivotLocation.ZeroBottomCenter);
            gameObject.mesh     = Rebuild(vertices.ToArray(), tris, UVs.ToArray());
            gameObject.material = new Material(MaterialName);

            return(gameObject);
        }
        public static GameObject GenerateShapeUVedPlanar_Balanced(this PolygonCuttingEar.CPolygonShape shape, OSMType type, string Id, string other, string tag, string MaterialName = "Area", float Height = 0, bool GenerateColliders = true)
        {
            GameObject gameObject = new GameObject(type + "|" + ((int)type) + "|" + Id + (!string.IsNullOrEmpty(other) ? "|" + other : ""));

            gameObject.tag = tag;

            List <Vector3> vertices = new List <Vector3>();

            for (int i = 0; i < shape.NumberOfPolygons; i++)
            {
                vertices.AddRange(shape.Polygons(i).ToVector3(Height));
            }

            // This is the starting index in the vertex list that belongs to the walls.
            // We use this to distinguish between roof UVs and wall UVs.
            int            WallStartIndex = vertices.Count;
            List <Vector2> UVs            = new List <Vector2>();
            var            minXRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.x).Min();
            var            minZRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.z).Min();
            var            maxXRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.x).Max();
            var            maxZRoof       = vertices.GetRange(0, WallStartIndex).Select(i => i.z).Max();
            var            average        = new Vector3(
                vertices.GetRange(0, WallStartIndex).Select(s => s.x).Average(),
                vertices.GetRange(0, WallStartIndex).Select(s => s.y).Average(),
                vertices.GetRange(0, WallStartIndex).Select(s => s.z).Average());

            //var avgx = linear(average.x, minXRoof, maxXRoof, 0, 1);
            //var avgy = linear(average.z, minZRoof, maxZRoof, 0, 1);
            //Vector3[] OriginalVertices = shape.InputVertices.ToVector3(Height);
            for (int i = 0; i < WallStartIndex; i++)
            {
                // bool found = false;
                var x = linear(vertices[i].x, minXRoof, maxXRoof, 0, 1);
                var y = linear(vertices[i].z, minZRoof, maxZRoof, 0, 1);
                //for (int j = 0; j < OriginalVertices.Length; j++)
                //{
                //    if (Math.Abs(OriginalVertices[j].x - vertices[i].x) < 0.001f && Math.Abs(OriginalVertices[j].z - vertices[i].z) < 0.001f)
                //    {
                //        //if (j % 2 == 0)
                //        //    UVs.Add(new Vector2(0, 0));
                //        //else
                //        //    UVs.Add(new Vector2(1, 0));
                //        if (x > avgx && Math.Abs(x - avgx) < Math.Abs(y - avgy))
                //            x = 1;
                //        else if (x <= avgx && Math.Abs(avgx - x) < Math.Abs(y - avgy))
                //            x = 0;

                //        if (y > avgy && Math.Abs(y - avgy) < Math.Abs(x - avgx))
                //            y = 1;
                //        else if (y <= avgy && Math.Abs(avgy - y) < Math.Abs(x - avgx))
                //            y = 0;
                //        UVs.Add(new Vector2(x, y));
                //        found = true;
                //        break;
                //    }
                //}
                //if (!found)
                //{
                //    var x = linear(vertices[i].x, minXRoof, maxXRoof, 0, 1);
                //    var y = linear(vertices[i].z, minZRoof, maxZRoof, 0, 1);
                UVs.Add(new Vector2(x, y));
                //}
            }



            Vector2[] UVRef = new Vector2[]
            {
                new Vector2(0, 0),               // top left
                new Vector2(1, 0),               // top right
                new Vector2(0, 1),               // bottom left
                new Vector2(1, 1)                // bottom right
                // new Vector2(0,1), // bottom left
                // new Vector2(1,1) // bottom right
            };

            Vector3 HeightVector = new Vector3(0, 0, 0);

            int[] tris = new int[shape.NumberOfPolygons * 3];
            for (int i = 0; i < tris.Length; i++)
            {
                tris[i] = i;
            }

            gameObject.position = CoordinateConvertor.ChangePivot(ref vertices, CoordinateConvertor.PivotLocation.ZeroBottomCenter);
            gameObject.mesh     = Rebuild(vertices.ToArray(), tris, UVs.ToArray());
            gameObject.material = new Material(MaterialName);

            return(gameObject);
        }
Пример #5
0
        /// <summary>
        /// Generates the mesh for a given openstreetmap element
        /// </summary>
        /// <param name="OSMid">The id of the OSM element</param>
        /// <param name="MinPointOnMap">Minimum point on the target map (to calculate the offset)</param>
        /// <param name="bounds">The boundaries of the used OSM map</param>
        /// <param name="properties">The details of the target scene generation.</param>
        /// <param name="connPostGreSql">The connection string to the database. Please refer to .Net Data Provider for MSSQL for format specifications</param>
        /// <param name="shape">The type of the generated mesh. Refer to <see cref="GaPSLabs.Geometry.MeshGenerator.OSMShape"/></param>
        /// <param name="RemoveRedundantPointsOnTheSameLine">If true, it will remove redundant points on straight parts of the shape according to<paramref name="RedundantPointErrorThreshold"/>.</param>
        /// <param name="RedundantPointErrorThreshold">The error toleration when removing redundant points. The default is 0.001f</param>
        /// <param name="SegmentLines">If true, it will segment the road geometry so that the texture will look uniform over the whole mesh.</param>
        /// <returns>Returns a <see cref="GaPSLabs.Geometry.GameObject"/> of the generated mesh.</returns>
        /// <remarks>
        /// <para>Removing the redundant points happen before the line segmentation. Therefore the points that were generated when setting <paramref name="SegmentLines"/> to true will not be removed.</para>
        /// <para>The <paramref name="RedundantPointErrorThreshold"/> specifies the difference in slope of the line segments that can be ignored.</para>
        /// </remarks>
        public static GameObject OSMtoGameObject(string OSMid, Vector3 MinPointOnMap, Bounds bounds, MapProperties properties, string connPostGreSql, OSMShape shape = OSMShape.Way, bool RemoveRedundantPointsOnTheSameLine = true, float RedundantPointErrorThreshold = 0.001f, bool SegmentLines = true)
        {
            if (rand == null)
            {
                rand = new Random((int)DateTime.Now.Ticks);
            }
            if (properties == null)
            {
                properties = Properties;
            }
            var   minmaxX       = properties.minMaxX;
            var   minmaxY       = properties.minMaxY;
            int   direction     = -1;
            float LineWidth     = properties.RoadLineThickness;
            float BuildingWidth = properties.BuildingLineThickness;
            float height        = properties.BuildingHeight;

            if (height < 4)
            {
                height = 4;
            }
            var FirstWay = OSMid;

            if (shape == OSMShape.Way)
            {
                if (FirstWay.Equals("41018641"))
                {
                    System.Console.WriteLine("Missing road found in WCF");
                }

                var            w = new Way(FirstWay);
                List <OsmNode> WayNodes;
                List <Tag>     WayTags;
                using (Npgsql.NpgsqlConnection con = new Npgsql.NpgsqlConnection(connPostGreSql))
                {
                    con.Open();
                    WayNodes = w.GetNodesPostgreSQL(FirstWay, con);
                    WayTags  = w.GetTagsPostgreSQL(FirstWay, con);
                    con.Close();
                }
                if (WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "landuse" || i.KeyValueSQL[0].ToLower() == "building" || i.KeyValueSQL[0].ToLower() == "highway").Count() != 0)
                {
                    var tempPoints = new Vector3[WayNodes.Count];

                    int counter = 0;
                    foreach (var node in WayNodes)
                    {
                        var result = CoordinateConvertor.SimpleInterpolation((float)node.PositionSQL.Lat, (float)node.PositionSQL.Lon, bounds, minmaxX, minmaxY);
                        // Testing the correct direction
                        tempPoints[counter] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap;
                        counter++;
                    }
                    if (RemoveRedundantPointsOnTheSameLine)
                    {
                        tempPoints = tempPoints.RemoveRedundantPointsInTheSameLines();
                    }
                    WayNodes = null;
                    var building    = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "building");
                    var highwayType = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "highway");
                    var onewayType  = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "oneway").FirstOrDefault();
                    var lanesType   = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "lanes").FirstOrDefault();
                    var areaType    = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "area").FirstOrDefault();
                    WayTags = null;
                    if (building.Count() != 0)
                    {
                        #region Buildings
                        // Check if it has overlapping start and ending points.
                        // NOTE: Replaced with the code to remove all the duplicates, not only the endpoints.
                        // Checking for duplicates:
                        tempPoints = tempPoints.ToArray().RemoveDuplicates();
                        var Skip = false;
                        if (tempPoints.Length <= 2)
                        {
                            // Buildings that are too small to show such as 76844368
                            // http://www.openstreetmap.org/browse/way/76844368
                            // "A weird building were found and ignored. FirstWay \nRelated url: http://www.openstreetmap.org/browse/way/{0}"
                            Skip = true; // continue;
                        }
                        if (!Skip)
                        {
                            var p2d = tempPoints.ToCPoint2D();
                            // TODO bug in the cpolygon, probably duplicates
                            var shp = new PolygonCuttingEar.CPolygonShape(p2d);
                            shp.CutEar();
                            p2d = null;
                            GC.Collect();
                            // TODO:
                            //var randHeight = CoordinateConvertor.linear((float)rand.NextDouble(), 0, 1, -3f, height);
                            // var randMaterial = (randHeight > height / 2f) ? "BuildingTall" : randHeight < height / 2f ? "Building2" : "Building";
                            var randHeight         = properties.BuildingHeightVariation.GetNextCircular();
                            var randMaterial       = (randHeight > (properties.BuildingHeightVariation.Average + properties.BuildingHeightVariation.Max) / 2f) ? "BuildingTall" : ("Building" + rand.Next(1, 5));
                            var resultedGameObject = shp.GenerateShapeUVedWithWalls_Balanced(
                                CoordinateConvertor.OSMType.Polygon, FirstWay,
                                "Building", "Building", randMaterial,
                                /*height +*/ randHeight, /* height + 7*/ properties.BuildingHeightVariation.Max, true);
                            return(resultedGameObject);
                        }
                        #endregion
                    }
                    else
                    {
                        if (highwayType.Count() != 0)
                        {
                            #region Roads
                            var hwtype = highwayType.First();
                            //Console.WriteLine("Generating roads..id=" + FirstWay);
                            switch (hwtype.KeyValueSQL[1])
                            {
                            case "cycleway":
                            {
                                var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(SegmentLines ? tempPoints.ToSegmentedPoints(2f) : tempPoints, properties.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.CycleWayMaterial.Name, -0.01f);
                                // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));

                                return(resultedGameObject);
                            }

                            case "footway":
                            case "path":
                            case "pedestrian":
                            {
                                if (areaType != null)
                                {
                                    tempPoints = tempPoints.ToArray().RemoveDuplicates();
                                    var Skip = false;
                                    if (tempPoints.Length <= 2)
                                    {
                                        // Buildings that are too small to show such as 76844368
                                        // http://www.openstreetmap.org/browse/way/76844368
                                        // "A weird building were found and ignored. FirstWay \nRelated url: http://www.openstreetmap.org/browse/way/{0}"
                                        Skip = true;         // continue;
                                    }
                                    if (!Skip)
                                    {
                                        var p2d = tempPoints.ToCPoint2D();
                                        // TODO bug in the cpolygon, probably duplicates
                                        var shp = new PolygonCuttingEar.CPolygonShape(p2d);
                                        shp.CutEar();
                                        p2d = null;
                                        GC.Collect();
                                        var resultedGameObject = shp.GenerateShapeUVedPlanar_Balanced(
                                            CoordinateConvertor.OSMType.Polygon, FirstWay,
                                            "FootwayArea", "Area", properties.AreaMaterial.Name,
                                            0, true);
                                        return(resultedGameObject);
                                    }
                                    break;
                                }
                                else
                                {
                                    var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(SegmentLines ? tempPoints.ToSegmentedPoints(4f) : tempPoints, properties.FootwayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.FootWayMaterial.Name, -0.01f);
                                    // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));
                                    return(resultedGameObject);
                                }
                            }

                            case "steps":
                            {
                                var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(SegmentLines ? tempPoints.ToSegmentedPoints(4f) : tempPoints, properties.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.StepsMaterial.Name, -0.01f);
                                return(resultedGameObject);
                            }

                            // Miguel R.C. commented these lines.
                            // Reason: Why breaking in the case "motorway"? That results in some roads missing when generating scenarios.
                            // With these lines commented, the motorways will be generated in the default case.
                            //case "motorway":
                            //    {
                            //        break;
                            //    }

                            default:
                            {
                                // Calculating the corrent road width based on the available information
                                // Parameters affecting the width are:
                                // 1- road direction: 'oneway' tag
                                // 2- number of lanes: 'lanes' tag. The defaults are: http://wiki.openstreetmap.org/wiki/Lane#Assumptions
                                //
                                // |If two-way then # of lanes is 2, and if one-way then # of lanes is 1|
                                // highway=residential
                                // highway=tertiary
                                // highway=secondary
                                // highway=primary
                                //
                                // |If two-way then # of lanes is 1, and if one-way then # of lanes is 1|
                                // highway=service
                                // highway=track
                                // highway=path
                                // The actual number of lanes for the following must always be tagged in the lanes value.
                                // highway=motorway
                                // highway=trunk

                                //TODO: USE lanes value.
                                var  calculatedRoadWidth = properties.RoadWidth;
                                bool useLaneInfo         = false;
                                if (lanesType != null)
                                {
                                    var   laneNumbers = lanesType.KeyValueSQL[1].Split(new char[] { '+' }, StringSplitOptions.RemoveEmptyEntries);
                                    float lanes       = 0;
                                    foreach (var lane in laneNumbers)
                                    {
                                        float templane;
                                        if (float.TryParse(lane, out templane))
                                        {
                                            lanes += templane;
                                        }
                                    }
                                    if (lanes != 0)
                                    {
                                        useLaneInfo         = true;
                                        calculatedRoadWidth = properties.RoadWidth * lanes;
                                    }
                                }
                                if (!useLaneInfo)
                                {
                                    if (onewayType == null)         // It is a 2-way by default
                                    {
                                        if (hwtype.KeyValueSQL[1] == Tags.Highways.residential ||
                                            hwtype.KeyValueSQL[1] == Tags.Highways.tertiary ||
                                            hwtype.KeyValueSQL[1] == Tags.Highways.secondary ||
                                            hwtype.KeyValueSQL[1] == Tags.Highways.primary)
                                        {
                                            calculatedRoadWidth = properties.RoadWidth * 2;
                                        }
                                        else if (hwtype.KeyValueSQL[1] == Tags.Highways.service ||
                                                 hwtype.KeyValueSQL[1] == Tags.Highways.track ||
                                                 hwtype.KeyValueSQL[1] == Tags.Highways.path)
                                        {
                                            calculatedRoadWidth = properties.RoadWidth;
                                        }
                                    }
                                    else if (onewayType.KeyValueSQL[1].ToLower() == "0" | onewayType.KeyValueSQL[1].ToLower() == "no")         // It is still a 2-way
                                    {
                                        if (hwtype.KeyValueSQL[1] == Tags.Highways.residential ||
                                            hwtype.KeyValueSQL[1] == Tags.Highways.tertiary ||
                                            hwtype.KeyValueSQL[1] == Tags.Highways.secondary ||
                                            hwtype.KeyValueSQL[1] == Tags.Highways.primary)
                                        {
                                            calculatedRoadWidth = properties.RoadWidth * 2;
                                        }
                                        else if (hwtype.KeyValueSQL[1] == Tags.Highways.service ||
                                                 hwtype.KeyValueSQL[1] == Tags.Highways.track ||
                                                 hwtype.KeyValueSQL[1] == Tags.Highways.path)
                                        {
                                            calculatedRoadWidth = properties.RoadWidth;
                                        }
                                    }
                                    else         // It is a one-way
                                    {
                                        calculatedRoadWidth = properties.RoadWidth;
                                    }
                                }
                                var matName = properties.RoadMaterial.Name;
                                if (hwtype.KeyValueSQL[1] == Tags.Highways.residential)
                                {
                                    matName = properties.ResidentialMaterial.Name;
                                }
                                else if (hwtype.KeyValueSQL[1] == Tags.Highways.service)
                                {
                                    matName = properties.ServiceMaterial.Name;
                                }
                                var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(SegmentLines ? tempPoints.ToSegmentedPoints(0.5f) : tempPoints, calculatedRoadWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", matName, 0f);

                                return(resultedGameObject);
                            }
                            }
                            #endregion
                        }
                    }
                }
            }
            else if (shape == OSMShape.Relation) // It is probably a multi-polygon building defined in a relation.
            {
                List <OsmNode[]> OuterNodes;
                //List<OsmNode> OuterWay;
                List <OsmNode[]> InnerNodes;
                List <Tag>       tags;
                Relation         r = new Relation(FirstWay);
                Way w = new Way();
                using (Npgsql.NpgsqlConnection con = new Npgsql.NpgsqlConnection(connPostGreSql))
                {
                    con.Open();

                    tags = r.GetTagsPostgreSQL(con);
                    var isMultiPolygon = tags.Exists(t => t.KeyValueSQL[0] == "type" && t.KeyValueSQL[1] == "multipolygon");
                    if (isMultiPolygon)
                    {
                        var Members = r.GetMembersPostgreSQLByType(r.id, 1, con);

                        OuterNodes = Members
                                     .Where(m => m.Role.ToLower() == Member.RoleOuter)
                                     .OrderBy(o => o.order)
                                     .Select(m => w.GetNodesPostgreSQL(m.ReferenceId, connPostGreSql).ToArray()).ToList();
                        InnerNodes = Members
                                     .Where(m => m.Role.ToLower() == Member.RoleInner)
                                     .OrderBy(o => o.order)
                                     .Select(m => w.GetNodesPostgreSQL(m.ReferenceId, connPostGreSql).ToArray()).ToList();


                        //OuterWay = new List<OsmNode>();
                        //foreach (var nodelist in OuterNodes)
                        //    OuterWay.AddRange(nodelist);


                        List <Vector3[]> tempPointsOuterPoints = new List <Vector3[]>();
                        int counter = 0;
                        foreach (var node in OuterNodes)
                        {
                            Vector3[] currrentOuter = new Vector3[node.Length];
                            for (int i = 0; i < node.Length; i++)
                            {
                                var result = CoordinateConvertor.SimpleInterpolation((float)node[i].PositionSQL.Lat, (float)node[i].PositionSQL.Lon, bounds, minmaxX, minmaxY);
                                // Testing the correct direction
                                currrentOuter[i] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap;
                            }
                            tempPointsOuterPoints.Add(currrentOuter.RemoveDuplicates());
                        }

                        List <Vector3[]> holes = new List <Vector3[]>();
                        for (int i = 0; i < InnerNodes.Count; i++)
                        {
                            holes.Add(new Vector3[InnerNodes[i].Length]);

                            for (int j = 0; j < InnerNodes[i].Length; j++)
                            {
                                var result = CoordinateConvertor.SimpleInterpolation((float)InnerNodes[i][j].PositionSQL.Lat, (float)InnerNodes[i][j].PositionSQL.Lon, bounds, minmaxX, minmaxY);
                                // Testing the correct direction
                                holes[i][j] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap;
                            }
                            holes[i] = holes[i].RemoveDuplicates();
                        }

                        if (RemoveRedundantPointsOnTheSameLine)
                        {
                            for (int i = 0; i < tempPointsOuterPoints.Count; i++)
                            {
                                tempPointsOuterPoints[i] = tempPointsOuterPoints[i].RemoveRedundantPointsInTheSameLines();
                            }
                            for (int i = 0; i < holes.Count; i++)
                            {
                                holes[i] = holes[i].RemoveRedundantPointsInTheSameLines();
                            }
                        }
                        // Check the holes against all outers
                        List <IEnumerable <Poly2Tri.PolygonPoint> > outerpolypoints = new List <IEnumerable <Poly2Tri.PolygonPoint> >();
                        for (int i = 0; i < tempPointsOuterPoints.Count; i++)
                        {
                            outerpolypoints.Add(tempPointsOuterPoints[i].Select(s => new Poly2Tri.PolygonPoint(s.x, s.z)));
                        }

                        //= tempPointsOuterPoints
                        var Polies = outerpolypoints.Select(opp => new Poly2Tri.Polygon(opp)).ToArray();
                        //Poly2Tri.Polygon poly = new Poly2Tri.Polygon(outerpolypoints);
                        // TODO: poly.IsPointInside() check the holes against all pieces

                        var innerspolypoints = new List <Poly2Tri.PolygonPoint[]>();
                        for (int i = 0; i < holes.Count; i++)
                        {
                            var currentInner = holes[i].Select(s => new Poly2Tri.PolygonPoint(s.x, s.z)).ToArray();
                            innerspolypoints.Add(currentInner);
                            for (int j = 0; j < Polies.Length; j++)
                            {
                                if (Polies[j].IsPointInside(new Poly2Tri.TriangulationPoint(currentInner[0].X, currentInner[0].Y)))
                                {
                                    Polies[j].AddHole(new Poly2Tri.Polygon(currentInner));
                                }
                            }
                        }
                        for (int i = 0; i < Polies.Length; i++)
                        {
                            try
                            {
                                Poly2Tri.P2T.Triangulate(Polies[i]);
                            }
                            catch (Exception e)
                            {
                                //throw e;
                            }
                        }

                        //var randHeight = CoordinateConvertor.linear((float)rand.NextDouble(), 0, 1, -3f, height);
                        //var randMaterial = (randHeight > height / 2f) ? "BuildingTall" : randHeight < height / 2f ? "Building2" : "Building";
                        var randHeight   = properties.BuildingHeightVariation.GetNextCircular();
                        var randMaterial = (randHeight > (properties.BuildingHeightVariation.Average + properties.BuildingHeightVariation.Max) / 2f) ? "BuildingTall" : ("Building" + rand.Next(1, 5));

                        List <GameObject> resultedGameObjects = new List <GameObject>();
                        for (int i = 0; i < Polies.Length; i++)
                        {
                            var currentGameObject = Polies[i].GenerateShapeUVedWithWalls_Balanced(
                                CoordinateConvertor.OSMType.Relation, FirstWay,
                                "Building", "Building", randMaterial,
                                /*height +*/ randHeight, /* height + 7*/ properties.BuildingHeightVariation.Max, true);
                            resultedGameObjects.Add(currentGameObject);
                        }
                        return(resultedGameObjects.CombineGameObjectsOfTheSameMaterial());
                    }
                    con.Close();
                }
            }
            return(null);
        }
Пример #6
0
        public static GameObject OSMtoGameObject2(string OSMid, Vector3 MinPointOnMap, Bounds bounds, MapProperties properties, string connPostGreSql, OSMShape shape = OSMShape.Way)
        {
            if (rand == null)
            {
                rand = new Random((int)DateTime.Now.Ticks);
            }
            if (properties == null)
            {
                properties = Properties;
            }
            var   minmaxX       = properties.minMaxX;
            var   minmaxY       = properties.minMaxY;
            int   direction     = -1;
            float LineWidth     = properties.RoadLineThickness;
            float BuildingWidth = properties.BuildingLineThickness;
            float height        = properties.BuildingHeight;

            if (height < 4)
            {
                height = 4;
            }
            var FirstWay = OSMid;

            if (shape == OSMShape.Way)
            {
                var            w = new Way(FirstWay);
                List <OsmNode> WayNodes;
                List <Tag>     WayTags;
                using (Npgsql.NpgsqlConnection con = new Npgsql.NpgsqlConnection(connPostGreSql))
                {
                    con.Open();
                    WayNodes = w.GetNodesPostgreSQL(FirstWay, con);
                    WayTags  = w.GetTagsPostgreSQL(FirstWay, con);
                    con.Close();
                }
                if (WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "landuse" || i.KeyValueSQL[0].ToLower() == "building" || i.KeyValueSQL[0].ToLower() == "highway").Count() != 0)
                {
                    var tempPoints = new Vector3[WayNodes.Count];

                    int counter = 0;
                    foreach (var node in WayNodes)
                    {
                        var result = CoordinateConvertor.SimpleInterpolation((float)node.PositionSQL.Lat, (float)node.PositionSQL.Lon, bounds, minmaxX, minmaxY);
                        // Testing the correct direction
                        tempPoints[counter] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap;
                        counter++;
                    }
                    WayNodes = null;
                    var building    = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "building");
                    var highwayType = WayTags.Where(i => i.KeyValueSQL[0].ToLower() == "highway");
                    WayTags = null;
                    if (building.Count() != 0)
                    {
                        #region Buildings
                        // Check if it has overlapping start and ending points.
                        // NOTE: Replaced with the code to remove all the duplicates, not only the endpoints.
                        // Checking for duplicates:
                        tempPoints = tempPoints.ToArray().RemoveDuplicates();
                        var Skip = false;
                        if (tempPoints.Length <= 2)
                        {
                            // Buildings that are too small to show such as 76844368
                            // http://www.openstreetmap.org/browse/way/76844368
                            // "A weird building were found and ignored. FirstWay \nRelated url: http://www.openstreetmap.org/browse/way/{0}"
                            Skip = true; // continue;
                        }
                        if (!Skip)
                        {
                            var p2d = tempPoints.ToCPoint2D();
                            // TODO bug in the cpolygon, probably duplicates
                            var shp = new PolygonCuttingEar.CPolygonShape(p2d);
                            shp.CutEar();
                            p2d = null;
                            GC.Collect();
                            // TODO:
                            var randHeight         = CoordinateConvertor.linear((float)rand.NextDouble(), 0, 1, -3f, height);
                            var randMaterial       = (randHeight > height / 2f) ? "BuildingTall" : randHeight < height / 2f ? "Building2" : "Building";
                            var resultedGameObject = shp.GenerateShapeUVedWithWalls_Balanced(
                                CoordinateConvertor.OSMType.Polygon, FirstWay,
                                "Building", "Building", randMaterial,
                                height + randHeight, height + 7, true);
                            return(resultedGameObject);
                        }
                        #endregion
                    }
                    else
                    {
                        if (highwayType.Count() != 0)
                        {
                            #region Roads
                            var hwtype = highwayType.First();
                            //Console.WriteLine("Generating roads..id=" + FirstWay);
                            switch (hwtype.KeyValueSQL[1])
                            {
                            case "cycleway":
                            {
                                var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(2f), properties.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.CycleWayMaterial.Name, -0.01f);
                                // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));

                                return(resultedGameObject);
                            }

                            case "footway":
                            case "path":
                            case "pedestrian":
                            {
                                var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(4f), properties.FootwayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.FootWayMaterial.Name, -0.01f);
                                // ObjFormat.MeshToFile(resultedGameObject,System.IO.Path.Combine( exportPath , resultedGameObject.Name.Replace("|", "-") + ".obj"));
                                return(resultedGameObject);
                            }

                            case "steps":
                            {
                                var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(4f), properties.CyclewayWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.StepsMaterial.Name, -0.01f);
                                return(resultedGameObject);
                            }

                            // Miguel R.C. commented these lines.
                            // Reason: Why breaking in the case "motorway"? That results in some roads missing when generating scenarios.
                            // With these lines commented, the motorways will be generated in the default case.
                            //case "motorway":
                            //    {
                            //        break;
                            //    }

                            default:
                            {
                                var resultedGameObject = CoordinateConvertor.MeshGenerationFilledCorners(tempPoints.ToSegmentedPoints(0.5f), properties.RoadWidth, CoordinateConvertor.OSMType.Line, FirstWay, hwtype.KeyValueSQL[1], "Line", properties.RoadMaterial.Name, 0f);

                                return(resultedGameObject);
                            }
                            }
                            #endregion
                        }
                    }
                }
            }
            else if (shape == OSMShape.Relation) // It is probably a multi-polygon building defined in a relation.
            {
                List <OsmNode[]> OuterNodes;
                List <OsmNode>   OuterWay;
                List <OsmNode[]> InnerNodes;
                List <Tag>       tags;
                Relation         r = new Relation(FirstWay);
                Way w = new Way();
                using (Npgsql.NpgsqlConnection con = new Npgsql.NpgsqlConnection(connPostGreSql))
                {
                    con.Open();

                    tags = r.GetTagsPostgreSQL(con);
                    var isMultiPolygon = tags.Exists(t => t.KeyValueSQL[0] == "type" && t.KeyValueSQL[1] == "multipolygon");
                    if (isMultiPolygon)
                    {
                        var Members = r.GetMembersPostgreSQLByType(r.id, 1, con);

                        OuterNodes = Members
                                     .Where(m => m.Role.ToLower() == Member.RoleOuter)
                                     .OrderBy(o => o.order)
                                     .Select(m => w.GetNodesPostgreSQL(m.ReferenceId, connPostGreSql).ToArray()).ToList();
                        InnerNodes = Members
                                     .Where(m => m.Role.ToLower() == Member.RoleInner)
                                     .OrderBy(o => o.order)
                                     .Select(m => w.GetNodesPostgreSQL(m.ReferenceId, connPostGreSql).ToArray()).ToList();


                        OuterWay = new List <OsmNode>();
                        foreach (var nodelist in OuterNodes)
                        {
                            OuterWay.AddRange(nodelist);
                        }


                        var tempPointsOuterPoints = new Vector3[OuterWay.Count];
                        int counter = 0;
                        foreach (var node in OuterWay)
                        {
                            var result = CoordinateConvertor.SimpleInterpolation((float)node.PositionSQL.Lat, (float)node.PositionSQL.Lon, bounds, minmaxX, minmaxY);
                            // Testing the correct direction
                            tempPointsOuterPoints[counter] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap;
                            counter++;
                        }

                        List <Vector3[]> holes = new List <Vector3[]>();
                        for (int i = 0; i < InnerNodes.Count; i++)
                        {
                            holes.Add(new Vector3[InnerNodes[i].Length]);

                            for (int j = 0; j < InnerNodes[i].Length; j++)
                            {
                                var result = CoordinateConvertor.SimpleInterpolation((float)InnerNodes[i][j].PositionSQL.Lat, (float)InnerNodes[i][j].PositionSQL.Lon, bounds, minmaxX, minmaxY);
                                // Testing the correct direction
                                holes[i][j] = new Vector3(direction * (float)result[0], 0, (float)result[1]) - MinPointOnMap;
                            }
                        }


                        var outerpolypoints   = tempPointsOuterPoints.Select(s => new Poly2Tri.PolygonPoint(s.x, s.z));
                        Poly2Tri.Polygon poly = new Poly2Tri.Polygon(outerpolypoints);
                        // TODO: poly.IsPointInside() check the holes against all pieces

                        var innerspolypoints = new List <Poly2Tri.PolygonPoint[]>();
                        for (int i = 0; i < holes.Count; i++)
                        {
                            var currentInner = holes[i].Select(s => new Poly2Tri.PolygonPoint(s.x, s.z)).ToArray();
                            innerspolypoints.Add(currentInner);
                            poly.AddHole(new Poly2Tri.Polygon(currentInner));
                        }
                        Poly2Tri.P2T.Triangulate(poly);

                        var randHeight         = CoordinateConvertor.linear((float)rand.NextDouble(), 0, 1, -3f, height);
                        var randMaterial       = (randHeight > height / 2f) ? "BuildingTall" : randHeight < height / 2f ? "Building2" : "Building";
                        var resultedGameObject = poly.GenerateShapeUVedWithWalls_Balanced(
                            CoordinateConvertor.OSMType.Relation, FirstWay,
                            "Building", "Building", randMaterial,
                            height + randHeight, height + 7, true);
                        return(resultedGameObject);
                    }
                    con.Close();
                }
            }
            return(null);
        }