コード例 #1
0
        private void CreateCornerFacades(ISubdivisionGeometry geometry, Footprint footprint, int topIndex, IReadOnlyList <IReadOnlyList <Vector2> > corners, string material)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(corners != null);
            Contract.Requires(_floors != null);

            //Calculate altitude of bottom and top of this facade
            var bot = _floors[footprint.BottomIndex].FloorAltitude;
            var top = _floors[topIndex].FloorAltitude + _floors[topIndex].Bounds.Height;
            var mid = (bot + top) * 0.5f;

            //Fill in corner sections (solid)
            foreach (var corner in corners)
            {
                try
                {
                    geometry.Union(geometry
                                   .CreatePrism(material, corner, top - bot)
                                   .Translate(new Vector3(0, mid, 0))
                                   );
                }
                catch (ArgumentException)
                {
                    //Suppress the argument exception, why?
                    //If we try to create a degenerate prism (negative height, only 2 points) we get an arg exception
                    //Corner sections can be very slim, sometimes *so slim* that the four points merge together
                    //In this case we don't care, the section is so small we'll just skip it!
                }
            }
        }
コード例 #2
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            //Create land parcels
            var nodes = CreateParcelNodes(GenerateParcels(bounds.Footprint).ToArray(), bounds.Height).ToArray();

            //Set ground height (for nodes which care)
            foreach (var grounded in nodes.Select(node => node.Value).OfType <IGrounded>())
            {
                grounded.GroundHeight = GroundHeight;
            }

            //Build neighbour set
            var neighbours = new NeighbourSet <ISubdivisionContext>();

            foreach (var keyValuePair in nodes)
            {
                foreach (var edge in keyValuePair.Key.Edges)
                {
                    neighbours.Add(new LineSegment2(edge.Start, edge.End), keyValuePair.Value);
                }
            }

            //Associate node with their neighbours (for nodes which care)
            foreach (var neighbour in nodes.Where(node => node.Value is INeighbour))
            {
                ((INeighbour)neighbour.Value).Neighbours = CalculateNeighbours(neighbour, neighbours).ToArray();
            }
        }
コード例 #3
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            //Select external building parameters
            var externals = SelectExternals().ToArray();

            //Create things
            _floors    = CreateFloors(SelectFloors().ToArray(), Footprints(externals));
            _verticals = SelectVerticals().ToArray();
            _facades   = CreateFacades(geometry, externals, hierarchicalParameters);

            //Setup relationship between floors (floor PrerequisiteOf floor-further-from-ground)
            foreach (var keyValuePair in _floors)
            {
                //Ground floor has no prerequisites
                if (keyValuePair.Key == 0)
                {
                    continue;
                }

                //Work out the index of the prerequisite
                var prereqIndex = keyValuePair.Key < 0 ? keyValuePair.Key + 1 : keyValuePair.Key - 1;

                //Try to find it (this *shouldn't* ever fail, if we have a continuous run of floors)
                IFloor prereq;
                if (_floors.TryGetValue(prereqIndex, out prereq))
                {
                    keyValuePair.Value.AddPrerequisite(prereq);
                }
            }
        }
コード例 #4
0
        private void CreateFootpathFromPair(ISubdivisionGeometry geometry, string material, float height, IHalfEdgeBuilder a, IHalfEdgeBuilder b)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(a != null);
            Contract.Requires(b != null);

            //Determine the inner point we're curving around
            bool r1LeftInner  = a.LeftEnd.TolerantEquals(b.RightEnd, 0.01f);
            bool r1RightInner = a.RightEnd.TolerantEquals(b.LeftEnd, 0.01f);

            //Straight on, no junction and no paths needed
            if (r1LeftInner && r1RightInner)
            {
                return;
            }

            if (r1LeftInner)
            {
                //One side is an inner side, create a footpath around that point
                CreateFootpath2Inner(geometry, material, height, true, a, b);
            }
            else
            {
                //No point is an inner point, follow around the outer edge connecting these two roads
                CreateFootpath2Outer(geometry, material, height, a, b);
            }
        }
コード例 #5
0
        /// <summary>
        /// Create the base block for this facade (which embossing stamps will be applied to)
        /// </summary>
        /// <param name="bounds"></param>
        /// <param name="geometry"></param>
        /// <param name="hierarchicalParameters"></param>
        /// <returns></returns>
        protected virtual ICsgShape CreateFacade(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(hierarchicalParameters != null);

            return(geometry.CreatePrism(hierarchicalParameters.DefaultMaterial(Random), bounds.Footprint, bounds.Height));
        }
コード例 #6
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            //Generate a topological map of city roads
            var m = GenerateBlockMesh();

            //Materialize the topological map into a topographical one
            MaterializeMesh(m);
        }
コード例 #7
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            if (!_deleted)
            {
                base.Subdivide(bounds, geometry, _parameters ?? hierarchicalParameters);
            }

            IsSubdivided = true;
        }
コード例 #8
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            var height   = (float)Math.Min(bounds.Height, Math.Sqrt(Math.Abs(bounds.Footprint.Area())) * (Random() + 0.5));
            var material = hierarchicalParameters.DefaultMaterial(Random);

            var prism = geometry.CreatePrism(material, bounds.Footprint, height).Transform(Matrix4x4.CreateTranslation(0, height / 2f - bounds.Height / 2f + GroundHeight, 0));

            geometry.Union(prism);
        }
コード例 #9
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            if (_designer == null)
            {
                _designer = hierarchicalParameters.GetValue(FloorDesignerName, false);
            }

            base.Subdivide(bounds, geometry, hierarchicalParameters);
        }
コード例 #10
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            //Get internals generated up tree in container
            var internals = hierarchicalParameters.GetValue(BaseSpecBuildingContainer.BuildingInternalsName);

            //Generate externals, now we can get the neighbour information that we need from the surrounding containers
            _design = internals.Externals(Random, hierarchicalParameters, (a, b) => ScriptReference.Find(a, b).Random((Func <double>)Random), GetNeighbourInfo(bounds));

            base.Subdivide(bounds, geometry, hierarchicalParameters);
        }
コード例 #11
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            var height = hierarchicalParameters.GetMaybeValue(new TypedName <float>("height")) ?? 1;

            this.CreateFlatPlane(geometry,
                                 hierarchicalParameters.GetValue(new TypedName <string>("material")) ?? "grass",
                                 bounds.Footprint,
                                 height,
                                 -height
                                 );
        }
コード例 #12
0
        private void CreateCeilings(Prism bounds, ISubdivisionGeometry geometry, IEnumerable <KeyValuePair <VerticalSelection, IRoomPlan> > verticalSubsections, string material)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(verticalSubsections != null);

            var ceiling = geometry.CreatePrism(material, bounds.Footprint, _ceilingThickness).Translate(new Vector3(0, bounds.Height / 2 - _ceilingThickness / 2, 0));

            ceiling = CutVerticalHoles(ceiling, geometry, material, verticalSubsections.Select(a => a.Value));

            geometry.Union(ceiling);
        }
コード例 #13
0
        public static void CreateFlatPlane(this IGrounded grounded, ISubdivisionGeometry geometry, string material, IReadOnlyList <Vector2> footprint, float height, float yOffset = 0)
        {
            Contract.Requires(grounded != null);
            Contract.Requires(geometry != null);
            Contract.Requires(footprint != null && footprint.Count >= 3);

            var offset = GroundOffset(grounded, height) + yOffset;

            var prism = geometry.CreatePrism(material, footprint, height).Transform(Matrix4x4.CreateTranslation(0, offset, 0));

            geometry.Union(prism);
        }
コード例 #14
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            //Sanity checks
            if (!_floorIndex.HasValue)
            {
                throw new InvalidOperationException("Attempted to subdivide BaseFloor, but FloorIndex is not set");
            }
            if (!_floorAltitude.HasValue)
            {
                throw new InvalidOperationException("Attempted to subdivide BaseFloor, but FloorAltitude is not set");
            }

            //Calculate some handy values
            _roomHeight = bounds.Height - _floorThickness - _ceilingThickness;
            var roomOffsetY = -bounds.Height / 2 + _roomHeight / 2 + _floorThickness;

            //Find vertical elements which start on this floor
            var constrainedVerticalElements = ConstrainVerticalElements(this.SearchUp <IBuilding, IBuilding>(a => a, typeof(IBuildingContainer)));

            //Create a plan for this floor
            var plan = new Plan.Geometric.GeometricFloorplan(Bounds.Footprint);
            var overlappingVerticalRooms = InsertOverlappingVerticals(
                plan,
                this.SearchUp <IVerticalFeatureContainer, IVerticalFeatureContainer>(a => a, typeof(IBuildingContainer)).Overlapping(FloorIndex, false)
                );

            var verticals = CreateFloorPlan(plan, overlappingVerticalRooms, constrainedVerticalElements).ToArray();

            _plan = plan.Freeze();

            PlanFrozen(_plan);

            //Create nodes for all the vertical elements which started on this floor
            CreateVerticalNodes(verticals);

            //Create Floor and ceiling (with holes for vertical sections)
            CreateFloors(bounds, geometry, verticals, HierarchicalParameters.DefaultCeilingMaterial(Random));
            CreateCeilings(bounds, geometry, verticals, HierarchicalParameters.DefaultCeilingMaterial(Random));

            //Create room scripts
            CreateRoomNodes(roomOffsetY, _roomHeight, _plan);

            //Create external facades (subsections of building over this floor facade)
            var externalFacades = CreateExternalFacades(bounds, _plan);

            //Create facades for rooms
            var dist = hierarchicalParameters.ExternalWallThickness(Random);

            CreateRoomFacades(externalFacades, roomOffsetY, dist, _plan);
        }
コード例 #15
0
        private void CreateFootpathN(ISubdivisionGeometry geometry, string material, float height)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(Vertex != null);

            //Order the edges by their angle around the vertex
            var orderedEdges = Vertex.OrderedEdges().ToArray();

            //Create path for pairs of roads
            for (int i = 0; i < orderedEdges.Length; i++)
            {
                var prev = orderedEdges[(i + orderedEdges.Length - 1) % orderedEdges.Length];
                var edge = orderedEdges[i];

                CreateFootpathFromPair(geometry, material, height, prev, edge);
            }
        }
コード例 #16
0
        private void CreateFootpaths(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters, string material, float height)
        {
            switch (Vertex.Edges.Count())
            {
            //A junction not connected to any roads... suspicious but not technically disallowed
            case 0:
            //Dead end, don't do anything - the road places everything it needs
            case 1: {
                break;
            }

            //N-Way junction
            default: {
                CreateFootpathN(geometry, material, height);
                break;
            }
            }
        }
コード例 #17
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            _internals = _designer.Internals(Random, HierarchicalParameters, ScriptReference.Find(Random));

            HierarchicalParameters.Set(BuildingInternalsName, _internals);

            base.Subdivide(bounds, geometry, hierarchicalParameters);

            //Create the node which will create the building form the spec
            var building = (SpecBuilding)CreateChild(bounds, Quaternion.Identity, Vector3.Zero, new ScriptReference(typeof(SpecBuilding)));

            //Make sure sibling container subdivide before building
            foreach (var sibling in Parent.Children.OfType <IBuildingContainer>())
            {
                building.AddPrerequisite(sibling, false);
            }

            //Copy neighbour data into building (from container)
            building.Neighbours = Neighbours;
        }
コード例 #18
0
        private static ICsgShape CutVerticalHoles(ICsgShape shape, ISubdivisionGeometry geometry, string material, IEnumerable <IRoomPlan> verticalSubsections)
        {
            Contract.Requires(shape != null);
            Contract.Requires(geometry != null);
            Contract.Requires(verticalSubsections != null);
            Contract.Ensures(Contract.Result <ICsgShape>() != null);

            var shapeHeight = (shape.Bounds.Max.Y - shape.Bounds.Min.Y) * 2f;
            var shapeMid    = (shape.Bounds.Min.Y + shape.Bounds.Max.Y) * 0.5f;

            foreach (var verticalSubsection in verticalSubsections)
            {
                shape = shape.Subtract(
                    geometry.CreatePrism(material, verticalSubsection.OuterFootprint, shapeHeight).Translate(new Vector3(0, shapeMid, 0))
                    );
                Contract.Assume(shape != null);
            }

            return(shape);
        }
コード例 #19
0
        private IReadOnlyCollection <IBuildingFacade> CreateFacades(ISubdivisionGeometry geometry, IEnumerable <Footprint> footprints, INamedDataCollection hierarchicalParameters)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(footprints != null);
            Contract.Requires(hierarchicalParameters != null);

            //Accumulate results
            var results = new List <IBuildingFacade>();

            //Calculate external wall thickness
            var thickness = hierarchicalParameters.ExternalWallThickness(Random);
            var material  = hierarchicalParameters.ExternalWallMaterial(Random);

            var footprintArr = footprints.OrderBy(a => a.BottomIndex).ToArray();

            for (var i = 0; i < footprintArr.Length; i++)
            {
                var footprint = footprintArr[i];
                var topIndex  = (i == footprintArr.Length - 1) ? (_floors[_floors.Keys.Max()].FloorIndex) : (footprintArr[i + 1].BottomIndex - 1);

                //Sanity check that we have the correct number of facades
                if (footprint.Facades.Count != footprint.Shape.Count)
                {
                    throw new InvalidOperationException(string.Format("Tried to created {0} facades for {1} walls", footprint.Facades.Count, footprint.Shape.Count));
                }

                //Generate wall sections to fill in
                Vector2[] inner;
                IReadOnlyList <IReadOnlyList <Vector2> > corners;
                var sections = footprint.Shape.Sections(thickness, out inner, out corners);

                //Create the tiny bits of facade in the corners
                CreateCornerFacades(geometry, footprint, topIndex, corners, material);

                //Now iterate through sides and create facades
                CreatePrimaryFacades(footprint, sections, results);
            }

            return(results);
        }
コード例 #20
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            //Create a brush which will represent our facade
            var facade = CreateFacade(bounds, geometry, hierarchicalParameters);

            //Convert stamps and apply them to the facade brush
            var stamps = EmbossingStamps(hierarchicalParameters, Section.Width, bounds.Height);

            foreach (var stamp in stamps)
            {
                var brush = ConvertStampToBrush(Section, stamp, stamp.Material, geometry, hierarchicalParameters);
                if (brush == null)
                {
                    continue;
                }

                //Add the shape if this is additive. However if this is a glass stamp ignore the additive flag and subtract always.
                facade = (stamp.Additive && !stamp.GlassFill.HasValue) ? facade.Union(brush) : facade.Subtract(brush);

                //Create a block of glass in the appropriate place
                if (stamp.GlassFill.HasValue)
                {
                    //Create a brusg for the glass. Either reuse the existing brush (if the material is the same) or create a new one with the glass material
                    var glassBrush = stamp.GlassFill.Value.Material == stamp.Material ? brush : ConvertStampToBrush(Section, stamp, stamp.GlassFill.Value.Material, geometry, hierarchicalParameters);
                    if (glassBrush == null)
                    {
                        continue;
                    }

                    //Transform this with world-transform to place window in correct place in world
                    Window.Create(this, glassBrush.Transform(WorldTransformation), stamp.GlassFill.Value.Opacity, stamp.GlassFill.Value.Scattering, stamp.GlassFill.Value.Attenuation);
                }
            }

            //Place the geometry in the world
            //Clip:false here allows the facade to overhang the bounds it is contained within (the wall section). Facades almost always do this in practice...
            //...e.g. fancy window decorations stick out from the wall a little bit
            geometry.Union(facade, clip: false);
        }
コード例 #21
0
 public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
 {
     _height = CalculateHeight();
 }
コード例 #22
0
        private void CreateFootpath2Outer(ISubdivisionGeometry geometry, string material, float height, IHalfEdgeBuilder r1, IHalfEdgeBuilder r2)
        {
            Contract.Requires(geometry != null);
            Contract.Requires(r1 != null);
            Contract.Requires(r2 != null);

            //r1.LeftEnd and r2.RightEnd are the outsides of the roads
            //Trace a path along the boundary between these points, use the path which does *not* include the other points
            Vector2[] cwp, ccwp;
            bool      cw, ccw;

            Bounds.Footprint.TraceConnectingPath(
                Vector3.Transform(r1.LeftEnd.X_Y(0), InverseWorldTransformation).XZ(),
                Vector3.Transform(r2.RightEnd.X_Y(0), InverseWorldTransformation).XZ(),
                0.01f, out cwp, out cw, out ccwp, out ccw,
                Vector3.Transform(r1.RightEnd.X_Y(0), InverseWorldTransformation).XZ(),
                Vector3.Transform(r2.LeftEnd.X_Y(0), InverseWorldTransformation).XZ());

            //Sanity check (only 1 direction should be acceptable)
            if (!(cw ^ ccw))
            {
                return;
            }

            //Follow along edge, then back along edge (pushed inwards by footpath width)
            //todo: Offset width by angle at end of road
            var outerPoints = cw ? cwp : ccwp;
            var innerPoints = new Vector2[cw ? cwp.Length : ccwp.Length];

            Contract.Assert(innerPoints.Length == outerPoints.Length);

            var widthStart = cw ? r1.SidewalkWidth : r2.SidewalkWidth;
            var widthEnd   = cw ? r2.SidewalkWidth : r1.SidewalkWidth;

            for (var i = 0; i < outerPoints.Length && outerPoints.Length > 1; i++)
            {
                Vector2 dir;
                float   w;
                if (i == 0)
                {
                    dir = Vector2.Normalize(cw ? r1.RightEnd - r1.LeftEnd : r2.LeftEnd - r2.RightEnd);
                    w   = CalculateFootpathAngleScale(cw ? r1.Direction : r2.Direction, dir, widthStart);
                }
                else if (i == outerPoints.Length - 1)
                {
                    dir = Vector2.Normalize(cw ? r2.LeftEnd - r2.RightEnd : r1.RightEnd - r1.LeftEnd);
                    w   = CalculateFootpathAngleScale(cw ? r2.Direction : r1.Direction, -dir, widthEnd);
                }
                else
                {
                    //perpendicular to path direction
                    dir = Vector2.Normalize(outerPoints[i] - outerPoints[i - 1]).Perpendicular() * (cw ? 1 : -1);
                    //Interpolate widths along path
                    var t = i / (float)(outerPoints.Length - 1);
                    w = MathHelper.Lerp(widthStart, widthEnd, t);
                }

                innerPoints[i] = outerPoints[i] + dir * w;
            }

            //Create footprint from 2 halves
            var footprint = cw ? outerPoints.Concat(innerPoints.Reverse()) : outerPoints.Reverse().Concat(innerPoints);

            geometry.Union(geometry
                           .CreatePrism(material, footprint.ToArray(), height)
                           .Translate(new Vector3(0, this.GroundOffset(height), 0))
                           );
        }
コード例 #23
0
        private void CreateFootpath2Inner(ISubdivisionGeometry geometry, string material, float height, bool r1LeftInner, IHalfEdgeBuilder r1, IHalfEdgeBuilder r2)
        {
            Contract.Requires(r1 != null);
            Contract.Requires(r2 != null);
            Contract.Requires(geometry != null);

            var innerPoint = r1LeftInner ? r1.LeftEnd : r1.RightEnd;

            var points = new List <Vector2> {
                innerPoint
            };

            //Points where the footpath terminates at the end of the road
            var r1Across = r1LeftInner ? r1.Direction.Perpendicular() : -r1.Direction.Perpendicular();
            var r1Point  = innerPoint + r1Across * r1.SidewalkWidth;
            var r2Across = r1LeftInner ? -r2.Direction.Perpendicular() : r2.Direction.Perpendicular();
            var r2Point  = innerPoint + r2Across * r2.SidewalkWidth;

            //Point to turn the connect around
            var centerPoint = new Ray2(r1Point, r1.Direction.Perpendicular()).Intersects(new Ray2(r2Point, r2.Direction.Perpendicular()));

            //Sanity check!
            if (!centerPoint.HasValue)
            {
                return;
            }

            //Evaluate segment
            var curve = new CircleSegment {
                CenterPoint = centerPoint.Value.Position,
                StartPoint  = r1Point,
                EndPoint    = r2Point,
            };

            points.AddRange(curve.Evaluate(0.05f));

            //Helpers function for creating prisms
            Action <IEnumerable <Vector2>, bool> unionPrism = (footprint, check) => geometry.Union(geometry
                                                                                                   .CreatePrism(material, footprint.ConvexHull().ToArray(), height)
                                                                                                   .Translate(new Vector3(0, this.GroundOffset(height), 0))
                                                                                                   .Transform(InverseWorldTransformation),
                                                                                                   check
                                                                                                   );

            //Materialize result
            unionPrism(points, false);

            //Extend straight sections to edge of node
            //We only need to do this if we were turning precisely about the contact points of these two roads
            if (centerPoint.Value.Position.TolerantEquals(innerPoint, 0.1f))
            {
                unionPrism(new[] {
                    r1Point,
                    innerPoint,
                    innerPoint - r1.Direction * r1.SidewalkWidth,
                    r1Point - r1.Direction * r1.SidewalkWidth
                }, true);

                unionPrism(new[] {
                    r2Point,
                    innerPoint,
                    innerPoint - r2.Direction * r2.SidewalkWidth,
                    r2Point - r2.Direction * r2.SidewalkWidth
                }, true);
            }
        }
コード例 #24
0
        public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
        {
            this.CreateFlatPlane(geometry, "tarmac", bounds.Footprint, 1, -1);

            CreateFootpaths(bounds, geometry, hierarchicalParameters, hierarchicalParameters.RoadSidewalkMaterial(Random), HierarchicalParameters.RoadSidewalkHeight(Random));
        }
コード例 #25
0
 public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
 {
 }
コード例 #26
0
 public override void Subdivide(Prism bounds, ISubdivisionGeometry geometry, INamedDataCollection hierarchicalParameters)
 {
     CreateChild(_prism, Quaternion.Identity, Vector3.Zero, _script);
 }