Beispiel #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);
        }
Beispiel #2
0
        public static OBBox GetBox()
        {
            OBBox output;

            if (_obPool.Count > 0)
            {
                output = _obPool[0];
                _obPool.RemoveAt(0);
            }
            else
            {
                output = new OBBox();
            }
            return(output);
        }
Beispiel #3
0
        public static OBBox GetBox(Vector2 newCenter, Vector2 dirA, float sizeA, Vector2 dirB, float sizeB)
        {
            OBBox output;

            if (_obPool.Count > 0)
            {
                output = _obPool[0];
                output.SetValues(newCenter, dirA, sizeA, dirB, sizeB);
                _obPool.RemoveAt(0);
            }
            else
            {
                output = new OBBox(newCenter, dirA, sizeA, dirB, sizeB);
            }
            return(output);
        }
Beispiel #4
0
        public OBBox CreateConvex(Vector2[] points)
        {
            if (points.Length == 0)
            {
                Debug.LogError("No points sent!");
            }
            int   pointCount = points.Length;
            OBBox defaultBox = GetBox();
            OBBox output     = defaultBox;
            float minArea    = Mathf.Infinity;

            for (int p = 0; p < pointCount; p++)
            {
                Vector2 p0  = points[p];
                Vector2 p1  = points[(p + 1) % pointCount];
                Vector2 dir = (p1 - p0).normalized;
                if (dir.sqrMagnitude < Mathf.Epsilon)
                {
                    continue;                                  //ignore duplicate points
                }
                float angle = JMath.SignAngle(dir);

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

                Vector2 center    = JMath.Rotate(_bounds.center, -angle);
                OBBox   candidate = GetBox(center, dir, _bounds.height, JMath.Rotate(dir, 90), _bounds.width);
                if (_bounds.Area() < minArea)
                {
                    if (output != defaultBox)
                    {
                        PutBox(output);
                    }
                    output = candidate;
                }
                else
                {
                    PutBox(candidate);
                }
            }

            return(output);
        }
Beispiel #5
0
        private Subplot[] SplitPlot(ProcessPlot processPlot)
        {
//            Profiler.BeginSample("SplitPlot");
            Subplot[] output = new Subplot[2];

            IPlot plot = processPlot.plot;

            if (processPlot.obbs.Count == 0)
            {
                if (plot.splitSettings.log)
                {
                    plot.notes = "no obb split options left";
                }
//                Profiler.EndSample();
                return(output);
            }

            OBBox obBox = processPlot.obbs[0];

            if (obBox.area < plot.splitSettings.minArea)
            {
                if (plot.splitSettings.log)
                {
                    plot.notes = "area smaller than minimum";
                }
//                Profiler.EndSample();
                return(output);
            }

            Vector2[]   points             = plot.pointsV2;
            Vector2[][] boundaryPoints     = plot.boundaryPoints;
            bool        boundaryPointsUsed = boundaryPoints != null && boundaryPoints.Length > 0;

            bool[] externals = plot.externals;
            int    shapeSize = points.Length;

            Vector2 cenExt       = processPlot.shortSplit && !processPlot.longSplit ? obBox.longDir * obBox.longSize * 0.5f : obBox.shortDir * obBox.shortSize * 0.5f;
            float   boxVariation = rGen.Range(-plot.splitSettings.variation * 0.5f, plot.splitSettings.variation * 0.5f) + 0.5f;

            if (processPlot.variationA && !processPlot.variationB)
            {
                boxVariation *= 1 - processPlot.variationAmount;
            }
            if (processPlot.variationA && processPlot.variationB)
            {
                boxVariation += (1f - boxVariation) * processPlot.variationAmount;
            }
            Vector2 cutCenter = Vector2.Lerp(obBox.center - cenExt, obBox.center + cenExt, boxVariation);
            Vector2 intExt    = processPlot.shortSplit && !processPlot.longSplit ? obBox.shortDir * obBox.shortSize : obBox.longDir * obBox.longSize;
            Vector2 intP0     = cutCenter - intExt;
            Vector2 intP1     = cutCenter + intExt;
            //            if(plot is Plot)
            //                        Debug.DrawLine(JMath.ToV3(intP0), JMath.ToV3(intP1), Color.magenta);

            List <Vector2> intersectionPoints = new List <Vector2>();
            List <int>     intersectionIndex  = new List <int>();

            for (int p = 0; p < shapeSize; p++)
            {
                Vector2 p0 = points[p];
                Vector2 p1 = points[(p + 1) % shapeSize];
                Vector2 intersectionPoint;
                if (Intersects(intP0, intP1, p0, p1, out intersectionPoint))
                {
                    intersectionPoints.Add(intersectionPoint);
                    intersectionIndex.Add(p);
                    if (intersectionPoints.Count == 2)
                    {
                        break;
                    }
                }
            }

            List <Vector2> shapeA            = new List <Vector2>();
            List <bool>    externalsA        = new List <bool>();
            List <Vector2> shapeB            = new List <Vector2>();
            List <bool>    externalsB        = new List <bool>();
            float          sqrMergeThreshold = plot.splitSettings.mergeThreashold * plot.splitSettings.mergeThreashold;

            if (intersectionPoints.Count == 2)
            {
                //rebuild shapes - from indicies
                int intersectionIndexA     = intersectionIndex[0];
                int intersectionIndexB     = intersectionIndex[1];
                int intersectionIndexAPlus = intersectionIndexA + 1 < shapeSize ? intersectionIndexA + 1 : 0;
                int intersectionIndexBPlus = intersectionIndexB + 1 < shapeSize ? intersectionIndexB + 1 : 0;
                int shapeAStartIndex       = intersectionIndexBPlus;
                int shapeAEndIndex         = intersectionIndexA;
                int shapeBStartIndex       = intersectionIndexAPlus;
                int shapeBEndIndex         = intersectionIndexB;

                //calculate boundary merge cases
                for (int i = 0; i < 2; i++)
                {
                    int     boundaryIndex      = intersectionIndex[i];
                    bool    boundaryIsExternal = externals[boundaryIndex];
                    Vector2 intersectionPoint  = intersectionPoints[i];

                    Vector2[] mergePoints;
                    if (plot.splitSettings.useBoundaryMergeOnExternalsOnly && !boundaryIsExternal || !boundaryPointsUsed)
                    {
                        mergePoints    = new Vector2[2];
                        mergePoints[0] = points[boundaryIndex];
                        mergePoints[1] = points[boundaryIndex < shapeSize - 1 ? boundaryIndex + 1 : 0];
                    }
                    else
                    {
                        mergePoints = boundaryPoints[boundaryIndex];
                    }
                    int   mergePointCount        = mergePoints.Length;
                    float smallestsqrmag         = float.PositiveInfinity;
                    int   nearestMergePointIndex = -1;
                    for (int m = 0; m < mergePointCount; m++)
                    {
                        float mpSqrMag = (mergePoints[m] - intersectionPoint).sqrMagnitude;
                        if (mpSqrMag < sqrMergeThreshold && mpSqrMag < smallestsqrmag)
                        {
                            smallestsqrmag         = mpSqrMag;
                            nearestMergePointIndex = m;
                        }
                    }

                    bool    mergeOccured = nearestMergePointIndex != -1;
                    Vector2 mergePoint   = mergeOccured ? mergePoints[nearestMergePointIndex] : intersectionPoint;

                    if (i == 0)
                    {
                        shapeA.Add(mergePoint);
                        externalsA.Add(false);
                        shapeB.Add(mergePoint);
                        externalsB.Add(boundaryIsExternal);
                    }
                    else
                    {
                        shapeA.Add(mergePoint);
                        externalsA.Add(boundaryIsExternal);
                        shapeB.Insert(0, mergePoint);
                        externalsB.Insert(0, false);
                    }

                    if (i == 0 && nearestMergePointIndex == 0)
                    {
                        shapeAEndIndex = intersectionIndexA % shapeSize;
                    }
                    if (i == 0 && nearestMergePointIndex == mergePointCount - 1)
                    {
                        shapeBStartIndex = (intersectionIndexA + 2) % shapeSize;
                    }
                    if (i == 1 && nearestMergePointIndex == 0)
                    {
                        shapeBEndIndex = intersectionIndexB % shapeSize;
                    }
                    if (i == 1 && nearestMergePointIndex == mergePointCount - 1)
                    {
                        shapeAStartIndex = (intersectionIndexB + 2) % shapeSize;
                    }
                }

                //build shape B
                while (true)
                {
                    shapeA.Add(points[shapeAStartIndex]);
                    externalsA.Add(externals[shapeAStartIndex]);

                    if (shapeAStartIndex == shapeAEndIndex)
                    {
                        break;
                    }
                    shapeAStartIndex = (shapeAStartIndex + 1) % shapeSize;
                }

                //build shape B
                while (true)
                {
                    shapeB.Add(points[shapeBStartIndex]);
                    externalsB.Add(externals[shapeBStartIndex]);

                    if (shapeBStartIndex == shapeBEndIndex)
                    {
                        break;
                    }
                    shapeBStartIndex = (shapeBStartIndex + 1) % shapeSize;
                }
            }
            else
            {
                Debug.LogError("Whaaps!");
                Debug.DrawLine(JMath.ToV3(intP0), JMath.ToV3(intP1), Color.yellow);
                Debug.DrawLine(JMath.ToV3(intP0), JMath.ToV3(intP0) + Vector3.up * 10, Color.yellow, 20);
                Debug.Log(intersectionPoints.Count);
                Debug.Log(processPlot.obbs.Count);
                Debug.Log(obBox.area);
                Debug.Log(obBox.longSize);
                Debug.Log(obBox.shortSize);
                Debug.Log(obBox.longDir);
                Debug.Log(obBox.shortDir);
                obBox.DebugDrawPlotCut(boxVariation);
                obBox.DebugDraw();
                obBox.DebugMark();
                DebugDraw(points, Color.magenta);
                processPlots.Clear();
//                Profiler.EndSample();
                return(output);
            }

            Subplot plotA = new Subplot(shapeA, _parent.splitSettings, externalsA);
            Subplot plotB = new Subplot(shapeB, _parent.splitSettings, externalsB);

            if (plot.splitSettings.minimumAccessLengthPercent < Mathf.Epsilon || (plotA.HasExternalAccess() && plotB.HasExternalAccess()))
            {
                output[0] = plotA;
                output[1] = plotB;
            }
            else//split was unsuccessful
            {
                if (!processPlot.longSplit && plot.splitSettings.fallbackSecondaryDivision)//restart split along long axis
                {
                    processPlot.longSplit = true;
                    processPlots.Insert(0, processPlot);
                }
                else
                {
                    if (processPlot.obbs.Count > 0 && plot.splitSettings.fallbackAlternativeObb)
                    {
                        processPlot.obbs.RemoveAt(0);
                        processPlot.longSplit  = false;
                        processPlot.variationA = false;
                        processPlot.variationB = false;
                        processPlots.Insert(0, processPlot);
                    }
                    else
                    {
                        if (plot.splitSettings.log)
                        {
                            plot.notes = "insufficient external access - no alternative";
                        }
                    }
                }
            }

//            Profiler.EndSample();

            return(output);
        }
Beispiel #6
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();
        }
Beispiel #7
0
 public static void PutBox(OBBox box)
 {
     box.Clear();
     _obPool.Add(box);
 }
Beispiel #8
0
        public List <OBBox> CreateConvexSortedList(Vector2[] points)
        {
            List <OBBox> output = new List <OBBox>();

            _obbList.Clear();
            _areaList.Clear();
            if (points.Length == 0)
            {
                Debug.LogError("No points sent!");
            }
            int pointCount = points.Length;

            for (int p = 0; p < pointCount; p++)
            {
                Vector2 p0  = points[p];
                Vector2 p1  = points[(p + 1) % pointCount];
                Vector2 dir = (p1 - p0).normalized;
                if (dir.sqrMagnitude < Mathf.Epsilon)
                {
                    continue;                                  //ignore invalid sides
                }
                float angle = JMath.SignAngle(dir);

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

                Vector2 center = JMath.Rotate(_bounds.center, -angle);
                OBBox   box    = GetBox(center, dir, _bounds.height, JMath.Rotate(dir, 90), _bounds.width);
                _obbList.Add(box);
                _areaList.Add(_bounds.Area());
            }

            int   obbCount   = _obbList.Count;
            OBBox defaultBox = GetBox();

            for (int i = 0; i < obbCount; i++)
            {
                float smallestArea = float.PositiveInfinity;
                OBBox candidate    = defaultBox;
                int   index        = -1;
                for (int j = 0; j < _obbList.Count; j++)
                {
                    if (smallestArea > _areaList[j])
                    {
                        candidate    = _obbList[j];
                        smallestArea = _areaList[j];
                        index        = j;
                    }
                }

                if (index != -1)
                {
                    output.Add(candidate);
                    _obbList.RemoveAt(index);
                    _areaList.RemoveAt(index);
                }
            }

            PutBox(defaultBox);
            while (_obbList.Count > 0)
            {
                PutBox(_obbList[0]);
                _obbList.RemoveAt(0);
            }

            return(output);
        }