コード例 #1
0
        /// <summary>
        /// Apply merging rules to reduce faces (removing oddly shaped faces)
        /// </summary>
        private void ReduceFaces(Mesh <FloorplanVertexTag, FloorplanHalfEdgeTag, FloorplanFaceTag> map)
        {
            //Calculate parameters for merging
            var angularWeight = _mergeParameters.AngularWeight.SelectFloatValue(_random, _metadata);
            var convexWeight  = _mergeParameters.ConvexWeight.SelectFloatValue(_random, _metadata);
            var areaWeight    = _mergeParameters.AreaWeight.SelectFloatValue(_random, _metadata);

            //Normalize weights into (0 -> 1 range)
            var totalWeight = (angularWeight + areaWeight + convexWeight);

            angularWeight /= totalWeight;
            convexWeight  /= totalWeight;
            areaWeight    /= totalWeight;

            var angularThreshold   = _mergeParameters.AngularThreshold.SelectFloatValue(_random, _metadata);
            var convexityThreshold = _mergeParameters.ConvexThreshold.SelectFloatValue(_random, _metadata);
            var areaThreshold      = _mergeParameters.AreaThreshold.SelectFloatValue(_random, _metadata);

            //Keep repeating this loop (tightening the boudns each time) until an iteration does no work (i.e. merges nothing)
            var iterations = 0;
            int workDone;

            do
            {
                workDone = 0;

                var angDeviationThreshold = Math.Pow(angularThreshold, 1f / (iterations + 1));
                var convThreshold         = Math.Pow(convexityThreshold, iterations + 1);

                //Remove faces with angular deviation too high or convexity too low
                workDone += RemoveFaces(map,
                                        a => a.Tag.AngularDeviation > angDeviationThreshold || a.Tag.Convexity < convThreshold,
                                        a => a.Tag.Mergeable,
                                        a =>
                {
                    var invAdjArea = 1 / Math.Max(1, a.Select(v => v.Position).Area() - areaThreshold);
                    var invAngDev  = 1 - FloorplanFaceTag.CalculateAngularDeviation(a);
                    var convexity  = FloorplanFaceTag.CalculateConvexity(a);

                    return((angularWeight * invAngDev) + (convexWeight * convexity) + (areaWeight * invAdjArea));
                },
                                        MergeTags,
                                        1
                                        );

                iterations++;
            } while (workDone > 0);

            //We've done our best to reduce faces by merging them with neighbours
            //It's possible some invalid faces were not merged (no good merge candidates)
            //Now we just discard those faces which are below the *area* threshold
            //Why not the other thresholds? It's easy to fix area, but essentially impossible to reliably fix the other two, so it would cut out too many rooms to treat those are hard cutoffs
            var areaCutoff    = _mergeParameters.AreaCutoff.SelectFloatValue(_random, _metadata);
            var facesToRemove = map.Faces.Where(a => a.Tag.Area < areaCutoff).ToArray();

            foreach (var face in facesToRemove)
            {
                map.Delete(face);
            }
        }
コード例 #2
0
        /// <summary>
        /// Merge 2 floorplan tags togehter
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private static FloorplanFaceTag MergeTags(FloorplanFaceTag a, FloorplanFaceTag b)
        {
            Contract.Requires(a != null && a.Mergeable);
            Contract.Requires(b != null && b.Mergeable);

            //Choose the non null spec (if either are not null)
            ISpec spec = null;

            if (a.Spec != null ^ b.Spec != null)
            {
                spec = a.Spec ?? b.Spec;
            }
            else if (a.Spec != null && b.Spec != null)
            {
                throw new NotImplementedException("Both faces in merge already have a spec assigned");
            }

            return(new FloorplanFaceTag(
                       true, //A and B must be mergeable (see contract) so therefore this must be mergeable
                       spec
                       ));
        }