//this is a support tool for TestShellGeomPLRHR public static Dictionary<string, List<VectorMath.Vector.MemorySafe_CartCoord>> GetShellGeomPts(XmlNode closedShell) { Dictionary<string, List<VectorMath.Vector.MemorySafe_CartCoord>> PtsDict = new Dictionary<string, List<Vector.MemorySafe_CartCoord>>(); string spaceId = "none"; int cartPtCount; try { //get the name of the space for which this point is defined XmlNode spaceNode = closedShell.ParentNode; XmlAttributeCollection spaceAtts = spaceNode.Attributes; foreach (XmlAttribute at in spaceAtts) { if (at.Name == "id") { spaceId = at.Value; break; } } //keep track of the number of polyloops in the closed shell int pLCount = 1; //store the geometry points foreach (XmlNode PolyLoops in closedShell) { List<VectorMath.Vector.MemorySafe_CartCoord> vCoords = new List<VectorMath.Vector.MemorySafe_CartCoord>(); List<Vector.CartCoord> PtsList = new List<Vector.CartCoord>(); cartPtCount = 0; foreach (XmlNode cartesianPoints in PolyLoops) { //reset surface area and unitRHR (this is how I know that there may be a problem //and these values are returned as points. It is not perfect Vector.CartCoord Pts = new Vector.CartCoord(); Pts.X = -999; Pts.Y = -999; Pts.Z = -999; PtsList.Add(Pts); int crdCount = 1; //gets a set of XYZ coordinates, one at a time foreach (XmlNode coordinate in cartesianPoints.ChildNodes) { double coord = Convert.ToDouble(coordinate.InnerText); switch (crdCount) { case 1: PtsList[cartPtCount].X = coord; break; case 2: PtsList[cartPtCount].Y = coord; break; case 3: PtsList[cartPtCount].Z = coord; break; default: break; } crdCount++; } cartPtCount++; } string spaceSurface = spaceId + "/" + pLCount.ToString(); //create memory safe points list List<Vector.MemorySafe_CartCoord> mptsList = new List<Vector.MemorySafe_CartCoord>(); foreach(Vector.CartCoord cd in PtsList) { mptsList.Add(new Vector.MemorySafe_CartCoord(cd.X, cd.Y, cd.Z)); } PtsDict.Add(spaceSurface, mptsList); pLCount++; //PtsList.Clear(); } } catch (Exception e) { } //I may want to test the number of coordinates to make sure it matches, or if it has a minimum number of coords return PtsDict; }
//<Get Surface Definitions in a gbXML file> //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation //This method will take each surface element and convert the xml language into an instance of a SurfaceDefinition //Each surface is converted in this way, with the resulting instance being stored in a list that is returned for later use //----------------------</p> //This is an important method because it stores all of the information about a surface in a gbXML file in a list //This list can later be recalled to perform analytics on the surfaces and the data contained within private static List<SurfaceDefinitions> GetFileSurfaceDefs(XmlDocument xmldoc, XmlNamespaceManager xmlns) { List<SurfaceDefinitions> surfaces = new List<SurfaceDefinitions>(); try { XmlNodeList nodes = xmldoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", xmlns); foreach (XmlNode surfaceNode in nodes) { //initialize a new instance of the class SurfaceDefinitions surfDef = new SurfaceDefinitions(); surfDef.AdjSpaceId = new List<string>(); surfDef.PlCoords = new List<Vector.MemorySafe_CartCoord>(); //get id and surfaceType XmlAttributeCollection spaceAtts = surfaceNode.Attributes; foreach (XmlAttribute at in spaceAtts) { if (at.Name == "id") { surfDef.SurfaceId = at.Value; } else if (at.Name == "surfaceType") { surfDef.SurfaceType = at.Value; } } if (surfaceNode.HasChildNodes) { XmlNodeList surfChildNodes = surfaceNode.ChildNodes; foreach (XmlNode node in surfChildNodes) { if (node.Name == "AdjacentSpaceId") { XmlAttributeCollection adjSpaceIdAt = node.Attributes; foreach (XmlAttribute at in adjSpaceIdAt) { if (at.Name == "spaceIdRef") { surfDef.AdjSpaceId.Add(at.Value); } } } else if (node.Name == "RectangularGeometry") { if (node.HasChildNodes) { XmlNodeList rectGeomChildren = node.ChildNodes; foreach (XmlNode rgChildNode in rectGeomChildren) { if (rgChildNode.Name == "Azimuth") { surfDef.Azimuth = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "CartesianPoint") { if (rgChildNode.HasChildNodes) { Vector.CartCoord cd = new Vector.CartCoord(); XmlNodeList coordinates = rgChildNode.ChildNodes; int pointCount = 1; foreach (XmlNode coordinate in coordinates) { switch (pointCount) { case 1: cd.X = Convert.ToDouble(coordinate.InnerText); break; case 2: cd.Y = Convert.ToDouble(coordinate.InnerText); break; case 3: cd.Z = Convert.ToDouble(coordinate.InnerText); break; } pointCount++; } surfDef.InsertionPoint = new VectorMath.Vector.MemorySafe_CartCoord(cd.X, cd.Y, cd.Z); } } else if (rgChildNode.Name == "Tilt") { surfDef.Tilt = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "Height") { surfDef.Height = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "Width") { surfDef.Width = Convert.ToDouble(rgChildNode.InnerText); } } } } else if (node.Name == "PlanarGeometry") { XmlNode polyLoop = node.FirstChild; if (polyLoop.HasChildNodes) { XmlNodeList cartesianPoints = polyLoop.ChildNodes; foreach (XmlNode coordinatePt in cartesianPoints) { Vector.CartCoord coord = new Vector.CartCoord(); if (coordinatePt.HasChildNodes) { XmlNodeList coordinates = coordinatePt.ChildNodes; int pointCount = 1; foreach (XmlNode coordinate in coordinatePt) { switch (pointCount) { case 1: coord.X = Convert.ToDouble(coordinate.InnerText); break; case 2: coord.Y = Convert.ToDouble(coordinate.InnerText); break; case 3: coord.Z = Convert.ToDouble(coordinate.InnerText); break; } pointCount++; } surfDef.PlCoords.Add(new Vector.MemorySafe_CartCoord(coord.X, coord.Y, coord.Z)); } } } } } } Vector.MemorySafe_CartVect plRHRVect = GetPLRHR(surfDef.PlCoords); surfDef.PlRHRVector = new Vector.MemorySafe_CartVect(plRHRVect.X,plRHRVect.Y,plRHRVect.Z); surfaces.Add(surfDef); } return surfaces; } catch (Exception e) { return surfaces; } }
public static LLRet GetLLForRoof(List<Vector.MemorySafe_CartCoord> surfacecoords) { LLRet ll = new LLRet(); ll.indices = new List<int>(); int surfindex = -1; CartesianPoint cp = new CartesianPoint(); Vector.CartCoord llsurf = new Vector.CartCoord(); Vector.MemorySafe_CartVect RHRVector = Vector.GetMemRHR(surfacecoords); if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == 1) { for (int sccount = 0; sccount < surfacecoords.Count; sccount++) { if (sccount == 0) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; continue; } //get lower left...most low(largest Y), then most left (smallest X) if (surfacecoords[sccount].Y >= llsurf.Y) { if (surfacecoords[sccount].X < llsurf.X) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; } } } } else { //special procedure for this type of roof } Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(llsurf.X, llsurf.Y, llsurf.Z); cp = makegbCartesianPt(LLeft); ll.cp = cp; ll.indices.Add(surfindex); return ll; }
private List<OpeningDefinitions> GetFileOpeningDefs(XmlDocument TestFile, XmlNamespaceManager TestNSM) { List<OpeningDefinitions> openings = new List<OpeningDefinitions>(); try { XmlNodeList nodes = TestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", TestNSM); foreach (XmlNode openingNode in nodes) { //initialize a new instance of the class OpeningDefinitions openingDef = new OpeningDefinitions(); openingDef.PlCoords = new List<Vector.MemorySafe_CartCoord>(); //get parent id XmlAttributeCollection parentSurfaceAttributes = openingNode.ParentNode.Attributes; foreach (XmlAttribute parentAt in parentSurfaceAttributes) { if (parentAt.Name == "id") { openingDef.ParentSurfaceId = parentAt.Value; break; } } //get Parent Azimuth and Tilt XmlNode surfaceParentNode = openingNode.ParentNode; if (surfaceParentNode.HasChildNodes) { XmlNodeList surfaceParentNodesChillun = surfaceParentNode.ChildNodes; foreach (XmlNode chileNode in surfaceParentNodesChillun) { if (chileNode.Name == "RectangularGeometry") { if (chileNode.HasChildNodes) { foreach (XmlNode grandchileNode in chileNode) { if (grandchileNode.Name == "Tilt") { openingDef.ParentTilt = Convert.ToDouble(grandchileNode.InnerText); } else if (grandchileNode.Name == "Azimuth") { openingDef.ParentAzimuth = Convert.ToDouble(grandchileNode.InnerText); } } } } } } else { } //get surface Id and Opening Type XmlAttributeCollection openingAtts = openingNode.Attributes; foreach (XmlAttribute at in openingAtts) { if (at.Name == "id") { openingDef.OpeningId = at.Value; } else if (at.Name == "openingType") { openingDef.OpeningType = at.Value; } } if (openingNode.HasChildNodes) { XmlNodeList surfChildNodes = openingNode.ChildNodes; foreach (XmlNode node in surfChildNodes) { if (node.Name == "RectangularGeometry") { if (node.HasChildNodes) { XmlNodeList rectGeomChildren = node.ChildNodes; foreach (XmlNode rgChildNode in rectGeomChildren) { if (rgChildNode.Name == "Azimuth") { openingDef.Azimuth = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "CartesianPoint") { if (rgChildNode.HasChildNodes) { XmlNodeList coordinates = rgChildNode.ChildNodes; int pointCount = 1; Vector.CartCoord od = new Vector.CartCoord(); foreach (XmlNode coordinate in coordinates) { switch (pointCount) { case 1: od.X = Convert.ToDouble(coordinate.InnerText); break; case 2: od.Y = Convert.ToDouble(coordinate.InnerText); break; case 3: od.Z = Convert.ToDouble(coordinate.InnerText); break; } pointCount++; } openingDef.InsertionPoint = new Vector.MemorySafe_CartCoord(od.X, od.Y, od.Z); } } else if (rgChildNode.Name == "Tilt") { openingDef.Tilt = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "Height") { openingDef.Height = Convert.ToDouble(rgChildNode.InnerText); } else if (rgChildNode.Name == "Width") { openingDef.Width = Convert.ToDouble(rgChildNode.InnerText); } } } } else if (node.Name == "PlanarGeometry") { XmlNode polyLoop = node.FirstChild; if (polyLoop.HasChildNodes) { XmlNodeList cartesianPoints = polyLoop.ChildNodes; foreach (XmlNode coordinatePt in cartesianPoints) { Vector.CartCoord coord = new Vector.CartCoord(); if (coordinatePt.HasChildNodes) { XmlNodeList coordinates = coordinatePt.ChildNodes; int pointCount = 1; foreach (XmlNode coordinate in coordinatePt) { switch (pointCount) { case 1: coord.X = Convert.ToDouble(coordinate.InnerText); break; case 2: coord.Y = Convert.ToDouble(coordinate.InnerText); break; case 3: coord.Z = Convert.ToDouble(coordinate.InnerText); break; } pointCount++; } openingDef.PlCoords.Add(new Vector.MemorySafe_CartCoord(coord.X,coord.Y,coord.Z)); } } } } } } Vector.MemorySafe_CartVect plRHRVect = GetPLRHR(openingDef.PlCoords); openingDef.PlRHRVector = new Vector.MemorySafe_CartVect(plRHRVect.X, plRHRVect.Y, plRHRVect.Z); //may want to forego the above since the orientation is embedded in the parent object. It may be smarter to just include the azimuth and tilt of the parent object? openings.Add(openingDef); } return openings; } catch (Exception e) { return openings; } }
//April 14, 2014 - Deprecated as not useful or within scope //private static Dictionary<Vector.CartCoord, Tuple<List<string>, List<bool>>> GetSBVertices(XmlNamespaceManager nsm, XmlDocument zexml) //{ // Dictionary<Vector.CartCoord,Tuple<List<string>,List<bool>>> sbdict = new Dictionary<Vector.CartCoord, Tuple<List<string>,List<bool>>>(); // //get each space boundary // XmlNodeList nodes = zexml.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:SpaceBoundary", nsm); // int sbcount = 0; // foreach (XmlNode sbnode in nodes) // { // //record the name of the space boundary // string sbname=""; // XmlAttributeCollection spaceAtts = sbnode.Attributes; // foreach (XmlAttribute at in spaceAtts) // { // if (at.Name == "surfaceIdRef") // { // sbname = at.Value; // break; // } // } // //create list of unique vertices // XmlNode closedshell = sbnode.FirstChild; // XmlNode PL = closedshell.FirstChild; // foreach (XmlNode cp in PL) // { // if (cp.Name == "CartesianPoint") // { // sbdict = AddCoordinate(sbcount, sbname, sbdict, cp); // } // } // //XmlNodeList cnodes = sbnode.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:SpaceBoundary/gbXMLv5:PlanarGeometry//gbXMLv5:PolyLoop", nsm); // sbcount++; // } // return sbdict; //} //private static Dictionary<Vector.CartCoord, Tuple<List<string>, List<bool>>> GetSurfVertices(XmlNamespaceManager nsm, XmlDocument zexml) //{ // Dictionary<Vector.CartCoord, Tuple<List<string>, List<bool>>> surfdict = new Dictionary<Vector.CartCoord, Tuple<List<string>, List<bool>>>(); // //get each space boundary // XmlNodeList nodes = zexml.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", nsm); // int surfcount = 0; // foreach (XmlNode surfnode in nodes) // { // //record the name of the space boundary // string surfname = ""; // XmlAttributeCollection spaceAtts = surfnode.Attributes; // foreach (XmlAttribute at in spaceAtts) // { // if (at.Name == "id") // { // surfname = at.Value; // break; // } // } // //create list of unique vertices // foreach (XmlNode childnode in surfnode) // { // if (childnode.Name == "PlanarGeometry") // { // XmlNode PL = childnode.FirstChild; // foreach (XmlNode cp in PL) // { // if (cp.Name == "CartesianPoint") // { // surfdict = AddCoordinate(surfcount, surfname, surfdict, cp); // } // } // surfcount++; // } // } // } // return surfdict; //} private static Vector.CartCoord makeCoord(XmlNode cartesianPoint) { Vector.CartCoord coordinst = new Vector.CartCoord(); if (cartesianPoint.HasChildNodes) { XmlNodeList coordinates = cartesianPoint.ChildNodes; int pointCount = 1; foreach (XmlNode coordinate in coordinates) { switch (pointCount) { case 1: coordinst.X = Convert.ToDouble(coordinate.InnerText); break; case 2: coordinst.Y = Convert.ToDouble(coordinate.InnerText); break; case 3: coordinst.Z = Convert.ToDouble(coordinate.InnerText); break; } pointCount++; } } return coordinst; }
//Reminder to factor in CADAzimuth if appropriate public static LLRet GetLLForOpening(List<Vector.MemorySafe_CartCoord> surfacecoords, List<Vector.MemorySafe_CartCoord> openingcoords) { LLRet ll = new LLRet(); ll.indices = new List<int>(); int surfindex=-1; int opindex=-1; CartesianPoint cp = new CartesianPoint(); //we want to verify that this is indeed correct //west-facing Vector.MemorySafe_CartVect RHRVector = Vector.GetMemRHR(surfacecoords); if (Math.Abs(RHRVector.X) == -1 && RHRVector.Y == 0 && RHRVector.Z == 0) { Vector.CartCoord llsurf = new Vector.CartCoord(); for (int sccount = 0; sccount < surfacecoords.Count; sccount++) { if (sccount == 0) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; continue; } //get lower left...most lowest(smallest Z), then most left (largest Y) if (surfacecoords[sccount].Z <= llsurf.Z) { if(surfacecoords[sccount].Y > llsurf.Y) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; } } } Vector.CartCoord llopening = new Vector.CartCoord(); for (int occount = 0; occount < openingcoords.Count; occount++) { if (occount == 0) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; continue; } //get lower left...most low(lowest Z), then most left (largest Y) if (openingcoords[occount].Z <= llopening.Z) { if(openingcoords[occount].Y > llopening.Y) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; } } } double diffX = Math.Abs(llsurf.Y - llopening.Y); double diffY = Math.Abs(llopening.Z - llsurf.Z); Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0); cp = makegbCartesianPt(LLeft); } //north-facing else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 1 && RHRVector.Z == 0) { Vector.CartCoord llsurf = new Vector.CartCoord(); for (int sccount = 0; sccount < surfacecoords.Count; sccount++) { if (sccount == 0) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; continue; } //get lower left...most low(smallest Z), then most left (largest X) if (surfacecoords[sccount].Z <= llsurf.Z) { if(surfacecoords[sccount].X > llsurf.X) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; } } } Vector.CartCoord llopening = new Vector.CartCoord(); for (int occount = 0; occount < openingcoords.Count; occount++) { if (occount == 0) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; continue; } //get lower left...most low(smallest Z), then most left (largest X) if (openingcoords[occount].Z <= llopening.Z) { if(openingcoords[occount].X > llopening.X) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; } } } double diffX = Math.Abs(llsurf.X - llopening.X); double diffY = Math.Abs(llsurf.Z - llopening.Z); Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0); cp= makegbCartesianPt(LLeft); } //south-facing else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == -1 && RHRVector.Z == 0) { Vector.CartCoord llsurf = new Vector.CartCoord(); for (int sccount = 0; sccount < surfacecoords.Count; sccount++) { if (sccount == 0) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; continue; } //get lower left...most low(smaller Z), then most left (smallest X) if (surfacecoords[sccount].Z <= llsurf.Z) { if(surfacecoords[sccount].X < llsurf.X) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; } } } Vector.CartCoord llopening = new Vector.CartCoord(); for (int occount = 0; occount < openingcoords.Count; occount++) { if (occount == 0) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; continue; } //get lower left...most low(smallest Z), then most left (smallest X) if (openingcoords[occount].Z <= llopening.Z) { if(openingcoords[occount].X < llopening.X) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; } } } double diffX = Math.Abs(llsurf.X - llopening.X); double diffY = Math.Abs(llsurf.Z - llopening.Z); Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0); cp = makegbCartesianPt(LLeft); } //east-facing else if (Math.Abs(RHRVector.X) == 1 && RHRVector.Y == 0 && RHRVector.Z == 0) { Vector.CartCoord llsurf = new Vector.CartCoord(); for (int sccount = 0; sccount < surfacecoords.Count; sccount++) { if (sccount == 0) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; continue; } //get lower left...most low(smaller Z), then most left (smallest Y) if (surfacecoords[sccount].Z <= llsurf.Z) { if(surfacecoords[sccount].Y < llsurf.Y) { llsurf.X = surfacecoords[sccount].X; llsurf.Y = surfacecoords[sccount].Y; llsurf.Z = surfacecoords[sccount].Z; surfindex = sccount; } } } Vector.CartCoord llopening = new Vector.CartCoord(); for (int occount = 0; occount < openingcoords.Count; occount++) { if (occount == 0) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; continue; } //get lower left...most low(smallest Z), then most left (smallest Y) if (openingcoords[occount].Z <= llopening.Z) { if(openingcoords[occount].Y < llopening.Y) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; } } } double diffX = Math.Abs(llsurf.Y - llopening.Y); double diffY = Math.Abs(llsurf.Z - llopening.Z); Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX,diffY,0); cp = makegbCartesianPt(LLeft); } //floors else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == -1) { Vector.CartCoord llsurf = new Vector.CartCoord(); LLRet llroof = GetLLForFloor(surfacecoords); llsurf.X = Convert.ToDouble(llroof.cp.Coordinate[0]); llsurf.Y = Convert.ToDouble(llroof.cp.Coordinate[1]); llsurf.Z = Convert.ToDouble(llroof.cp.Coordinate[2]); surfindex = llroof.indices[0]; Vector.CartCoord llopening = new Vector.CartCoord(); for (int occount = 0; occount < openingcoords.Count; occount++) { if (occount == 0) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; continue; } //get lower left...most low(smallest Y), then most left (largest X) if (openingcoords[occount].Y <= llopening.Y) { if (openingcoords[occount].X > llopening.X) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; } } } double diffX = Math.Abs(llsurf.X - llopening.X); double diffY = Math.Abs(llsurf.Y - llopening.Y); Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0); cp = makegbCartesianPt(LLeft); } //flat roof else if (Math.Abs(RHRVector.X) == 0 && RHRVector.Y == 0 && RHRVector.Z == 1) { Vector.CartCoord llsurf = new Vector.CartCoord(); LLRet llroof = GetLLForRoof(surfacecoords); llsurf.X = Convert.ToDouble(llroof.cp.Coordinate[0]); llsurf.Y = Convert.ToDouble(llroof.cp.Coordinate[1]); llsurf.Z = Convert.ToDouble(llroof.cp.Coordinate[2]); surfindex = llroof.indices[0]; Vector.CartCoord llopening = new Vector.CartCoord(); for (int occount = 0; occount < openingcoords.Count; occount++) { if (occount == 0) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; continue; } //get lower left...most low(largest Y), then most left (smallest X) if (openingcoords[occount].Y >= llopening.Y) { if (openingcoords[occount].X < llopening.X) { llopening.X = openingcoords[occount].X; llopening.Y = openingcoords[occount].Y; llopening.Z = openingcoords[occount].Z; opindex = occount; } } } double diffX = Math.Abs(llsurf.X - llopening.X); double diffY = Math.Abs(llsurf.Y - llopening.Y); Vector.MemorySafe_CartCoord LLeft = new Vector.MemorySafe_CartCoord(diffX, diffY, 0); cp = makegbCartesianPt(LLeft); } //plane does not reside on a primary axis else { //I will deal with this later //have to factor in what is a "roof" or "floor" or "wall" based on the default tilt settings } ll.cp = cp; ll.indices.Add(surfindex); ll.indices.Add(opindex); return ll; }
//April 11, 2014 //This is the algorithm that attempts to find matches of edges on the enclosure. It is used by all the Check Enclosure routines. //by Chien Harriman - Carmel Software Corporation public static DOEgbXMLPhase2Report MatchEdges(Dictionary<int, Vector.EdgeFamily> uniqueedges, List<string> ml, DOEgbXMLPhase2Report report, string spaceid) { try { int totaledgect = 0; int matchededges = 0; string lastedgenm = ""; int surfedgect = 0; foreach (KeyValuePair<int, Vector.EdgeFamily> edgekp in uniqueedges) { //a way to count edges if (edgekp.Value.sbdec != lastedgenm) { //reset lastedgenm = edgekp.Value.sbdec; surfedgect = 0; } //here is the easiest case where there is only one related edge //we know this must be a perfect match, or entirely envelopes the edge if (edgekp.Value.relatedEdges.Count() == 1) { Vector.MemorySafe_CartCoord edgestart = edgekp.Value.startendpt[0]; Vector.MemorySafe_CartCoord edgeend = edgekp.Value.startendpt[1]; Vector.MemorySafe_CartCoord relstart = edgekp.Value.relatedEdges[0].startendpt[0]; Vector.MemorySafe_CartCoord relend = edgekp.Value.relatedEdges[0].startendpt[1]; //if the lengths are the same, then they should match perfectly. //this is a valid conclusion because we already have identified that they aligh and //are in the same space. double edgeX = edgestart.X - edgeend.X; double edgeY = edgestart.Y - edgeend.Y; double edgeZ = edgestart.Z - edgeend.Z; Vector.MemorySafe_CartVect edgev = new Vector.MemorySafe_CartVect(edgeX, edgeY, edgeZ); double edgemag = Vector.VectorMagnitude(edgev); double relX = relstart.X - relend.X; double relY = relstart.Y - relend.Y; double relZ = relstart.Z - relend.Z; Vector.MemorySafe_CartVect relv = new Vector.MemorySafe_CartVect(relX, relY, relZ); double relmag = Vector.VectorMagnitude(relv); //do the check here to see if the two edges (current and related) are the same length if (Math.Abs(relmag - edgemag) < report.coordtol) { //should match perfectly ml.Add(edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " should have perfectly matched coordinates."); List<bool> match = new List<bool>(); double tol = report.tolerance; for (int i = 0; i < 2; i++) { Vector.MemorySafe_CartCoord p1 = edgekp.Value.relatedEdges[0].startendpt[i]; for (int j = 0; j < 2; j++) { string x = p1.X.ToString(); string y = p1.Y.ToString(); string z = p1.Z.ToString(); string coordstr = "(" + x + "," + y + "," + z + ")"; Vector.MemorySafe_CartCoord p2 = edgekp.Value.startendpt[j]; if (p2.X == p1.X && p2.Y == p1.Y && p2.Z == p1.Z) { match.Add(true); ml.Add("PERFECT MATCH: " + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " Coordinate " + coordstr); } else if (Math.Abs(p2.X - p1.X) < tol && Math.Abs(p2.Y - p1.Y) < report.coordtol && Math.Abs(p2.Z - p1.Z) < report.coordtol) { match.Add(true); ml.Add("MATCH: " + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " Coordinate " + coordstr); report.passOrFail = false; } } } if (match.Count() == 2) { ml.Add("PASS: "******" Edge " + surfedgect.ToString() + " forms a tight enclosure with its neighbor."); report.passOrFail = true; //we +2 here because the related edge is not recorded totaledgect += 2; matchededges += 2; } else { ml.Add("FAIL: " + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " does not form a tight enclosure with its neighbor."); report.passOrFail = false; //we +2 here because the related edge is not recorded totaledgect += 2; matchededges += 0; } } //April 7 2014 //it is safe to conclude that the the two are related, but they overlap. In this case, since there is only one neighbor //it should be the case that one edge entirely envelops the other edge. //this edge, has to be the one that is enveloped, because it only has one related edge, by convention else { ml.Add(edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " should be enclosed by its neighboring edge."); //es--------------ee //rs-------------------re if (Math.Abs(edgestart.X - relstart.X) <= report.coordtol && Math.Abs(edgestart.Y - relstart.Y) <= report.coordtol && Math.Abs(edgestart.Z - relstart.Z) <= coordtol) { string x = edgestart.X.ToString(); string y = edgestart.Y.ToString(); string z = edgestart.Z.ToString(); string coordstr = "(" + x + "," + y + "," + z + ")"; ml.Add("MATCH: " + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " Coordinate " + coordstr); double Cx = edgeend.X - relstart.X; double Cy = edgeend.Y - relstart.Y; double Cz = edgeend.Z - relstart.Z; Vector.MemorySafe_CartVect C = new Vector.MemorySafe_CartVect(Cx, Cy, Cz); double Dx = edgeend.X - relend.X; double Dy = edgeend.Y - relend.Y; double Dz = edgeend.Z - relend.Z; Vector.MemorySafe_CartVect D = new Vector.MemorySafe_CartVect(Dx, Dy, Dz); double dotend = Vector.DotProductMag(C, D); //both of these dot products should point in opposite directions, proving the edge is entirely enveloped if (Math.Abs(dotend) - 1 <= report.vectorangletol) { ml.Add("PASS" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor forms a tight enclosure with its neighbor."); } else { ml.Add("FAIL" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + "overlapping neighbor does not form a tight enclosure with its neighbor."); report.passOrFail = false; } } //es-----------------ee //re--------------------------rs else if (Math.Abs(edgestart.X - relend.X) <= report.coordtol && Math.Abs(edgestart.Y - relend.Y) <= report.coordtol && Math.Abs(edgestart.Z - relend.Z) <= coordtol) { string x = edgestart.X.ToString(); string y = edgestart.Y.ToString(); string z = edgestart.Z.ToString(); string coordstr = "(" + x + "," + y + "," + z + ")"; ml.Add("MATCH: " + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " Coordinate " + coordstr); double Cx = edgeend.X - relstart.X; double Cy = edgeend.Y - relstart.Y; double Cz = edgeend.Z - relstart.Z; Vector.MemorySafe_CartVect C = new Vector.MemorySafe_CartVect(Cx, Cy, Cz); double Dx = edgeend.X - relend.X; double Dy = edgeend.Y - relend.Y; double Dz = edgeend.Z - relend.Z; Vector.MemorySafe_CartVect D = new Vector.MemorySafe_CartVect(Dx, Dy, Dz); double dotend = Vector.DotProductMag(C, D); //both of these dot products should point in opposite directions, proving the edge is entirely enveloped if (Math.Abs(dotend) - 1 <= report.vectorangletol) { ml.Add("PASS" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor forms a tight enclosure with its neighbor."); totaledgect += 1; matchededges += 1; } else { ml.Add("FAIL" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor does not form a tight enclosure with its neighbor."); report.passOrFail = false; totaledgect += 1; matchededges += 0; } } //ee-----------------es //rs--------------------------re else if (Math.Abs(edgeend.X - relstart.X) <= report.coordtol && Math.Abs(edgeend.Y - relstart.Y) <= report.coordtol && Math.Abs(edgeend.Z - relstart.Z) <= coordtol) { string x = edgeend.X.ToString(); string y = edgeend.Y.ToString(); string z = edgeend.Z.ToString(); string coordstr = "(" + x + "," + y + "," + z + ")"; ml.Add("MATCH: " + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " Coordinate " + coordstr); double Ax = edgestart.X - relstart.X; double Ay = edgestart.Y - relstart.Y; double Az = edgestart.Z - relstart.Z; Vector.MemorySafe_CartVect A = new Vector.MemorySafe_CartVect(Ax, Ay, Az); double Bx = edgestart.X - relend.X; double By = edgestart.Y - relend.Y; double Bz = edgestart.Z - relend.Z; Vector.MemorySafe_CartVect B = new Vector.MemorySafe_CartVect(Bx, By, Bz); double dotstart = Vector.DotProductMag(A, B); //both of these dot products should point in opposite directions, proving the edge is entirely enveloped if (Math.Abs(dotstart) - 1 <= report.vectorangletol) { ml.Add("PASS" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor forms a tight enclosure with its neighbor."); totaledgect += 1; matchededges += 1; } else { ml.Add("FAIL" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor does not form a tight enclosure with its neighbor."); report.passOrFail = false; totaledgect += 1; matchededges += 0; } } //ee-----------------es //re--------------------------rs else if (Math.Abs(edgeend.X - relend.X) <= report.coordtol && Math.Abs(edgeend.Y - relend.Y) <= report.coordtol && Math.Abs(edgeend.Z - relend.Z) <= coordtol) { string x = edgeend.X.ToString(); string y = edgeend.Y.ToString(); string z = edgeend.Z.ToString(); string coordstr = "(" + x + "," + y + "," + z + ")"; ml.Add("MATCH: " + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " Coordinate " + coordstr); double Ax = edgestart.X - relstart.X; double Ay = edgestart.Y - relstart.Y; double Az = edgestart.Z - relstart.Z; Vector.MemorySafe_CartVect A = new Vector.MemorySafe_CartVect(Ax, Ay, Az); double Bx = edgestart.X - relend.X; double By = edgestart.Y - relend.Y; double Bz = edgestart.Z - relend.Z; Vector.MemorySafe_CartVect B = new Vector.MemorySafe_CartVect(Bx, By, Bz); double dotstart = Vector.DotProductMag(A, B); //both of these dot products should point in opposite directions, proving the edge is entirely enveloped if (Math.Abs(dotstart) - 1 <= report.vectorangletol) { ml.Add("PASS" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor forms a tight enclosure with its neighbor."); totaledgect += 1; matchededges += 1; } else { ml.Add("FAIL" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor does not form a tight enclosure with its neighbor."); report.passOrFail = false; totaledgect += 1; matchededges += 0; } } //overlapping edges else { ml.Add(edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " is overlapped at both ends by its neighboring edge."); double Ax = edgestart.X - relstart.X; double Ay = edgestart.Y - relstart.Y; double Az = edgestart.Z - relstart.Z; Vector.MemorySafe_CartVect A = new Vector.MemorySafe_CartVect(Ax, Ay, Az); double Bx = edgestart.X - relend.X; double By = edgestart.Y - relend.Y; double Bz = edgestart.Z - relend.Z; Vector.MemorySafe_CartVect B = new Vector.MemorySafe_CartVect(Bx, By, Bz); double Cx = edgeend.X - relstart.X; double Cy = edgeend.Y - relstart.Y; double Cz = edgeend.Z - relstart.Z; Vector.MemorySafe_CartVect C = new Vector.MemorySafe_CartVect(Cx, Cy, Cz); double Dx = edgeend.X - relend.X; double Dy = edgeend.Y - relend.Y; double Dz = edgeend.Z - relend.Z; Vector.MemorySafe_CartVect D = new Vector.MemorySafe_CartVect(Dx, Dy, Dz); double dotstart = Vector.DotProductMag(A, B); double dotend = Vector.DotProductMag(C, D); //both of these dot products should point in opposite directions, proving the edge is entirely enveloped if (Math.Abs(dotstart) - 1 <= report.vectorangletol && Math.Abs(dotend) - 1 <= report.vectorangletol) { ml.Add("PASS" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor forms a tight enclosure with its neighbor."); totaledgect += 1; matchededges += 1; } else { ml.Add("FAIL" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " overlapping neighbor does not form a tight enclosure with its neighbor."); report.passOrFail = false; totaledgect += 1; matchededges += 0; } } } } else if (edgekp.Value.relatedEdges.Count() > 1) { ml.Add(edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " has " + edgekp.Value.relatedEdges.Count() + " neighboring edges."); //more robust testing Vector.EdgeFamily[] orderededges = new Vector.EdgeFamily[edgekp.Value.relatedEdges.Count()]; //align the related edges orderededges = AlignEdges(orderededges, edgekp.Value, coordtol); int coordcount = 0; double segmentslength = 0; int lastct = edgekp.Value.relatedEdges.Count() * 2 - 2; Vector.CartCoord st = new Vector.CartCoord(); Vector.CartCoord end = new Vector.CartCoord(); foreach (Vector.EdgeFamily edge in orderededges) { if (coordcount == 0) { st.X = edge.startendpt[0].X; st.Y = edge.startendpt[0].Y; st.Z = edge.startendpt[0].Z; } if (coordcount == lastct) { end.X = edge.startendpt[1].X; end.Y = edge.startendpt[1].Y; end.Z = edge.startendpt[1].Z; } Vector.MemorySafe_CartVect v = Vector.CreateMemorySafe_Vector(edge.startendpt[0], edge.startendpt[1]); double mag = Vector.VectorMagnitude(v); segmentslength += mag; coordcount += 2; } Vector.MemorySafe_CartVect v2 = Vector.CreateMemorySafe_Vector(edgekp.Value.startendpt[0], edgekp.Value.startendpt[1]); double mag2 = Vector.VectorMagnitude(v2); if (Math.Abs(segmentslength - mag2) < report.lengthtol) { ml.Add(edgekp.Value.sbdec + ":PASS:Multiple Overlapping edges properly match."); } else { //then something is wrong. ml.Add(edgekp.Value.sbdec + ":FAIL:Overlapping edges do not match as expected."); report.passOrFail = false; } } else if (edgekp.Value.relatedEdges.Count() == 0) { //something is wrong ml.Add(edgekp.Value.sbdec + "FAIL:" + edgekp.Value.sbdec + " Edge " + surfedgect.ToString() + " has no reported neighboring edges."); report.passOrFail = false; } surfedgect += 1; } report.MessageList[spaceid] = ml; //all edges align = true if (report.passOrFail) { report.longMsg = "TEST PASSED: " + totaledgect + " edges in the gbXML file. " + matchededges + " edges found with ideal alignment."; } //all edges align = false else { report.longMsg = "TEST FAILED: " + totaledgect + " edges in the gbXML file. " + matchededges + " edges found with ideal alignment."; } return report; } catch (Exception e) { report.longMsg = ("ERROR, we have run into an unexpected issue:" + e.ToString()); report.passOrFail = false; 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 simple = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); coordList.Add(simple); } 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 simple = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); testCoordList.Add(simple); } 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 simple = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); coordList.Add(simple); } 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 simple = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); testCoordList.Add(simple); } 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 simple = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); coordList.Add(simple); } 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 simple = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); testCoordList.Add(simple); } 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 tempY = new Vector.CartVect(); Vector.MemorySafe_CartVect globalReferenceX = new Vector.MemorySafe_CartVect(1,0,0); tempY = Vector.CrossProductNVRetMSMS(standardOpening.PlRHRVector, globalReferenceX); tempY = Vector.UnitVector(tempY); Vector.MemorySafe_CartVect localY = Vector.convertToMemorySafeVector(tempY); //new X axis is the localY cross the surface normal vector Vector.CartVect tempX = new Vector.CartVect(); tempX = Vector.CrossProductNVRetMSMS(localY, standardOpening.PlRHRVector); tempX = Vector.UnitVector(tempX); Vector.MemorySafe_CartVect localX = Vector.convertToMemorySafeVector(tempX); //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; Vector.CartCoord translatedPt = new Vector.CartCoord(); //x coordinate is distance vector dot the new local X axis translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; //y coordinate is distance vector dot the new local Y axis translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; translatedPt.Z = 0; Vector.MemorySafe_CartCoord memsafetranspt = Vector.convertToMemorySafeCoord(translatedPt); translatedCoordinates.Add(memsafetranspt); } 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 testtempY = new Vector.CartVect(); Vector.MemorySafe_CartVect testglobalReferenceX = new Vector.MemorySafe_CartVect(1,0,0); testtempY = Vector.CrossProductNVRetMSMS(testOpening.PlRHRVector, testglobalReferenceX); testtempY = Vector.UnitVector(tempY); Vector.MemorySafe_CartVect testlocalY = Vector.convertToMemorySafeVector(testtempY); //new X axis is the localY cross the surface normal vector Vector.CartVect testtempX = new Vector.CartVect(); testtempX = Vector.CrossProductNVRetMSMS(testlocalY, testOpening.PlRHRVector); testtempX = Vector.UnitVector(testtempX); Vector.MemorySafe_CartVect testlocalX = Vector.convertToMemorySafeVector(testtempX); //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; Vector.CartCoord translatedPt = new Vector.CartCoord(); //x coordinate is distance vector dot the new local X axis translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; //y coordinate is distance vector dot the new local Y axis translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; translatedPt.Z = 0; Vector.MemorySafe_CartCoord memsafetranspt = Vector.convertToMemorySafeCoord(translatedPt); testtranslatedCoordinates.Add(memsafetranspt); } 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; }
private DOEgbXMLReportingObj GetPossibleSurfaceMatches(SurfaceDefinitions surface, List<SurfaceDefinitions> TestSurfaces, DOEgbXMLReportingObj report) { //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; //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 foreach (SurfaceDefinitions testSurface in TestSurfaces) { //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; } foreach (string testAdjSpaceId in testSurface.AdjSpaceId) { //loop only returns true if all AdjSpaceIds in both surfaces are identical adjSpaceIdMatch = false; foreach (string standardAdjSpaceId in surface.AdjSpaceId) { if (testAdjSpaceId == standardAdjSpaceId) { adjSpaceIdMatch = true; } } } //if adjacent space Ids match and the surface types match, note this if (adjSpaceIdMatch && testSurface.SurfaceType == surface.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 = Math.Abs(testSurface.Tilt - surface.Tilt); double azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth); //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."); bool isRegular = IsSurfaceRegular(surface); foreach (SurfaceDefinitions regSurface in possiblesList2) { //ensures likewise that all the test surface candidates are regular, //if they are not, then the entire set is assumed to be irregular isRegular = IsSurfaceRegular(regSurface); if (isRegular == false) break; } if (isRegular) { //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 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(testsurface.Width - surface.Width); double heightDiff = Math.Abs(testsurface.Height - surface.Height); 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 + " ft and " + DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance + "ft, 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 Vector.MemorySafe_CartCoord simplecoord = new Vector.MemorySafe_CartCoord(0,coord.Y,coord.Z); coordList.Add(simplecoord); } 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 simple = new Vector.MemorySafe_CartCoord(0, coord.Y, coord.Z); testCoordList.Add(simple); } 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"); } double difference = Math.Abs(area - testSurfacesArea); 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 simple = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); coordList.Add(simple); } 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 simple = new Vector.MemorySafe_CartCoord(coord.X, 0, coord.Z); testCoordList.Add(simple); } 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"); } double difference = Math.Abs(area - testSurfacesArea); 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 simple = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); coordList.Add(coord); } 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 simple = new Vector.MemorySafe_CartCoord(coord.X, coord.Y, 0); testCoordList.Add(coord); } 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"); } double difference = Math.Abs(area - testSurfacesArea); 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 tempY = new Vector.CartVect(); Vector.MemorySafe_CartVect globalReferenceX = new Vector.MemorySafe_CartVect(1,0,0); tempY = Vector.CrossProductNVRetMSMS(surface.PlRHRVector, globalReferenceX); tempY = Vector.UnitVector(tempY); Vector.MemorySafe_CartVect localY = Vector.convertToMemorySafeVector(tempY); //new X axis is the localY cross the surface normal vector Vector.CartVect tempX = new Vector.CartVect(); tempX = Vector.CrossProductNVRetMSMS(localY, surface.PlRHRVector); tempX = Vector.UnitVector(tempX); Vector.MemorySafe_CartVect localX = Vector.convertToMemorySafeVector(tempX); //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; Vector.CartCoord translatedPt = new Vector.CartCoord(); //x coordinate is distance vector dot the new local X axis translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; //y coordinate is distance vector dot the new local Y axis translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; translatedPt.Z = 0; Vector.MemorySafe_CartCoord memsafetranspt = Vector.convertToMemorySafeCoord(translatedPt); translatedCoordinates.Add(memsafetranspt); } 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 testtempY = new Vector.CartVect(); Vector.MemorySafe_CartVect testglobalReferenceX = new Vector.MemorySafe_CartVect(1,0,0); testtempY = Vector.CrossProductNVRetMSMS(surface.PlRHRVector, testglobalReferenceX); testtempY = Vector.UnitVector(testtempY); Vector.MemorySafe_CartVect testlocalY = Vector.convertToMemorySafeVector(testtempY); //new X axis is the localY cross the surface normal vector Vector.CartVect testtempX = new Vector.CartVect(); testtempX = Vector.CrossProductNVRetMSMS(testlocalY, surface.PlRHRVector); testtempX = Vector.UnitVector(testtempX); Vector.MemorySafe_CartVect testlocalX = Vector.convertToMemorySafeVector(testtempX); //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; Vector.CartCoord translatedPt = new Vector.CartCoord(); //x coordinate is distance vector dot the new local X axis translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; //y coordinate is distance vector dot the new local Y axis translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; translatedPt.Z = 0; Vector.MemorySafe_CartCoord memsafetranspt = Vector.convertToMemorySafeCoord(translatedPt); testtranslatedCoordinates.Add(memsafetranspt); } 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"); } double difference = Math.Abs(area - testarea); 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); 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>"); 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 - surface.InsertionPoint.X); double insPtYDiff = Math.Abs(testSurface.InsertionPoint.Y - surface.InsertionPoint.Y); double insPtZDiff = Math.Abs(testSurface.InsertionPoint.Z - surface.InsertionPoint.Z); 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; } return report; } catch (Exception e) { report.longMsg = (e.ToString()); return report; } }
public static List<gbXMLSpaces> getSimpleSpaces(XmlDocument xmldoc, XmlNamespaceManager xmlns) { List<gbXMLSpaces> retspaces = new List<gbXMLSpaces>(); try { XmlNodeList nodes = xmldoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", xmlns); foreach (XmlNode spaceNode in nodes) { //initialize a new instance of the class gbXMLSpaces space = new gbXMLSpaces(); space.spacebounds = new List<SpaceBoundary>(); //get id and space XmlAttributeCollection spaceAtts = spaceNode.Attributes; foreach (XmlAttribute at in spaceAtts) { if (at.Name == "id") { space.id = at.Value; break; } } if (spaceNode.HasChildNodes) { XmlNodeList childNodes = spaceNode.ChildNodes; foreach (XmlNode node in childNodes) { if (node.Name == "PlanarGeometry") { space.pg = new PlanarGeometry(); XmlNodeList childnodes = node.ChildNodes; foreach (XmlNode node2 in childnodes) { if (node2.Name == "PolyLoop") { space.pg.pl = new PolyLoop(); space.pg.pl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = node2.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); space.pg.pl.plcoords.Add(memsafecoord); } } } } } else if (node.Name == "ShellGeometry") { space.sg = new ShellGeometry(); XmlAttributeCollection sgAtts = spaceNode.Attributes; foreach (XmlAttribute at in sgAtts) { if (at.Name == "id") { space.sg.id = at.Value; break; } } XmlNodeList childnodes = node.ChildNodes; foreach (XmlNode sgnode in childnodes) { if (sgnode.Name == "ClosedShell") { space.sg.cs = new ClosedShell(); space.sg.cs.ploops = new List<PolyLoop>(); foreach (XmlNode pl in sgnode) { if (pl.Name == "PolyLoop") { PolyLoop sgpl = new PolyLoop(); sgpl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = pl.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); sgpl.plcoords.Add(memsafecoord); } } space.sg.cs.ploops.Add(sgpl); } } } } } else if (node.Name == "SpaceBoundary") { SpaceBoundary sb = new SpaceBoundary(); XmlAttributeCollection spbatts = node.Attributes; foreach (XmlAttribute at in spbatts) { if (at.Name == "surfaceIdRef") { sb.surfaceIdRef = at.Value; break; } } XmlNodeList sbchilds = node.ChildNodes; foreach (XmlNode sbpnode in sbchilds) { if (sbpnode.Name == "PlanarGeometry") { sb.sbplane = new PlanarGeometry(); XmlNodeList pgchilds = sbpnode.ChildNodes; foreach (XmlNode pgchild in pgchilds) { if (pgchild.Name == "PolyLoop") { sb.sbplane.pl = new PolyLoop(); sb.sbplane.pl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = pgchild.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); sb.sbplane.pl.plcoords.Add(memsafecoord); } } } } } } //finally, add the thing here space.spacebounds.Add(sb); } } } else { //throw something } retspaces.Add(space); } } catch (Exception e) { } return retspaces; }
private static SpaceBoundary MakeSBPlanarGeometry(SpaceBoundary sb, XmlNodeList pgchilds) { try { foreach (XmlNode pgchild in pgchilds) { if (pgchild.Name == "PolyLoop") { sb.sbplane.pl = new PolyLoop(); sb.sbplane.pl.plcoords = new List<Vector.MemorySafe_CartCoord>(); XmlNodeList cartPoints = pgchild.ChildNodes; foreach (XmlNode point in cartPoints) { if (point.Name == "CartesianPoint") { Vector.CartCoord coord = new Vector.CartCoord(); XmlNodeList val = point.ChildNodes; int pointcount = 1; foreach (XmlNode cpoint in val) { switch (pointcount) { case 1: coord.X = Convert.ToDouble(cpoint.InnerText); break; case 2: coord.Y = Convert.ToDouble(cpoint.InnerText); break; case 3: coord.Z = Convert.ToDouble(cpoint.InnerText); break; } pointcount++; } Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord); sb.sbplane.pl.plcoords.Add(memsafecoord); } } } } } catch (Exception e) { } return sb; }