//March15 2013 //by CHarriman Senior Product Manager Carmel Software Corporation //this is a function only used internally. It is used to verify if a surface object only has four coordinates, and if those coordinates form //a square or rectangle. private static bool IsSurfaceRegular(SurfaceDefinitions Surface) { //tests to see if all candidate surfaces and the standard surface are regular (rectangular polygons) bool isRegularPolygon = true; //see if the standard surface has four coordinates defining its polyloop (one marker of a rectangle) int standSurfaceCoordinateCount = Surface.PlCoords.Count; if (standSurfaceCoordinateCount == 4) { //check the two potentially parallel sides, to ensure they are indeed parallel Vector.CartVect v1 = Vector.CreateVector(Surface.PlCoords[0], Surface.PlCoords[1]); Vector.CartVect v2 = Vector.CreateVector(Surface.PlCoords[2], Surface.PlCoords[3]); Vector.CartVect v1xv2 = Vector.CrossProduct(v1, v2); v1xv2 = Vector.UnitVector(v1xv2); double magnitudev1xv2 = Vector.VectorMagnitude(v1xv2); Vector.CartVect v3 = Vector.CreateVector(Surface.PlCoords[1], Surface.PlCoords[2]); Vector.CartVect v4 = Vector.CreateVector(Surface.PlCoords[3], Surface.PlCoords[0]); Vector.CartVect v3xv4 = Vector.CrossProduct(v3, v4); v3xv4 = Vector.UnitVector(v3xv4); double magnitudev3xv4 = Vector.VectorMagnitude(v3xv4); //the unit vector will not be a number NaN if the Cross product detects a zero vector (indicating parallel vectors) if (double.IsNaN(magnitudev1xv2) && double.IsNaN(magnitudev3xv4)) { isRegularPolygon = true; } else { isRegularPolygon = false; } } else { //might as well stop here because isRegularPolygon = false; return isRegularPolygon; } return isRegularPolygon; }
private static double GetSurfaceArea(SurfaceDefinitions surface, double areaConversion) { logger.Debug("STARTING SUBROUTINE: GetSurfaceArea."); logger.Debug("PROGAMMER'S NOTE: PolyLoop coordinates will be used to calculate the area."); double area = -1; //there are two basic cases, one where we get the area using greens theorem when the surface is parallel //to one of the axes of the project global reference frame //and the second where the surface is not parallel to one of the axes of the global reference frame //Surface normal Parallel to global reference frame X Axis if (Math.Abs(surface.PlRHRVector.X) == 1 && surface.PlRHRVector.Y == 0 && surface.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in surface.PlCoords) { //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same //create new Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); coordList.Add(c2); } area = GetAreaFrom2DPolyLoop(coordList); if (area == -999) { logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined."); logger.Debug("The coordinates should be 2D and could not be translated to 2D"); logger.Fatal("ATTENTION: Attempting to calculate surface area. Test may be inaccurate and requires gbXML.org support"); } } //Surface normal Parallel to global reference frame y Axis else if (surface.PlRHRVector.X == 0 && Math.Abs(surface.PlRHRVector.Y) == 1 && surface.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in surface.PlCoords) { //only take the X and Z coordinates and throw out the Y because we can assume that they are all the same Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); coordList.Add(c2); } area = GetAreaFrom2DPolyLoop(coordList); if (area == -999) { logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined."); logger.Debug("The coordinates should be 2D and could not be translated to 2D"); logger.Fatal("ATTENTION: Attempting to calculate surface area. Test may be inaccurate and requires gbXML.org support"); } } else if (surface.PlRHRVector.X == 0 && surface.PlRHRVector.Y == 0 && Math.Abs(surface.PlRHRVector.Z) == 1) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in surface.PlCoords) { //only take the X and Y coordinates and throw out the Z because we can assume that they are all the same Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); coordList.Add(c2); } area = GetAreaFrom2DPolyLoop(coordList); if (area == -999) { logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined."); logger.Debug("The coordinates should be 2D and could not be translated to 2D"); logger.Fatal("ATTENTION: Attempting to calculate surface area. Test may be inaccurate and requires gbXML.org support"); } } //the surface is not aligned with one of the reference frame axes, which requires a bit more work to determine the right answer. else { logger.Debug("The standard surface is not aligned along an axis, and will be rotated into a new coordinate frame"); //New Z Axis for this plane is the normal vector, does not need to be created //Get New Y Axis which is the surface Normal Vector cross the original global reference X unit vector (all unit vectors please Vector.CartVect globalReferenceX = new Vector.CartVect(); globalReferenceX.X = 1; globalReferenceX.Y = 0; globalReferenceX.Z = 0; Vector.MemorySafe_CartVect localY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(surface.PlRHRVector, globalReferenceX)); //new X axis is the localY cross the surface normal vector Vector.MemorySafe_CartVect localX = Vector.UnitVector(Vector.CrossProduct(localY, surface.PlRHRVector)); //convert the polyloop coordinates to a local 2-D reference frame //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane List<Vector.MemorySafe_CartCoord> translatedCoordinates = new List<Vector.MemorySafe_CartCoord>(); Vector.MemorySafe_CartCoord newOrigin = new Vector.MemorySafe_CartCoord(0, 0, 0); translatedCoordinates.Add(newOrigin); for (int j = 1; j < surface.PlCoords.Count; j++) { //randomly assigns the first polyLoop coordinate as the origin Vector.MemorySafe_CartCoord origin = surface.PlCoords[0]; //captures the components of a vector drawn from the new origin to the Vector.CartVect distance = new Vector.CartVect(); distance.X = surface.PlCoords[j].X - origin.X; distance.Y = surface.PlCoords[j].Y - origin.Y; distance.Z = surface.PlCoords[j].Z - origin.Z; //x coordinate is distance vector dot the new local X axis double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; //y coordinate is distance vector dot the new local Y axis double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; double tZ = 0; Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX, tY, tZ); translatedCoordinates.Add(translatedPt); } area = GetAreaFrom2DPolyLoop(translatedCoordinates); if (area == -999) { logger.Debug("The coordinates of the standard file polyloop has been incorrectly defined."); logger.Debug("The coordinates should be 2D and could not be translated to 2D"); logger.Fatal("ATTENTION: Attempting to calculate surface area. Test may be inaccurate and requires gbXML.org support"); } } logger.Debug("ENDING SUBROUTINE: GetSurfaceArea"); logger.Debug("Area:" + Math.Abs(area).ToString()); if (area != -1 || area != -999) { return Math.Abs(area * areaConversion); } else return area; }
private static bool IsHighTiltSurface(SurfaceDefinitions surface) { bool isHighTilt = false; if (surface.SurfaceType == "InteriorFloor" || surface.SurfaceType == "RaisedFloor" || surface.SurfaceType == "SlabOnGrade" || surface.SurfaceType == "UndergroundSlab" || surface.SurfaceType == "ExposedFloor") isHighTilt = true; return isHighTilt; }
private static DOEgbXMLReportingObj GetPolyLoopCoordMatch(Vector.MemorySafe_CartCoord standardPolyLoopCoord, SurfaceDefinitions testSurface, DOEgbXMLReportingObj report, string standardSurfaceId, double testlengthConversion, double standardlengthConversion) { List<Vector.MemorySafe_CartCoord> possibleMatch = new List<Vector.MemorySafe_CartCoord>(); List<Vector.MemorySafe_CartCoord> exactMatch = new List<Vector.MemorySafe_CartCoord>(); report.MessageList.Add("Testing Polyloop coordinates for Standard surface " + standardSurfaceId); report.MessageList.Add(" X: " + standardPolyLoopCoord.X.ToString() + ", Y: " + standardPolyLoopCoord.Y.ToString() + ", Z: " + standardPolyLoopCoord.Z.ToString()); foreach (Vector.MemorySafe_CartCoord testPolyLoopCoord in testSurface.PlCoords) { //find an appropriate match double diffX = Math.Abs((testPolyLoopCoord.X * testlengthConversion) - (standardPolyLoopCoord.X * standardlengthConversion)); if (diffX < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) { //found a perfect X Match if (diffX == 0) { //test Y double diffY = Math.Abs((testPolyLoopCoord.Y * testlengthConversion) - (standardPolyLoopCoord.Y*standardlengthConversion)); if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) { //perfect Y Match if (diffY == 0) { double diffZ = Math.Abs((testPolyLoopCoord.Z * testlengthConversion) - (standardPolyLoopCoord.Z*standardlengthConversion)); if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) { //perfect Z match if (diffZ == 0) { report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " exactly"); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); exactMatch.Add(testPolyLoopCoord); } else { //not a perfect Z match but within bounds report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " X and Y coordinates exactly. Z coordinate within allowable tolerance."); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); possibleMatch.Add(testPolyLoopCoord); } } else { //z coordinate not within tolerance continue; } } //Y Match is within the allowable tolerance else { double diffZ = Math.Abs((testPolyLoopCoord.Z * testlengthConversion) - (standardPolyLoopCoord.Z*standardlengthConversion)); if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) { //perfect Z match if (diffZ == 0) { report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " in the X and Z coordinates, exactly. Y coordinate is within tolerance."); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); possibleMatch.Add(testPolyLoopCoord); } else { report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " X exactly. Y and Z coordinates are within tolerance."); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); possibleMatch.Add(testPolyLoopCoord); } } else { //z coordinate is not within tolerance continue; } } } else { //a y match could not be found within tolerance continue; } } else { //not a perfect X match, but within tolerance //test Y double diffY = Math.Abs((testPolyLoopCoord.Y * testlengthConversion) - (standardPolyLoopCoord.Y*standardlengthConversion)); if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) { //perfect Y Match if (diffY == 0) { double diffZ = Math.Abs((testPolyLoopCoord.Z * testlengthConversion) - (standardPolyLoopCoord.Z*standardlengthConversion)); if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) { //perfect Z match if (diffZ == 0) { report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Y and Z coordinate exactly. X is within tolerance."); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); possibleMatch.Add(testPolyLoopCoord); } else { report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Y coordinate exactly. X and Z is within tolerance."); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); possibleMatch.Add(testPolyLoopCoord); } } else { //z is not matched so continue continue; } } // the Y match is not perfect but within tolerance else { double diffZ = Math.Abs((testPolyLoopCoord.Z * testlengthConversion) - (standardPolyLoopCoord.Z*standardlengthConversion)); if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) { //perfect Z match if (diffZ == 0) { report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Z coordinate exactly. The X and Y coordinates are within tolerance."); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); possibleMatch.Add(testPolyLoopCoord); } else { report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + ". The X, Y, and Z coordinates are within tolerance."); report.MessageList.Add("Test Surface " + testSurface.SurfaceId); report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); possibleMatch.Add(testPolyLoopCoord); } } // no match found for the Z else { continue; } } } //no match could be found for the Y else { continue; } } } else { //not a match found for the X and continue continue; } } if (exactMatch.Count > 1) { report.MessageList.Add("Error, overlapping polyLoop coordinates found in the Test Surface PolyLoop."); report.passOrFail = false; return report; } else if (exactMatch.Count == 1) { report.MessageList.Add("One coordinate candidate found. Exact match"); report.passOrFail = true; return report; } if (possibleMatch.Count > 1) { report.MessageList.Add("No exact solution for a match of the polyLoop coordinate. More than one coordinate candidate found."); report.passOrFail = false; return report; } else if (possibleMatch.Count == 1) { report.MessageList.Add("One coordinate candidate found."); report.passOrFail = true; return report; } else { report.MessageList.Add("No coordinate candidate found."); report.passOrFail = false; return report; } }
//designed to be passed a pre-vetted surface definition from a Standard File private static bool IsLowTiltSurface(SurfaceDefinitions surface) { bool isLowTilt = false; if (surface.SurfaceType == "Ceiling" || surface.SurfaceType == "Roof" || surface.SurfaceType == "UndergroundCeiling") { isLowTilt = true; } return isLowTilt; }
private DOEgbXMLReportingObj GetPossibleSurfaceMatches(SurfaceDefinitions surface, List<SurfaceDefinitions> TestSurfaces, DOEgbXMLReportingObj report, Conversions.lengthUnitEnum standardLengthUnits, Conversions.lengthUnitEnum testLengthUnits, double testlengthConversion, double standardlengthConversion, Conversions.areaUnitEnum standardAreaUnits, Conversions.areaUnitEnum testAreaUnits, double testareaConversion, double standardareaConversion) { //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 Mar 14 2013 report.testSummary = "This test tries to match each Surface element in the standard file with an equivalent in your test file"; report.testSummary += " To be as flexible about what constitutes a \"Good Match\", this test finds a pool of possible candidate "; report.testSummary += "surfaces in your test file and then begins to eliminate them as they fail different tests."; report.testSummary += " At the end, there should be only one surface candidate remaining that constitutes a good match. "; report.testSummary += "You can see the result of this filtering process by reviewing the mini-report that is provided for you below."; report.testSummary += "</br>"; //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 March 14 2013 report.testSummary += " The search routine first tries to find all surfaces that have the same SurfaceType and adjacentSpaceIds."; report.testSummary += " Everytime there is a match found in the test file, meeting these criteria, a message will appear in the "; report.testSummary += "mini-report, indicating that a match has been found."; report.testSummary += " There may be more than one match in your test file."; report.testSummary += " If there are no matches found for SurfaceType and AdjacencyId, this message will be printed (and the test will end as failed):"; report.testSummary += " In the test file, no matches could be found in the standard file that have the same AdjacentSpaceId(s) and SurfaceType."; report.testSummary += "</br>"; report.testSummary += " If this set of tests is successful, the routine next tries to remove those surfaces that do not meet"; report.testSummary += " the tilt and azimuth tolerances. Let's pretend for example that the tilt and azimuth for the standard surface"; report.testSummary += " in question are both 90 degrees. If the tilt and azimuth test tolerance are 1 degree, then the search"; report.testSummary += " routine will only keep those walls that have 89<=tilt<=91 && <=89azimuth<=91 && match the SurfaceType and"; report.testSummary += " adjacency relationships."; report.testSummary += " The mini-report will let you know which surfaces pass the tilt and azimuth test and which do not."; report.testSummary += "</br>"; report.testSummary += " Next the search routine takes any of the remaining surface candidates that have passed all the tests so far, "; report.testSummary += "and tries to determine if the Surface Areas defined by the polyLoops match to within a pre-defined % tolerance."; report.testSummary += "</br>"; report.testSummary += " the final tests are to physically test the coordinates of the polyloop and insertion point to make sure"; report.testSummary += " that a match for the standard surface can be found."; report.testSummary += " You should see additional messages telling you which surface in your test file matches, or doesn't match"; report.testSummary += " the standard surface being searched against. If there is no match, the mini-report tells you."; report.testSummary += " By making the tests this way, it is hoped that you can see exactly why your test file is failing against"; report.testSummary += " the standard file's surface definitions."; try { report.MessageList.Add("Standard Surface Id: " + surface.SurfaceId); report.MessageList.Add("</br>"); //initialize the return list //alternate between these two to filter out bad matches List<SurfaceDefinitions> possiblesList1 = new List<SurfaceDefinitions>(); List<SurfaceDefinitions> possiblesList2 = new List<SurfaceDefinitions>(); bool adjSpaceIdMatch = false; bool isLowTiltObject = false; bool isHighTiltObject = false; bool interiorWallFlipped = false; bool issurfaceRegular = false; bool istestSurfaceRegular = false; //try to find a surface in the test file that has the same: //adjacent space Id signature //surfaceType //free list is 1 //list 2 is not used for(int ts = 0; ts<TestSurfaces.Count;ts++) { SurfaceDefinitions testSurface = TestSurfaces[ts]; //has to have the same number of Adjacent Space Ids if (testSurface.AdjSpaceId.Count == surface.AdjSpaceId.Count) { //an exception for a shading device if (surface.AdjSpaceId.Count == 0) { adjSpaceIdMatch = true; } //has to have the same order of adjacent space id strings to qualify. This method assumes the strings are identical if(surface.AdjSpaceId.Count == 1) { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; } } if(surface.AdjSpaceId.Count == 2) { if(surface.SurfaceType == "Ceiling" && testSurface.SurfaceType == "InteriorFloor") { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; } } else if (surface.SurfaceType == "InteriorFloor" && testSurface.SurfaceType == "Ceiling") { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; } } else if (surface.SurfaceType == "InteriorWall" && testSurface.SurfaceType == "InteriorWall") { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[1]) { adjSpaceIdMatch = true; } if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; interiorWallFlipped = true; } } else { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[1]) { adjSpaceIdMatch = true; } } } //if adjacent space Ids match and the surface types match, note this if (adjSpaceIdMatch) { if(!IsHighTiltSurface(surface) && !IsLowTiltSurface(surface)) { if(surface.SurfaceType == testSurface.SurfaceType) { report.MessageList.Add("AdjancentSpaceId(s) and surfaceType Match."); report.MessageList.Add("Surface id: " + testSurface.SurfaceId + " is a candidate."); report.MessageList.Add("</br>"); possiblesList1.Add(testSurface); } } else { if(IsLowTiltSurface(surface)) isLowTiltObject = true; if (IsHighTiltSurface(surface)) isHighTiltObject = true; if(surface.SurfaceType == testSurface.SurfaceType) { report.MessageList.Add("AdjancentSpaceId(s) and surfaceType Match."); report.MessageList.Add("Surface id: " + testSurface.SurfaceId + " is a candidate."); report.MessageList.Add("</br>"); possiblesList1.Add(testSurface); } } } } } if (possiblesList1.Count == 1) { report.MessageList.Add("Based on a comparison of the surface Type and Adjacent SpaceIds, there is " + possiblesList1.Count.ToString() + " surface in the test file that is a possible match for " + surface.SurfaceId + " of the Standard File."); report.MessageList.Add("<br/>"); } else if (possiblesList1.Count > 1) { report.MessageList.Add("Based on a comparison of the surface Type and Adjacent SpaceIds, there are " + possiblesList1.Count.ToString() + " surface in the test file that are possible matches for " + surface.SurfaceId + " of the Standard File."); report.MessageList.Add("<br/>"); } else { report.longMsg = "In the test file, no matches could be found in the standard file that have the same AdjacentSpaceId(s) and SurfaceType."; report.passOrFail = false; return report; } //begin to filter back this list //tilt //azimuth //list 1 is analyzed //list 2 is free if (possiblesList1.Count > 0) { foreach (SurfaceDefinitions testSurface in possiblesList1) { double tiltDifference = 0; double azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth); if(isLowTiltObject) { if(IsLowTiltSurface(testSurface)) //they are the same, both have small tils { tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt); } else //they are 180 degrees different, and the test surface is a high tilt while the standard is low tilt { if (testSurface.SurfaceType == "InteriorFloor") { tiltDifference = Math.Abs(Math.Abs(testSurface.Tilt - 180) - surface.Tilt); } else { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); report.MessageList.Add("</br>"); continue; } } //no azimuth tests if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) //azimuth no longer matters for these surfaces { if(surface.Tilt != 0) { if(azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance) { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); report.MessageList.Add("</br>"); continue; } } else { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); report.MessageList.Add("</br>"); continue; } } //if the tilt and azimuth is within tolerance else { //add to the free List if (surface.Tilt == 0) { possiblesList2.Add(testSurface); if (tiltDifference == 0) { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " matches the standard surface tilt and azimuth exactly."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } else { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " is within the azimuth and tilt tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance + " and " + DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance + ", respectively. It matches the standard file surface within the allowable tolerance."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } } else { //check the azimuth if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance || azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance) { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); report.MessageList.Add("</br>"); continue; } //if the tilt and azimuth is within tolerance else { //add to the free List possiblesList2.Add(testSurface); if (tiltDifference == 0 && azimuthDifference == 0) { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " matches the standard surface tilt and azimuth exactly."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } else { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " is within the azimuth and tilt tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance + " and " + DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance + ", respectively. It matches the standard file surface within the allowable tolerance."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } } } } } else if (isHighTiltObject) { if(IsHighTiltSurface(testSurface)) //both high tilt interior surfaces { tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt); } else //standard is high tilt, test is low tilt { if(testSurface.SurfaceType == "Ceiling") { tiltDifference = Math.Abs(Math.Abs(testSurface.Tilt - 180) - surface.Tilt); } else { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); report.MessageList.Add("</br>"); continue; } } //no azimuth tests if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) //azimuth no longer matters for these surfaces { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); report.MessageList.Add("</br>"); continue; } //if the tilt and azimuth is within tolerance else { //add to the free List possiblesList2.Add(testSurface); if (tiltDifference == 0) { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " matches the standard surface tilt and azimuth exactly."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } else { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " is within the azimuth and tilt tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance + " and " + DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance + ", respectively. It matches the standard file surface within the allowable tolerance."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } } } else { azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth); if (interiorWallFlipped) //both high tilt interior surfaces { azimuthDifference = Math.Abs(Math.Abs(testSurface.Azimuth - surface.Azimuth) - 180); //180 is needed because they should be separated by 180 } tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt); //if the tilt and azimuth is outside of tolerance if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance || azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance) { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); report.MessageList.Add("</br>"); continue; } //if the tilt and azimuth is within tolerance else { //add to the free List possiblesList2.Add(testSurface); if (tiltDifference == 0 && azimuthDifference == 0) { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " matches the standard surface tilt and azimuth exactly."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } else { report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " is within the azimuth and tilt tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance + " and " + DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance + ", respectively. It matches the standard file surface within the allowable tolerance."); report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); report.MessageList.Add("</br>"); } } } } } // report to the user that no matches could be found else { report.longMsg = "In the test file, surfaces could be found that match the standard file's AdjacentSpaceId and SurfaceType, but of these matches, none could be identified that also have a tilt or azimuth that exactly matches the standard file's, or is within the allowable tolerance."; report.passOrFail = false; return report; } //clear the first list possiblesList1.Clear(); //start to loop through the new refined list //generally want to look at the polyLoop coordinates //list 2 is analyzed //list 1 is free report.MessageList.Add("Starting Surface Area Match tests......"); report.MessageList.Add("</br>"); if (possiblesList2.Count > 0) { //simple method from this point forward is just to simply start doing a polyloop check //check the standard surface PolyLoop and the test Surface(s) polyloop(s) //check the absolute coordinates of the testSurface(s) polyloop(s) if (possiblesList2.Count == 1) { report.MessageList.Add("Only one Surface Candidate remaining from the original test pool."); report.MessageList.Add("<br/>"); //meaning there is only one candidate still available //go on to test the polyLoop coordinates and the insertion point possiblesList1.Add(possiblesList2[0]); } //more than one candidate still exists even after the adjacency test, surfaceType test, and tilt and azimuth tests, so filter through else { //The user should be able to determine, based on output which surfaces are left for consideration //Option 1: (easiest) find the one best candidate //do so based on an area match, matching the area of the test surface with the area of the test surface //(without regard for absolute polyloop coordinates) //We find the area using area formulas for both regular polygons and irregular polygons //first we check for the type of surface that it is (regular polygon or not), and we then take it from there //in the case of a rectangular polygon, we only count rectangles or squares as regular, everything else is //assumed to be irregular, though this does not fit the classic definition of a classic polygon. //The language is just semantics //first try to find if the standard file has a regular rectangular or square profile report.MessageList.Add("Checking if the surface is a square or rectangle."); issurfaceRegular = IsSurfaceRegular(surface); foreach (SurfaceDefinitions regSurface in possiblesList2) { //ensures likewise that all the test surface candidates are regular, //TODO: if they are not, then the entire set is assumed to be irregular (this could be improved) istestSurfaceRegular = IsSurfaceRegular(regSurface); if (istestSurfaceRegular == false) break; } if (issurfaceRegular && istestSurfaceRegular) { //we take a shortcut and use the width and height as a way to simplify the area checking scheme //we assume that the width and height are properly entered in this simplified case report.MessageList.Add("Rectangle or Square = TRUE"); report.MessageList.Add("Comparisons of the Width and Height values will be used as a proxy for surface Area."); foreach (SurfaceDefinitions testsurface in possiblesList2) { //it first analyzes the test file to see if slivers are present. If they are, it will fail the test //if slivers are not allowed for the test. This is the first time we check for slivers //TODO: consider removing or giving a feature to allow this to be overridded. if (testsurface.Width <= DOEgbXMLBasics.Tolerances.SliverDimensionTolerance || testsurface.Height <= DOEgbXMLBasics.Tolerances.SliverDimensionTolerance) { if (!DOEgbXMLBasics.SliversAllowed) { report.MessageList.Add("This test does not allow slivers less than " + DOEgbXMLBasics.Tolerances.SliverDimensionTolerance + " ft. A sliver has been detected. Test surface id: " + testsurface.SurfaceId + " is a sliver."); report.passOrFail = false; return report; } } //otherwise, if the sliver test passes double widthDiff = Math.Abs((testlengthConversion * testsurface.Width) - surface.Width * standardlengthConversion); if(widthDiff > DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance) { widthDiff = Math.Abs((testlengthConversion * testsurface.Height) - surface.Width * standardlengthConversion); if(widthDiff < DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance) { //we will swap them double heightDiff = Math.Abs((testlengthConversion * testsurface.Width) - surface.Height * standardlengthConversion); if (heightDiff > DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance) { report.MessageList.Add("Test file's Surface id: " + testsurface.SurfaceId + " width and height do not both match the standard file surface id: " + surface.SurfaceId + ". This surface has been removed as a candidate."); continue; } else { //this surface is a candidate possiblesList1.Add(testsurface); if (widthDiff == 0 && heightDiff == 0) { report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " have has the width and height swapped, but the width and height exactly match the standard file."); //go ahead and now check the polyLoop coordinates, and then the insertion point } else { report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " have been swapped, but are within the width and height tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance + standardLengthUnits + " and " + DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance + standardLengthUnits + ", respectively."); //go ahead and now check the polyloop coordinates, and then the insertion point } } } } else { //we won't swap them double heightDiff = Math.Abs((testlengthConversion * testsurface.Height) - surface.Height * standardlengthConversion); if (widthDiff > DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance || heightDiff > DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance) { report.MessageList.Add("Test file's Surface id: " + testsurface.SurfaceId + " width and height do not both match the standard file surface id: " + surface.SurfaceId + ". This surface has been removed as a candidate."); continue; } else { //this surface is a candidate possiblesList1.Add(testsurface); if (widthDiff == 0 && heightDiff == 0) { report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " matches the width and height exactly of the standard file."); //go ahead and now check the polyLoop coordinates, and then the insertion point } else { report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " is within the width and height tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance + standardLengthUnits + " and " + DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance + standardLengthUnits + ", respectively."); //go ahead and now check the polyloop coordinates, and then the insertion point } } } } } //It is not "regular". Find the one surface with the area that most closely matches, and then check its polyloops //1. get the polyloop area of the standard file's surface polyloops //2. get the area of the test file surface candidates using the polyloop coordinates else { report.MessageList.Add("The surface is not a square or rectangle."); report.MessageList.Add("PolyLoop coordinates will be used to calculate the area."); //there are two basic cases, one where we get the area using greens theorem when the surface is parallel //to one of the axes of the project global reference frame //and the second where the surface is not parallel to one of the axes of the global reference frame //Surface normal Parallel to global reference frame X Axis if (Math.Abs(surface.PlRHRVector.X) == 1 && surface.PlRHRVector.Y == 0 && surface.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in surface.PlCoords) { //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same //create new Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); coordList.Add(c2); } double area = GetAreaFrom2DPolyLoop(coordList); if (area == -999) { report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); } double testSurfacesArea = 0; foreach (SurfaceDefinitions testSurface in possiblesList2) { if (Math.Abs(testSurface.PlRHRVector.X) == 1 && testSurface.PlRHRVector.Y == 0 && testSurface.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in testSurface.PlCoords) { Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); testCoordList.Add(c2); } testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList); if (testSurfacesArea == -999) { report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); } //convert from the test units to the standard units double difference = Math.Abs((area*standardareaConversion) - (testSurfacesArea * testareaConversion)); if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) { possiblesList1.Add(testSurface); if (difference == 0) { //then it perfectly matches, go on to check the poly loop coordinates //then check the insertion point report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly."); } else { report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance."); } } else { report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates"); //don't return here, it will be returned below } } else { //do nothing, it will be handled by the more general case and then translated to a 2-D surface } } } //Surface normal Parallel to global reference frame y Axis else if (surface.PlRHRVector.X == 0 && Math.Abs(surface.PlRHRVector.Y) == 1 && surface.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in surface.PlCoords) { //only take the X and Z coordinates and throw out the Y because we can assume that they are all the same Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); coordList.Add(c2); } double area = GetAreaFrom2DPolyLoop(coordList); if (area == -999) { report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); } double testSurfacesArea = 0; foreach (SurfaceDefinitions testSurface in possiblesList2) { if (Math.Abs(testSurface.PlRHRVector.X) == 0 && Math.Abs(testSurface.PlRHRVector.Y) == 1 && testSurface.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in testSurface.PlCoords) { Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); testCoordList.Add(c2); } testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList); if (testSurfacesArea == -999) { report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); } //convert the testSurfaceArea double difference = Math.Abs((area*standardareaConversion) - (testSurfacesArea * testareaConversion)); if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) { possiblesList1.Add(testSurface); if (difference == 0) { //then it perfectly matches, go on to check the poly loop coordinates //then check the insertion point report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly."); } else { report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance."); } } else { report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates"); //don't return here, it will be returned below } } else { //do nothing, it will be handled by the more general code below and translated to 2D } } } else if (surface.PlRHRVector.X == 0 && surface.PlRHRVector.Y == 0 && Math.Abs(surface.PlRHRVector.Z) == 1) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in surface.PlCoords) { //only take the X and Y coordinates and throw out the Z because we can assume that they are all the same Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); coordList.Add(c2); } double area = GetAreaFrom2DPolyLoop(coordList); if (area == -999) { report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); } double testSurfacesArea = 0; foreach (SurfaceDefinitions testSurface in possiblesList2) { if (Math.Abs(testSurface.PlRHRVector.X) == 0 && testSurface.PlRHRVector.Y == 0 && Math.Abs(testSurface.PlRHRVector.Z) == 1) { List<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in testSurface.PlCoords) { Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); testCoordList.Add(c2); } testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList); if (testSurfacesArea == -999) { report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); } //provide area conversion double difference = Math.Abs((area*standardareaConversion) - (testSurfacesArea * testareaConversion)); if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) { possiblesList1.Add(testSurface); if (difference == 0) { //then it perfectly matches, go on to check the poly loop coordinates //then check the insertion point report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly."); } else { report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance."); } } else { report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates"); //don't return here, it will be returned below } } else { //do nothing. The code below will handle the more general case where it is not aligned with reference frame axes } } } //the surface is not aligned with one of the reference frame axes, which requires a bit more work to determine the right answer. else { report.MessageList.Add("The standard surface is not aligned along an axis, and will be rotated into a new coordinate frame"); //New Z Axis for this plane is the normal vector, does not need to be created //Get New Y Axis which is the surface Normal Vector cross the original global reference X unit vector (all unit vectors please Vector.CartVect globalReferenceX = new Vector.CartVect(); globalReferenceX.X = 1; globalReferenceX.Y = 0; globalReferenceX.Z = 0; Vector.MemorySafe_CartVect localY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(surface.PlRHRVector, globalReferenceX)); //new X axis is the localY cross the surface normal vector Vector.MemorySafe_CartVect localX = Vector.UnitVector(Vector.CrossProduct(localY, surface.PlRHRVector)); //convert the polyloop coordinates to a local 2-D reference frame //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane List<Vector.MemorySafe_CartCoord> translatedCoordinates = new List<Vector.MemorySafe_CartCoord>(); Vector.MemorySafe_CartCoord newOrigin = new Vector.MemorySafe_CartCoord(0,0,0); translatedCoordinates.Add(newOrigin); for (int j = 1; j < surface.PlCoords.Count; j++) { //randomly assigns the first polyLoop coordinate as the origin Vector.MemorySafe_CartCoord origin = surface.PlCoords[0]; //captures the components of a vector drawn from the new origin to the Vector.CartVect distance = new Vector.CartVect(); distance.X = surface.PlCoords[j].X - origin.X; distance.Y = surface.PlCoords[j].Y - origin.Y; distance.Z = surface.PlCoords[j].Z - origin.Z; //x coordinate is distance vector dot the new local X axis double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; //y coordinate is distance vector dot the new local Y axis double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; double tZ = 0; Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX,tY,tZ); translatedCoordinates.Add(translatedPt); } double area = GetAreaFrom2DPolyLoop(translatedCoordinates); if (area == -999) { report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); } //get the area of the test candidates using the polyloop coordinates foreach (SurfaceDefinitions testSurface in possiblesList2) { Vector.CartVect testglobalReferenceX = new Vector.CartVect(); globalReferenceX.X = 1; globalReferenceX.Y = 0; globalReferenceX.Z = 0; Vector.MemorySafe_CartVect testlocalY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(surface.PlRHRVector, testglobalReferenceX)); //new X axis is the localY cross the surface normal vector Vector.MemorySafe_CartVect testlocalX = Vector.UnitVector(Vector.CrossProduct(testlocalY, surface.PlRHRVector)); //convert the polyloop coordinates to a local 2-D reference frame //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane List<Vector.MemorySafe_CartCoord> testtranslatedCoordinates = new List<Vector.MemorySafe_CartCoord>(); Vector.MemorySafe_CartCoord newOriginTest = new Vector.MemorySafe_CartCoord(0,0,0); testtranslatedCoordinates.Add(newOriginTest); for (int j = 1; j < surface.PlCoords.Count; j++) { //randomly assigns the first polyLoop coordinate as the origin Vector.MemorySafe_CartCoord origin = testSurface.PlCoords[0]; //captures the components of a vector drawn from the new origin to the Vector.CartVect distance = new Vector.CartVect(); distance.X = testSurface.PlCoords[j].X - origin.X; distance.Y = testSurface.PlCoords[j].Y - origin.Y; distance.Z = testSurface.PlCoords[j].Z - origin.Z; //x coordinate is distance vector dot the new local X axis double tX = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; //y coordinate is distance vector dot the new local Y axis double tY = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; double tZ = 0; Vector.MemorySafe_CartCoord translatedPt = new Vector.MemorySafe_CartCoord(tX,tY,tZ); testtranslatedCoordinates.Add(translatedPt); } double testarea = GetAreaFrom2DPolyLoop(translatedCoordinates); if (testarea == -999) { report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); } //convert to the standard units double difference = Math.Abs((area*standardareaConversion) - (testarea * testareaConversion)); if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) { possiblesList1.Add(testSurface); //within reason if (difference == 0) { report.MessageList.Add ("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly."); } else { report.MessageList.Add ("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance."); } } else { //not within reason, so the test will fail //don't return yet, it will be returned below when possiblesList1 is found empty } } } } } possiblesList2.Clear(); //polyLoop absolute coordinates //list 1 is analyzed //list 2 is free report.MessageList.Add("</br>"); report.MessageList.Add("Starting PolyLoop coordinate comparisons......."); report.MessageList.Add("</br>"); if (possiblesList1.Count > 0) { foreach (SurfaceDefinitions testSurface in possiblesList1) { //check the polyLoop coordinates foreach (Vector.MemorySafe_CartCoord standardPolyLoopCoord in surface.PlCoords) { report = GetPolyLoopCoordMatch(standardPolyLoopCoord, testSurface, report, surface.SurfaceId, testlengthConversion, standardlengthConversion); if (report.passOrFail) { continue; } else { report.MessageList.Add("Could not find a coordinate match in the test surface polyloop."); break; } } if (report.passOrFail) { possiblesList2.Add(testSurface); } } } else { report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, and Surface Area. Failed when attempting to match the surface area."; report.passOrFail = false; return report; } possiblesList1.Clear(); report.MessageList.Add("</br>"); if(!isHighTiltObject && !isLowTiltObject && issurfaceRegular) //no point in doing this if thing is not square and regular { report.MessageList.Add("Starting Insertion Point Coordinate comparisons......."); report.MessageList.Add("</br>"); if (possiblesList2.Count > 0) { //check the insertion point coordinate foreach (SurfaceDefinitions testSurface in possiblesList2) { //now match the differences double insPtXDiff = Math.Abs((testSurface.InsertionPoint.X * testlengthConversion) - (surface.InsertionPoint.X*standardlengthConversion)); double insPtYDiff = Math.Abs((testSurface.InsertionPoint.Y * testlengthConversion) - (surface.InsertionPoint.Y*standardlengthConversion)); double insPtZDiff = Math.Abs((testSurface.InsertionPoint.Z * testlengthConversion) - (surface.InsertionPoint.Z*standardlengthConversion)); if(interiorWallFlipped) { report.MessageList.Add("The azimuths are flipped. Looking to see if the test surface has properly defined the insertion point it has."); report.MessageList.Add("</br>"); //find the complimenting insertion point for(int pt = 0; pt<testSurface.PlCoords.Count; pt++) { if(Math.Abs((surface.InsertionPoint.Z*standardlengthConversion) - (testSurface.PlCoords[pt].Z * testlengthConversion)) < DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance) { //this is a potential candidate if(Math.Abs((surface.InsertionPoint.X*standardlengthConversion) - testSurface.PlCoords[pt].X * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance) { if(Math.Abs((surface.InsertionPoint.Y*standardlengthConversion) - testSurface.PlCoords[pt].Y * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance) { //a match insPtXDiff = Math.Abs((testSurface.PlCoords[pt].X * testlengthConversion) - (surface.InsertionPoint.X*standardlengthConversion)); insPtYDiff = Math.Abs((testSurface.PlCoords[pt].Y * testlengthConversion) - (surface.InsertionPoint.Y*standardlengthConversion)); insPtZDiff = Math.Abs((testSurface.PlCoords[pt].Z * testlengthConversion) - (surface.InsertionPoint.Z*standardlengthConversion)); } else { //didn't find a candidate } } else { if (Math.Abs((surface.InsertionPoint.Y*standardlengthConversion) - testSurface.PlCoords[pt].Y * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance) { //didn't find a candidate } else { //didn't find a candidate } } } } } if (insPtXDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance || insPtYDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance || insPtZDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance) { report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " insertion point coordinates do not both match the standard file surface id: " + surface.SurfaceId + ". It has been removed as a candidate."); continue; } else { //possible match possiblesList1.Add(testSurface); if (insPtXDiff == 0 && insPtYDiff == 0 && insPtZDiff == 0) { //perfect match report.MessageList.Add("Test file's Surface with id: " + testSurface.SurfaceId + " matches the insertion point in the standard file exactly."); } else { //perfect match report.MessageList.Add(" Test file's Surface with id: " + testSurface.SurfaceId + " has an insertion point that is within the allowable tolerances of X:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance + " ft, Y:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance + "ft, Z:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance + "ft."); } } } } else { report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, and PolyLoop Coordinates. Failed when matching PolyLoop coordinates."; report.passOrFail = false; return report; } if (possiblesList1.Count == 1) { report.longMsg = "Advanced Surface Test found a match for Standard file surface id: " + surface.SurfaceId + " in the test file. Only one match was found to be within all the tolerances allowed. Surface id: " + possiblesList2[0].SurfaceId + "."; report.passOrFail = true; List<string> testFileSurfIds = new List<string>(); foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); return report; } else if (possiblesList1.Count == 0) { report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, PolyLoop Coordinates, and Insertion Point. Failed when attempting to match the insertion point coordinates."; report.passOrFail = false; return report; } else if (possiblesList1.Count > 1) { report.longMsg = "Advanced Surface Test found more than one match for Standard file surface id: " + surface.SurfaceId + " in the test file. It was not possible to determine only one unique surface."; report.passOrFail = false; //List<string> testFileSurfIds = new List<string>(); //foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } //report.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); return report; } return report; } else { //we do not conduct insertion point tests for horizontal surfaces if (possiblesList2.Count == 1) { report.longMsg = "Advanced Surface Test found a match for Standard file surface id: " + surface.SurfaceId + " in the test file. Only one match was found to be within all the tolerances allowed. Surface id: " + possiblesList2[0].SurfaceId + "."; report.passOrFail = true; List<string> testFileSurfIds = new List<string>(); foreach (SurfaceDefinitions surf in possiblesList2) { testFileSurfIds.Add(surf.SurfaceId); } globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); return report; } else if (possiblesList2.Count == 0) { report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, PolyLoop Coordinates, and Insertion Point. Failed when attempting to match the insertion point coordinates."; report.passOrFail = false; return report; } else if (possiblesList2.Count > 1) { report.longMsg = "Advanced Surface Test found more than one match for Standard file surface id: " + surface.SurfaceId + " in the test file. It was not possible to determine only one unique surface."; report.passOrFail = false; //List<string> testFileSurfIds = new List<string>(); //foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } //report.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); return report; } return report; } } return report; } catch (Exception e) { report.longMsg = (e.ToString()); return report; } }
private bool DoesSurfaceContainSurface(SurfaceDefinitions surface, SurfaceDefinitions testSurface, double testlengthConversion, double standardlengthConversion) { logger.Info("Starting to check if test surface " + testSurface.SurfaceId + " lies within surface " + surface.SurfaceId); int coordcount = testSurface.PlCoords.Count(); try { List<List<Vector.MemorySafe_CartCoord>> surfaceTriangles = new List<List<Vector.MemorySafe_CartCoord>>(); if(IsSurfaceRegular(surface)) { //triangulate in a very simple way List<Vector.MemorySafe_CartCoord> triangle1 = surface.PlCoords.GetRange(0, 3); List<Vector.MemorySafe_CartCoord> triangle2 = surface.PlCoords.GetRange(2, 2); triangle2.Add(surface.PlCoords[0]); //note this is a little hack to get back to the zero index. surfaceTriangles.Add(triangle1); surfaceTriangles.Add(triangle2); } else { //is the surface already a triangle? if(surface.PlCoords.Count == 3) { logger.Info("Surface " + surface.SurfaceId + " is a triangle."); surfaceTriangles.Add(surface.PlCoords); } else { //is the surface still a quadrilateral? if(surface.PlCoords.Count == 4) { //triangulate in a very simple way (as above) List<Vector.MemorySafe_CartCoord> triangle1 = surface.PlCoords.GetRange(0, 3); List<Vector.MemorySafe_CartCoord> triangle2 = surface.PlCoords.GetRange(2, 2); triangle2.Add(surface.PlCoords[0]); //note this is a little hack to get back to the zero index. surfaceTriangles.Add(triangle1); surfaceTriangles.Add(triangle2); } else { //perform some advanced triangulation. logger.Info("PROGRAMMER'S NOTE: NEW CODE PATH YET TO BE DEFINED : Advanced Triangulation"); } } } foreach(Vector.MemorySafe_CartCoord coord in testSurface.PlCoords) { foreach(List<Vector.MemorySafe_CartCoord> triangle in surfaceTriangles) { if(IsTestCoordMatchSurface(coord, triangle, surface.SurfaceId, testlengthConversion, standardlengthConversion)) { coordcount--; logger.Info("Test surface coord "+ coord.X+","+coord.Y+","+coord.Z+" matches exactly."); break; } else { //use the fact that the sum of angles for a point that subdivides a rectangle should be 2pi Vector.CartVect p1_p = Vector.UnitVector(Vector.CreateVector(coord,triangle[0])); Vector.CartVect p2_p = Vector.UnitVector(Vector.CreateVector(coord,triangle[1])); Vector.CartVect p3_p = Vector.UnitVector(Vector.CreateVector(coord,triangle[2])); double angle_a1 = Math.Acos(p1_p.X*p2_p.X + p1_p.Y*p2_p.Y + p1_p.Z*p2_p.Z); double angle_a2 = Math.Acos(p2_p.X*p3_p.X + p2_p.Y+p3_p.Y + p2_p.Z+p3_p.Z); double angle_a3 = Math.Acos(p3_p.X*p1_p.X + p3_p.Y*p1_p.Y + p3_p.Z*p3_p.Z); if((angle_a1+angle_a2+angle_a3)*180 / Math.PI < 0.01) //TODO: this is hardcoded and needs to be updated. { coordcount--; logger.Info("Test surface "+ coord.X+","+coord.Y+","+coord.Z+" is inside of the test surface."); break; } } } } if(coordcount == 0) return true; else return false; } catch(Exception e) { logger.Error("Exception thrown in method Does SurfaceContainSurface."); return false; } }
//Created July 2016 by Chien Si Harriman. Note the area tolerance checks are based on percentage tolerances and not absolute tolerances. private void GetSurfaceMatches(SurfaceDefinitions surface, List<SurfaceDefinitions> TestSurfaces, ref DetailedSurfaceSummary ssSummary,Conversions.lengthUnitEnum standardLengthUnits, Conversions.lengthUnitEnum testLengthUnits, double testlengthConversion, double standardlengthConversion, Conversions.areaUnitEnum standardAreaUnits, Conversions.areaUnitEnum testAreaUnits, double testareaConversion, double standardareaConversion) { try{ List<SurfaceDefinitions> possiblesList1 = new List<SurfaceDefinitions>(); List<SurfaceDefinitions> possiblesList2 = new List<SurfaceDefinitions>(); bool adjSpaceIdMatch = false; bool isLowTiltObject = false; bool isHighTiltObject = false; bool interiorWallFlipped = false; bool issurfaceRegular = false; bool istestSurfaceRegular = false; //try to find a surface in the test file that has the same: //adjacent space Id signature //surfaceType //free list is 1 //list 2 is not used ssSummary.ID = surface.SurfaceId; ssSummary.AreaUnits = "SquareFeet"; //TODO, try to remove this hardcoding. ssSummary.TotalSurfaceArea = GetSurfaceArea(surface,standardareaConversion); #region logger.Info("SURFACE ID: " + surface.SurfaceId); logger.Info("START SUBTEST: AdjacencyId check."); for(int ts = 0; ts<TestSurfaces.Count;ts++) { SurfaceDefinitions testSurface = TestSurfaces[ts]; //has to have the same number of Adjacent Space Ids if (testSurface.AdjSpaceId.Count == surface.AdjSpaceId.Count) { //an exception for a shading device if (surface.AdjSpaceId.Count == 0) { adjSpaceIdMatch = true; //must be set to true for if statements below to work. logger.Info("SHADING EXCEPTION: " + surface.SurfaceId + " is a shading device. No AdjacencyId checks performed."); } //has to have the same order of adjacent space id strings to qualify. This method assumes the strings are identical if(surface.AdjSpaceId.Count == 1) { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: "+ testSurface.SurfaceId+ " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: "+ testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } if(surface.AdjSpaceId.Count == 2) { if(surface.SurfaceType == "Ceiling" && testSurface.SurfaceType == "InteriorFloor") { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } else if (surface.SurfaceType == "InteriorFloor" && testSurface.SurfaceType == "Ceiling") { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } else if (surface.SurfaceType == "InteriorWall" && testSurface.SurfaceType == "InteriorWall") { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[1]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[1] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; interiorWallFlipped = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } else { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[1]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } } } else { if (surface.SurfaceType == "SlabOnGrade") //slab on grade for some reason we see sometimes with two adjacent space ids, depending on the vendor { if(testSurface.AdjSpaceId.Count == 2 && surface.AdjSpaceId.Count == 2) { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[1]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } else if (surface.AdjSpaceId.Count == 2) { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0] && surface.AdjSpaceId[1] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } else { if (surface.AdjSpaceId[0] == testSurface.AdjSpaceId[0]) { adjSpaceIdMatch = true; logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH SUCCESS"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " AdjacencyID MATCH FAILED"); } } } else { logger.Info("TEST SURFACE: AdjacencyID MATCH FAILED. Surfaces should have the same number of Adjacent Space Ids, with the one allowance we give for Slab on Grade."); } } if (adjSpaceIdMatch) { logger.Info("END SUBTEST: AdjacencyId check."); logger.Info("START SUBTEST: surfaceType check."); if(!IsHighTiltSurface(surface) && !IsLowTiltSurface(surface)) { if(surface.SurfaceType == testSurface.SurfaceType) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH SUCCESS"); possiblesList1.Add(testSurface); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH FAILED"); } } else { if(IsLowTiltSurface(surface)) isLowTiltObject = true; if (IsHighTiltSurface(surface)) isHighTiltObject = true; if(IsLowTiltSurface(testSurface) && isHighTiltObject) { if(testSurface.SurfaceType == "Ceiling" && surface.SurfaceType == "InteriorFloor") { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH SUCCESS"); possiblesList1.Add(testSurface); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH FAILED"); } } else if(IsHighTiltSurface(testSurface) && isHighTiltObject) { if(surface.SurfaceType == testSurface.SurfaceType) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH SUCCESS"); possiblesList1.Add(testSurface); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH FAILED"); } } else if(IsLowTiltSurface(testSurface) && isLowTiltObject) { if (surface.SurfaceType == testSurface.SurfaceType) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH SUCCESS"); possiblesList1.Add(testSurface); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH FAILED"); } } else if (IsHighTiltSurface(testSurface) && isLowTiltObject) { if(testSurface.SurfaceType == "InteriorFloor" && surface.SurfaceType == "Ceiling") { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH SUCCESS"); possiblesList1.Add(testSurface); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " surfaceType MATCH FAILED"); } } } adjSpaceIdMatch = false; //must reset it to make sure it will find other valid surfaces for only the proper adjacency. } } logger.Info("END SUBTEST: surfaceType check."); // #reporting if (possiblesList1.Count == 1) { logger.Info("TEST SUMMARY: Based on a comparison of the surface Type and Adjacent SpaceIds, there is " + possiblesList1.Count.ToString() + " surface in the test file that is a possible match for " + surface.SurfaceId + " of the Standard File."); } else if (possiblesList1.Count > 1) { logger.Info("TEST SUMMARY: Based on a comparison of the surface Type and Adjacent SpaceIds, there are " + possiblesList1.Count.ToString() + " surfaces in the test file that are possible matches for " + surface.SurfaceId + " of the Standard File."); } else { logger.Error("TEST SUMMARY: In the vendor test file, no matches could be found for this surface that have the same AdjacentSpaceId(s) and SurfaceType."); ssSummary.FoundMatch = false; return; } #endregion //there is at least one surface that matches the above criteria //now checking for tilt and azimuth criteria, as these have to match //TODO: consider removing, minor clean up if (possiblesList1.Count > 0) { logger.Info("START SUBTEST: Azimuth and Tilt check."); foreach (SurfaceDefinitions testSurface in possiblesList1) { double tiltDifference = 0; double azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth); #region if(isLowTiltObject) { if(IsLowTiltSurface(testSurface)) //they are the same, both have small tilts { tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt); } else //they are 180 degrees different, and the test surface is a high tilt while the standard is low tilt { if (testSurface.SurfaceType == "InteriorFloor") { tiltDifference = Math.Abs(Math.Abs(testSurface.Tilt - 180) - surface.Tilt); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH FAILED"); logger.Info("PROGRAMMER'S NOTE: Expecting test surface type to be Interior Floor"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); logger.Info("TEST SURFACE: "+testSurface.SurfaceId + " has been removed as a candidate for matching."); continue; } } //no azimuth tests for horizontal surfaces if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH FAILED"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " has been removed as a candidate for matching."); continue; } //if the is within tolerance else { //if the surface is horizontal, just add to the free List because we don't check for azimuth in this case if (surface.Tilt == 0) { possiblesList2.Add(testSurface); if (tiltDifference == 0) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH SUCCESS:PERFECT"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH SUCCESS"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } } else { logger.Info("START SUBTEST: azimuth checks."); //check the azimuth if (azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Azimuth MATCH FAILED"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " has been removed as a candidate for matching."); continue; } //if the tilt and azimuth is within tolerance else { //add to the free List possiblesList2.Add(testSurface); if (tiltDifference == 0 && azimuthDifference == 0) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Azimuth MATCH SUCCESS:PERFECT"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Azimuth MATCH SUCCESS"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } } } } } else if (isHighTiltObject) { if(IsHighTiltSurface(testSurface)) //both high tilt interior surfaces { tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt); } else //standard is high tilt, test is low tilt { if(testSurface.SurfaceType == "Ceiling") { tiltDifference = Math.Abs(Math.Abs(testSurface.Tilt - 180) - surface.Tilt); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH FAILED"); logger.Info("PROGRAMMER' NOTE: Expected surfaceType to be Ceiling."); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " has been removed as a candidate for matching."); continue; } } //no azimuth tests if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) //azimuth no longer matters for these surfaces { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH FAILED"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " has been removed as a candidate for matching."); continue; } //if the tilt and azimuth is within tolerance else { //if the surface is horizontal, just add to the free List because we don't check for azimuth in this case if (surface.Tilt == 180) { possiblesList2.Add(testSurface); if (tiltDifference == 0) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH SUCCESS:PERFECT"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt MATCH PERFECT"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } } else { //check the azimuth if (azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Azimuth MATCH FAILED"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " has been removed as a candidate for matching."); continue; } //if the tilt and azimuth is within tolerance else { //add to the free List possiblesList2.Add(testSurface); if (tiltDifference == 0 && azimuthDifference == 0) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Azimuth MATCH SUCCESS:PERFECT"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Azimuth MATCH SUCCESS"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } } } } } #endregion //the surface is neither a ceiling nor a floor, it is just something regular else { azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth); if (interiorWallFlipped) //both high tilt interior surfaces { azimuthDifference = Math.Abs(Math.Abs(testSurface.Azimuth - surface.Azimuth) - 180); //180 is needed because they should be separated by 180 } tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt); //if the tilt and azimuth is outside of tolerance if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance || azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt Or Azimuth MATCH FAILED"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " has been removed as a candidate for matching."); continue; } //if the tilt and azimuth is within tolerance else { //add to the free List possiblesList2.Add(testSurface); if (tiltDifference == 0 && azimuthDifference == 0) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt And Azimuth MATCH SUCCESS:PERFECT"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Tilt And Azimuth MATCH SUCCESS"); logger.Debug("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); logger.Debug("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString() + ")"); } } } logger.Info("END SUBTEST: Azimuth and Tilt check."); } } // //report to the user that no matches could be found else { logger.Error("TEST SUMMARY: In the test file, surfaces could be found that match the standard file's AdjacentSpaceId and SurfaceType, but of these matches, none could be identified that also have a tilt or azimuth that exactly matches the standard file's, or is within the allowable tolerance."); ssSummary.FoundMatch = false; return; } //clear the first list possiblesList1.Clear(); //start to loop through the new refined list //generally want to look at the polyLoop coordinates //list 2 is analyzed //list 1 is free ; if (possiblesList2.Count > 0) { //simple method from this point forward is just to simply start doing a polyloop check //check the standard surface PolyLoop and the test Surface(s) polyloop(s) //check the absolute coordinates of the testSurface(s) polyloop(s) if (possiblesList2.Count == 1) { logger.Info("PROGRAMMER'S INFO: Only one Surface Candidate remaining."); //meaning there is only one candidate still available //go on to test the polyLoop coordinates and the insertion point possiblesList1.Add(possiblesList2[0]); //this should mean theoretically that you can do a one for one comparison and do the simplistic check possiblesList2.Clear(); //polyLoop absolute coordinates //list 1 is analyzed //list 2 is free logger.Info("START SUBTEST: PolyLoop coordinate checks."); #region if (possiblesList1.Count > 0) { foreach (SurfaceDefinitions testSurface in possiblesList1) { //check the polyLoop coordinates bool coordsMatch = false; foreach (Vector.MemorySafe_CartCoord standardPolyLoopCoord in surface.PlCoords) { coordsMatch = GetPolyLoopCoordMatch(standardPolyLoopCoord, testSurface, surface.SurfaceId, testlengthConversion, standardlengthConversion); if (coordsMatch) { continue; } else { logger.Info("TEST SURFACE: "+testSurface.SurfaceId+ " polyloop coordinate MATCH FAILED. It has been removed from the candidate list."); break; } } if (coordsMatch) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " polyloop coordinate MATCH SUCCESS."); possiblesList2.Add(testSurface); } } } else { logger.Error("TEST SUMMARY: In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, and Surface Area. Failed when attempting to match its polyloop coordinates."); ssSummary.FoundMatch = false; return; } logger.Info("END SUBTEST: PolyLoop coordinate checks."); #endregion possiblesList1.Clear(); issurfaceRegular = IsSurfaceRegular(surface); //Insertion point tests. if (!isHighTiltObject && !isLowTiltObject && issurfaceRegular) //no point in doing these checks if thing is not square and regular #region { logger.Info("PROGRAMMER'S NOTE: Standard Surface is square or rectangle non-horizontal. Assumption that test surface candidate should also be same type of shape."); logger.Info("START SUBTEST: Insertion Point Coordinate check."); if (possiblesList2.Count > 0) { //check the insertion point coordinate foreach (SurfaceDefinitions testSurface in possiblesList2) { //now match the differences double insPtXDiff = Math.Abs((testSurface.InsertionPoint.X * testlengthConversion) - (surface.InsertionPoint.X * standardlengthConversion)); double insPtYDiff = Math.Abs((testSurface.InsertionPoint.Y * testlengthConversion) - (surface.InsertionPoint.Y * standardlengthConversion)); double insPtZDiff = Math.Abs((testSurface.InsertionPoint.Z * testlengthConversion) - (surface.InsertionPoint.Z * standardlengthConversion)); //TODO: this interior flipped algorithm could be improved vastly. How to tell if in lower left has not been solved. if (interiorWallFlipped) { logger.Info("PROGRAMMER'S NOTE: The azimuths are flipped. Adjusting the insertion point test to factor this into account.."); //find the complimenting insertion point for (int pt = 0; pt < testSurface.PlCoords.Count; pt++) { if (Math.Abs((surface.InsertionPoint.Z * standardlengthConversion) - (testSurface.PlCoords[pt].Z * testlengthConversion)) < DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance) { if (Math.Abs((surface.InsertionPoint.X * standardlengthConversion) - testSurface.PlCoords[pt].X * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance) { if (Math.Abs((surface.InsertionPoint.Y * standardlengthConversion) - testSurface.PlCoords[pt].Y * testlengthConversion) < DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance) { //a match insPtXDiff = Math.Abs((testSurface.PlCoords[pt].X * testlengthConversion) - (surface.InsertionPoint.X * standardlengthConversion)); insPtYDiff = Math.Abs((testSurface.PlCoords[pt].Y * testlengthConversion) - (surface.InsertionPoint.Y * standardlengthConversion)); insPtZDiff = Math.Abs((testSurface.PlCoords[pt].Z * testlengthConversion) - (surface.InsertionPoint.Z * standardlengthConversion)); logger.Info("TEST SURFACE: " + testSurface.SurfaceId + "Insertion Point MATCH SUCCESS."); possiblesList1.Add(testSurface); break; } else { //didn't find a candidate logger.Info("TEST SURFACE: " + testSurface.SurfaceId + "Insertion Point did not Match."); } } } } } else { if (insPtXDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance || insPtYDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance || insPtZDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance) { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Insertion Point MATCH FAILED. It has been removed as a candidate."); continue; } else { //possible match if (insPtXDiff == 0 && insPtYDiff == 0 && insPtZDiff == 0) { //perfect match logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Insertion Point MATCH SUCCESS:PERFECT"); possiblesList1.Add(testSurface); } else { logger.Info("TEST SURFACE: " + testSurface.SurfaceId + " Insertion Point MATCH SUCCESS"); possiblesList1.Add(testSurface); } } } } } else { logger.Error("TEST SUMMARY: In the test file, no surfaces could be found that match standard file's Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, and PolyLoop Coordinates. Failed when matching PolyLoop coordinates."); ssSummary.FoundMatch = false; return; } possiblesList2.Clear(); logger.Info("END SUBTEST: Insertion point coordinate check."); if (possiblesList1.Count == 1) { logger.Info("TEST SUMMARY: MATCH SUCCESS for Standard file surface id: " + surface.SurfaceId + " in the test file. Only one match was found to be within all the tolerances allowed."); List<string> testFileSurfIds = new List<string>(); foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); ssSummary.FoundMatch = true; ssSummary.TestSurfaceIDs = testFileSurfIds; ssSummary.TotalTestSurfaceArea = GetSurfaceArea(possiblesList1[0],testareaConversion); return; } else if (possiblesList1.Count == 0) { logger.Error("TEST SUMMARY: No surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, PolyLoop Coordinates, and Insertion Point. Failed when attempting to match the insertion point coordinates."); ssSummary.FoundMatch = false; return; } else if (possiblesList1.Count > 1) { logger.Error("TEST SUMMARY: Advanced Surface Test found more than one match for Standard file surface id: " + surface.SurfaceId + " in the test file. It was not possible to determine only one unique surface."); ssSummary.FoundMatch = false; return; } } #endregion else { if (possiblesList2.Count == 1) //we do not check insertion points for horizontal surfaces. { possiblesList1 = possiblesList2; //this is just to keep the below code consistent with convention. logger.Info("TEST FILE SUCCESS: for Standard file surface id: " + surface.SurfaceId + " in the test file. Only one match was found to be within all the tolerances allowed."); List<string> testFileSurfIds = new List<string>(); foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); ssSummary.FoundMatch = true; ssSummary.TestSurfaceIDs = testFileSurfIds; ssSummary.TotalTestSurfaceArea = GetSurfaceArea(possiblesList1[0],testareaConversion); return; } else if (possiblesList2.Count == 0) { logger.Error("TEST FILE FAILURE: No surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, PolyLoop Coordinates, and Insertion Point. Failed when attempting to match the insertion point coordinates."); ssSummary.FoundMatch = false; return; } else if (possiblesList2.Count > 1) { logger.Error("TEST FILE FAILRE: Advanced Surface Test found more than one match for Standard file surface id: " + surface.SurfaceId + " in the test file. It was not possible to determine only one unique surface."); ssSummary.FoundMatch = false; return; } } } //more than one candidate still exists even after the adjacency test, surfaceType test, and tilt and azimuth tests, so filter through #region else { //check to see if the remaining area sums matches the standard surface area, //and that the edges of the test surfaces do not overlap, etc. //first try to find if the standard file has a regular rectangular or square profile logger.Debug("More than one surface remains in the test subset."); logger.Info("PROGRAMMER'S NOTE: Performing advanced surface bondary tests."); //checks to see if the testSurface vertices all lie within the standard surface polygonal boundary foreach(SurfaceDefinitions testSurface in possiblesList2) { logger.Info("Testing test surface " +testSurface.SurfaceId); if(DoesSurfaceContainSurface(surface,testSurface,testlengthConversion,standardlengthConversion)) { possiblesList1.Add(testSurface); } } //now we check to see which of the remaining surfaces and their edges form a coherent surface. //do their edges overlap? is the polygon self-intersecting? //add the surface the the existing possibles list possiblesList1.Insert(0, surface); var edgeDict = FindMatchingEdges(possiblesList1); if(EdgesAreValid(edgeDict)) { //finally, we see if the total area of the remaining surfaces equals the area of the standard surface. If all this above has passed, it should not be an issue. double standardArea = ssSummary.TotalSurfaceArea; double testArea = 0; //remove the zero index surface, because this is the standard surface possiblesList1.RemoveAt(0); //these are the remaining candidates foreach(var ts in possiblesList1) { testArea += GetSurfaceArea(ts,testareaConversion); } if(Math.Abs(standardArea - testArea)/standardArea < DOEgbXMLBasics.Tolerances.AreaPercentageTolerance) { logger.Info("TEST FILE SUCCESS: for Standard file surface id: " + surface.SurfaceId + " in the test file. The wall candidates remaining meet the allowable gemoetry constraints."); List<string> testFileSurfIds = new List<string>(); foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } ssSummary.FoundMatch = true; ssSummary.TestSurfaceIDs = testFileSurfIds; ssSummary.TotalTestSurfaceArea = testArea; } else { logger.Info("TEST FILE FAILURE: for Standard file surface id: " + surface.SurfaceId + " in the test file. The wall candidates remaining did not pass the area test."); } } else { //problem logger.Info("TEST FILE FAILURE: for Standard file surface id: " + surface.SurfaceId + " in the test file. The wall candidates remaining do not meet the allowable geometry constraints."); List<string> testFileSurfIds = new List<string>(); foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); ssSummary.FoundMatch = false; ssSummary.TestSurfaceIDs = testFileSurfIds; } } #endregion } } catch(Exception e){ logger.Fatal(e.ToString()); return; } }
//<Get Surface Definitions in a gbXML file> //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation //This method will take each surface element and convert the xml language into an instance of a SurfaceDefinition //Each surface is converted in this way, with the resulting instance being stored in a list that is returned for later use //----------------------</p> //This is an important method because it stores all of the information about a surface in a gbXML file in a list //This list can later be recalled to perform analytics on the surfaces and the data contained within private static List<SurfaceDefinitions> GetFileSurfaceDefs(XmlDocument xmldoc, XmlNamespaceManager xmlns) { List<SurfaceDefinitions> surfaces = new List<SurfaceDefinitions>(); try { XmlNodeList nodes = xmldoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", xmlns); foreach (XmlNode surfaceNode in nodes) { //initialize a new instance of the class SurfaceDefinitions surfDef = new SurfaceDefinitions(); surfDef.AdjSpaceId = new List<string>(); surfDef.PlCoords = new List<Vector.MemorySafe_CartCoord>(); //get id and surfaceType XmlAttributeCollection spaceAtts = surfaceNode.Attributes; foreach (XmlAttribute at in spaceAtts) { if (at.Name == "id") { surfDef.SurfaceId = at.Value; } else if (at.Name == "surfaceType") { surfDef.SurfaceType = at.Value; } } if (surfaceNode.HasChildNodes) { XmlNodeList surfChildNodes = surfaceNode.ChildNodes; foreach (XmlNode node in surfChildNodes) { if (node.Name == "AdjacentSpaceId") { XmlAttributeCollection adjSpaceIdAt = node.Attributes; foreach (XmlAttribute at in adjSpaceIdAt) { if (at.Name == "spaceIdRef") { surfDef.AdjSpaceId.Add(at.Value); } } } else if (node.Name == "RectangularGeometry") { if (node.HasChildNodes) { XmlNodeList rectGeomChildren = node.ChildNodes; foreach (XmlNode rgChildNode in rectGeomChildren) { if (rgChildNode.Name == "Azimuth") { surfDef.Azimuth = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "CartesianPoint") { if (rgChildNode.HasChildNodes) { Vector.CartCoord cd = new Vector.CartCoord(); XmlNodeList coordinates = rgChildNode.ChildNodes; int pointCount = 1; foreach (XmlNode coordinate in coordinates) { switch (pointCount) { case 1: cd.X = Convert.ToDouble(coordinate.InnerText); break; case 2: cd.Y = Convert.ToDouble(coordinate.InnerText); break; case 3: cd.Z = Convert.ToDouble(coordinate.InnerText); break; } pointCount++; } surfDef.InsertionPoint = new VectorMath.Vector.MemorySafe_CartCoord(cd.X, cd.Y, cd.Z); } } else if (rgChildNode.Name == "Tilt") { surfDef.Tilt = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "Height") { surfDef.Height = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "Width") { surfDef.Width = Convert.ToDouble(rgChildNode.InnerText); } } } } else if (node.Name == "PlanarGeometry") { XmlNode polyLoop = node.FirstChild; if (polyLoop.HasChildNodes) { XmlNodeList cartesianPoints = polyLoop.ChildNodes; foreach (XmlNode coordinatePt in cartesianPoints) { Vector.CartCoord coord = new Vector.CartCoord(); if (coordinatePt.HasChildNodes) { XmlNodeList coordinates = coordinatePt.ChildNodes; int pointCount = 1; foreach (XmlNode coordinate in coordinatePt) { switch (pointCount) { case 1: coord.X = Convert.ToDouble(coordinate.InnerText); break; case 2: coord.Y = Convert.ToDouble(coordinate.InnerText); break; case 3: coord.Z = Convert.ToDouble(coordinate.InnerText); break; } pointCount++; } surfDef.PlCoords.Add(new Vector.MemorySafe_CartCoord(coord.X, coord.Y, coord.Z)); } } } } } } Vector.MemorySafe_CartVect plRHRVect = GetPLRHR(surfDef.PlCoords); surfDef.PlRHRVector = new Vector.MemorySafe_CartVect(plRHRVect.X,plRHRVect.Y,plRHRVect.Z); surfaces.Add(surfDef); } return surfaces; } catch (Exception e) { return surfaces; } }