public static GameObject CombineGameObjectsOfTheSameMaterial(this List <GameObject> GameObjects)
        {
            if (GameObjects.Count == 1)
            {
                return(GameObjects[0]);
            }

            List <Vector3> CombinedVertices = new List <Vector3>();
            List <int>     CombinedTris     = new List <int>();
            List <Vector2> CombinedUVs      = new List <Vector2>();

            foreach (var go in GameObjects)
            {
                var vertLength = CombinedVertices.Count;
                CombinedVertices.AddRange(go.mesh.vertices.Select(v => v + go.position));
                CombinedTris.AddRange(go.mesh.triangles.Select(v => v + vertLength));
                CombinedUVs.AddRange(go.mesh.uv);
            }
            GameObject CombinedObject = new GameObject(GameObjects[0].Name);

            CombinedObject.material = GameObjects[0].material;
            CombinedObject.tag      = GameObjects[0].tag;
            CombinedObject.type     = GameObjects[0].type;

            CombinedObject.position = CoordinateConvertor.ChangePivot(ref CombinedVertices, CoordinateConvertor.PivotLocation.ZeroBottomCenter);
            CombinedObject.mesh     = Rebuild(CombinedVertices.ToArray(), CombinedTris.ToArray(), CombinedUVs.ToArray());
            return(CombinedObject);
        }
Exemplo n.º 2
0
 public void RecalculateNormals()
 {
     normals = new Vector3[vertices.Length];
     for (int i = 0; i < vertices.Length - 2; i += 3)
     {
         var temp =
             CoordinateConvertor.CalculateNormal(
                 vertices[triangles[i]], vertices[triangles[i + 1]], vertices[triangles[i + 2]]
                 );
         normals[i]     = temp;
         normals[i + 1] = temp;
         normals[i + 2] = temp;
     }
 }
Exemplo n.º 3
0
 public static float Angle(Vector2 from, Vector2 to)
 {
     return((float)(Math.Acos(CoordinateConvertor.Clamp(Dot(from.normalized, to.normalized), -1f, 1f)) * 57.29578f));
 }
        public static GameObject GenerateShapeUVedWithWalls_Balanced(this Poly2Tri.Polygon 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;
            if (shape.Triangles == null)
            {
                return(gameObject);
            }
            if (shape.Triangles.Count == 0)
            {
                return(gameObject);
            }
            List <Vector3> vertices = new List <Vector3>();

            for (int i = 0; i < shape.Triangles.Count; i++)
            {
                vertices.AddRange(shape.Triangles[i].Points.Select(s => new Vector3((float)s.X, WallHeight, (float)s.Y)).Reverse());
            }

            // 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
            };
            #region Outer wall
            Vector3   HeightVector     = new Vector3(0, WallHeight, 0);
            Vector3[] OriginalVertices = shape.Points.Select(s => new Vector3((float)s.X, WallHeight, (float)s.Y)).ToArray();


            // 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]);

            #endregion

            #region Inner walls
            List <Vector3[]> OriginalInnerVertices = new List <Vector3[]>();
            if (shape.Holes != null)
            {
                for (int i = 0; i < shape.Holes.Count; i++)
                {
                    OriginalInnerVertices.Add(shape.Holes[i].Points.Select(s => new Vector3((float)s.X, WallHeight, (float)s.Y)).ToArray());
                }

                for (int holeidx = 0; holeidx < shape.Holes.Count; holeidx++)
                {
                    // Generating Walls - Total: (OriginalInnerVertices.Length)*4*3
                    for (int i = 0; i < OriginalInnerVertices[holeidx].Length - 1; i++)
                    {
                        Vector3 v1   = OriginalInnerVertices[holeidx][i];
                        Vector3 v2   = OriginalInnerVertices[holeidx][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 = OriginalInnerVertices[holeidx][i] - HeightVector;
                        Vector3 v4 = OriginalInnerVertices[holeidx][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_hole    = OriginalInnerVertices[holeidx][OriginalInnerVertices[holeidx].Length - 1];
                    Vector3 lv2_hole    = OriginalInnerVertices[holeidx][0];
                    var     distlw_hole = Vector3.Distance(lv1_hole, lv2_hole);
                    //Debug.Log("Distance: "+distlw_hole);
                    distlw_hole = distlw_hole.Clamp(0, 5);
                    var     UVratioTopRightlw_hole    = new Vector2(distlw_hole / 5, UVRef[1].y);
                    var     UVratioBottomRightlw_hole = new Vector2(distlw_hole / 5, UVRef[3].y);
                    Vector3 lv3_hole = OriginalInnerVertices[holeidx][OriginalInnerVertices[holeidx].Length - 1] - HeightVector;
                    Vector3 lv4_hole = OriginalInnerVertices[holeidx][0] - HeightVector;
                    vertices.AddRange(new Vector3[] { lv1_hole, lv2_hole, lv3_hole });
                    UVs.Add(UVRef[0]);
                    UVs.Add(UVratioTopRightlw_hole); //UVs.Add(UVRef[1]);
                    UVs.Add(UVRef[2]);
                    vertices.AddRange(new Vector3[] { lv3_hole, lv2_hole, lv4_hole });
                    UVs.Add(UVRef[2]);
                    UVs.Add(UVratioTopRightlw_hole);    //UVs.Add(UVRef[1]);
                    UVs.Add(UVratioBottomRightlw_hole); //UVs.Add(UVRef[3]);
                    // Reverse
                    vertices.AddRange(new Vector3[] { lv1_hole, lv3_hole, lv2_hole });
                    UVs.Add(UVRef[0]);
                    UVs.Add(UVRef[2]);
                    UVs.Add(UVratioTopRightlw_hole); //UVs.Add(UVRef[1]);
                    vertices.AddRange(new Vector3[] { lv3_hole, lv4_hole, lv2_hole });
                    UVs.Add(UVRef[2]);
                    UVs.Add(UVratioBottomRightlw_hole); //UVs.Add(UVRef[3]);
                    UVs.Add(UVratioTopRightlw_hole);    //UVs.Add(UVRef[1]);
                }
            }
            #endregion

            // int[] tris = new int[shape.Triangles.Count * 3 + (OriginalVertices.Length - 1) * 4 * 3 + 4 * 3];
            int innerTriCount = 0;
            for (int i = 0; i < OriginalInnerVertices.Count; i++)
            {
                innerTriCount += (OriginalInnerVertices[i].Length - 1) * 4 * 3 + 4 * 3;
            }
            int[] tris = new int[shape.Triangles.Count * 3 + (OriginalVertices.Length - 1) * 4 * 3 + 4 * 3 + innerTriCount];
            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);
        }
Exemplo n.º 6
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);
        }
Exemplo n.º 7
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);
        }