public override System.Collections.IEnumerator Build(Node n, MapChunkLoader mcl)
    {
        Vector3 position = new Vector3((float)(n.easthing - mcl.offsetPositionX), 15000.0f, (float)(n.northing - mcl.offsetPositionZ));
        RaycastHit hit;
        if (Physics.Raycast(position, -Vector3.up, out hit, Mathf.Infinity, mcl.layerMask))
        {
            position.y = hit.point.y;
            yield return null;
        }

        MapChunkLoader.Instantiate(Resources.Load("/Prefabs/Tree.prefab"), position, Quaternion.identity);
        yield return null;
    }
 public abstract IEnumerator Build(Node n, MapChunkLoader mcl);
 public abstract IEnumerator Build(Way w, MapChunkLoader mcl);
 public override System.Collections.IEnumerator Build(Way n, MapChunkLoader mcl)
 {
     throw new NotImplementedException();
 }
    public override IEnumerator Build(Way w, MapChunkLoader mcl)
    {
        Vector3[] nodes = new Vector3[w.nodes.Count];
        Vector2[] xz = new Vector2[w.nodes.Count];

        float height = 0;

        mcl.mapManager.mapHash.Add(w.id);
        mcl.wayList.Add(w.id);
        GameObject roof = new GameObject();
        // roof.transform.position = new Vector3(0, centroid.y, 0);
        roof.name = "Area - " + (2 * w.id).ToString();
        mcl.mapManager.mapHash.Add(2 * w.id);
        mcl.wayList.Add(2 * w.id);
        roof.isStatic = true;
        if (w.name != null)
        {
            GameObject label = new GameObject();
            FloatingLabel lb = label.AddComponent<FloatingLabel>();
            lb.text = w.name;
            //lb.transform.position = centroid;
            lb.target = GameObject.FindGameObjectWithTag("Player").transform;
            label.transform.parent = roof.transform;
        }
        roof.transform.parent = mcl.transform;
        Mesh roofm = new Mesh();
        roof.AddComponent<MeshRenderer>();
        MeshFilter filter2 = roof.AddComponent<MeshFilter>();
        roof.AddComponent<MeshCollider>();

        string areaPath = Application.persistentDataPath + "Assets/Resources/Objs/" + roof.name + ".obj";

        if (!File.Exists(areaPath)) // If the file isn't cached we calculate everything and then we cache it
        {

            if (w.height != 0)
                height = w.height;

            Vector3 centroid = new Vector3();
            for (int a = 0; a < w.nodes.Count; a++)
            {
                yield return null;
                RaycastHit hit;
                Node n = w.nodes[a];
                nodes[a] = new Vector3((float)((n.easthing - mcl.offsetPositionX) / MapChunkLoader.precision), 5000, (float)((n.northing - mcl.offsetPositionZ) / MapChunkLoader.precision));
                if (Physics.Raycast(nodes[a], -Vector3.up, out hit, Mathf.Infinity, mcl.layerMask))
                {
                    nodes[a].y = hit.point.y + height + 0.5f;
                }
                else
                {
                    nodes[a].y = 1;
                }
                xz[a] = new Vector2((float)((n.easthing - mcl.offsetPositionX) / MapChunkLoader.precision), (float)((n.northing - mcl.offsetPositionZ) / MapChunkLoader.precision));
                centroid += nodes[a];
            }
            centroid /= w.nodes.Count;
            centroid.y += 1;

            //  Vector3 position = new Vector3(centroid.x, 5000, centroid.z);
            float baseHeight = 0;

            /*RaycastHit hit;
            if (Physics.Raycast(position, -Vector3.up, out hit, Mathf.Infinity, layerMask))
            {
                baseHeight = hit.point.y;
            }*/
            //centroid = new Vector3(centroid.x, centroid.y + baseHeight, centroid.z);

            Vector2[] xzRoof = new Vector2[w.nodes.Count - 1];

            for (int a = 0; a < xzRoof.Length; a++)
            {
                xzRoof[a] = xz[a];
            }

            Triangulator tr = new Triangulator(xzRoof);

            int[] indices = tr.Triangulate();
            // Create the mesh

            roofm.vertices = nodes;
            roofm.triangles = indices;

            Vector2[] uvs = new Vector2[nodes.Length];
            for (int a = 0; a < nodes.Length; a++)
            {
                if (a < nodes.Length - 1)
                {
                    uvs[a] = new Vector2(Mathf.Abs(nodes[a].x) / nodes[nodes.Length - 1].x, Mathf.Abs(nodes[a].z) / nodes[nodes.Length - 1].x);
                }
                else
                {
                    uvs[a] = new Vector2(1, 1);
                }
            }

            roofm.uv = uvs;
            roofm.RecalculateNormals();
            roofm.RecalculateBounds();
            filter2.sharedMesh = roofm;

            if (mcl.exportObjs)
            {
                ObjExporter oe = new ObjExporter();
                oe.MeshToFile(filter2, areaPath);
            }
        }
        else
        {
            ObjImporter oi = new ObjImporter();
            mcl.StartCoroutine(oi.FileToMesh("file://" + areaPath));
            while (oi._myMesh == null)
            {
                yield return null;
            }

            filter2.sharedMesh = oi._myMesh;
            Debug.LogWarning("Loaded Area from cache " + areaPath);
        }

        if (w.type == WayType.Parking)
            roof.GetComponent<MeshRenderer>().material = Resources.Load("Materials/Parking Material") as Material;
        if (w.type == WayType.Park)
            roof.GetComponent<MeshRenderer>().material = Resources.Load("Materials/Park Material") as Material;
        if (w.type == WayType.RiverBank)
            roof.GetComponent<MeshRenderer>().material = Resources.Load("Materials/River Material") as Material;
    }
 public override IEnumerator Build(Node n, MapChunkLoader mcl)
 {
     return null;
 }
    public override IEnumerator Build(Way w, MapChunkLoader mcl)
    {
        //CreateBuilding(Way w)

        Mesh roofm = new Mesh();
        Mesh wallsm = new Mesh();

        GameObject build = new GameObject();
        build.name = "Building - " +  w.id.ToString();

        build.transform.parent = mcl.transform;
        GameObject roof = new GameObject();
        //roof.transform.position = new Vector3(0,baseHeight,0);
        roof.name = "Roof - " +(2 * w.id).ToString();
        mcl.mapManager.mapHash.Add(2 * w.id);
        mcl.wayList.Add(2 * w.id);

        GameObject walls = new GameObject();
        walls.name = "Walls - " + (3 * w.id).ToString();
        //walls.transform.position = new Vector3(0,baseHeight,0);
        mcl.mapManager.mapHash.Add(3 * w.id);
        mcl.wayList.Add(3 * w.id);

        walls.AddComponent<MeshCollider>();
        walls.AddComponent(typeof(MeshRenderer));
        MeshFilter filter = walls.AddComponent(typeof(MeshFilter)) as MeshFilter;

        roof.AddComponent<MeshCollider>();
        roof.AddComponent(typeof(MeshRenderer));
        MeshFilter filter2 = roof.AddComponent(typeof(MeshFilter)) as MeshFilter;

        string buildPath = Application.persistentDataPath + "Assets/Resources/Objs/" + build.name + ".obj";

        string roofPath = Application.persistentDataPath+"Assets/Resources/Objs/" + roof.name + ".obj";

        if (!File.Exists(buildPath) && !File.Exists(roofPath)) // If the file isn't cached we calculate everything and then we cache it
        {
            Vector3[] nodes = new Vector3[w.nodes.Count];
            Vector2[] xz = new Vector2[w.nodes.Count];

            float height = (float)w.nodes[0].northing % referenceVariationHeight + referenceBaseHeight;

            if (w.height != 0)
            {
                height = w.height;
                referenceVariationHeight = Mathf.Abs(referenceVariationHeight - height);
                referenceBaseHeight = (referenceBaseHeight + height) / 2;
            }
            Vector3 centroid = new Vector3();

                Vector3 position;
                RaycastHit hit;
                for (int a = 0; a < w.nodes.Count; a++)
                {
                    yield return null;
                    Node n = w.nodes[a];
                    position = new Vector3((float)((n.easthing - mcl.offsetPositionX) / MapChunkLoader.precision), 5000, (float)((n.northing - mcl.offsetPositionZ) / MapChunkLoader.precision));
                    float castH = 0;

                    if (Physics.Raycast(position, -Vector3.up, out hit, Mathf.Infinity, mcl.layerMask))
                    {
                        castH = hit.point.y;
                    }
                    nodes[a] = new Vector3(position.x, castH + height, position.z);
                    xz[a] = new Vector2(position.x, position.z);
                    centroid += nodes[a];
                }
                centroid /= w.nodes.Count;
                centroid.y += 1;

            Vector2[] xzRoof = new Vector2[w.nodes.Count -1];

            for (int a = 0; a < xzRoof.Length; a++)
            {
                xzRoof[a] = xz[a];
            }
            int[] indices;
            Vector3[] roofNodes;
            if (nodes.Length != 5 && nodes.Length != 6 && nodes.Length != 7 && nodes.Length != 8)
             {
                 Triangulator tr = new Triangulator(xzRoof);

                 int[] tempIndices = tr.Triangulate();
                 indices = tempIndices;
                 roofNodes = nodes;

             }
             else
             {
                 int[] tempIndices = new int[(nodes.Length-1)*3];
                 Vector3 midpoint = new Vector3();

                 for (int i = 0; i < nodes.Length-1; i++)
                 {
                     midpoint.x += nodes[i].x;
                     midpoint.y += nodes[i].y;
                     midpoint.z += nodes[i].z;
                 }

                 roofNodes = new Vector3[nodes.Length];
                 midpoint.x = midpoint.x / (nodes.Length-1);
                 midpoint.y = midpoint.y / (nodes.Length - 1) + height/5;
                 midpoint.z = midpoint.z / (nodes.Length - 1);

                 for (int i = 0; i < roofNodes.Length - 1; i++)
                 {
                     roofNodes[i] = nodes[i];
                 }

                 roofNodes[roofNodes.Length - 1] = midpoint;

                Triangle test = new Triangle();
                 test.a = roofNodes[0];
                 test.b = roofNodes[1];
                 test.c = roofNodes[4];
                 Vector3 testVector = test.Normal;

                 int u = 0;
                 for (int i = 0; i < roofNodes.Length - 2; i += 1)
                 {
                     if (testVector.y > 0)
                     {
                         tempIndices[u] = i;
                         tempIndices[u + 1] = i + 1;
                         tempIndices[u + 2] = roofNodes.Length - 1;
                     }
                     else
                     {
                         tempIndices[u + 1] = i;
                         tempIndices[u] = i + 1;
                         tempIndices[u + 2] = roofNodes.Length - 1;
                     }
                     u += 3;
                     if (u >= tempIndices.Length - 3)
                     {
                         i += 1;
                         if (testVector.y > 0)
                         {
                             tempIndices[u] = i;
                             tempIndices[u + 1] = 0;
                             tempIndices[u + 2] = roofNodes.Length - 1;
                         }
                         else
                         {
                             tempIndices[u + 1] = i;
                             tempIndices[u] = 0;
                             tempIndices[u + 2] = roofNodes.Length - 1;
                         }
                     }
                 }

                 indices = tempIndices;

             }
            // Create the mesh

            Vector2[] uvs = new Vector2[roofNodes.Length];
            for (int a = 0; a < roofNodes.Length; a++)
            {
                if (a < roofNodes.Length - 1)
                {
                    uvs[a] = new Vector2(a,0);
                }
                else
                {
                    uvs[a] = new Vector2(a/2, 1);
                }
            }

            roofm.vertices = roofNodes;
            roofm.triangles = indices;
            roofm.uv = uvs;
            roofm.RecalculateNormals();
            roofm.RecalculateBounds();

            // Set up game object with mesh;
                centroid = new Vector3(centroid.x, centroid.y, centroid.z);
                wallsm = BuildingCountourMesh(nodes, wallsm, height);

                if (w.name != null)
                {
                    GameObject label = new GameObject();
                    FloatingLabel lb = label.AddComponent<FloatingLabel>();
                    lb.transform.parent = roof.transform;
                    lb.text = w.name;
                    lb.target = GameObject.FindGameObjectWithTag("Player").transform;
                    lb.transform.position = centroid;
                }
                build.transform.parent = mcl.transform;
                walls.transform.parent = build.transform;
                roof.transform.parent = build.transform;

              //Wall
                filter.sharedMesh = wallsm;
               // wallmc.sharedMesh = wallsm;

              //Roof
                filter2.sharedMesh = roofm;
                //roofmc.sharedMesh = roofm;

                if (mcl.exportObjs)
                {
                    ObjExporter oe1 = new ObjExporter();
                    ObjExporter oe2 = new ObjExporter();
                    oe1.MeshToFile(filter, buildPath);
                    oe2.MeshToFile(filter2, roofPath);
                }
            }
            else
            {
                ObjImporter oi = new ObjImporter();
                mcl.StartCoroutine(oi.FileToMesh("file://" + buildPath));

                while (oi._myMesh == null)
                {
                    yield return null;
                }

                filter.sharedMesh = oi._myMesh;
                Debug.LogWarning("Loaded Walls from cache " + buildPath);

                ObjImporter oi2 = new ObjImporter();
                mcl.StartCoroutine(oi2.FileToMesh("file://" + roofPath));

                while (oi2._myMesh == null)
                {
                    yield return null;
                }

                filter2.sharedMesh = oi2._myMesh;
                Debug.LogWarning("Loaded Roof from cache " + roofPath);
            }

        /*if (w.height != 0)
        {
            walls.GetComponent<MeshRenderer>().material = Resources.Load("Materials/Real Height Material") as Material;
        }
        else*/
        {
            int textureIndex = UnityEngine.Random.Range(1,4);

            walls.GetComponent<MeshRenderer>().material = Resources.Load("Materials/BuildingMaterial" + textureIndex) as Material;
        }
        /*if (w.height != 0)
        {
            roof.GetComponent<MeshRenderer>().material = Resources.Load("Materials/Real Height Material") as Material;
        }
        else*/
        {
            int textureIndex = UnityEngine.Random.Range(1, 3);
            roof.GetComponent<MeshRenderer>().material = Resources.Load("Materials/Roof" + textureIndex) as Material;
        }
    }
    public override IEnumerator Build(Way w, MapChunkLoader mcl)
    {
        //GameObject go = new GameObject();
        //go.name = "Road";

        GameObject road = new GameObject();
        road.name = "Road - " + w.id.ToString();
        road.isStatic = true;
        road.transform.parent = mcl.transform;
        string roadPath = Application.persistentDataPath + "Assets/Resources/Objs/" + road.name + ".obj";

        if (!File.Exists(roadPath)) // If the file isn't cached we calculate everything and then we cache it
        {
            Debug.Log("STARTED CREATING ROAD");
            PolyLine pl = new PolyLine(w.id.ToString());
            pl.SetOffset(mcl.offsetPositionX, mcl.offsetPositionZ);
            pl.heigth = w.height;

            if (w.type == WayType.Footway)
            {
                pl.material = Resources.Load("Materials/Footway Material") as Material;
                pl.width = 1;
            }
            if (w.type == WayType.Motorway)
            {
                pl.material = Resources.Load("Materials/Road Material") as Material;
                pl.width = 4;
                pl.lanes = 2;
            }
            if (w.type == WayType.Residential)
            {
                pl.material = Resources.Load("Materials/Road Material") as Material;
                pl.width = 2;
            }
            if (w.type == WayType.River)
            {
                pl.material = Resources.Load("Materials/River Material") as Material;
                pl.width = 8;
            }

            for (int a = 0; a < w.nodes.Count; a++)
            {
                Node n = w.nodes[a];

                Vector3 position = new Vector3((float)(n.easthing - mcl.offsetPositionX), 5000, (float)(n.northing - mcl.offsetPositionZ));
                float baseHeight = 0;
                RaycastHit hit;

                if (Physics.Raycast(position, -Vector3.up, out hit, Mathf.Infinity, mcl.layerMask))
                {
                    baseHeight = hit.point.y;
                }
                n.height = baseHeight;
                pl.Add(n);

            }
            //Closed road;
            mcl.StartCoroutine(pl.Close(road));

            if (mcl.exportObjs)
            {
                while (road.GetComponent<MeshFilter>() == null)
                {
                    yield return null;
                }
                MeshFilter mf = road.GetComponent<MeshFilter>();
                ObjExporter oe = new ObjExporter();
                oe.MeshToFile(mf, roadPath);

            }
        }
        else
        {
            ObjImporter oi = new ObjImporter();
            mcl.StartCoroutine(oi.FileToMesh("file://" + roadPath));
            while (oi._myMesh == null)
            {
                yield return null;

            }
            MeshFilter mf = road.AddComponent<MeshFilter>();
            MeshRenderer mr = road.AddComponent<MeshRenderer>();
            mf.sharedMesh = oi._myMesh;
            Debug.LogWarning("Loaded Road from cache " + roadPath);
            if (w.type == WayType.Footway)
            {
                mr.material = Resources.Load("Materials/Footway Material") as Material;

            }
            if (w.type == WayType.Motorway)
            {
                mr.material = Resources.Load("Materials/Road Material") as Material;

            }
            if (w.type == WayType.Residential)
            {
                mr.material = Resources.Load("Materials/Road Material") as Material;

            }
            if (w.type == WayType.River)
            {
                mr.material = Resources.Load("Materials/River Material") as Material;

            }
        }
    }