public void TransformSolidRectangularProfileDef()
        {
            using (var m = XbimModel.CreateTemporaryModel())
            {
                using (var txn = m.BeginTransaction())
                {

                    var profile = IfcModelBuilder.MakeRectangleHollowProfileDef(m, 20, 10, 1);
                    var extrude = IfcModelBuilder.MakeExtrudedAreaSolid(m, profile, 40);
                    var solid = _xbimGeometryCreator.CreateSolid(extrude);
                    var transform = new XbimMatrix3D(); //test first with identity
                    var solid2 = (IXbimSolid)solid.Transform(transform);
                    var s1Verts = solid.Vertices.ToList();
                    var s2Verts = solid2.Vertices.ToList();
                    for (int i = 0; i < s1Verts.Count; i++)
                    {
                        XbimVector3D v = s1Verts[i].VertexGeometry - s2Verts[i].VertexGeometry;
                        Assert.IsTrue(v.Length < m.ModelFactors.Precision, "vertices not the same");
                    }
                    transform.RotateAroundXAxis(Math.PI/2);
                    transform.RotateAroundYAxis(Math.PI/4);
                    transform.RotateAroundZAxis(Math.PI);
                    transform.OffsetX += 100;
                    transform.OffsetY += 200;
                    transform.OffsetZ += 300;
                    solid2 = (IXbimSolid)solid.Transform(transform);
                    Assert.IsTrue(Math.Abs(solid.Volume - solid2.Volume) < 0.001, "Volume differs");
                    transform.Invert();
                    solid2 = (IXbimSolid)solid2.Transform(transform);
                    s1Verts = solid.Vertices.ToList();
                    s2Verts = solid2.Vertices.ToList();
                    for (int i = 0; i < s1Verts.Count; i++)
                    {
                        XbimVector3D v = s1Verts[i].VertexGeometry-s2Verts[i].VertexGeometry;
                        Assert.IsTrue(v.Length < m.ModelFactors.Precision, "vertices not the same");
                    }
                }
            }
        }
        /// <summary>
        /// Calculate the ObjectPlacment for an IfcProduct from row data and the parent object
        /// </summary>
        /// <param name="row">COBieCoordinateRow holding the data</param>
        /// <param name="placementRelToIfcProduct">IfcProduct that the ObjectPlacment relates too, i.e. the parent of the ifcProduct ObjectPlacment we are calculating</param>
        /// <returns></returns>
        private IfcLocalPlacement CalcObjectPlacement(COBieCoordinateRow row, IfcProduct placementRelToIfcProduct)
        {
            XbimPoint3D locationPt;
            bool havePoint = GetPointFromRow(row, out locationPt);
            if (havePoint)
            {
                if ((placementRelToIfcProduct != null) && (placementRelToIfcProduct.ObjectPlacement is IfcLocalPlacement))
                {
                    //TEST, change the building position to see if the same point comes out in Excel sheet, it should be, and in test was.
                    //((IfcAxis2Placement3D)((IfcLocalPlacement)placementRelToIfcProduct.ObjectPlacement).RelativePlacement).SetNewLocation(10.0, 10.0, 0.0);
                    IfcLocalPlacement placementRelTo = (IfcLocalPlacement)placementRelToIfcProduct.ObjectPlacement;
                    XbimMatrix3D matrix3D = ConvertMatrix3D(placementRelTo);
                    
                    //we want to take off the translations and rotations caused by IfcLocalPlacement of the parent objects as we will add these to the new IfcLocalPlacement for this floor
                    matrix3D.Invert(); //so invert matrix to remove the translations to give the origin for the next IfcLocalPlacement
                    locationPt = matrix3D.Transform(locationPt); //get the point with relation to the last IfcLocalPlacement i.e the parent element
                    
                    //Get the WCS matrix values
                    double rotX, rotY, rotZ;
                    if (!(double.TryParse(row.YawRotation, out rotX) && (double.NaN.CompareTo(rotX) != 0)))
                        rotX = 0.0;

                    if (!(double.TryParse(row.ElevationalRotation, out rotY) && (double.NaN.CompareTo(rotY) != 0)))
                        rotY = 0.0;

                    if (double.TryParse(row.ClockwiseRotation, out rotZ) && (double.NaN.CompareTo(rotZ) != 0))
                        rotZ = rotZ * -1; //convert back from clockwise to anti clockwise
                    else
                        rotZ = 0.0;

                    //apply the WCS rotation from COBie Coordinates stored values
                    XbimMatrix3D matrixNewRot3D = new XbimMatrix3D();
                    if (rotX != 0.0)
                        matrixNewRot3D.RotateAroundXAxis(TransformedBoundingBox.DegreesToRadians(rotX));
                    if (rotY != 0.0)
                        matrixNewRot3D.RotateAroundYAxis(TransformedBoundingBox.DegreesToRadians(rotY));
                    if (rotZ != 0.0)
                        matrixNewRot3D.RotateAroundZAxis(TransformedBoundingBox.DegreesToRadians(rotZ));
                    
                    //remove any displacement from the matrix which moved/rotated us to the object space
                    matrix3D.OffsetX = 0.0F;
                    matrix3D.OffsetY = 0.0F;
                    matrix3D.OffsetZ = 0.0F;
                    
                    //remove the matrix that got use to the object space from the WCS location of this object
                    XbimMatrix3D matrixRot3D = matrixNewRot3D * matrix3D;
                    
                    //get the rotation vectors to place in the new IfcAxis2Placement3D for the new IfcLocalPlacement for this object
                    XbimVector3D ucsAxisX = matrixRot3D.Transform(new XbimVector3D(1, 0, 0));
                    XbimVector3D ucsAxisZ = matrixRot3D.Transform(new XbimVector3D(0, 0, 1));
                    ucsAxisX.Normalize();
                    ucsAxisZ.Normalize();

                    //create the new IfcAxis2Placement3D 
                    IfcAxis2Placement3D relativePlacemant = Model.Instances.New<IfcAxis2Placement3D>();
                    relativePlacemant.SetNewDirectionOf_XZ(ucsAxisX.X, ucsAxisX.Y, ucsAxisX.Z, ucsAxisZ.X, ucsAxisZ.Y, ucsAxisZ.Z);
                    relativePlacemant.SetNewLocation(locationPt.X, locationPt.Y, locationPt.Z);

                    //Set up IfcLocalPlacement
                    IfcLocalPlacement objectPlacement = Model.Instances.New<IfcLocalPlacement>();
                    objectPlacement.PlacementRelTo = placementRelTo;
                    objectPlacement.RelativePlacement = relativePlacemant;

                    return objectPlacement;
                }
            }
            return null;
           
        }