//<Get Shell Geometry Poly Loop RHR> //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation //Designed to take a Dictionary <key=spaceId/SurfNum, value = List of cartesian coordinates that have been pulled //from a gbXML geometry format file. //This list of cart coordinates are associated with a key whoese string name = spaceId+surface number //This key was generated in the function GetShellGeomPts //------------------</p> //Each set of points are then turned into vectors, which are then put through a cross product to determine the //normal vector. we only arbitrarily take the first three points in the list, which potentially could cause some issue. //This is planned to be fixed in a future release. //The normal vector calculated is the value in the key value pair, the key being the spaceId+surfaceNumber, //The Dictionary is returned with it includes a key value pair for each surface it has analyzed. //Therefore, if the Dictionary sent to it has 12 key value pairs, then it will return 12 key value pairs as well. //This is not checked for explicitly but mentioned for clarity. public static Dictionary<string, List<VectorMath.Vector.CartVect>> GetShellGeomPolyRHR(Dictionary<string, List<VectorMath.Vector.MemorySafe_CartCoord>> PtsList) { //reg expressions string iDPatt = "(.+)[^/][0-9]"; string numPatt = "[0-9]+"; //initialize variables needed in this method VectorMath.Vector.CartVect unitRHR = new VectorMath.Vector.CartVect(); List<Vector.MemorySafe_CartCoord> vCoords = new List<Vector.MemorySafe_CartCoord>(); List<Vector.CartVect> vVect = new List<Vector.CartVect>(); string spaceId = "none"; string spacenum = ""; //dictionary that will be returned by this method Dictionary<string, List<VectorMath.Vector.CartVect>> plRHRDict = new Dictionary<string, List<VectorMath.Vector.CartVect>>(); //begin iterating through the Cartesian Points passed into the method (PtsList) for (int i = 0; i < PtsList.Count; i++) { //get the identification strings associated with each list of points in the dictionary passed to the method string spaceSurf = PtsList.Keys.ElementAt(i); foreach (Match match in Regex.Matches(spaceSurf, iDPatt)) { spaceId = match.ToString(); } string spaceSurf2 = PtsList.Keys.ElementAt(i); foreach (Match match in Regex.Matches(spaceSurf2, numPatt)) { spacenum = match.ToString(); } //take the list of coordinates and store them locally //this step does not need to be taken, but it does simplify the coding a little bit. foreach (Vector.MemorySafe_CartCoord coord in PtsList.Values.ElementAt(i)) { vCoords.Add(coord); } //just arbitrarily take the first 3 coordinates //this can lead to bad results, but is used until the next release of the software VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(vCoords[0], vCoords[1]); VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(vCoords[1], vCoords[2]); unitRHR = VectorMath.Vector.CrossProduct(v1, v2); unitRHR = Vector.UnitVector(unitRHR); vVect.Add(unitRHR); vCoords.Clear(); } plRHRDict.Add(spaceId, vVect); return plRHRDict; }
public static bool TestBuildingStoryRHR(List<XmlDocument> gbXMLDocs, List<XmlNamespaceManager> gbXMLnsm, ref CampusReport cr) { //stores the list of z heights for both files List<List<string>> fileLevelZz = new List<List<string>>(); //stores the RHR x product and the corresonding z height for a level Dictionary<string, VectorMath.Vector.CartVect> levelVct = new Dictionary<string, VectorMath.Vector.CartVect>(); VectorMath.Vector.CartVect vector = new VectorMath.Vector.CartVect(); int errorCount = 0; for (int i = 0; i < gbXMLDocs.Count; i++) { try { //refresh //stores the level's z heights List<string> LevelZs = new List<string>(); //stores a list of the RHR x product and corresponding z height for both files List<Dictionary<string, VectorMath.Vector.CartVect>> fileLevelVct = new List<Dictionary<string, VectorMath.Vector.CartVect>>(); XmlDocument gbXMLTestFile = gbXMLDocs[i]; XmlNamespaceManager gbXMLns = gbXMLnsm[i]; //maybe it would be good if the test result spits out the name of the story? TBD XmlNodeList PlanarGeometry = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry", gbXMLns); XmlNodeList PolyLoops = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry/gbXMLv5:PolyLoop", gbXMLns); int nodecount = PolyLoops.Count; //get the normals for each level in the Standard File //get the z-coordinate for each level (we assume that the levels are going to be parallel to Z LevelZs = GetLevelZs(PlanarGeometry, LevelZs); if (LevelZs.Count == 0) { logger.Info("PROGRAMMER's NOTE: No level polyloops found in this file. Level polyloop checks are being ignored."); return false; } foreach (string level in LevelZs) { //a simple attempt to filter out exceptions, which could be returned in some instances if (level.Length < 10) { vector = GetPolyLoopXProduct(PlanarGeometry, level); string levelValue = level; //if (i == 0) { levelValue += "-T"; } //else { levelValue += "-S"; } levelVct.Add(levelValue, vector); } } fileLevelZz.Add(LevelZs); fileLevelVct.Add(levelVct); //reporting if (i % 2 != 0) { if(fileLevelVct[0].Count > 0) { Dictionary<string, VectorMath.Vector.CartVect> standDict = fileLevelVct[1]; Dictionary<string, VectorMath.Vector.CartVect> testDict = fileLevelVct[0]; foreach (KeyValuePair<string, VectorMath.Vector.CartVect> pair in standDict) { if (testDict.ContainsKey(pair.Key)) { logger.Info("PROGRAMMERS NOTE: While searching for matching building levels, there has been a Successful match. Building Story Level " + pair.Key + " in the Standard file found a match in the Test File."); //perform cross product again of the two vectors in question. The result should be a zero since they should be parallel VectorMath.Vector.CartVect rhrTestVector = VectorMath.Vector.CrossProduct(testDict[pair.Key], standDict[pair.Key]); if (Math.Abs(rhrTestVector.X) <= 0.1 && Math.Abs(rhrTestVector.Y) == 0.1 && Math.Abs(rhrTestVector.Z) == 0.1) { logger.Info("TEST FILE SUCCESS: For this level match, there is Normal Vector Test Success. The right hand rule test identified a parallel normal vector for Level " + pair.Key + " in both the Standard and Test gbXML Files."); } else { logger.Info("TEST FILE FAILURE: For this level match, there not Normal Vector Test Success. The right hand rule test shows the vectors are not parallel for Level " + pair.Key + " in both the Standard and Test gbXML Files."); } } else { logger.Fatal("The right hand rule test for Level " + pair.Key + " in the Standard File could not be completed. A match for this level could not be found in the test file."); return false; } } } } else { continue; } //need to comapre and have if then statement depending on the outcome of the accuracy tests if (errorCount == 0) { logger.Info("TEST FILE SUCCESS: Building Stories RHR in the Test File match the RHR in the Standard File for all Levels."); } else { logger.Info("TEST FILE FAILURE: Not all levels in the Standard File found equivalent levels and normal vectors in the Test File."); return false; } } catch (Exception e) { logger.Debug(e.ToString()); logger.Fatal(" Failed to complete RHR Test for the Building Storey Nodes. Exception noted."); return false; } } return true; }
//this is a simple way to get the polyLoop X product. //this is a support function used by the Function TestBuildingStory RHR above //This X Product routine is the first attempt to produce a X product from coordinates Since the coordinates used to define //a level plane never create an irregular polygon, this scheme worked. //it will only assuredly work properly for a triangle, square, or rectangle. Shapes other than these should use subsequent XProduct //functions as created below. //Created by CHarriman, Senior Product Manager Carmel Software //Nov 2012 public static VectorMath.Vector.CartVect GetPolyLoopXProduct(XmlNodeList PlanarGeometry, string level) { int cartPtCount = 0; VectorMath.Vector.CartVect xProd = new VectorMath.Vector.CartVect(); //gathers all the cartesian points in a given polyloop int nodecount = PlanarGeometry.Count; VectorMath.Vector.CartCoord[] vCoords = new VectorMath.Vector.CartCoord[3]; foreach (XmlNode PolyLoops in PlanarGeometry) { foreach (XmlNode cartesianPoints in PolyLoops) { //test the polyloop RHR convention //count the total number of cartesian coordinates int coordcount = cartesianPoints.ChildNodes.Count; //I may want to test the number of coordinates to make sure it matches, or if it has a minimum number of coords if (coordcount < minPlanePoints) { //result += "Insufficient number of cartesian points to define a plane"; return xProd; } else { cartPtCount = 0; //gets a set of XYZ coordinates, one at a time foreach (XmlNode coordinates in cartesianPoints.ChildNodes) { if (cartPtCount < 3) { VectorMath.Vector.CartCoord vC = new VectorMath.Vector.CartCoord(); vCoords[cartPtCount] = vC; } else { break; } int crdCount = 1; //gets each coordinate one at a time //filtering through the inner children of the PolyLoop foreach (XmlNode coordinate in coordinates.ChildNodes) { double coord = Convert.ToDouble(coordinate.InnerText); switch (crdCount) { case 1: vCoords[cartPtCount].X = coord; break; case 2: vCoords[cartPtCount].Y = coord; break; case 3: vCoords[cartPtCount].Z = coord; break; default: break; } if (vCoords[cartPtCount].Z.ToString() == level) { break; }; crdCount++; } cartPtCount++; } } } if (vCoords[(cartPtCount - 1)].Z.ToString() == level) { break; } } //Get the Cross Product VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(vCoords[0], vCoords[1]); VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(vCoords[1], vCoords[2]); xProd = VectorMath.Vector.CrossProduct(v1, v2); xProd = Vector.UnitVector(xProd); return xProd; }
public static DOEgbXMLReportingObj TestBuildingStoryRHR(List<XmlDocument> gbXMLDocs, List<XmlNamespaceManager> gbXMLnsm, DOEgbXMLReportingObj report, string Units) { //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML //added Feb 13 2013 report.testSummary = "This test analyzes each of the story PolyLoop coordinates in the standard and test files. These PolyLoop "; report.testSummary += "coordinates define the z-height and orientation of each story plane. This test analyzes the normal vector "; report.testSummary += "created by the PolyLoop coordinates. The PolyLoop coordinates must be sequenced in a counterclockwise manner "; report.testSummary += " such that when the right hand rule is applied to this sequence of coordinates, a resultant normal vector "; report.testSummary += " will point in the +z direction."; report.testSummary += " If the PolyLoop coordinates do not form vectors that point in the +Z direction"; report.testSummary += " (when the right hand rule is applied), then this test will fail. It is assumed that the vectors that define"; report.testSummary += " the story plane will be parallel to the X-Y axis.The tolerance is always zero for this test, "; report.testSummary += "meaning the resulting unit vector will point in the positive Z direction with no margin for error."; report.unit = Units; //stores the level's z heights List<string> LevelZs = new List<string>(); //stores the list of z heights for both files List<List<string>> fileLevelZz = new List<List<string>>(); //stores the RHR x product and the corresonding z height for a level Dictionary<string, VectorMath.Vector.CartVect> levelVct = new Dictionary<string, VectorMath.Vector.CartVect>(); //stores a list of the RHR x product and corresponding z height for both files List<Dictionary<string, VectorMath.Vector.CartVect>> fileLevelVct = new List<Dictionary<string, VectorMath.Vector.CartVect>>(); VectorMath.Vector.CartVect vector = new VectorMath.Vector.CartVect(); int errorCount = 0; for (int i = 0; i < gbXMLDocs.Count; i++) { try { //refresh LevelZs.Clear(); levelVct.Clear(); XmlDocument gbXMLTestFile = gbXMLDocs[i]; XmlNamespaceManager gbXMLns = gbXMLnsm[i]; //maybe it would be good if the test result spits out the name of the story? TBD XmlNodeList PlanarGeometry = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry", gbXMLns); XmlNodeList PolyLoops = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry/gbXMLv5:PolyLoop", gbXMLns); int nodecount = PolyLoops.Count; //get the normals for each level in the Standard File //get the z-coordinate for each level (we assume that the levels are going to be parallel to Z LevelZs = GetLevelZs(PlanarGeometry, LevelZs); foreach (string level in LevelZs) { //a simple attempt to filter out exceptions, which could be returned in some instances if (level.Length < 10) { vector = GetPolyLoopXProduct(PlanarGeometry, level); string levelValue = level; //if (i == 0) { levelValue += "-T"; } //else { levelValue += "-S"; } levelVct.Add(levelValue, vector); } } fileLevelZz.Add(LevelZs); fileLevelVct.Add(levelVct); //reporting if (i % 2 != 0) { Dictionary<string, VectorMath.Vector.CartVect> standDict = fileLevelVct[1]; Dictionary<string, VectorMath.Vector.CartVect> testDict = fileLevelVct[0]; foreach (KeyValuePair<string, VectorMath.Vector.CartVect> pair in standDict) { if (testDict.ContainsKey(pair.Key)) { report.MessageList.Add("While searching for matching building levels, there has been a Successful match. Building Story Level " + pair.Key + " in the Standard file found a match in the Test File."); report.passOrFail = true; //perform cross product again of the two vectors in question. The result should be a zero since they should be parallel VectorMath.Vector.CartVect rhrTestVector = VectorMath.Vector.CrossProduct(testDict[pair.Key], standDict[pair.Key]); if (rhrTestVector.X == 0 && rhrTestVector.Y == 0 && rhrTestVector.Z == 0) { report.MessageList.Add("For this level match, there is Normal Vector Test Success. The right hand rule test identified a parallel normal vector for Level " + pair.Key + " in both the Standard and Test gbXML Files."); report.passOrFail = true; } else { VectorMath.Vector.CartVect rhrTestVectorU = VectorMath.Vector.UnitVector(rhrTestVector); //create a test to determine the angular difference between the two vectors is within tolerance //|A||B|cos theta = A x B //if the angle is within the allowable tolerance, then pass the test with a note that the vectors //were not parallel } } else { report.MessageList.Add("The right hand rule test for Level " + pair.Key + " in the Standard File could not be completed. A match for this level could not be found in the test file."); report.passOrFail = false; errorCount++; } } } else { continue; } //need to comapre and have if then statement depending on the outcome of the accuracy tests if (errorCount == 0) { report.longMsg = "Test Success: Building Stories RHR in the Test File match the RHR in the Standard File for all Levels."; } else { report.longMsg = "Not all levels in the Standard File found equivalent levels and normal vectors in the Test File."; } return report; } catch (Exception e) { report.MessageList.Add(e.ToString()); report.longMsg = " Failed to complete RHR Test for the Building Storey Nodes. Exception noted."; report.passOrFail = false; return report; } } report.longMsg = "Fatal " + report.testType + " Test Failure"; return report; }