Пример #1
0
        private void Triangulate()
        {
            TPPLPoly poly = new TPPLPoly();

            foreach (PointF p in _points)
            {
                poly.Points.Add(new TPPLPoint(p.X, p.Y));
            }

            poly.SetOrientation(TPPLOrder.CCW);

            List <TPPLPoly> triangles = new List <TPPLPoly>();
            TPPLPartition   part      = new TPPLPartition();

            part.Triangulate_EC(poly, triangles);

            _triangles.Clear();

            foreach (TPPLPoly triangle in triangles)
            {
                Triangle tr = new Triangle();

                triangle.SetOrientation(TPPLOrder.CW);

                tr.Alpha   = new PointF(triangle[0].X, triangle[0].Y);
                tr.Bravo   = new PointF(triangle[1].X, triangle[1].Y);
                tr.Charlie = new PointF(triangle[2].X, triangle[2].Y);

                _triangles.Add(tr);
            }
        }
Пример #2
0
        public static float PolyArea2(Vector2[] points)
        {
            TPPLPoly poly = new TPPLPoly();

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

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

            List <TPPLPoly> triangles = new List <TPPLPoly>();
            TPPLPartition   part      = new TPPLPartition();

            part.Triangulate_EC(poly, triangles);

            int   triCount = triangles.Count;
            float output   = 0;

            for (int t = 0; t < triCount; t += 3)
            {
                TPPLPoint tv0 = triangles[t][0];
                TPPLPoint tv1 = triangles[t][1];
                TPPLPoint tv2 = triangles[t][2];

                Vector2 v0 = new Vector2(tv0.X, tv0.Y);
                Vector2 v1 = new Vector2(tv1.X, tv1.Y);
                Vector2 v2 = new Vector2(tv2.X, tv2.Y);

                float a = Vector2.Distance(v0, v1);
                float b = Vector2.Distance(v1, v2);
                float c = Vector2.Distance(v2, v0);

                output += TriangleAreaHeron(a, b, c);
            }
            return(output);
        }
        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);
            //            }
        }