Пример #1
0
        public static OBBox CreateAlongSide(Vector2[] points, int index)
        {
            if (points.Length == 0)
            {
                Debug.LogError("No points sent!");
            }
            int   pointCount = points.Length;
            OBBox output     = GetBox();

            Vector2 p0    = points[index];
            Vector2 p1    = points[index < pointCount - 1 ? index + 1 : 0];
            Vector2 dir   = (p1 - p0).normalized;
            float   angle = JMath.SignAngle(dir);

            FlatBounds bounds = new FlatBounds();

            for (int o = 0; o < pointCount; o++)//encapsulate rotated points
            {
                bounds.Encapsulate(JMath.Rotate(points[o], angle));
            }

            Vector2 center = JMath.Rotate(bounds.center, -angle);

            output.SetValues(center, dir, bounds.height, JMath.Rotate(dir, 90), bounds.width);

            return(output);
        }
Пример #2
0
        public static bool PointInsidePoly(Vector2Int point, Vector2Int[] poly)
        {
            FlatBounds bounds = new FlatBounds();

            foreach (Vector2Int polyPoint in poly)
            {
                bounds.Encapsulate(polyPoint.vector2);
            }
            if (!bounds.Contains(point.vector2))
            {
                return(false);
            }

            Vector2Int pointRight = point + new Vector2Int(bounds.width, 0);

            int numberOfPolyPoints = poly.Length;
            int numberOfCrossOvers = 0;

            for (int i = 0; i < numberOfPolyPoints; i++)
            {
                Vector2Int p0 = poly[i];
                Vector2Int p1 = poly[(i + 1) % numberOfPolyPoints];
                if (FastLineIntersection(point, pointRight, p0, p1))
                {
                    numberOfCrossOvers++;
                }
            }
            //            if(numberOfCrossOvers % 2 != 0) bounds.DrawDebug(Color.green);

            return(numberOfCrossOvers % 2 != 0);
        }
Пример #3
0
        private static Vector2 GetCenter(Vector2[] points)
        {
            FlatBounds bounds     = new FlatBounds();
            int        pointCount = points.Length;

            for (int i = 0; i < pointCount; i++)
            {
                bounds.Encapsulate(points[i]);
            }
            return(bounds.center);
        }
Пример #4
0
        /// <summary>
        /// This one ignores finding openings within specific shapes as we'll be doing this for rooms in floorplan gen
        /// </summary>
        /// <param name="building"></param>
        /// <param name="volume"></param>
        /// <returns></returns>
        public static VerticalOpening[] GetOpeningsQuick(IBuilding building, IVolume volume)
        {
            List <VerticalOpening> output = new List <VerticalOpening>();
            int count = building.openingCount;

            VerticalOpening[] openings = building.GetAllOpenings();

            int volumeBaseFloor = building.VolumeBaseFloor(volume);
            int volumeTopFloor  = volumeBaseFloor + volume.floors;

            for (int i = 0; i < count; i++)
            {
                VerticalOpening opening          = openings[i];
                int             openingBaseFloor = opening.baseFloor;
                int             openingTopFloor  = openingBaseFloor + opening.floors;

//                Debug.Log("CHECK IT " + openingTopFloor + " " + volume.name);
//                Debug.Log(volumeBaseFloor + " < " + openingTopFloor + " && " + openingBaseFloor + " < " + volumeTopFloor);

                if (volumeBaseFloor <= openingTopFloor && openingBaseFloor < volumeTopFloor)//opening and volume floors intersect
                {
//                    Debug.Log("opening " + openingTopFloor + " "+ volume.name);
                    FlatBounds volumeBounds = new FlatBounds(volume.bounds);
                    volumeBounds.Expand(VerticalOpening.WALL_THICKNESS);
                    Vector2[]  openingPoints = opening.PointsRotated();
                    FlatBounds openingBounds = new FlatBounds(openingPoints);


//                    if(volume.name == "Roof Exit")
//                    {
//                        Debug.Log(volumeBounds.Overlaps(openingBounds, true));
//                        Debug.Log(openingBounds.Overlaps(volumeBounds, true));
//                        volumeBounds.DrawDebug(Color.red);
//                        openingBounds.DrawDebug(Color.green);
//                    }

                    if (openingBounds.Overlaps(volumeBounds, true))// opening is within the AABB bounds of the volume
                    {
                        output.Add(opening);
//                        Debug.Log("opening bounds " + openingTopFloor + " " + volume.name);
                    }
                    else
                    {
//                        Debug.Log("opening NOT " + openingTopFloor + " " + volume.name);
                    }
                }
//                Debug.Log("=================================");
            }
            return(output.ToArray());
        }
Пример #5
0
        public Room(FlatBounds bounds, Vector3 offset)
        {
            _points.Clear();
            Vector2Int of = new Vector2Int(offset.x, offset.z);
            Vector2Int p0 = new Vector2Int(bounds.xMin, bounds.yMin) + of;
            Vector2Int p1 = new Vector2Int(bounds.xMax, bounds.yMin) + of;
            Vector2Int p2 = new Vector2Int(bounds.xMax, bounds.yMax) + of;
            Vector2Int p3 = new Vector2Int(bounds.xMin, bounds.yMax) + of;

            _points.Add(new RoomPoint(p0));
            _points.Add(new RoomPoint(p1));
            _points.Add(new RoomPoint(p2));
            _points.Add(new RoomPoint(p3));

            MarkModified();
        }
            public FloorSegment(float area, FlatBounds bounds, params Vector2Int[] input)
            {
                int inputCount = input.Length;

                points      = new Vector2Int[inputCount];
                this.bounds = bounds;
                for (int p = 0; p < inputCount; p++)
                {
                    points[p] = input[p];
                }
                //                CalculateNormals();
                position = new Vector2Int(bounds.center);
                nBounds  = new FlatBounds(bounds);
                nBounds.Expand(0.25f);
                this.area  = area;
                neighbours = new List <FloorSegment>();
            }
Пример #7
0
        public static Vector2[] RoomCut(Vector2[] roomShape, List <Vector2[]> cutShape)
        {
            Vector2[] cut         = cutShape[0];
            int       baseCount   = roomShape.Length;
            int       cutCount    = cut.Length;
            int       outputCount = baseCount + cutCount;//todo add 2 and align

            Vector2[]  output       = new Vector2[outputCount];
            FlatBounds bounds       = new FlatBounds(cut);
            Vector2    center       = bounds.center;
            float      nrest        = Mathf.Infinity;
            int        nearestIndex = 0;

            Array.Reverse(cut);//reverse winding to create cut
            for (int b = 0; b < baseCount; b++)
            {
                float sqrMag = (roomShape[b] - center).sqrMagnitude;
                if (sqrMag < nrest)
                {
                    Vector2 a1 = center;
                    Vector2 a2 = roomShape[b];
                    bool    intersectsShape = false;
                    for (int x = 0; x < baseCount; x++)
                    {
                        if (b == x)
                        {
                            continue;
                        }
                        int x2 = (x + 1) % baseCount;
                        if (b == x2)
                        {
                            continue;
                        }
                        Vector2 b1 = roomShape[x];
                        Vector2 b2 = roomShape[x2];
                        if (FastLineIntersection(a1, a2, b1, b2))
                        {
                            intersectsShape = true;
                            break;
                        }
                    }
                    if (!intersectsShape)
                    {
                        nearestIndex = b;
                        nrest        = sqrMag;
                    }
                    //intersection check
                }
            }

            for (int o = 0; o < outputCount; o++)
            {
                if (o < nearestIndex)
                {
                    output[o] = roomShape[o];
                }
                else if (o >= nearestIndex && o < nearestIndex + cutCount)
                {
                    int cutIndex = o - nearestIndex;
                    output[o] = cut[cutIndex];
                }
                else
                {
                    int finalIndex = o - cutCount;
                    output[o] = roomShape[finalIndex];
                }
            }

            return(output);
        }
Пример #8
0
        public static void Generate(IBuilding building, IVolume volume, IFloorplan floorplan, int volumeFloor, VerticalOpening[] openings, BuildRMesh mesh, BuildRCollider collider)
        {
            SubmeshLibrary submeshLibrary = mesh.submeshLibrary;

            bool           generateColliders     = building.colliderType != BuildingColliderTypes.None;
            bool           generateMeshColliders = building.colliderType != BuildingColliderTypes.Primitive && generateColliders;
            BuildRCollider sendCollider          = (generateColliders) ? collider : null;

            collider.thickness = volume.wallThickness;
            if (!generateMeshColliders)
            {
                collider = null;
            }

            float   wallThickness = volume.wallThickness;
            float   wallUp        = volume.floorHeight - wallThickness;
            Vector3 wallUpV       = Vector3.up * wallUp;
            Vector3 floorBaseV    = Vector3.up * volume.baseHeight;

            int roomCount = floorplan.RoomCount;

            int actualFloor  = building.VolumeBaseFloor(volume) + volumeFloor;
            int openingCount = openings.Length;

            bool[]       openingBelow           = new bool[openingCount];
            bool[]       openingAbove           = new bool[openingCount];
            FlatBounds[] openingBounds          = new FlatBounds[openingCount];
            Vector2[][]  openingShapes          = new Vector2[openingCount][];
            bool[]       openingUsedInThisFloor = new bool[openingCount];
            for (int o = 0; o < openingCount; o++)
            {
                VerticalOpening opening = openings[o];
                if (!openings[o].FloorIsIncluded(actualFloor))
                {
                    continue;
                }
                openingBelow[o]  = opening.FloorIsIncluded(actualFloor - 1);
                openingAbove[o]  = opening.FloorIsIncluded(actualFloor + 1);
                openingShapes[o] = opening.PointsRotated();
                openingBounds[o] = new FlatBounds(openingShapes[o]);

                submeshLibrary.Add(opening.surfaceA);
                submeshLibrary.Add(opening.surfaceB);
                submeshLibrary.Add(opening.surfaceC);
                submeshLibrary.Add(opening.surfaceD);
            }

            Dictionary <int, List <Vector2Int> > externalWallAnchors = volume.facadeWallAnchors;

            Room[] rooms = floorplan.AllRooms();
            for (int r = 0; r < roomCount; r++)
            {
                Room room       = rooms[r];
                int  pointCount = room.numberOfPoints;

                Surface floorSurface   = null;
                Surface wallSurface    = null;
                Surface ceilingSurface = null;

                if (room.style != null)
                {
                    RoomStyle style = room.style;
                    floorSurface   = style.floorSurface;
                    wallSurface    = style.wallSurface;
                    ceilingSurface = style.ceilingSurface;
                }

                int floorSubmesh   = submeshLibrary.SubmeshAdd(floorSurface);
                int wallSubmesh    = submeshLibrary.SubmeshAdd(wallSurface);
                int ceilingSubmesh = submeshLibrary.SubmeshAdd(ceilingSurface);

                FloorplanUtil.RoomWall[] walls = FloorplanUtil.CalculatePoints(room, volume);
                Vector2[] roomArchorPoints     = FloorplanUtil.RoomArchorPoints(walls);

                Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right);

                Vector2[] offsetRoomAnchorPoints = QuickPolyOffset.Execute(roomArchorPoints, wallThickness);

                FlatBounds             roomBounds   = new FlatBounds(offsetRoomAnchorPoints);
                List <Vector2[]>       floorCuts    = new List <Vector2[]>();
                List <Vector2[]>       ceilingCuts  = new List <Vector2[]>();
                List <VerticalOpening> roomOpenings = new List <VerticalOpening>();
                for (int o = 0; o < openingCount; o++)
                {
                    if (openings[o].FloorIsIncluded(actualFloor))
                    {
                        if (roomBounds.Overlaps(openingBounds[o]))
                        {
                            if (CheckShapeWithinRoom(offsetRoomAnchorPoints, openingShapes[o]))
                            {
                                if (openingBelow[o])
                                {
                                    floorCuts.Add(openingShapes[o]);
                                }
                                if (openingAbove[o])
                                {
                                    ceilingCuts.Add(openingShapes[o]);
                                }
                                if (openingAbove[o] || openingBelow[o])
                                {
                                    roomOpenings.Add(openings[o]);
                                    openingUsedInThisFloor[o] = true;
                                }
                            }
                        }
                    }
                }

                int offsetPointBase = 0;
                for (int p = 0; p < pointCount; p++)//generate room walls
                {
                    FloorplanUtil.RoomWall wall = walls[p];
                    int wallPointCount          = wall.offsetPoints.Length;

                    List <RoomPortal> wallPortals = floorplan.GetWallPortals(room, p);
                    int wallPortalCount           = wallPortals.Count;

                    if (!wall.isExternal)
                    {
                        int     indexA    = offsetPointBase;
                        int     indexB    = (offsetPointBase + 1) % roomArchorPoints.Length;
                        Vector2 origBaseA = roomArchorPoints[indexA];
                        Vector2 origBaseB = roomArchorPoints[indexB];
                        Vector2 baseA     = offsetRoomAnchorPoints[indexA];
                        Vector2 baseB     = offsetRoomAnchorPoints[indexB];
                        Vector3 v0        = new Vector3(origBaseA.x, 0, origBaseA.y) + floorBaseV;
                        Vector3 v1        = new Vector3(origBaseB.x, 0, origBaseB.y) + floorBaseV;
                        Vector3 vOffset0  = new Vector3(baseA.x, 0, baseA.y) + floorBaseV;
                        Vector3 vOffset1  = new Vector3(baseB.x, 0, baseB.y) + floorBaseV;
                        if (wallPortalCount == 0)  //just draw the wall - no portals to cut

                        {
                            Vector3 v2 = vOffset1 + wallUpV;
                            Vector3 v3 = vOffset0 + wallUpV;

                            Vector2 minUV = Vector2.zero;
                            Vector2 maxUV = new Vector2(Vector2.Distance(baseA, baseB), wallUp);
                            if (wallSurface != null)
                            {
                                maxUV = wallSurface.CalculateUV(maxUV);
                            }
                            Vector3 wallDir     = (vOffset0 - vOffset1).normalized;
                            Vector3 wallNormal  = Vector3.Cross(Vector3.up, wallDir);
                            Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir);
                            mesh.AddPlane(vOffset1, vOffset0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface);

                            if (generateColliders)
                            {
                                collider.AddPlane(vOffset1, vOffset0, v2, v3);
                            }
                        }
                        else
                        {
                            List <float> useLaterals = new List <float>();
                            List <bool>  hasPortals  = new List <bool>();
                            for (int wp = 0; wp < wallPortalCount; wp++)
                            {
                                RoomPortal portal    = wallPortals[wp];
                                bool       hasPortal = room.HasPortal(portal);
                                hasPortals.Add(hasPortal);
                                if (hasPortal)
                                {
                                    useLaterals.Add(portal.lateralPosition);
                                }
                                else
                                {
                                    useLaterals.Add(1 - portal.lateralPosition);//portal from other wall - wall orientation is flipped
                                }
                            }

                            Vector3 wallVector               = vOffset1 - vOffset0;
                            Vector3 wallDirection            = wallVector.normalized;
                            Vector3 wallStart                = vOffset0;
                            Vector4 wallTangent              = BuildRMesh.CalculateTangent(wallDirection);
                            Vector3 wallNormal               = Vector3.Cross(Vector3.up, wallDirection);
                            Vector4 wallNormalTangent        = BuildRMesh.CalculateTangent(wallNormal);
                            Vector4 wallNormalTangentReverse = BuildRMesh.CalculateTangent(-wallNormal);

                            while (wallPortalCount > 0)
                            {
                                int        portalIndex = 0;
                                RoomPortal usePortal   = wallPortals[0];
                                float      lowestLat   = useLaterals[0];
                                for (int wp = 1; wp < wallPortalCount; wp++)
                                {
                                    if (useLaterals[wp] < lowestLat)
                                    {
                                        portalIndex = wp;
                                        usePortal   = wallPortals[wp];
                                        lowestLat   = useLaterals[wp];
                                    }
                                }

                                wallPortals.RemoveAt(portalIndex);
                                useLaterals.RemoveAt(portalIndex);
                                wallPortalCount--;

                                Vector3 vl0 = v0 + (-wallNormal + wallDirection) * wallThickness;
                                Vector3 vl1 = v1 + (-wallNormal - wallDirection) * wallThickness;

                                Vector3 portalCenter     = Vector3.Lerp(vl0, vl1, lowestLat);
                                Vector3 portalHalfvector = wallDirection * (usePortal.width * 0.5f);
                                Vector3 portalBase       = Vector3.up * (volume.floorHeight - usePortal.height) * usePortal.verticalPosition;
                                Vector3 portalUp         = portalBase + Vector3.up * usePortal.height;
                                Vector3 portalStart      = portalCenter - portalHalfvector;
                                Vector3 portalEnd        = portalCenter + portalHalfvector;

                                Vector2 initalWallUVMin = new Vector2(Vector3.Dot(portalStart, wallDirection), 0);
                                Vector2 initalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp);
                                mesh.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV, initalWallUVMin, initalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//initial wall
                                if (generateColliders)
                                {
                                    collider.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV);
                                }
                                if (usePortal.verticalPosition > 0)
                                {
                                    Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), 0);
                                    Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), portalBase.y);
                                    mesh.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//bottom
                                    if (generateColliders)
                                    {
                                        collider.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase);
                                    }
                                }
                                if (usePortal.verticalPosition < 1)
                                {
                                    Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), portalUp.y);
                                    Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), wallUp);
                                    mesh.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//top
                                    if (generateColliders)
                                    {
                                        collider.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV);
                                    }
                                }

                                if (hasPortals[portalIndex])//only do this once - from the room it's attached to
                                {
                                    //portal interior frame
                                    Vector3 portalDepth = wallNormal * wallThickness * 2;

                                    //sides
                                    mesh.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp, wallDirection, wallNormalTangentReverse, wallSubmesh);
                                    mesh.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp, -wallDirection, wallNormalTangent, wallSubmesh);

                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp);
                                        collider.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp);
                                    }

                                    //floor
                                    Vector2 minFloorUv = new Vector2((portalEnd + portalBase).z, (portalEnd + portalBase).x);
                                    Vector2 maxFloorUv = minFloorUv + new Vector2(wallThickness, usePortal.width);
                                    mesh.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase, minFloorUv, maxFloorUv, Vector3.up, wallTangent, floorSubmesh, floorSurface);
                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase);
                                    }

                                    //ceiling
                                    mesh.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp, Vector3.down, wallTangent, wallSubmesh);
                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp);
                                    }
                                }

                                wallStart = portalEnd;//move the start for the next calculation
                            }

                            Vector2 finalWallUVMin = new Vector2(Vector3.Dot(vOffset1, wallDirection), 0);
                            Vector2 finalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp);
                            mesh.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV, finalWallUVMin, finalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//final wall section
                            if (generateColliders)
                            {
                                collider.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV);
                            }
                        }
                        offsetPointBase += 1;
                    }
                    else//external anchored wall
                    {
                        int    facadeIndex  = wall.facadeIndex;
                        Facade facadeDesign = volume.GetFacade(facadeIndex);
                        int    currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count - 1;
                        int    currentWallSectionIndex        = wall.offsetPointWallSection[0];
                        int    wallOffsetPoints = wall.offsetPoints.Length;
                        for (int w = 0; w < wallOffsetPoints - 1; w++)
                        {
                            int     roomPointIndex   = offsetPointBase + w;
                            Vector2 baseA            = offsetRoomAnchorPoints[roomPointIndex];
                            int     offsetIndexB     = (roomPointIndex + 1) % offsetRoomAnchorPoints.Length;
                            Vector2 baseB            = offsetRoomAnchorPoints[offsetIndexB];
                            Vector3 v0               = new Vector3(baseA.x, 0, baseA.y) + floorBaseV;
                            Vector3 v1               = new Vector3(baseB.x, 0, baseB.y) + floorBaseV;
                            int     wallSectionIndex = wall.offsetPointWallSection[w];

                            bool canGenerateWallSection = facadeDesign != null;

                            Vector3 wallVector = v0 - v1;
                            Vector3 wallDir    = wallVector.normalized;
                            float   wallLength = wallVector.magnitude;

                            if (!canGenerateWallSection)
                            {
                                if (wallSurface != null)
                                {
                                    submeshLibrary.Add(wallSurface);
                                }

                                Vector3 v2 = v1 + wallUpV;
                                Vector3 v3 = v0 + wallUpV;

                                Vector2 minUV       = Vector2.zero;
                                Vector2 maxUV       = new Vector2(Vector2.Distance(baseA, baseB), wallUp);
                                Vector3 wallNormal  = Vector3.Cross(Vector3.up, wallDir);
                                Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir);
                                mesh.AddPlane(v1, v0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface);

                                if (generateMeshColliders)
                                {
                                    collider.AddPlane(v1, v0, v2, v3);
                                }
                            }
                            else
                            {
                                WallSection section = facadeDesign.GetWallSection(wallSectionIndex, volumeFloor, currentFacadeWallSectionLength, volume.floors);
                                if (section.model != null)
                                {
                                    continue;//cannot account for custom meshes assume custom mesh does include interior mesh or if does - will be generated with the exterior
                                }
                                GenerationOutput generatedSection = GenerationOutput.CreateRawOutput();
                                Vector2          wallSectionSize  = new Vector2(wallLength, wallUp + wallThickness);
                                bool             cullOpening      = building.cullDoors && section.isDoor;
                                SubmeshLibrary   sectionLib       = new SubmeshLibrary();

                                if (wallSurface != null)
                                {
                                    sectionLib.Add(wallSurface);//add interior wall surface
                                    submeshLibrary.Add(wallSurface);
                                }

                                sectionLib.Add(section.openingSurface);//add windows - the only surface we'll use in the interior room
                                submeshLibrary.Add(section.openingSurface);

                                float offset = 0;
                                if (w == 0)
                                {
                                    offset = wallThickness;
                                }
                                if (w == wallOffsetPoints - 2)
                                {
                                    offset = -wallThickness;
                                }
                                WallSectionGenerator.Generate(section, generatedSection, wallSectionSize, true, wallThickness, cullOpening, null, sectionLib, offset);
                                int[]   mapping     = submeshLibrary.MapSubmeshes(generatedSection.raw.materials);
                                Vector3 curveNormal = Vector3.Cross(wallDir, Vector3.up);

                                Quaternion meshRot = Quaternion.LookRotation(curveNormal, Vector3.up);
                                Vector3    meshPos = new Vector3(v1.x, volume.baseHeight, v1.z) + wallDir * wallSectionSize.x + Vector3.up * wallSectionSize.y;
                                meshPos += meshRot * -new Vector3(wallSectionSize.x, wallSectionSize.y, 0) * 0.5f;
                                mesh.AddData(generatedSection.raw, mapping, meshPos, meshRot, Vector3.one);
                            }


                            currentWallSectionIndex++;
                            if (currentWallSectionIndex >= currentFacadeWallSectionLength)
                            {
                                //reached the end of the facade - move to the next one and continue
                                currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count;
                                currentWallSectionIndex        = 0;
                            }
                        }

                        offsetPointBase += wallPointCount - 1;
                    }
                }

                //FLOOR
                Vector2[]   mainShape      = offsetRoomAnchorPoints;
                Vector2[][] floorCutPoints = floorCuts.ToArray();
                int         floorVertCount = mainShape.Length;
                for (int flc = 0; flc < floorCutPoints.Length; flc++)
                {
                    floorVertCount += floorCutPoints[flc].Length;
                }

                Vector2[] allFloorPoints  = new Vector2[floorVertCount];
                int       mainShapeLength = mainShape.Length;
                for (int ms = 0; ms < mainShapeLength; ms++)
                {
                    allFloorPoints[ms] = mainShape[ms];
                }
                int cutPointIterator = mainShapeLength;
                for (int flc = 0; flc < floorCutPoints.Length; flc++)
                {
                    for (int flcp = 0; flcp < floorCutPoints[flc].Length; flcp++)
                    {
                        allFloorPoints[cutPointIterator] = floorCutPoints[flc][flcp];
                        cutPointIterator++;
                    }
                }

                Vector3[] floorPoints   = new Vector3[floorVertCount];
                Vector2[] floorUvs      = new Vector2[floorVertCount];
                Vector3[] floorNorms    = new Vector3[floorVertCount];
                Vector4[] floorTangents = new Vector4[floorVertCount];
                for (int rp = 0; rp < floorVertCount; rp++)
                {
                    floorPoints[rp] = new Vector3(allFloorPoints[rp].x, 0, allFloorPoints[rp].y) + floorBaseV;
                    Vector2 uv = allFloorPoints[rp];
                    if (floorSurface != null)
                    {
                        uv = floorSurface.CalculateUV(uv);
                    }
                    floorUvs[rp]      = uv;
                    floorNorms[rp]    = Vector3.up;
                    floorTangents[rp] = tangent;
                }

                int[] tris = Poly2TriWrapper.Triangulate(mainShape, true, floorCutPoints);

                mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, floorSubmesh);
                if (generateColliders)
                {
                    collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0);
                }

                //CEILING!
                Vector2[][] ceilingCutPoints = ceilingCuts.ToArray();
                int         ceilingVertCount = mainShape.Length;
                for (int flc = 0; flc < ceilingCutPoints.Length; flc++)
                {
                    ceilingVertCount += ceilingCutPoints[flc].Length;
                }

                Vector2[] allCeilingPoints = new Vector2[ceilingVertCount];
                for (int ms = 0; ms < mainShapeLength; ms++)
                {
                    allCeilingPoints[ms] = mainShape[ms];
                }
                cutPointIterator = mainShapeLength;
                for (int flc = 0; flc < ceilingCutPoints.Length; flc++)
                {
                    for (int flcp = 0; flcp < ceilingCutPoints[flc].Length; flcp++)
                    {
                        allCeilingPoints[cutPointIterator] = ceilingCutPoints[flc][flcp];
                        cutPointIterator++;
                    }
                }

                Vector3[] ceilingPoints   = new Vector3[ceilingVertCount];
                Vector2[] ceilingUvs      = new Vector2[ceilingVertCount];
                Vector3[] ceilingNorms    = new Vector3[ceilingVertCount];
                Vector4[] ceilingTangents = new Vector4[ceilingVertCount];
                for (int rp = 0; rp < ceilingVertCount; rp++)
                {
                    ceilingPoints[rp] = new Vector3(allCeilingPoints[rp].x, wallUp, allCeilingPoints[rp].y) + floorBaseV;
                    Vector2 uv = allCeilingPoints[rp];
                    if (floorSurface != null)
                    {
                        uv = ceilingSurface.CalculateUV(uv);
                    }
                    ceilingUvs[rp]      = uv;
                    ceilingNorms[rp]    = Vector3.down;
                    ceilingTangents[rp] = tangent;
                }

                tris = Poly2TriWrapper.Triangulate(mainShape, false, ceilingCutPoints);
                mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, ceilingSubmesh);
                if (generateColliders)
                {
                    collider.mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, 0);
                }

                for (int ob = 0; ob < openingCount; ob++)
                {
                    VerticalOpening opening      = openings[ob];
                    int             openingIndex = Array.IndexOf(openings, opening);
                    Vector3         basePosition = openingBounds[openingIndex].center;
                    basePosition.z = basePosition.y;
                    basePosition.y = volume.baseHeight;

                    if (roomOpenings.Contains(opening))//opening used in this floorplan
                    {
                        int externalWallSubmesh = wallSubmesh != -1 ? wallSubmesh : -1;
                        switch (opening.usage)
                        {
                        case VerticalOpening.Usages.Space:
                            if (ceilingCutPoints.Length <= ob)
                            {
                                continue;
                            }
                            Vector3   ceilingCutUpV = Vector3.up * wallThickness;
                            Vector2[] ceilingCut    = ceilingCutPoints[ob];
                            int       custSize      = ceilingCut.Length;
                            for (int cp = 0; cp < custSize; cp++)
                            {
                                int     indexA = (cp + 1) % custSize;
                                int     indexB = cp;
                                Vector3 cp0    = new Vector3(ceilingCut[indexA].x, wallUp, ceilingCut[indexA].y) + floorBaseV;
                                Vector3 cp1    = new Vector3(ceilingCut[indexB].x, wallUp, ceilingCut[indexB].y) + floorBaseV;
                                Vector3 cp2    = cp0 + ceilingCutUpV;
                                Vector3 cp3    = cp1 + ceilingCutUpV;
                                mesh.AddPlane(cp0, cp1, cp2, cp3, ceilingSubmesh);
                                if (generateColliders)
                                {
                                    collider.AddPlane(cp0, cp1, cp2, cp3);
                                }
                            }
                            break;

                        case VerticalOpening.Usages.Stairwell:
                            StaircaseGenerator.Generate(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider);
                            if (volumeFloor == volume.floors - 1 && opening.baseFloor + opening.floors > building.VolumeBaseFloor(volume) + volume.floors - 1 && volume.abovePlanCount == 0)
                            {
                                StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider);
                            }
                            break;

                        case VerticalOpening.Usages.Elevator:
                            ElevatorShaftGenerator.Generate(ref mesh, opening, actualFloor, basePosition, volume.floorHeight, externalWallSubmesh, sendCollider);
                            break;
                        }
                    }
                }
            }

            for (int ob = 0; ob < openingCount; ob++)
            {
                Vector2[] openingShape = openingShapes[ob];
                if (openingShape == null)
                {
                    continue;                      //opening not used by this floorplan
                }
                if (openingUsedInThisFloor[ob])
                {
                    continue;                            //opening already generated
                }
                //seal this opening from the void
                VerticalOpening opening      = openings[ob];
                int             openingIndex = Array.IndexOf(openings, opening);
                Vector3         basePosition = openingBounds[openingIndex].center;
                basePosition.z = basePosition.y;
                basePosition.y = 0;

                int       cutSize            = openingShape.Length;
                Vector3   sealingWallUpV     = Vector3.up * volume.floorHeight;
                int       sealWallSubmesh    = submeshLibrary.SubmeshAdd(opening.surfaceB);
                Vector2[] offsetOpeningShape = QuickPolyOffset.Execute(openingShape, wallThickness);
                for (int cp = 0; cp < cutSize; cp++)
                {
                    int     indexA = (cp + 1) % cutSize;
                    int     indexB = cp;
                    Vector2 p0     = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexA] : offsetOpeningShape[indexA];
                    Vector2 p1     = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexB] : offsetOpeningShape[indexB];
                    Vector3 cp0    = new Vector3(p0.x, 0, p0.y) + floorBaseV;
                    Vector3 cp1    = new Vector3(p1.x, 0, p1.y) + floorBaseV;
                    Vector3 cp2    = cp0 + sealingWallUpV;
                    Vector3 cp3    = cp1 + sealingWallUpV;
                    mesh.AddPlane(cp0, cp1, cp2, cp3, sealWallSubmesh);
                    if (generateColliders)
                    {
                        collider.AddPlane(cp0, cp1, cp2, cp3);
                    }
                }

                switch (opening.usage)
                {
                case VerticalOpening.Usages.Space:
                    //nothing to implement
                    break;

                case VerticalOpening.Usages.Stairwell:
                    //need stairs to connect used floors
                    StaircaseGenerator.GenerateStairs(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider);
                    if (volumeFloor == volume.floors - 1)
                    {
                        StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider);
                    }
                    break;

                case VerticalOpening.Usages.Elevator:
                    //nothing to implement
                    break;
                }
            }
        }
Пример #9
0
        /// <summary>
        /// Return a shape with a defined shape cut out of it.
        /// Will test find the best closest non intersectional cut to make in the base shape
        /// Assumes the cut doesn't intersect the shape lines and is inside the base shape
        /// </summary>
        /// <param name="baseShape"></param>
        /// <param name="cut"></param>
        /// <returns></returns>
        public static Vector2[] Execute(Vector2[] baseShape, List <Vector2[]> cuts)
        {
            bool dbg = false;

            Vector2[] cut         = (Vector2[])cuts[0].Clone();//todo multiple cuts
            int       baseCount   = baseShape.Length;
            int       cutCount    = cut.Length;
            int       outputCount = baseCount + cutCount + 2;

            Vector2[]  output = new Vector2[outputCount];
            FlatBounds bounds = new FlatBounds(cut);

            if (dbg)
            {
                bounds.DrawDebug(Color.magenta);
            }
            Vector2 center       = bounds.center;
            float   nrest        = Mathf.Infinity;
            int     nearestIndex = 0;

            Array.Reverse(cut);//reverse winding to create cut
            for (int b = 0; b < baseCount; b++)
            {
                float sqrMag = (baseShape[b] - center).sqrMagnitude;
                if (sqrMag < nrest)
                {
                    Vector2 a1 = center;
                    Vector2 a2 = baseShape[b];

                    bool intersectsShape = false;
                    for (int x = 0; x < baseCount; x++)
                    {
                        if (b == x)
                        {
                            continue;
                        }
                        int x2 = (x + 1) % baseCount;
                        if (b == x2)
                        {
                            continue;
                        }
                        Vector2 b1 = baseShape[x];
                        Vector2 b2 = baseShape[x2];
                        if (dbg)
                        {
                            Debug.DrawLine(ToV3(b1), ToV3(b2), Color.yellow);
                        }
                        if (FastLineIntersection(a1, a2, b1, b2))
                        {
                            intersectsShape = true;
                            break;
                        }
                    }
                    if (!intersectsShape)
                    {
                        nearestIndex = b;
                        nrest        = sqrMag;
                    }
                    //intersection check
                }
            }

            //find nearest cut point to base point
            int     nearestCutIndex = 0;
            float   nearestCut      = Mathf.Infinity;
            Vector2 baseCut         = baseShape[nearestIndex];

            for (int i = 0; i < cutCount; i++)
            {
                float sqrMag = (cut[i] - baseCut).sqrMagnitude;
                if (sqrMag < nearestCut)
                {
                    nearestCutIndex = i;
                    nearestCut      = sqrMag;
                }
            }

            if (dbg)
            {
                Debug.Log(nearestIndex);
                Debug.DrawLine(ToV3(baseShape[nearestIndex]), ToV3(center), Color.red);
            }

            for (int o = 0; o < outputCount; o++)
            {
                if (o <= nearestIndex)
                {
                    output[o] = baseShape[o];
                    if (dbg && o > 0)
                    {
                        Debug.DrawLine(ToV3(output[o]), ToV3(output[o - 1]) + Vector3.up, Color.blue, 60);
                    }
                    if (dbg)
                    {
                        Debug.Log("0x " + baseCount + " " + cutCount + " " + output.Length + " " + o);
                    }
                }
                else if (o > nearestIndex && o <= nearestIndex + cutCount + 1)
                {
                    int cutIndex = (nearestCutIndex + o - nearestIndex - 1) % cutCount;
                    output[o] = cut[cutIndex];
                    if (dbg && o > 0)
                    {
                        Debug.DrawLine(ToV3(output[o]), ToV3(output[o - 1]) + Vector3.up, Color.blue, 60);
                    }
                    if (dbg)
                    {
                        Debug.Log("1x " + cutIndex + " " + baseCount + " " + cutCount + " " + output.Length + " " + o);
                    }
                }
                else
                {
                    int finalIndex = (o - cutCount - 2 + baseCount) % baseCount;
                    if (dbg)
                    {
                        Debug.Log("2x " + finalIndex + " " + baseCount + " " + cutCount + " " + output.Length + " " + o);
                    }
                    output[o] = baseShape[finalIndex];
                    if (dbg && o > 0)
                    {
                        Debug.DrawLine(ToV3(output[o]), ToV3(output[o - 1]) + Vector3.up, Color.blue, 60);
                    }
                }
            }

            return(output);
        }
Пример #10
0
        public static void BMesh(BuildRMesh mesh, float height, Surface surface, int submesh, Vector2[] shape, Rect clampUV, bool flipTri = false, Vector2[][] holes = null, BuildRCollider collider = null)
        {
            int shapeSize = shape.Length;

            bool[] useHole = new bool[0];
            if (holes != null)
            {
                int holeCount = holes.Length;
//                Debug.Log("BMesh "+holeCount);
                useHole = new bool[holeCount];
                for (int flc = 0; flc < holeCount; flc++)
                {
                    useHole[flc] = true;
                    int holeSize = holes[flc].Length;

//                    for(int h = 0; h < holeSize; h++)
//                    {
//                        Vector2 holePoint = holes[flc][h];
//                        holeIntersections[h] = PointInShape(holePoint, shape);
////                        Debug.Log("intersection length " + intersections.Length);
//                        useHole[flc] = holeIntersections[h].Length == 0;
//                    }

                    //                    for(int flcp = 0; flcp < holeSize; flcp++)
                    //                    {
//                                            if(!PointInPolygon(holes[flc][flcp], shape))
                    //                        {
                    //                            useHole[flc] = false;
                    //                            break;
                    //                        }
                    //                    }
                    if (useHole[flc])
                    {
                        shapeSize += holeSize;
                    }
                }
            }

            Vector2[] allFloorPoints  = new Vector2[shapeSize];
            int       mainShapeLength = shape.Length;

            for (int ms = 0; ms < mainShapeLength; ms++)
            {
                allFloorPoints[ms] = shape[ms];
            }
            int cutPointIterator = mainShapeLength;

            if (holes != null)
            {
                for (int flc = 0; flc < holes.Length; flc++)
                {
                    if (!useHole[flc])
                    {
                        continue;
                    }
                    for (int flcp = 0; flcp < holes[flc].Length; flcp++)
                    {
                        allFloorPoints[cutPointIterator] = holes[flc][flcp];
                        cutPointIterator++;
                    }
                }
            }

            FlatBounds bounds = new FlatBounds();

            if (clampUV.width > 0)
            {
                for (int fvc = 0; fvc < mainShapeLength; fvc++)
                {
                    bounds.Encapsulate(shape[fvc]);
                }
            }

            Vector3[] floorPoints   = new Vector3[shapeSize];
            Vector2[] floorUvs      = new Vector2[shapeSize];
            Vector3[] floorNorms    = new Vector3[shapeSize];
            Vector4[] floorTangents = new Vector4[shapeSize];
            Vector3   normal        = flipTri ? Vector3.up : Vector3.down;
            Vector4   tangent       = BuildRMesh.CalculateTangent(Vector3.right);

            for (int rp = 0; rp < shapeSize; rp++)
            {
                floorPoints[rp] = new Vector3(allFloorPoints[rp].x, height, allFloorPoints[rp].y);
                if (clampUV.width > 0)
                {
                    Vector2 clampedUV = new Vector2();
                    clampedUV.x  = ((floorPoints[rp].x - bounds.xMin) / bounds.width) * clampUV.width + clampUV.x;
                    clampedUV.y  = ((floorPoints[rp].z - bounds.yMin) / bounds.height) * clampUV.height + clampUV.y;
                    floorUvs[rp] = clampedUV;
                }
                else
                {
                    if (surface != null)
                    {
                        floorUvs[rp] = surface.CalculateUV(allFloorPoints[rp]);
                    }
                    else
                    {
                        floorUvs[rp] = allFloorPoints[rp];
                    }
                }
                floorNorms[rp]    = normal;
                floorTangents[rp] = tangent;
            }

            int[] tris = Triangulate(shape, flipTri, holes);

            //                Debug.Log(volumeFloor + " " + actualFloor + " " + floorPoints.Length + " " + tris.Length+" "+r);
            int useFloorSubmesh = submesh != -1 ? submesh : 0;

            mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, useFloorSubmesh);
            if (collider != null)
            {
                collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0);
            }
        }
Пример #11
0
        public void Execute(Plot plot, uint seed)
        {
            processPlots.Clear();
            plots.Clear();
            debug.Clear();

            int plotSize = plot.numberOfEdges;

            bool[] plotExternals = new bool[plotSize];
            for (int p = 0; p < plotSize; p++)
            {
                plotExternals[p] = true;
            }
            _parent = plot;
            ProcessPlot initialPlot = new ProcessPlot(_parent, obbFit.CreateSorted(plot.pointsV2));

            processPlots.Add(initialPlot);
            float initialArea = initialPlot.obbs[0].area;

            if (plot.splitSettings.autoArea)
            {
                FlatBounds pBounds = new FlatBounds();
                pBounds.Encapsulate(plot.getAllPointsV2);
                plot.splitSettings.minArea = Mathf.Min(pBounds.size.x, pBounds.size.y) * plot.splitSettings.autoAreaRatio;
                plot.splitSettings.maxArea = Mathf.Max(pBounds.size.x, pBounds.size.y) * plot.splitSettings.autoAreaRatio;
            }

            if (initialArea < plot.splitSettings.maxArea)// if the supplied plot is already small enough - return it
            {
                plots.Add(_parent);
                processPlots.Clear();
//                Debug.Log("Plot size (" + initialArea + ") below max area " + plot.splitSettings.maxArea);
                return;
            }

            rGen = new RandomGen(seed);

            int it = 0;

            while (processPlots.Count > 0)
            {
                ProcessPlot processPlot = processPlots[0];
                IPlot       currentPlot = processPlot.plot;
                processPlots.RemoveAt(0);
                Subplot[] newPlots = SplitPlot(processPlot);

                bool earlyTermination = newPlots[0] == null;
                if (newPlots[1] == null)
                {
                    earlyTermination = true;
                }
                if (rGen.output < plot.splitSettings.randomTerminationChance)
                {
                    earlyTermination = true;
                }
                Subplot      plotA = null, plotB = null;
                List <OBBox> obbsA = null;
                List <OBBox> obbsB = null;
                if (!earlyTermination)
                {
                    plotA = newPlots[0];
                    plotB = newPlots[1];

                    if (plotA.plotAccessPercentage < plot.splitSettings.minimumAccessLengthPercent)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotA.notes = "insufficient access";
                        }
                        earlyTermination = true;
                    }
                    if (plotB.plotAccessPercentage < plot.splitSettings.minimumAccessLengthPercent)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotB.notes = "insufficient access";
                        }
                        earlyTermination = true;
                    }
                    if (plotA.numberOfEdges < 4 && !plot.splitSettings.allowTrianglularPlots)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotA.notes = "triangular split";
                        }
                        earlyTermination = true;
                    }
                    if (plotB.numberOfEdges < 4 && !plot.splitSettings.allowTrianglularPlots)
                    {
                        plotB.notes      = "triangular split";
                        earlyTermination = true;
                    }

                    obbsA = obbFit.CreateSorted(plotA.pointsV2);
                    if (obbsA.Count == 0)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotA.notes = "no obb generated";
                        }
                        earlyTermination = true;
                    }
                    else if (obbsA[0].aspect < plot.splitSettings.minimumAspect)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotA.notes = "aspect issue";
                        }
                        earlyTermination = true;
                    }
                    else if (obbsA[0].area < plot.splitSettings.minArea)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotA.notes = "area smaller than minimum";
                        }
                        earlyTermination = true;
                    }

                    obbsB = obbFit.CreateSorted(plotB.pointsV2);
                    if (obbsB.Count == 0)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotB.notes = "no obb generated";
                        }
                        earlyTermination = true;
                    }
                    else if (obbsB[0].aspect < plot.splitSettings.minimumAspect)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotB.notes = "aspect issue";
                        }
                        earlyTermination = true;
                    }
                    else if (obbsB[0].area < plot.splitSettings.minArea)
                    {
                        if (plot.splitSettings.log)
                        {
                            plotB.notes = "area smaller than minimum";
                        }
                        earlyTermination = true;
                    }
                }

                if (earlyTermination)
                {
                    if (plotA != null && plotB != null)
                    {
                        if (plot.splitSettings.log)
                        {
                            currentPlot.notes = string.Format("plotA:{0}  plotB:{1}  {2}", plotA.notes, plotB.notes, processPlot);
                        }

                        if (plot.splitSettings.debug)//output debug info
                        {
                            DebugSplitInfo info = new DebugSplitInfo();
                            info.plot  = currentPlot;
                            info.plotA = plotA;
                            info.plotB = plotB;
                            debug.Add(info);
                        }
                    }
                    //figure on appropirate fallback
                    if (!processPlot.longSplit && plot.splitSettings.fallbackSecondaryDivision)//divide along the longer split
                    {
                        processPlot.longSplit = true;
                        processPlots.Insert(0, processPlot);
                    }
                    else
                    {
                        if (!processPlot.variationA && plot.splitSettings.fallbackVariations)//use a variation on the split
                        {
                            processPlot.variationA = true;
                            processPlots.Insert(0, processPlot);
                        }
                        else
                        {
                            if (!processPlot.variationB && plot.splitSettings.fallbackVariations)//use a variation on the split
                            {
                                processPlot.variationB = true;
                                processPlots.Insert(0, processPlot);
                            }
                            else
                            {
                                if (processPlot.obbs.Count > 1 && plot.splitSettings.fallbackAlternativeObb)//if there are other cut options - use them!
                                {
                                    processPlot.obbs.RemoveAt(0);
                                    processPlot.longSplit  = false;
                                    processPlot.variationA = false;
                                    processPlot.variationB = false;
                                    processPlots.Insert(0, processPlot);
                                }
                                else
                                {
                                    plots.Add(currentPlot);//termination - all allowable fallbacks used
                                }
                            }
                        }
                    }
                    continue;//next
                }

                OBBox obbA       = obbsA[0];
                OBBox obbB       = obbsB[0];
                bool  terminateA = obbA.area < plot.splitSettings.maxArea && rGen.output < 0.3f;
                if (!terminateA)
                {
                    processPlots.Add(new ProcessPlot(plotA, obbsA));
                }
                else
                {
                    if (plot.splitSettings.log)
                    {
                        plotA.notes = "small enough to end";
                    }
                    plots.Add(plotA);//termination
                }

                bool terminateB = obbB.area < plot.splitSettings.maxArea && rGen.output < 0.3f;
                if (!terminateB)
                {
                    processPlots.Add(new ProcessPlot(plotB, obbsB));
                }
                else
                {
                    if (plot.splitSettings.log)
                    {
                        plotB.notes = "small enough to end";
                    }
                    plots.Add(plotB);//termination
                }

                it++;
                if (it > 5000)
                {
                    UnityEngine.Profiling.Profiler.EndSample();
                    return;
                }
            }
//            Profiler.EndSample();
        }
Пример #12
0
 public bool Overlaps(FlatBounds other, bool allowInverse = false)
 {
     return(_core.Overlaps(other.rect, allowInverse));
 }
Пример #13
0
        public static VerticalOpening[] GetOpenings(Building building, Volume volume)
        {
            List <VerticalOpening> output = new List <VerticalOpening>();
            int count = building.openingCount;

            VerticalOpening[] openings = building.GetAllOpenings();

            int volumeBaseFloor = building.VolumeBaseFloor(volume);
            int volumeTopFloor  = volumeBaseFloor + volume.floors;

            for (int i = 0; i < count; i++)
            {
                VerticalOpening opening          = openings[i];
                int             openingBaseFloor = opening.baseFloor;
                int             openingTopFloor  = openingBaseFloor + opening.floors - 1;

                if (volumeBaseFloor < openingTopFloor && openingBaseFloor < volumeTopFloor)//opening and volume floors intersect
                {
                    FlatBounds volumeBounds  = new FlatBounds(volume.bounds);
                    Vector2[]  openingPoints = opening.PointsRotated();
                    FlatBounds openingBounds = new FlatBounds(openingPoints);

                    if (volumeBounds.Overlaps(openingBounds, true))// opening is within the AABB bounds of the volume
                    {
                        Vector2[] volumePoints      = volume.AllPointsV2();
                        int       volumePointCount  = volumePoints.Length;
                        int       openingPointCount = openingPoints.Length;
                        bool      openingIntersects = false;

                        for (int op = 0; op < openingPointCount; op++)
                        {
                            Vector2 opa = openingPoints[op];
                            Vector2 opb = openingPoints[(op + 1) % openingPointCount];

                            for (int vp = 0; vp < volumePointCount; vp++)
                            {
                                Vector2 vpa = volumePoints[vp];
                                Vector2 vpb = volumePoints[(vp + 1) % volumePointCount];

                                if (FastLineIntersection(opa, opb, vpa, vpb))
                                {
                                    openingIntersects = true;
                                }

                                if (openingIntersects)
                                {
                                    break;
                                }
                            }

                            if (openingIntersects)
                            {
                                break;
                            }
                        }

                        if (!openingIntersects)//check that the opening is within the volume shape
                        {
                            Vector2 opa           = openingPoints[0];
                            Vector2 opb           = openingPoints[1];
                            int     intersections = 0;//we should intersect an odd number of times
                            for (int vp = 0; vp < volumePointCount; vp++)
                            {
                                Vector2 vpa = volumePoints[vp];
                                Vector2 vpb = volumePoints[(vp + 1) % volumePointCount];

                                if (FastLineIntersection(opa, opb, vpa, vpb))
                                {
                                    intersections++;
                                }
                            }

                            if (intersections % 2 != 0)
                            {
                                output.Add(opening);
                            }
                        }
                    }
                }
            }
            return(output.ToArray());
        }
Пример #14
0
 public FlatBounds(FlatBounds copy)
 {
     _core        = new Rect(copy.x, copy.y, copy.width, copy.height);
     _initialised = copy.initialised;
 }
Пример #15
0
        public static bool SweepIntersects(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, Vector2 l1, Vector2 l2, out Vector2 intersection, out float percent, float accuracy = 1)
        {
            intersection = Vector2.zero;
            percent      = 0;
            Vector2 lineDelta = l2 - l1;
            Vector2 point     = l2;

            b1 += -lineDelta;
            b2 += -lineDelta;
            Vector2[]  poly   = { a1, a2, b2, b1 };
            FlatBounds bounds = new FlatBounds(poly);

            if (!bounds.Contains(l1))
            {
                return(false);
            }

//            bounds.DrawDebug(Color.yellow);

            Vector2 pointRight = point + new Vector2(Mathf.Max(bounds.width, bounds.height), 0);
            //            Vector2 pointRight = point - lineDelta * bounds.width * bounds.height;
//            Debug.DrawLine(ToV3(point), ToV3(pointRight), Color.cyan);

            int numberOfPolyPoints = poly.Length;
            int numberOfCrossOvers = 0;

            for (int i = 0; i < numberOfPolyPoints; i++)
            {
                Vector2 p0 = poly[i];
                Vector2 p1 = poly[(i + 1) % numberOfPolyPoints];
//                Debug.DrawLine(ToV3(p0), ToV3(p1), Color.blue);
                if (FastLineIntersection(point, pointRight, p0, p1))
                {
                    numberOfCrossOvers++;
                }
            }

            if (numberOfCrossOvers % 2 == 0)
            {
                return(false);//point not within shape
            }
            bounds.DrawDebug(Color.green);

            Vector2 delta1     = b1 - a1;
            Vector2 delta2     = b2 - a2;
            float   maxDelta   = Mathf.Max(delta1.magnitude, delta2.magnitude);
            int     iterations = Mathf.CeilToInt(Mathf.Sqrt(maxDelta / accuracy));

            for (int i = 0; i < iterations; i++)
            {
                Vector2 c1 = Vector2.Lerp(a1, b1, 0.5f);
                Vector2 c2 = Vector2.Lerp(a2, b2, 0.5f);
                if (!Ccw(c1, c2, point))
                {
                    a1      = c1;
                    a2      = c2;
                    percent = Mathf.Lerp(percent, 1, 0.5f);
                }
                else
                {
                    b1      = c1;
                    b2      = c2;
                    percent = Mathf.Lerp(0, percent, 0.5f);
                }
            }

//            Vector2 x1 = Vector2.Lerp(a1, b1, 0.5f);
//            Vector2 x2 = Vector2.Lerp(a2, b2, 0.5f);
//            float dist1 = Vector2.Distance(x1, point);
//            float dist2 = Vector2.Distance(x2, point);
//            float xpercent = dist1 / (dist1 + dist2);
//            intersection = Vector2.Lerp(x1, x2, xpercent);
            intersection = Vector2.Lerp(l1, l2, percent);//translate the point to the real movement point
            Debug.DrawLine(ToV3(intersection), ToV3(intersection) + Vector3.up * 5, Color.red);
            return(true);
        }
Пример #16
0
        public static bool SweepIntersects2(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, Vector2 l1, Vector2 l2, out Vector2 intersection, out float percent, float accuracy = 1, bool debug = false)
        {
            intersection = Vector2.zero;
            percent      = 0;
            Vector2[]  poly       = { a1, a2, b2, b1 };
            FlatBounds edgeBounds = new FlatBounds(poly);
            FlatBounds lineBounds = new FlatBounds(new [] { l1, l2 });

            if (!edgeBounds.Overlaps(lineBounds, true))
            {
                if (debug)
                {
                    edgeBounds.DrawDebug(Color.cyan);
                }
                if (debug)
                {
                    lineBounds.DrawDebug(Color.green);
                }
                if (debug)
                {
                    Debug.DrawLine(ToV3(l1), ToV3(l2), Color.cyan);
                }
                return(false);
            }

            int  numberOfPolyPoints  = poly.Length;
            bool lineIntersectsShape = false;

            for (int i = 0; i < numberOfPolyPoints; i++)
            {
                Vector2 p0 = poly[i];
                Vector2 p1 = poly[(i + 1) % numberOfPolyPoints];
                if (debug)
                {
                    Debug.DrawLine(ToV3(p0), ToV3(p1), Color.blue);
                }
                if (FastLineIntersection(p0, p1, l1, l2))
                {
                    lineIntersectsShape = true;
                    break;
                }
            }

            if (!lineIntersectsShape)//line never crosses shape
            {
                Vector2 right = new Vector2(Mathf.Max(edgeBounds.width, edgeBounds.height), 0);
                int     shapeIntersections = 0;
                for (int i = 0; i < numberOfPolyPoints; i++)
                {
                    Vector2 p0 = poly[i];
                    Vector2 p1 = poly[(i + 1) % numberOfPolyPoints];
                    if (debug)
                    {
                        Debug.DrawLine(ToV3(p0) + Vector3.up * 5, ToV3(p1) + Vector3.up * 5, Color.blue);
                    }
                    if (FastLineIntersection(l1, l1 + right, p0, p1))
                    {
                        if (debug)
                        {
                            Debug.DrawLine(ToV3(l1), ToV3(l1) + Vector3.up * 5, Color.magenta);
                        }
                        shapeIntersections++;
                    }
                    if (FastLineIntersection(l2, l2 + right, p0, p1))
                    {
                        if (debug)
                        {
                            Debug.DrawLine(ToV3(l1), ToV3(l1) + Vector3.up * 5, Color.magenta);
                        }
                        shapeIntersections++;
                        break;
                    }
                }

                if (shapeIntersections % 2 == 0)
                {
                    return(false);//line not within shape
                }
            }
            if (debug)
            {
                edgeBounds.DrawDebug(Color.green);
            }

            Vector2 delta1      = b1 - a1;
            Vector2 delta2      = b2 - a2;
            float   maxDelta    = Mathf.Max(delta1.magnitude, delta2.magnitude);
            int     iterations  = Mathf.CeilToInt(maxDelta / accuracy);
            bool    initalState = Ccw(a1, a2, l1);

            for (int i = 1; i < iterations; i++)
            {
                percent = i / (iterations - 1f);

                Vector2 e1 = Vector2.Lerp(a1, b1, percent);
                Vector2 e2 = Vector2.Lerp(a2, b2, percent);
                if (debug)
                {
                    Debug.DrawLine(ToV3(e1), ToV3(e2), new Color(1, 0, 1, 0.5f));
                }
                Vector2 p = Vector2.Lerp(l1, l2, percent);

                bool currentState = Ccw(e1, e2, p);

                if (currentState != initalState || i == iterations - 1)
                {
                    float dist1    = Vector2.Distance(e1, p);
                    float dist2    = Vector2.Distance(e2, p);
                    float xpercent = dist1 / (dist1 + dist2);
                    intersection = Vector2.Lerp(e1, e2, xpercent);
                    if (debug)
                    {
                        Debug.DrawLine(ToV3(e1), ToV3(e2), Color.red);
                    }
                    if (debug)
                    {
                        Debug.DrawLine(ToV3(intersection), ToV3(intersection) + Vector3.up * 10, Color.red);
                    }

                    break;
                }
            }
            return(true);
        }
Пример #17
0
        public void Execute()
        {
            calculatedPartitions.Clear();


            //remvoe duplicate points
            for (int i = 0; i < shape.Count; i++)
            {
                Vector2Int p0   = shape[i];
                Vector2Int p1   = shape[i < shape.Count - 1 ? i + 1 : 0];
                float      sqrM = Vector2Int.SqrMagnitudeFloat(p1, p0);
                if (sqrM < Mathf.Epsilon)
                {
                    shape.RemoveAt(i);
                    i--;
                }
            }

            //break poly down into convex shapes
            TPPLPoly poly = new TPPLPoly();

            for (int i = 0; i < shape.Count; i++)
            {
                poly.Points.Add(new TPPLPoint(shape[i].x, shape[i].y));
            }

            if (BuildrPolyClockwise.Check(shape))
            {
                poly.SetOrientation(TPPLOrder.CW);
            }
            else
            {
                poly.SetOrientation(TPPLOrder.CCW);
            }

            List <TPPLPoly> parts         = new List <TPPLPoly>();
            TPPLPartition   tpplPartition = new TPPLPartition();

            tpplPartition.ConvexPartition_HM(poly, parts);

            //generate an irregular grid upon each convex poly
            int          partCount    = parts.Count;
            PlotSplitter plotSplitter = new PlotSplitter();

            floorSegments.Clear();
            for (int p = 0; p < partCount; p++)
            {
                TPPLPoly          partPoly   = parts[p];
                int               partSize   = partPoly.Count;
                List <Vector2Int> plotPoints = new List <Vector2Int>();
                for (int w = 0; w < partSize; w++)
                {
                    TPPLPoint  tpplPoint = partPoly[w];
                    Vector2Int p0        = new Vector2Int(tpplPoint.X, tpplPoint.Y);
                    plotPoints.Add(p0);
                }

                Plot plot = new Plot(seed, plotPoints, minimumWallUnitSpacing);
                plot.splitSettings = splitSettings;
                plotSplitter.Execute(plot, seed);
                int splitCount = plotSplitter.plots.Count;
                for (int s = 0; s < splitCount; s++)
                {
                    IPlot        segmentPlot = plotSplitter.plots[s];
                    Vector2Int[] points      = Vector2Int.Parse(segmentPlot.pointsV2);
                    FloorSegment segment     = new FloorSegment(segmentPlot.area, segmentPlot.flatbounds, points);
                    floorSegments.Add(segment);
                }
            }

            int segmentCount = floorSegments.Count;
            List <FloorSegment> availableSegments = new List <FloorSegment>(floorSegments);
            int       restrictedAreaCount         = restrictedAreas.Count;
            Partition restrictedPartition         = null;

            for (int r = 0; r < restrictedAreaCount; r++)
            {
                RestrictedArea area       = restrictedAreas[r];
                FlatBounds     areaBounds = new FlatBounds();
                areaBounds.Encapsulate(Vector2Int.Parse(area.shape));
                for (int fs = 0; fs < segmentCount; fs++)
                {
                    FloorSegment segment = availableSegments[fs];
                    if (areaBounds.Overlaps(segment.bounds))
                    {
                        if (JMath.ShapesIntersect(Vector2Int.Parse(area.shape), Vector2Int.Parse(segment.points)))
                        {
                            if (restrictedPartition == null)
                            {
                                restrictedPartition = new Partition();
                            }
                            restrictedPartition.AddSegment(segment);
                            availableSegments.Remove(segment);
                            segmentCount--;
                            fs--;
                        }
                    }
                }
            }

            //Link up floor segments
            segmentCount = availableSegments.Count;
            for (int x = 0; x < segmentCount; x++)
            {
                FloorSegment subject       = floorSegments[x];
                FlatBounds   subjectBounds = subject.nBounds;
                for (int y = 0; y < segmentCount; y++)
                {
                    if (x == y)
                    {
                        continue;
                    }

                    FloorSegment candidate = floorSegments[y];


                    FlatBounds candidateBounds = candidate.nBounds;
                    if (subjectBounds.Overlaps(candidateBounds))
                    {
                        if (candidate.neighbours.Contains(subject))
                        {
                            continue;
                        }
                        subject.neighbours.Add(candidate);
                        candidate.neighbours.Add(subject);
                    }
                }
            }

            //Grow out partitions to fill the available space
            List <PartitionGrowth> partitionGs = new List <PartitionGrowth>();
            Dictionary <FloorSegment, FloorSegmentClaim> segmentClaims = new Dictionary <FloorSegment, FloorSegmentClaim>();

            for (int i = 0; i < partitions.Count; i++)
            {
                partitionGs.Add(new PartitionGrowth(partitions[i]));
            }

            int it = 1000;

            while (true)
            {
                int   growthCount = partitionGs.Count;
                int   completePartitionGrowths = 0;
                int[] partitionGrowthAmount    = new int[growthCount];
                segmentClaims.Clear();

                for (int g = 0; g < growthCount; g++)
                {
                    PartitionGrowth partitionG = partitionGs[g];
                    if (!partitionG.active)
                    {
                        completePartitionGrowths++;
                        continue;
                    }

                    if (availableSegments.Count == 0)
                    {
                        break;
                    }

                    //assign inital segment to begin partition from
                    if (!partitionG.initialised)
                    {
                        float        nearestSqrMag = float.PositiveInfinity;
                        FloorSegment candidate     = availableSegments[0];
                        for (int x = 0; x < availableSegments.Count; x++)
                        {
                            FloorSegment subject = availableSegments[x];
                            float        sqrMag  = Vector2Int.SqrMagnitudeFloat(partitionG.subject.position, subject.position);
                            if (sqrMag < nearestSqrMag)
                            {
                                candidate     = subject;
                                nearestSqrMag = sqrMag;
                            }
                        }

                        partitionG.capturedSegments.Add(candidate);
                        partitionG.processSegments.Add(candidate);
                        availableSegments.Remove(candidate);
                        partitionG.initialised   = true;
                        partitionGrowthAmount[g] = 1;
                        continue;//don't start growth until next iteration
                    }

                    //grow partition
                    if (partitionG.initialised)
                    {
                        List <FloorSegment> neighbourCandiates = new List <FloorSegment>();
                        int processCount = partitionG.processSegments.Count;
//                        float additionalArea = 0;
                        for (int p = 0; p < processCount; p++)
                        {
                            FloorSegment processSegment        = partitionG.processSegments[p];
                            int          processNeighbourCount = processSegment.neighbours.Count;
                            for (int n = 0; n < processNeighbourCount; n++)
                            {
                                FloorSegment neighbour             = processSegment.neighbours[n];
                                bool         isAvailable           = availableSegments.Contains(neighbour);
                                bool         notDuplicateNeighbour = !neighbourCandiates.Contains(neighbour);
                                if (isAvailable && notDuplicateNeighbour)
                                {
                                    neighbourCandiates.Add(neighbour);
                                    float fit = processSegment.BestFit(neighbour);
                                    if (fit > Mathf.Epsilon)
                                    {
                                        FloorSegmentClaim newClaim = new FloorSegmentClaim();
                                        newClaim.partition   = partitionG;
                                        newClaim.growthIndex = g;
                                        newClaim.segment     = neighbour;
                                        newClaim.priority    = partitionG.subject.priority * fit;

                                        if (!segmentClaims.ContainsKey(neighbour))
                                        {
                                            segmentClaims.Add(neighbour, newClaim);
                                        }
                                        else
                                        {
                                            FloorSegmentClaim currentClaim = segmentClaims[neighbour];
                                            if (currentClaim.priority < newClaim.priority)
                                            {
                                                segmentClaims[neighbour] = newClaim;
                                            }
                                        }
                                    }
//                                    additionalArea += neighbour.area;
                                }
                            }
                        }

//                        int neighbourCandiatesCount = neighbourCandiates.Count;
//                        for (int n = 0; n < neighbourCandiatesCount; n++) {
//                            FloorSegment segement = neighbourCandiates[n];
//
//                            if (segmentClaims.ContainsKey(segement)) {
//
//                            }
//                            else {
//
//                            }
//                        }
                        //                        if (neighbourCandiatesCount > 0) {
                        //
                        //                            bool canAddAll = partitionG.AvailableArea(additionalArea);
                        //                            if (canAddAll) {
                        //                                partitionG.processSegments.Clear();
                        //                                for (int n = 0; n < neighbourCandiatesCount; n++)
                        //                                    availableSegments.Remove(neighbourCandiates[n]);
                        ////                                partitionG.AddSegments(neighbourCandiates);
                        //                            }
                        //                            else {
                        //                                //                                TODO partial add (?)
                        ////                                partitionG.AddSegments(neighbourCandiates);
                        //                                partitionG.Complete();
                        //                            }
                        //                        }
                        //                        else {
                        //                            partitionG.Complete();
                        //                        }

//                        if (partitionG.processSegments.Count == 0)
//                            partitionG.Complete();
                    }
                }

                foreach (KeyValuePair <FloorSegment, FloorSegmentClaim> kv in segmentClaims)
                {
                    //TODO - support instance when new areas to add are too large
                    //TODO - fall back on partial adding of single side
                    FloorSegmentClaim claim = kv.Value;
                    claim.partition.AddSegment(claim.segment);
                    availableSegments.Remove(claim.segment);
                    partitionGrowthAmount[claim.growthIndex]++;
                }

                for (int g = 0; g < growthCount; g++)
                {
                    PartitionGrowth partitionG = partitionGs[g];
                    if (!partitionG.active)
                    {
                        continue;
                    }
//                    Debug.Log(g+" "+ partitionG.AcceptableAreaUsed()+" " + partitionGrowthAmount[g]+" "+ partitionG.processSegments.Count);
                    if (partitionG.AcceptableAreaUsed() || partitionGrowthAmount[g] == 0 || partitionG.processSegments.Count == 0)
                    {
                        completePartitionGrowths++;
                        partitionG.Complete();
                    }
                }

                if (completePartitionGrowths == growthCount) //all partitions have been completed
                {
                    break;
                }

                if (availableSegments.Count == 0)
                {
                    foreach (PartitionGrowth part in partitionGs)
                    {
                        if (part.active)
                        {
                            part.Complete();
                        }
                    }

                    foreach (PartitionGrowth part in partitionGs)
                    {
                        int childCount = part.subject.children.Count;
                        if (childCount > 0)
                        {
                            for (int c = 0; c < childCount; c++)
                            {
                                partitionGs.Add(new PartitionGrowth(part.subject.children[c]));
                            }
                            part.subject.children.Clear();
                            availableSegments.AddRange(part.capturedSegments);
                            part.capturedSegments.Clear();
                            break;
                        }
                    }

                    if (availableSegments.Count == 0)
                    {
                        break;
                    }
                }

                it--;
                if (it == 0)
                {
                    Debug.Log(" MAX reached!");
                    Debug.Log(availableSegments.Count);
                    foreach (PartitionGrowth pg in partitionGs)
                    {
                        Debug.Log(pg.processSegments.Count);
                        Debug.Log(pg.capturedSegments.Count);
                        pg.Complete();
                    }
                    break;
                }
            }


            foreach (PartitionGrowth part in partitionGs)
            {
                if (part.active)
                {
                    part.Complete();
                }
                calculatedPartitions.Add(part.subject);
            }

//            if (floorplan != null)
//            {
//                int roomCount = calculatedPartitions.Count;
//
//
//
//
//                Room floorplanRoom = new Room();
//
//
//                floorplan.rooms.Add();
//            }

            //            foreach (Partition part in partitions) {
            //                Debug.Log(part.segments.Count);
            //            }
        }
Пример #18
0
        public static bool Generate(BuildRMesh mesh, BuildRCollider collider, Vector2[] points, int[] facadeIndices, float roofBaseHeight, IVolume volume, Rect clampUV)
        {
            Roof           design     = volume.roof;
            OffsetSkeleton offsetPoly = new OffsetSkeleton(points);

            offsetPoly.direction = 1;
            offsetPoly.Execute();
            Shape shape       = offsetPoly.shape;
            int   submesh     = mesh.submeshLibrary.SubmeshAdd(design.mainSurface); // surfaceMapping.IndexOf(design.mainSurface);
            int   wallSubmesh = mesh.submeshLibrary.SubmeshAdd(design.wallSurface); //surfaceMapping.IndexOf(design.wallSurface);

            if (shape == null)
            {
                return(false);
            }

            List <Edge> edges     = new List <Edge>(shape.edges);
            List <Edge> baseEdges = new List <Edge>(shape.baseEdges);

            float shapeHeight  = shape.HeighestPoint();
            float designHeight = design.height;
            float heightScale  = designHeight / shapeHeight;

            Vector2 clampUVScale = Vector2.one;

            if (clampUV.width > 0)
            {
                FlatBounds bounds = new FlatBounds();
                for (int fvc = 0; fvc < points.Length; fvc++)
                {
                    bounds.Encapsulate(points[fvc]);
                }
                clampUVScale.x = bounds.width / clampUV.width;
                clampUVScale.y = bounds.height / clampUV.height;
            }

            Dictionary <Node, int>          shapeConnectionCount = new Dictionary <Node, int>();
            Dictionary <Node, List <Node> > shapeConnections     = new Dictionary <Node, List <Node> >();
            int edgeCount = edges.Count;

            for (int e = 0; e < edgeCount; e++)
            {
                Edge edge = edges[e];

                if (edge.length < Mathf.Epsilon)
                {
                    continue;
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeA))
                {
                    shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeA, new List <Node> {
                        edge.nodeB
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeA]++;
                    if (!shapeConnections[edge.nodeA].Contains(edge.nodeB))
                    {
                        shapeConnections[edge.nodeA].Add(edge.nodeB);
                    }
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeB))
                {
                    shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeB, new List <Node> {
                        edge.nodeA
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeB]++;
                    if (!shapeConnections[edge.nodeB].Contains(edge.nodeA))
                    {
                        shapeConnections[edge.nodeB].Add(edge.nodeA);
                    }
                }
            }

            int baseEdgeCount = baseEdges.Count;

            for (int b = 0; b < baseEdgeCount; b++)
            {
                Edge baseEdge = baseEdges[b];
                Node nodeA    = baseEdge.nodeA;
                Node nodeB    = baseEdge.nodeB;

                Node        currentNode = nodeA;
                Node        lastNode    = nodeB;
                int         itMax       = 50;
                List <Node> edgeShape   = new List <Node>()
                {
                    nodeA
                };

                while (currentNode != nodeB)
                {
                    List <Node> nodeConnections     = shapeConnections[currentNode];
                    int         nodeConnectionCount = nodeConnections.Count;
                    float       minAngle            = Mathf.Infinity;
                    Node        nextNode            = null;
                    Vector2     currentDirection    = (currentNode.position - lastNode.position).normalized;
                    for (int n = 0; n < nodeConnectionCount; n++)
                    {
                        Node connectingNode = nodeConnections[n];
                        if (connectingNode == lastNode)
                        {
                            continue;
                        }
                        Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized;
                        float   nodeAngle     = JMath.SignAngleDirection(currentDirection, nextDirection);
                        if (nodeAngle < minAngle)
                        {
                            minAngle = nodeAngle;
                            nextNode = connectingNode;
                        }
                    }
                    if (nextNode != null)
                    {
                        edgeShape.Add(nextNode);
                        lastNode    = currentNode;
                        currentNode = nextNode;
                    }


                    itMax--;
                    if (itMax < 0)
                    {
                        break;
                    }
                }

                int edgeShapeCount = edgeShape.Count;
                if (edgeShapeCount < 3)
                {
                    continue;
                }
//                Debug.Log("Generate edgeShapeCount "+ edgeShapeCount);

                Vector3[] verts = new Vector3[edgeShapeCount];

                Vector2[] uvs = new Vector2[edgeShapeCount];
                Vector3   baseShapeDirection = ShapeOffset.Utils.ToV3(nodeB.position - nodeA.position).normalized;
                float     uvAngle            = JMath.SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90;

                Vector2[] faceShape = new Vector2[edgeShapeCount];
                Vector3[] normals   = new Vector3[edgeShapeCount];
                Vector4[] tangents  = new Vector4[edgeShapeCount];
                //                Vector3 normal = Vector3.up;//BuildRMesh.CalculateNormal(); TODO
                Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection);
                for (int i = 0; i < edgeShapeCount; i++)//what on earth did I write here?
                {
                    Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y);
                    verts[i] = newVert;

                    Vector2 baseUV = new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z);
                    Vector2 newUV  = Vector2.zero;
                    if (i != 0)
                    {
                        newUV = JMath.Rotate(baseUV, uvAngle);
                    }
                    if (clampUV.width > Mathf.Epsilon)
                    {
                        newUV.x = Mathf.Clamp(clampUV.x + newUV.x / clampUVScale.x, clampUV.xMin, clampUV.xMax);
                        newUV.y = Mathf.Clamp(clampUV.y + newUV.y / clampUVScale.y, clampUV.yMin, clampUV.yMax);
                    }
                    else
                    {
                        if (i != 0)
                        {
                            float faceHeight = edgeShape[i].height * heightScale;
                            newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight));//hypotenuse of roof to give length of roof face
                            if (design.mainSurface != null)
                            {
                                newUV = design.mainSurface.CalculateUV(newUV);
                            }
                        }
                    }
                    uvs[i] = newUV;

                    faceShape[i] = edgeShape[i].position;//used for triangulation
                    //                    normals[i] = normal;
                    tangents[i] = tangent;
                }
//                int[] tris = EarClipper.Triangulate(faceShape, 0, -1);
                int[] tris     = Poly2TriWrapper.Triangulate(faceShape, true);
                int   triCount = tris.Length;

                Vector3 normal = (verts.Length > 2 && triCount > 2) ? BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]) : Vector3.up;
                for (int i = 0; i < edgeShapeCount; i++)
                {
                    normals[i] = normal;
                }

                mesh.AddData(verts, uvs, tris, normals, tangents, submesh);

                //gable
                bool isGabled = volume[facadeIndices[b]].isGabled;
                if (isGabled)
                {
                    for (int t = 0; t < triCount; t += 3)
                    {
                        if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0)
                        {
                            int beB = edgeShapeCount - 1;
                            if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB)
                            {
                                Vector3 b0       = verts[0];
                                Vector3 b1       = verts[beB];
                                Vector3 g0       = b0;
                                Vector3 g1       = b1;
                                int     topIndex = 0;
                                for (int tx = 0; tx < 3; tx++)
                                {
                                    if (tris[t + tx] != 0 && tris[t + tx] != beB)
                                    {
                                        topIndex = tris[t + tx];
                                    }
                                }
                                Vector3 b2 = verts[topIndex];

                                Vector3 baseV = b1 - b0;
                                Vector3 dir   = baseV.normalized;
                                Vector3 face  = Vector3.Cross(Vector3.up, dir).normalized;
                                Vector3 up    = Vector3.Project(b2 - b0, Vector3.up);

                                //clear triangle
                                tris[t]     = 0;
                                tris[t + 1] = 0;
                                tris[t + 2] = 0;

                                bool  simpleGable      = volume[facadeIndices[b]].simpleGable;
                                Gable gableStyle       = volume[facadeIndices[b]].gableStyle;
                                float thickness        = volume[facadeIndices[b]].gableThickness;
                                float additionalHeight = volume[facadeIndices[b]].gableHeight;
                                float height           = up.magnitude + additionalHeight;

                                if (simpleGable || gableStyle != null)
                                {
                                    Vector3 pitchVectorA = (b2 - b0).normalized;
                                    Vector3 pitchVectorB = (b2 - b1).normalized;
                                    float   angle        = Vector3.Angle(-face, pitchVectorA);
                                    float   scale        = Mathf.Cos(angle / 57.2957795f);
                                    b0 += pitchVectorA * (thickness * (1 / scale));
                                    b1 += pitchVectorB * (thickness * (1 / scale));
                                }

                                Vector3 center = Vector3.Lerp(b0, b1, 0.5f);
                                up = Vector3.Project(b2 - b0, Vector3.up); //recalculate after b change(?)
                                Vector3 b3 = center + up;
                                if (simpleGable)                           //generate a simple gable
                                {
                                    //generate simple gable based on roof
                                    Vector3 gCenter = Vector3.Lerp(g0, g1, 0.5f);
                                    Vector3 gBaseUp = Vector3.up * additionalHeight;
                                    Vector3 gUp     = up.normalized * height;
                                    Vector3 gBack   = -face * thickness;
                                    //todo further calculations
                                    //face
                                    mesh.AddPlane(g0, g1, g0 + gBaseUp, g1 + gBaseUp, wallSubmesh);
                                    mesh.AddTri(g1 + gBaseUp, g0 + gBaseUp, gCenter + gUp, dir, wallSubmesh);
                                    //backface
                                    mesh.AddPlane(g1 + gBack, g0 + gBack, g1 + gBaseUp + gBack, g0 + gBaseUp + gBack, wallSubmesh);
                                    mesh.AddTri(g0 + gBack + gBaseUp, g1 + gBack + gBaseUp, b3 + gBaseUp, -dir, wallSubmesh);
                                    //left
                                    mesh.AddPlane(g0 + gBack, g0, g0 + gBaseUp + gBack, g0 + gBaseUp, wallSubmesh);
                                    mesh.AddPlane(g0 + gBaseUp + gBack, g0 + gBaseUp, b3 + gBaseUp, gCenter + gUp, wallSubmesh);
                                    //right
                                    mesh.AddPlane(g1, g1 + gBack, g1 + gBaseUp, g1 + gBaseUp + gBack, wallSubmesh);
                                    mesh.AddPlane(g1 + gBaseUp, g1 + gBaseUp + gBack, gCenter + gUp, b3 + gBaseUp, wallSubmesh);
                                }
                                else if (volume[facadeIndices[b]].gableStyle != null)
                                {
                                    Vector2 baseUV = new Vector2(0, volume.planHeight);
                                    GableGenerator.Generate(ref mesh, gableStyle, g0, g1, height, thickness, baseUV);
                                }
                                else
                                {
                                    mesh.AddTri(b0, b3, b1, dir, submesh);//face - no separate gable
                                }

                                mesh.AddTri(b0, b2, b3, face, submesh);  //left
                                mesh.AddTri(b1, b3, b2, -face, submesh); //right
                            }
                        }
                    }
                }
            }

            return(true);
        }
Пример #19
0
 public void Encapsulate(FlatBounds bounds)
 {
     Encapsulate(bounds.min);
     Encapsulate(bounds.max);
 }