private void CreatePrimaryFacades(Footprint footprint, IEnumerable <Section> sections, ICollection <IBuildingFacade> results) { for (var sideIndex = 0; sideIndex < footprint.Facades.Count; sideIndex++) { //Get start and end point of this wall var sideStart = footprint.Shape[sideIndex]; var sideEnd = footprint.Shape[(sideIndex + 1) % footprint.Shape.Count]; //find which section this side is for var sideSegment = new LineSegment2(sideStart, sideEnd).Line; var maybeSection = (from s in sections let aP = sideSegment.ClosestPointDistanceAlongLine(s.ExternalLineSegment.Start) * sideSegment.Direction + sideSegment.Position let aD = Vector2.Distance(aP, s.ExternalLineSegment.Start) where aD < 0.1f let bP = sideSegment.ClosestPointDistanceAlongLine(s.ExternalLineSegment.End) * sideSegment.Direction + sideSegment.Position let bD = Vector2.Distance(bP, s.ExternalLineSegment.End) where bD < 0.1f let d = aD + bD orderby d select s).Cast <Section?>().FirstOrDefault(); //Failed to find a section, this can happen when wall segments are so small the two corner segments either end completely cover the actual wall if (!maybeSection.HasValue) { continue; } var section = maybeSection.Value; //There are multiple facades for any one wall section, iterate through them and create them foreach (var facade in footprint.Facades[sideIndex]) { //Sanity check that the facade does not underrun the valid range //We can't sanity check overrun (easily) because that's based on the start of the *next* footprint if (facade.Bottom < footprint.BottomIndex) { throw new InvalidOperationException(string.Format("Facade associated with wall at floor {0} attempted to place itself at floor {1}", footprint.BottomIndex, facade.Bottom)); } var bot = _floors[facade.Bottom].FloorAltitude; var top = _floors[facade.Top].FloorAltitude + _floors[facade.Top].Bounds.Height; var mid = (bot + top) * 0.5f; var prism = new Prism(top - bot, section.Inner1, section.Inner2, section.Outer1, section.Outer2); //Create a configurable facade in the space var configurableNode = (ConfigurableFacade)CreateChild(prism, Quaternion.Identity, new Vector3(0, mid, 0), new ScriptReference(typeof(ConfigurableFacade))); configurableNode.Section = section; //Create the specified facade in the *same* space //This facade is just a proxy which passes all it's stamps to the configurable facade (created above) var externalFacade = (BaseBuildingFacade)CreateChild(prism, Quaternion.Identity, new Vector3(0, mid, 0), facade.Script); externalFacade.Facade = configurableNode; externalFacade.Section = section; externalFacade.BottomFloorIndex = facade.Bottom; externalFacade.TopFloorIndex = facade.Top; results.Add(externalFacade); //Make sure the building facade subdivides before the configurable facade (this ensures it can configure the facade) configurableNode.AddPrerequisite(externalFacade, true); //Make sure floors subdivide before configurable facade (this ensures it too can configure the facade) for (var i = externalFacade.BottomFloorIndex; i <= externalFacade.TopFloorIndex; i++) { configurableNode.AddPrerequisite(_floors[i], false); } //Make sure the building facade subdivides before the floor (this ensures the floor can see the effects of the facade) for (var i = externalFacade.BottomFloorIndex; i <= externalFacade.TopFloorIndex; i++) { _floors[i].AddPrerequisite(externalFacade, true); } } } }