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 Vector.MemorySafe_CartVect GetPLRHR(List<Vector.MemorySafe_CartCoord> plCoords) { Vector.CartVect plRHRVect = new Vector.CartVect(); //this list will store all of the rhr values returned by any arbitrary polyloop List<Vector.CartVect> RHRs = new List<Vector.CartVect>(); int coordCount = plCoords.Count; for (int i = 0; i < coordCount - 2; i++) { Vector.CartVect v1 = Vector.CreateVector(plCoords[i], plCoords[i + 1]); Vector.CartVect v2 = Vector.CreateVector(plCoords[i + 1], plCoords[i + 2]); Vector.CartVect uv = Vector.UnitVector(Vector.CrossProduct(v1, v2)); RHRs.Add(uv); } int RHRVectorCount = RHRs.Count; List<Vector.CartVect> distinctRHRs = new List<Vector.CartVect>(); //the Distinct().ToList() routine did not work because, we believe, the item in the list is not recognized by Distinct() //distinctRHRs = RHRs.Distinct().ToList(); //so we took the following approach to try and find unique vectors and store them distinctRHRs.Add(RHRs[0]); for (int j = 1; j < RHRVectorCount; j++) { foreach (Vector.CartVect distinctVector in distinctRHRs) { //this could contain wacky RHRs that are removed below if (RHRs[j].X != distinctVector.X && RHRs[j].Y != distinctVector.Y && RHRs[j].Z != distinctVector.Z) { distinctRHRs.Add(RHRs[j]); } } } int RHRDistinctVectCount = distinctRHRs.Count; if (RHRDistinctVectCount == 1) { plRHRVect = distinctRHRs[0]; return new Vector.MemorySafe_CartVect(plRHRVect.X,plRHRVect.Y,plRHRVect.Z); } else { Dictionary<int, Vector.CartVect> uniqueVectorCount = new Dictionary<int, Vector.CartVect>(); //determine which vector shows up the most often foreach (Vector.CartVect distinctVector in distinctRHRs) { int count = 0; foreach (Vector.CartVect vect in RHRs) { if (distinctVector.X == vect.X && distinctVector.Y == vect.Y && distinctVector.Z == vect.Z) { count++; } } uniqueVectorCount.Add(count, distinctVector); } //returns the vector that has the largest count //get the largest integer in the list of //may also be able to use //uniqueVectorCount.Keys.Max(); List<int> keysList = uniqueVectorCount.Keys.ToList(); keysList.Sort(); int max = 0; foreach (int key in keysList) { if (key > max) { max = key; } } plRHRVect = uniqueVectorCount[max]; return new Vector.MemorySafe_CartVect(plRHRVect.X,plRHRVect.Y,plRHRVect.Z); } }
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 DOEgbXMLReportingObj GetPossibleOpeningMatches(OpeningDefinitions standardOpening, List<OpeningDefinitions> TestOpenings, DOEgbXMLReportingObj report) { report.testSummary = "This test checks the geometric accuracy of each opening in your test file against the standard file."; report.testSummary += " For each opening (window, door, skylight) this validator seeks out a similar opening in your test file and"; //match surfaces at this stage so we know which surface is associated with the window report.testSummary += " The validator first seeks to find all openings that have a parent surface (roof, external wall, etc.) with"; report.testSummary += " the same azimuth and tilt. If it finds more than one opening candidate that matches the parent surface tilt and azimuth,"; report.testSummary += " the validator will make all of these openings possible candidates."; report.testSummary += " The validator then takes these candidates and looks at their polyloop coordinates. "; report.testSummary += " and will keep only those openings that have similar polyLoop coordinates"; report.testSummary += " Next it matches the area, then the width and height, if applicable, and finally checks the insertion"; report.testSummary += " point coordinates. If all of these come back within tolerance, the opening has found a match."; report.testSummary += " Otherwise, the test will fail."; report.testSummary += " The summary at the bottom of the page will show the logic of how the test arrived at its conclusion."; bool matchedParentAz = false; bool matchedParentTilt = false; bool matchedPolyLoopCoords = false; List<OpeningDefinitions> possibleMatches = new List<OpeningDefinitions>(); List<OpeningDefinitions> possibleMatches2 = new List<OpeningDefinitions>(); try { //find match of parent surface //try matching based on the surface matches //if that does not work, then just try to match the parent tilt and parent azimuth to one another int i = 0; report.MessageList.Add("Starting Parent Azimuth and Tilt Match test...."); report.MessageList.Add("</br>"); while (true) { //reset matchedParentAz = false; matchedParentTilt = false; OpeningDefinitions testOpening = TestOpenings[i]; if (testOpening.ParentAzimuth == standardOpening.ParentAzimuth && testOpening.ParentTilt == standardOpening.ParentTilt) { report.MessageList.Add("Candidate Found. Test file opening has EXACTLY matched its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt."); report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]"); report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]"); matchedParentAz = true; matchedParentTilt = true; } else { double azDifference = Math.Abs(testOpening.ParentAzimuth - standardOpening.ParentAzimuth); double tiltDifference = Math.Abs(testOpening.ParentTilt - standardOpening.ParentTilt); if (azDifference < DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance && tiltDifference < DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) { report.MessageList.Add("Candidate found. Test file opening HAS matched WITHIN ALLOWABLE TOLERANCE its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt."); report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]"); report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]"); matchedParentAz = true; matchedParentTilt = true; } else { report.MessageList.Add("Candidate rejected. Test file opening HAS NOT matched WITHIN ALLOWABLE TOLERANCE its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt."); report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]"); report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]"); report.MessageList.Add("</br>"); } } if (matchedParentAz && matchedParentTilt) { possibleMatches.Add(testOpening); report.MessageList.Add("Successful Match Candidate Identified."); report.MessageList.Add("</br>"); } i++; if (i == TestOpenings.Count) { if (possibleMatches.Count == 0) { //no candidates found report.MessageList.Add("No candidates found in the test file to match standard file opening " + standardOpening.OpeningId); report.passOrFail = false; report.longMsg = "Test to find suitable opening candidate in the test file has failed. Parent Tilt and Azimuth matches could not be established."; //no need to go further return report; } break; } } report.MessageList.Add("</br>"); report.MessageList.Add("Starting Opening PolyLoop Coordinate Match test........."); i = 0; while (true) { OpeningDefinitions testOpening = possibleMatches[i]; //continue to next test //continue the next batch of tests //polyloop absolute coordinates //check the polyLoop coordinates foreach (Vector.MemorySafe_CartCoord standardPolyLoopCoord in standardOpening.PlCoords) { report = GetOpeningPolyLoopCoordMatch(standardPolyLoopCoord, testOpening, report, standardOpening.OpeningId); if (report.passOrFail) { matchedPolyLoopCoords = true; continue; } else { report.MessageList.Add("Could not find a coordinate match in the test opening polyloop."); matchedPolyLoopCoords = false; break; } } //if matchePolyLoopCoords comes back true, then a candidate has been found that matches all polyloop coords within tolerance if (matchedPolyLoopCoords == true) { possibleMatches2.Add(testOpening); } i++; if (i == possibleMatches.Count) { if (possibleMatches2.Count == 0) { report.MessageList.Add("No candidates found in the test file to match standard file opening " + standardOpening.OpeningId); report.passOrFail = false; report.longMsg = "Test to find suitable opening candidate in the test file has failed. Parent Tilt and Azimuth matches were established, but these candidates did not produce good polyLoop coordinate matches."; //no need to go further return report; } break; } } //next set of tests //polyloop area tests report.MessageList.Add("</br>"); report.MessageList.Add("Starting Opening Surface Area Match test........."); possibleMatches.Clear(); i = 0; while (true) { #region OpeningDefinitions testOpening = possibleMatches2[i]; if (Math.Abs(standardOpening.PlRHRVector.X) == 1 && standardOpening.PlRHRVector.Y == 0 && standardOpening.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in standardOpening.PlCoords) { //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same Vector.MemorySafe_CartCoord c2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); coordList.Add(c2); } double area = Math.Abs(GetAreaFrom2DPolyLoop(coordList)); standardOpening.surfaceArea = area; if (area == -999) { //these messages should never occur and are a sign of some sort of serious, as of yet unknown error //March 20 2013 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"); report.longMsg = "Fatal error. Please contact gbXML administrator"; report.passOrFail = false; return report; } double testOpeningArea = 0; if (Math.Abs(testOpening.PlRHRVector.X) == 1 && testOpening.PlRHRVector.Y == 0 && testOpening.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in testOpening.PlCoords) { Vector.MemorySafe_CartCoord o2 = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); testCoordList.Add(o2); } testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList)); testOpening.surfaceArea = testOpeningArea; if (testOpeningArea == -999) { //these messages should never occur and are a sign of some sort of serious, as of yet unknown error //March 20 2013 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"); report.longMsg = "Fatal error. Please contact gbXML administrator"; report.passOrFail = false; return report; } double difference = Math.Abs(area) - Math.Abs(testOpeningArea); if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) { 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 Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard opening: " + standardOpening.OpeningId + " exactly."); possibleMatches.Add(testOpening); } else { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); possibleMatches.Add(testOpening); } } else { report.MessageList.Add("The standard file opening cannot find a match for its surface area of opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test opening: " + testOpening.OpeningId); //don't return here, it will be returned below } } else { //by definition, the Window opening should always use coordinates that create a normal vector that points in the //positive or negative X direction. If the test file does not do this, then this is in violation of the //gbXML spec report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates "); report.longMsg += (" that do not have the same normal vector as the standard opening."); report.passOrFail = false; } } else if (standardOpening.PlRHRVector.X == 0 && Math.Abs(standardOpening.PlRHRVector.Y) == 1 && standardOpening.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in standardOpening.PlCoords) { //only take the Y and Z coordinates and throw out the X 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 = Math.Abs(GetAreaFrom2DPolyLoop(coordList)); standardOpening.surfaceArea = area; if (area == -999) { //these messages should never occur and are a sign of some sort of serious, as of yet unknown error //March 20 2013 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"); report.longMsg = "Fatal error. Please contact gbXML administrator"; report.passOrFail = false; return report; } double testOpeningArea = 0; if (testOpening.PlRHRVector.X == 0 && Math.Abs(testOpening.PlRHRVector.Y) == 1 && testOpening.PlRHRVector.Z == 0) { List<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in testOpening.PlCoords) { Vector.MemorySafe_CartCoord o2 = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); testCoordList.Add(o2); } testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList)); testOpening.surfaceArea = testOpeningArea; if (testOpeningArea == -999) { //these messages should never occur and are a sign of some sort of serious, as of yet unknown error //March 20 2013 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"); report.longMsg = "Fatal error. Please contact gbXML administrator"; report.passOrFail = false; return report; } double difference = Math.Abs(area) - Math.Abs(testOpeningArea); if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) { 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 Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly."); possibleMatches.Add(testOpening); } else { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); possibleMatches.Add(testOpening); } } else { report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId); //don't return here, it will be returned below } } else { //by definition, the Window opening should always use coordinates that create a normal vector that points in the //positive or negative X direction. If the test file does not do this, then this is in violation of the //gbXML spec report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates "); report.longMsg += (" that do not have the same normal vector as the standard opening."); report.passOrFail = false; } } else if (standardOpening.PlRHRVector.X == 0 && standardOpening.PlRHRVector.Y == 0 && Math.Abs(standardOpening.PlRHRVector.Z) == 1) { List<Vector.MemorySafe_CartCoord> coordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in standardOpening.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 = Math.Abs(GetAreaFrom2DPolyLoop(coordList)); standardOpening.surfaceArea = area; 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 testOpeningArea = 0; if (testOpening.PlRHRVector.X == 0 && testOpening.PlRHRVector.Y == 0 && Math.Abs(testOpening.PlRHRVector.Z) == 1) { List<Vector.MemorySafe_CartCoord> testCoordList = new List<Vector.MemorySafe_CartCoord>(); foreach (Vector.MemorySafe_CartCoord coord in testOpening.PlCoords) { Vector.MemorySafe_CartCoord c02 = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); testCoordList.Add(coord); } testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList)); testOpening.surfaceArea = testOpeningArea; if (testOpeningArea == -999) { //these messages should never occur and are a sign of some sort of serious, as of yet unknown error //March 20 2013 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"); report.longMsg = "Fatal error. Please contact gbXML administrator"; report.passOrFail = false; return report; } double difference = Math.Abs(area) - Math.Abs(testOpeningArea); if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) { 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 Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly."); possibleMatches.Add(testOpening); } else { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); possibleMatches.Add(testOpening); } } else { report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId); //don't return here, it will be returned below } } else { //by definition, the Window opening should always use coordinates that create a normal vector that points in the //positive or negative X direction. If the test file does not do this, then this is in violation of the //gbXML spec report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates "); report.longMsg += (" that do not have the same normal vector as the standard opening."); report.passOrFail = false; } } //the opening is not aligned along a reference frame axis else { report.MessageList.Add("This standard Opening is not aligned along a reference plane axis, and will be rotated into a new coordinate frame."); report.MessageList.Add("Commencing rotation to 2-D."); //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(standardOpening.PlRHRVector, globalReferenceX)); localY = Vector.UnitVector(localY); //new X axis is the localY cross the surface normal vector Vector.MemorySafe_CartVect localX = Vector.UnitVector(Vector.CrossProduct(localY, standardOpening.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 < standardOpening.PlCoords.Count; j++) { //randomly assigns the first polyLoop coordinate as the origin Vector.MemorySafe_CartCoord origin = standardOpening.PlCoords[0]; //captures the components of a vector drawn from the new origin to the Vector.CartVect distance = new Vector.CartVect(); distance.X = standardOpening.PlCoords[j].X - origin.X; distance.Y = standardOpening.PlCoords[j].Y - origin.Y; distance.Z = standardOpening.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); standardOpening.surfaceArea = area; 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 Vector.CartVect testglobalReferenceX = new Vector.CartVect(); globalReferenceX.X = 1; globalReferenceX.Y = 0; globalReferenceX.Z = 0; Vector.MemorySafe_CartVect testlocalY = Vector.UnitVector(Vector.CrossProductMSRetMSNV(testOpening.PlRHRVector, testglobalReferenceX)); //new X axis is the localY cross the surface normal vector Vector.MemorySafe_CartVect testlocalX = Vector.UnitVector(Vector.CrossProduct(testlocalY, testOpening.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 < testOpening.PlCoords.Count; j++) { //randomly assigns the first polyLoop coordinate as the origin Vector.MemorySafe_CartCoord origin = testOpening.PlCoords[0]; //captures the components of a vector drawn from the new origin to the Vector.CartVect distance = new Vector.CartVect(); distance.X = testOpening.PlCoords[j].X - origin.X; distance.Y = testOpening.PlCoords[j].Y - origin.Y; distance.Z = testOpening.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 testOpeningArea = GetAreaFrom2DPolyLoop(translatedCoordinates); testOpening.surfaceArea = testOpeningArea; if (testOpeningArea == -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"); } double difference = Math.Abs(area) - Math.Abs(testOpeningArea); if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) { 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 Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly."); possibleMatches.Add(testOpening); } else { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); possibleMatches.Add(testOpening); } } else { report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId); //don't return here, it will be returned below } } i++; if (i == possibleMatches2.Count) { if (possibleMatches.Count == 0) { report.MessageList.Add("No area match could be found for standard opening: " + standardOpening.OpeningId + "."); report.longMsg = "The search routine has ended and could not find a match for opening: " + standardOpening.OpeningId + ". Attempt to match the area of the standard file with test file openings failed."; return report; } else { //you are good to go with some more matches report.MessageList.Add("Area matching SUCCESS for standard file Opening id: " + standardOpening.OpeningId); report.MessageList.Add("Commencing comparisons of height, width, and insertion point."); break; } } #endregion } //test the width and height, if applicable report.MessageList.Add("</br>"); report.MessageList.Add("Starting Width and Height Match test........."); possibleMatches2.Clear(); i = 0; //surface area using the coordinates of the polyloop. We already assume that they are planar, as previously tested while (true) { //see if the openings are regular bool isStandardRegular = IsOpeningRegular(standardOpening); bool isTestRegular = IsOpeningRegular(possibleMatches[i]); //if they are...go ahead and use width and height, otherwise the values are not reliable if (isStandardRegular) { //output something if (isTestRegular) { //output something //perform tests OpeningDefinitions testOpening = possibleMatches[i]; double testWidth = testOpening.Width; double standardWidth = standardOpening.Width; double testHeight = testOpening.Height; double standardHeight = standardOpening.Height; double widthDifference = Math.Abs(testWidth - standardWidth); double heightDiffefence = Math.Abs(testHeight - standardHeight); if (widthDifference <= DOEgbXMLBasics.Tolerances.OpeningWidthTolerance) { if (widthDifference == 0) { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Width value matches the Width value of the standard Opening: " + standardOpening.OpeningId + " exactly."); } else { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Width value matches the Width value of the standard Opening: " + standardOpening.OpeningId + " within the allowable tolerance."); } //check the height if (heightDiffefence <= DOEgbXMLBasics.Tolerances.OpeningHeightTolerance) { if (heightDiffefence == 0) { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Height value matches the Height value of the standard Opening: " + standardOpening.OpeningId + " exactly."); possibleMatches2.Add(testOpening); } else { report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Height value matches the Height value of the standard Opening: " + standardOpening.OpeningId + " within the allowable tolerance."); possibleMatches2.Add(testOpening); } } else { //fail, did not match height report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + "The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " after comparison its Height value with test opening: " + testOpening.OpeningId); report.passOrFail = false; continue; } } else { //failed, did not match width report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + " cannot find a match for its width after comparison the width value of test Opening: " + testOpening.OpeningId); report.passOrFail = false; continue; } } else { //let them know the the test opening is not a square or rectangle, but the standard file opening is //go ahead and break out of the while loop because we aren't testing for width and height report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + " is a rectangle or square, but the test file Opening: " + standardOpening.OpeningId + " is not. Cannot test for a valid width and height."); report.MessageList.Add("Searching for another test Opening."); continue; } } else { //tell them that the widths and Heights will Not be checked //because the standard file opening is not a square or rectangle report.MessageList.Add("Will not be testing for the Width and Height values for standard Opening: " + standardOpening.OpeningId + ". The Opening is not shaped like a rectangle or square."); report.MessageList.Add("Going on to check insertion point accuracy."); //needed to transfer values over to possibleMatches2, so deep copy possibleMatches2 = new List<OpeningDefinitions>(possibleMatches); break; } i++; if (possibleMatches.Count == i) { //means that there is no match for width and height if (possibleMatches2.Count == 0) { report.MessageList.Add("There is no match found for the width and height for Opening: " + standardOpening.OpeningId); report.passOrFail = false; report.longMsg = "The opening test has ended at the search for width and height values equal to standard Opening: " + standardOpening.OpeningId; return report; } break; } } report.MessageList.Add("</br>"); report.MessageList.Add("Starting Insertion Point Coordinate Match test........."); possibleMatches.Clear(); //test the insertion point coordinates i = 0; while (true) { OpeningDefinitions testOpening = possibleMatches2[i]; double diffX = Math.Abs(testOpening.InsertionPoint.X - standardOpening.InsertionPoint.X); double diffY = Math.Abs(testOpening.InsertionPoint.Y - standardOpening.InsertionPoint.Y); double diffZ = Math.Abs(testOpening.InsertionPoint.Z - standardOpening.InsertionPoint.Z); if (diffX <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtXTolerance && diffY <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtYTolerance && diffZ <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtZTolerance) { if (diffX == 0) { //perfect X coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point X-Coordinate when compared with test Opening: " + testOpening.OpeningId); if (diffY == 0) { //perfect Y coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId); if (diffZ == 0) { //perfect Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); possibleMatches.Add(testOpening); } else { // Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with Test opening: " + testOpening.OpeningId); //we continue because we search for other matches if there are any possibleMatches.Add(testOpening); } } else { //y-coordinate is within tolerance report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Y-Coordinate when compared with Test opening: " + testOpening.OpeningId); if (diffZ == 0) { //perfect Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with Test opening: " + testOpening.OpeningId); possibleMatches.Add(testOpening); } else { //perfect Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); //we continue because we search for other matches if there are any possibleMatches.Add(testOpening); } } } // X is within tolerance else { report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point X-Coordinate when compared with test Opening: " + testOpening.OpeningId); if (diffY == 0) { //perfect Y coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId); if (diffZ == 0) { //perfect Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); possibleMatches.Add(testOpening); } else { //perfect Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); //we continue because we search for other matches if there are any possibleMatches.Add(testOpening); } } else { //y-coordinate is within tolerance report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId); if (diffZ == 0) { //perfect Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); possibleMatches.Add(testOpening); } else { //perfect Z coordinate match report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); //we continue because we search for other matches if there are any possibleMatches.Add(testOpening); } } } } report.MessageList.Add("Standard Opening Ins Pt: (" + standardOpening.InsertionPoint.X.ToString() + "," + standardOpening.InsertionPoint.Y.ToString() + "," + standardOpening.InsertionPoint.Z.ToString() + ")"); report.MessageList.Add("Test File Opening Ins Pt: (" + testOpening.InsertionPoint.X.ToString() + "," + testOpening.InsertionPoint.Y.ToString() + "," + testOpening.InsertionPoint.Z.ToString() + ")"); i++; if (possibleMatches2.Count == i) { if (possibleMatches.Count == 1) { List<string> openingMatch = new List<string>(); openingMatch.Add(possibleMatches[0].OpeningId); report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " is matched to test file Opening: " + testOpening.OpeningId); globalMatchObject.MatchedOpeningIds.Add(standardOpening.OpeningId, openingMatch); report.passOrFail = true; return report; } else { if (possibleMatches.Count == 0) { report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " found no match for insertion point in the test file of the remaining candidates."); report.passOrFail = false; return report; } else { report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " is matched to multiple openings:"); foreach (OpeningDefinitions opening in possibleMatches) { report.MessageList.Add("Test Opening:" + opening.OpeningId + "matched insertion point"); } //resolve by trying to match to the standard opening and test opening parent surfaces. //for the standard opening if (globalMatchObject.MatchedSurfaceIds.ContainsKey(standardOpening.ParentSurfaceId)) { List<string> possibleSurfaceMatches = globalMatchObject.MatchedSurfaceIds[standardOpening.ParentSurfaceId]; if (possibleSurfaceMatches.Count == 1) { //then a match was found originally during get possible surface matches. That is good, we only want one foreach (OpeningDefinitions openingRemaining in possibleMatches) { if (openingRemaining.ParentSurfaceId == possibleSurfaceMatches[0]) { //this is the match we want //else we would have to continue report.MessageList.Add("The test Opening: " + openingRemaining.OpeningId + " has been matched to the standard Opening: " + standardOpening.OpeningId + ". Their parent surface ids have been matched. Thus the conflict has been resolved. (Standard opening parent surface Id, test opening parent surface Id" + standardOpening.ParentSurfaceId + "," + openingRemaining.ParentSurfaceId); report.passOrFail = true; List<string> openingMatch = new List<string>(); openingMatch.Add(possibleMatches[0].OpeningId); globalMatchObject.MatchedOpeningIds.Add(standardOpening.OpeningId, openingMatch); return report; } else { //do nothing. Maybe report that the parent Surface Id does not match the standard Opening report.MessageList.Add("Test Opening:" + openingRemaining.OpeningId + " does not match the standard Opening: " + standardOpening.OpeningId + ". Their parent surface ids do not coincide. (Standard Opening parent surface id, test Opening parent surface id)" + standardOpening.ParentSurfaceId + "," + openingRemaining.ParentSurfaceId); } } } } report.passOrFail = false; return report; } } } } //finished } catch (Exception e) { report.longMsg = e.ToString(); } return report; }