Example #1
0
        /// <summary>
        /// Returns an integer to indicate if two vectors are parallel, antiparallel or not.
        /// </summary>
        /// <param name="a">The one vector.</param>
        /// <param name="b">The other vector.</param>
        /// <returns>1 parallel, -1 antiparallel, 0 not parallel.</returns>
        public static int VectorsAreParallel2(XYZ a, XYZ b)
        {
            if (a == null || b == null)
            {
                return(0);
            }

            double aa, bb, ab;
            double epsSq    = Eps() * Eps();
            double angleEps = Math.PI / 1800.0;

            aa = a.DotProduct(a);
            bb = b.DotProduct(b);

            if (aa < epsSq || bb < epsSq)
            {
                return(0);
            }

            ab = a.DotProduct(b);
            double cosAngleSq = (ab / aa) * (ab / bb);

            if (cosAngleSq < 1.0 - angleEps * angleEps)
            {
                return(0);
            }

            return(ab > 0 ? 1 : -1);
        }
Example #2
0
        public static PlanarFace LastFace(IList <PlanarFace> listFace, XYZ vector, Transform transform)
        {
            PlanarFace         result = null;
            IList <PlanarFace> list   = Facelibry.PerpendicularFace(listFace, vector, transform);
            double             num    = 0.0;

            foreach (PlanarFace planarFace in list)
            {
                XYZ xyz = planarFace.Origin;
                xyz = transform.OfPoint(xyz);
                bool flag = MathLib.IsEqual(num, 0.0, 0.0001);
                if (flag)
                {
                    num    = vector.DotProduct(xyz);
                    result = planarFace;
                }
                else
                {
                    double num2  = vector.DotProduct(xyz);
                    bool   flag2 = num2 > num;
                    if (flag2)
                    {
                        result = planarFace;
                        num    = num2;
                    }
                }
            }
            return(result);
        }
Example #3
0
        public static PlanarFace FirstFace(IList <PlanarFace> listFace, XYZ vector)
        {
            PlanarFace         result = null;
            IList <PlanarFace> list   = Facelibry.PerpendicularFace(listFace, vector);
            double             num    = 0.0;

            foreach (PlanarFace planarFace in list)
            {
                XYZ  source = Facelibry.CenterPoint(planarFace);
                bool flag   = MathLib.IsEqual(num, 0.0, 0.0001);
                if (flag)
                {
                    num    = vector.DotProduct(source);
                    result = planarFace;
                }
                else
                {
                    double num2  = vector.DotProduct(source);
                    bool   flag2 = num2 < num;
                    if (flag2)
                    {
                        result = planarFace;
                        num    = num2;
                    }
                }
            }
            return(result);
        }
Example #4
0
        /// <summary>
        /// Project given 3D XYZ point into plane,
        /// returning the UV coordinates of the result
        /// in the local 2D plane coordinate system.
        /// </summary>
        public static UV ProjectInto(this Plane plane, XYZ p)
        {
            XYZ    q = plane.ProjectOnto(p);
            XYZ    o = plane.Origin;
            XYZ    d = q - o;
            double u = d.DotProduct(plane.XVec);
            double v = d.DotProduct(plane.YVec);

            return(new UV(u, v));
        }
Example #5
0
        //From Jeremy Tammik - The Building Coder - Util.cs
        public static UV ProjectInto(this Plane plane, XYZ p)
        {
            XYZ    _q = ProjectOnto(plane, p);
            XYZ    _o = plane.Origin;
            XYZ    _d = _q - _o;
            double _u = _d.DotProduct(plane.XVec);
            double _v = _d.DotProduct(plane.YVec);

            return(new UV(_u, _v));
        }
        /// <summary>
        /// Align the given grid horizontally or vertically
        /// if it is very slightly off axis, by Fair59 in
        /// https://forums.autodesk.com/t5/revit-api-forum/grids-off-axis/m-p/7129065
        /// </summary>
        void AlignOffAxisGrid(
            Grid grid)
        {
            //Grid grid = doc.GetElement(
            //  sel.GetElementIds().FirstOrDefault() ) as Grid;

            Document doc = grid.Document;

            XYZ direction = grid.Curve
                            .GetEndPoint(1)
                            .Subtract(grid.Curve.GetEndPoint(0))
                            .Normalize();

            double distance2hor  = direction.DotProduct(XYZ.BasisY);
            double distance2vert = direction.DotProduct(XYZ.BasisX);
            double angle         = 0;

            // Maybe use another criterium then <0.0001

            double max_distance = 0.0001;

            if (Math.Abs(distance2hor) < max_distance)
            {
                XYZ vector = direction.X < 0
          ? direction.Negate()
          : direction;

                angle = Math.Asin(-vector.Y);
            }

            if (Math.Abs(distance2vert) < max_distance)
            {
                XYZ vector = direction.Y < 0
          ? direction.Negate()
          : direction;

                angle = Math.Asin(vector.X);
            }

            if (angle.CompareTo(0) != 0)
            {
                using (Transaction t = new Transaction(doc))
                {
                    t.Start("correctGrid");

                    ElementTransformUtils.RotateElement(doc,
                                                        grid.Id,
                                                        Line.CreateBound(grid.Curve.GetEndPoint(0),
                                                                         grid.Curve.GetEndPoint(0).Add(XYZ.BasisZ)),
                                                        angle);

                    t.Commit();
                }
            }
        }
Example #7
0
        //++++++++++++++++++++++++++++++++
        //   BinAdd
        //   xuzhaobin
        //++++++++++++++++++++++++++++++++

        /// <summary>
        /// 点在面上的投影点
        /// </summary>
        /// <param name="po"></param>
        /// <param name="p"></param>
        /// <returns></returns>
        public static XYZ ProjectToPlane(this XYZ po, Plane p)
        {
            XYZ vec_po_to_planeOrigin = p.Origin - po;

            if (!IsEqual(vec_po_to_planeOrigin.DotProduct(p.Normal), 0))
            {
                return(po + p.Normal * vec_po_to_planeOrigin.DotProduct(p.Normal));
            }
            else
            {
                return(po);
            }
        }
        /// <summary>
        /// Transform all 3D points to the 2D points.
        /// </summary>
        private void transform22D()
        {
            if (_Points.Count > 2)
            {
                var zdist = _Points.Select(s => s.Z).Distinct();
                if ((_Points.Max(s => s.Z) - _Points.Min(s => s.Z)) < 1.0e-6)
                {
                    _vPoints2d = _Points.Select(s => new UV(s.X, s.Y)).ToList();
                    UV move = new UV(_vPoints2d.Min(s => s.U), _vPoints2d.Min(s => s.V));
                    _vPoints2d = _vPoints2d.Select(s => (new UV(s.U - move.U, s.V - move.V))).ToList();
                }
                else
                {
                    int indLast = _Points.Count - 1;
                    XYZ vX      = null;
                    for (int i = 0; i <= indLast; i++)
                    {
                        vX = (_Points[i] - _Points[0]).Normalize();
                        if (!vX.IsZeroLength())
                        {
                            break;
                        }
                    }

                    XYZ vY = null;
                    for (int i = indLast; i >= 0; i--)
                    {
                        XYZ v2 = _Points[0] - _Points[i],
                            vZ = vX.CrossProduct(v2).Normalize();
                        if (!vZ.IsZeroLength())
                        {
                            vY = vZ.CrossProduct(vX);
                            break;
                        }
                    }

                    {
                        XYZ        p0   = _Points[0];
                        List <XYZ> vSrc = _vPointsTransformed;
                        List <UV>  vTar = _vPoints2d;

                        foreach (XYZ pt in vSrc)
                        {
                            XYZ u = pt - p0;
                            vTar.Add(new UV(u.DotProduct(vX), u.DotProduct(vY)));
                        }
                    }
                }
            }
        }
Example #9
0
        /// <summary>
        /// This method constructs the winder corner and two straight runs.
        /// Please be sure the input properties being set properly before calling this method.
        /// </summary>
        private void Construct()
        {
            //
            // Construct the winder corner.
            //
            XYZ dir1 = (ControlPoints[1] - ControlPoints[0]).Normalize();
            XYZ dir2 = (ControlPoints[2] - ControlPoints[1]).Normalize();

            m_corner = new WinderSinglePoint(ControlPoints[1], dir1, dir2, NumStepsInCorner);
            m_corner.Construct(RunWidth, CenterOffsetE, CenterOffsetF);

            //
            // Construct two straight runs to connect to the winder corner.
            //
            XYZ startPnt          = m_corner.StartPoint - TreadDepth * NumStepsAtStart * dir1;
            XYZ endPnt            = m_corner.EndPoint + TreadDepth * NumStepsAtEnd * dir2;
            XYZ bisectDir         = (dir2 - dir1).Normalize();
            XYZ perpendicularDir1 = new XYZ(-dir1.Y, dir1.X, 0);
            XYZ perpendicularDir2 = new XYZ(-dir2.Y, dir2.X, 0);

            if (bisectDir.DotProduct(perpendicularDir1) < 0)
            {
                perpendicularDir1 = perpendicularDir1.Negate();
                perpendicularDir2 = perpendicularDir2.Negate();
            }
            m_straightAtStart = new WinderStraight(
                startPnt, m_corner.StartPoint, perpendicularDir1, NumStepsAtStart);
            m_straightAtEnd = new WinderStraight(
                m_corner.EndPoint, endPnt, perpendicularDir2, NumStepsAtEnd);
        }
Example #10
0
        static bool ModifiedProfile(Wall wall)
        {
            Solid solid       = GetUppermostSolid(wall);
            XYZ   orientation = wall.Orientation;
            Face  face        = null;

            foreach (Face f in solid.Faces)
            {
                if (orientation
                    .DotProduct(f.ComputeNormal(new UV(0, 0))) > 0)
                {
                    face = f;
                    break;
                }
            }
            if (face == null)
            {
                throw new ArgumentNullException("Something has gone wrong!");
            }

            if (face.GetEdgesAsCurveLoops().Count > 1)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
Example #11
0
        static public XYZ Project(this XYZ vector, XYZ vectorV)
        {
            double magnitude  = Math.Abs(vectorV.GetLength());
            XYZ    projection = vectorV.Multiply(vector.DotProduct(vectorV) / (magnitude * magnitude));

            return(projection);
        }
Example #12
0
 public static bool IsPerpendicular(XYZ v, XYZ w)
 {
     double length = v.GetLength();
     double length2 = v.GetLength();
     double num = Math.Abs(v.DotProduct(w));
     return 1E-09 < length && 1E-09 < length2 && 1E-09 > num;
 }
        /// <summary>
        /// Transform all 3D points to the plane.
        /// </summary>
        private void transform2Plane()
        {
            if (_Points.Count > 2)
            {
                if ((_Points.Max(s => s.Z) - _Points.Min(s => s.Z)) < 1.0e-6)
                {
                    _vPointsTransformed = new List <XYZ>(_Points);
                }
                else
                {
                    XYZ v1 = _Points[1] - _Points[0],
                        v2 = _Points[2] - _Points[1],
                        n  = v1.CrossProduct(v2).Normalize(),
                        p0 = _Points[0];

                    for (int i = 0; i < 2; i++)
                    {
                        bool       bContour = i == 0;
                        List <XYZ> vSrc     = _Points,
                                   vTar     = _vPointsTransformed;

                        foreach (XYZ pt in vSrc)
                        {
                            XYZ u       = pt - p0,
                                     u1 = u - n.Multiply(u.DotProduct(n));
                            vTar.Add(p0 + u1);
                        }
                    }
                }
            }
        }
Example #14
0
File: XYZ.cs Project: l2obin/Dynamo
        public override FScheme.Value Evaluate(FSharpList <FScheme.Value> args)
        {
            XYZ a = (XYZ)((FScheme.Value.Container)args[0]).Item;
            XYZ b = (XYZ)((FScheme.Value.Container)args[1]).Item;

            return(FScheme.Value.NewContainer(a.DotProduct(b)));
        }
Example #15
0
        /// <summary>
        /// Calculate the CenterPoint base on Australia single-point layout algorithm.
        /// </summary>
        /// <param name="runWidth">Stairs Runwidth</param>
        /// <param name="offset1">CenterPoint Offset from the first inner boundary</param>
        /// <param name="offset2">CenterPoint Offset from the second inner boundary</param>
        public void Construct(double runWidth, double offset1, double offset2)
        {
            XYZ bisectDir         = (Direction2 - Direction1).Normalize();
            XYZ perpendicularDir1 = new XYZ(-Direction1.Y, Direction1.X, 0);
            XYZ perpendicularDir2 = new XYZ(-Direction2.Y, Direction2.X, 0);

            if (bisectDir.DotProduct(perpendicularDir1) < 0)
            {
                perpendicularDir1 = perpendicularDir1.Negate();
                perpendicularDir2 = perpendicularDir2.Negate();
            }

            Line line1Offset = Line.CreateUnbound(
                CornerPoint + perpendicularDir1 * (runWidth + offset1), Direction1);
            Line line2Offset = Line.CreateUnbound(
                CornerPoint + perpendicularDir2 * (runWidth + offset2), Direction2);

            IntersectionResultArray xsect;

            line1Offset.Intersect(line2Offset, out xsect);
            CenterPoint = xsect.get_Item(0).XYZPoint;

            Line line1 = Line.CreateUnbound(CornerPoint, Direction1.Negate());
            Line line2 = Line.CreateUnbound(CornerPoint, Direction2);

            var proj1 = line1.Project(CenterPoint);
            var proj2 = line2.Project(CenterPoint);

            Distance1 = proj1.Parameter;
            Distance2 = proj2.Parameter;
        }
        private XYZ ProjectionOnPlane(XYZ q, Plane plane)
        {
            XYZ origin = plane.get_Origin();
            XYZ xyz    = plane.get_Normal().Normalize();

            return(XYZ.op_Subtraction(q, xyz.Multiply(xyz.DotProduct(XYZ.op_Subtraction(q, origin)))));
        }
        /// <summary>
        /// Offsets an arc along the offset direction from the point on the arc.
        /// </summary>
        /// <param name="arc">The arc.</param>
        /// <param name="offsetPntOnArc">The point on the arc.</param>
        /// <param name="offset">The offset vector.</param>
        /// <returns>The offset Arc.</returns>
        private static Arc OffsetArc(Arc arc, XYZ offsetPntOnArc, XYZ offset)
        {
            if (arc == null || offset == null)
            {
                throw new ArgumentNullException();
            }

            if (offset.IsZeroLength())
            {
                return(arc);
            }

            XYZ axis = arc.Normal.Normalize();

            XYZ offsetAlongAxis   = axis.Multiply(offset.DotProduct(axis));
            XYZ offsetOrthAxis    = offset - offsetAlongAxis;
            XYZ offsetPntToCenter = (arc.Center - offsetPntOnArc).Normalize();

            double signedOffsetLengthTowardCenter = offsetOrthAxis.DotProduct(offsetPntToCenter);
            double newRadius = arc.Radius - signedOffsetLengthTowardCenter; // signedOffsetLengthTowardCenter > 0, minus, < 0, add

            Arc offsetArc = Arc.Create(arc.Center, newRadius, arc.GetEndParameter(0), arc.GetEndParameter(1), arc.XDirection, arc.YDirection);

            offsetArc = GeometryUtil.MoveCurve(offsetArc, offsetAlongAxis) as Arc;

            return(offsetArc);
        }
        public List <FamilyInstance> GetFamilyInstances2(Document doc, View view, FamilyInstance firstInstance, FamilyInstance secondInstance, XYZ dimDirection)
        {
            List <FamilyInstance> list = new List <FamilyInstance>();
            bool flag = firstInstance.Id == secondInstance.Id;
            List <FamilyInstance> result;

            if (flag)
            {
                list.Add(firstInstance);
                result = list;
            }
            else
            {
                LocationPoint locationPoint  = firstInstance.Location as LocationPoint;
                LocationPoint locationPoint2 = secondInstance.Location as LocationPoint;
                bool          flag2          = locationPoint == null || locationPoint2 == null;
                if (flag2)
                {
                    result = list;
                }
                else
                {
                    list.Add(firstInstance);
                    list.Add(secondInstance);
                    PLane3D pLane3D = new PLane3D(doc.ActiveView.Origin, doc.ActiveView.ViewDirection);
                    XYZ     point1  = pLane3D.ProjectPointOnPlane(locationPoint.Point);
                    XYZ     point2  = pLane3D.ProjectPointOnPlane(locationPoint2.Point);
                    //XYZ tranlator = Timdiemthu3(point1,point2);
                    //XYZ direction = (tranlator - point2);
                    XYZ direction = (point1 - point2);
                    FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc, view.Id);
                    IList <FamilyInstance>   list2 = (from x in filteredElementCollector.OfClass(typeof(FamilyInstance)).OfCategory(firstInstance.Category.ToBuiltinCategory()).Cast <FamilyInstance>() where x.Symbol.Name.Contains(firstInstance.Symbol.Name) select x).ToList();
                    foreach (var item in list2)
                    {
                        if (item.Id != firstInstance.Id && item.Id != secondInstance.Id)
                        {
                            XYZ locationinstance = item.Getlocationofinstacne();

                            //XYZ tranlatoritem = Timdiemthu3(locationinstance, locationPoint2.Point);
                            //XYZ vector = (pLane3D.ProjectPointOnPlane(tranlatoritem) - point2);

                            XYZ vector = (pLane3D.ProjectPointOnPlane(locationinstance) - point2);
                            if (vector.IsParallel(direction))
                            {
                                if (vector.GetLength() <= direction.GetLength())
                                {
                                    bool flag3 = vector.DotProduct(direction) != 0;
                                    if (flag3)
                                    {
                                        list.Add(item);
                                    }
                                }
                            }
                        }
                    }
                    result = list;
                }
            }
            return(result);
        }
        public PlanarFace Facexanhat(XYZ point, XYZ direction, IList <PlanarFace> listFaces, Transform transform)
        {
            PlanarFace planarFace = null;
            double     num        = double.MinValue;
            PLane3D    plane3D    = new PLane3D(point, direction);

            foreach (PlanarFace i in listFaces)
            {
                XYZ  xyz   = transform.OfVector(i.FaceNormal);
                XYZ  xyz2  = direction.CrossProduct(xyz);
                bool check = xyz2.GetLength() > 0.001 || xyz.DotProduct(direction) < 0.0;
                if (!check)
                {
                    double num2  = plane3D.DistancepointtoPlane(transform.OfPoint(i.Origin));
                    bool   flag2 = num2 < 0.001;
                    if (!flag2)
                    {
                        bool flag3 = num2 > num;
                        if (flag3)
                        {
                            planarFace = i;
                            num        = num2;
                        }
                    }
                }
            }
            return(planarFace);
        }
        List <XYZ> intersectPoints(List <XYZ> polygons, XYZ lineParas)
        {
            if (polygons == null && polygons.Count == 0)
            {
                return(null);
            }
            XYZ        axis            = new XYZ(lineParas.Y, lineParas.X, 0);
            List <XYZ> intersectpoints = new List <XYZ>();

            for (int i = 0; i < polygons.Count - 1; i++)
            {
                //计算交点时,只计算与水平方向和垂直方向接近垂直的两个点组成的直线;即两个向量的夹角大于60小于120
                XYZ    vector1  = (polygons[i] - polygons[i + 1]).Normalize();
                double cosValue = vector1.DotProduct(axis);
                if (cosValue > -0.5f && cosValue < 0.5f)
                {
                    XYZ temppoint = Intersect(polygons[i], polygons[i + 1], lineParas);
                    if (temppoint != null)
                    {
                        intersectpoints.Add(temppoint);
                    }
                }
            }
            return(intersectpoints);
        }
Example #21
0
        public static PlanarFace FurthestFace(XYZ point, XYZ direction, IList <PlanarFace> listFaces, Transform transform)
        {
            PlanarFace result     = null;
            double     num        = double.MinValue;
            PLane3D    plane3DLib = new PLane3D(point, direction);

            foreach (PlanarFace planarFace in listFaces)
            {
                XYZ  xyz  = transform.OfVector(planarFace.FaceNormal);
                XYZ  xyz2 = direction.CrossProduct(xyz);
                bool flag = xyz2.GetLength() > 0.001 || xyz.DotProduct(direction) < 0.0;
                if (!flag)
                {
                    double num2  = plane3DLib.DistanceFromPointToPlane(transform.OfPoint(planarFace.Origin));
                    bool   flag2 = num2 < 0.001;
                    if (!flag2)
                    {
                        bool flag3 = num2 > num;
                        if (flag3)
                        {
                            result = planarFace;
                            num    = num2;
                        }
                    }
                }
            }
            return(result);
        }
Example #22
0
        static bool ModifiedProfile(Wall wall)
        {
            Solid solid       = RvtGeometryUtils.GetSolid(wall);
            XYZ   orientation = wall.Orientation;
            Face  face        = null;

            foreach (Face f in solid.Faces)
            {
                if (orientation
                    .DotProduct(f.ComputeNormal(new UV(0, 0))) > 0)
                {
                    face = f;
                    break;
                }
            }
            if (face == null)
            {
                Trace.WriteIf(generalSwitch.TraceError, "Unable to extract a face from the wall.");
                throw new ArgumentNullException("Something has gone wrong!");
            }


            if (face.GetEdgesAsCurveLoops().Count > 1)
            {
                return(true);
            }
            else
            {
                return(false);
            }
        }
        static Face GetClosestFace(Element e, XYZ p, XYZ normal, Options opt)
        {
            Face            face        = null;
            double          minDistance = double.MaxValue;
            GeometryElement geo         = e.get_Geometry(opt);

            foreach (GeometryObject obj in geo)
            {
                Solid solid = obj as Solid;
                if (solid != null)
                {
                    FaceArray fa = solid.Faces;
                    foreach (Face f in fa)
                    {
                        PlanarFace pf = f as PlanarFace;
                        if (null != pf && IsParallel(normal, pf.FaceNormal))
                        {
                            XYZ    v = p - pf.Origin;
                            double d = v.DotProduct(-pf.FaceNormal);
                            if (d < minDistance)
                            {
                                face        = f;
                                minDistance = d;
                            }
                        }
                    }
                }
            }

            return(face);
        }
Example #24
0
        public static double PointToFace(XYZ point, PlanarFace face)
        {
            XYZ faceNormal = face.FaceNormal;
            XYZ xyz        = point - face.Origin;

            return(Math.Abs(xyz.DotProduct(faceNormal) / faceNormal.GetLength()));
        }
        public override void Action()
        {
            XYZ u = XYZ.BasisX;
            XYZ v = XYZ.BasisY;
            XYZ w = XYZ.BasisZ;

            //dot product : Angle Between Vector
            double dotProduct = u.DotProduct(v); // cos90 = 0

            MessageBox.Show($"Angle : {dotProduct}");

            //cross product : matrix
            //https://en.wikipedia.org/wiki/Cross_product

            XYZ crossProduct = u.CrossProduct(v); //Cross Same Direction with Z

            crossProduct.ShowMessageBox(nameof(crossProduct));

            //This article is about ternary operations on vectors. For the identity in number theory, see Jacobi triple product.
            // https://en.wikipedia.org/wiki/Triple_product
            //(u,v,w)=u⋅(v×w)=v⋅(w×u)=w⋅(u×v)
            //(u,v,w)=(w,u,v)=(v,w,u)=−(v,u,w)=−(w,v,u)=−(u,w,v)
            // ku⋅(v×w)=k(u,v,w)
            //(u,v,w)=u⋅(v×w)
            double tripleProduct = u.TripleProduct(v, w);

            System.Windows.Forms.MessageBox.Show($"{nameof(tripleProduct)}: {tripleProduct}");

            // Write By Step By Step
            //Dot Product
            DotProduct(u, v).ShowMessageBox();
            //Cross Product
            CrossProduct(u, v).ShowMessageBox();
        }
Example #26
0
        /// <summary>
        /// 对8个面基于平行关系 分成列表
        /// </summary>
        /// <param name="twoFaces"></param>
        /// <returns></returns>
        internal List <List <Face> > FindParallelPlane(List <Face> eightFaces)
        {
            List <Face> faces01 = new List <Face>();
            List <Face> faces02 = new List <Face>();

            Face face01    = eightFaces.First();
            XYZ  normalXyz = (face01 as PlanarFace).FaceNormal;

            foreach (Face face in eightFaces)
            {
                XYZ    _normalXyz = (face as PlanarFace).FaceNormal;
                double dotResult  = normalXyz.DotProduct(_normalXyz);
                if (EqualPrecision(dotResult, 1) || EqualPrecision(dotResult, -1))
                {
                    faces01.Add(face);
                }
                else
                {
                    faces02.Add(face);
                }
            }
            // 求平行且距离最短的两个对面faces
            return(new List <List <Face> >()
            {
                faces01, faces02
            });
        }
        // test to see if one Point has collinearity
        private bool hasCollinearity(int index, double angle)
        {
            if (index == 0 || index == this.processedPolygon.Count - 1)
            {
                return(false);
            }
            int after      = (index == this.processedPolygon.Count - 1) ? 0 : index + 1;
            int before     = (index == 0) ? this.processedPolygon.Count - 1 : index - 1;
            XYZ bfr        = this.processedPolygon[before];
            XYZ pnt        = this.processedPolygon[index];
            XYZ aftr       = this.processedPolygon[after];
            XYZ direction1 = (pnt - bfr);
            XYZ direction2 = (aftr - pnt);

            if (direction1 == XYZ.Zero || direction2 == XYZ.Zero)
            {
                return(true);
            }
            direction1 = direction1.Normalize();
            direction2 = direction2.Normalize();
            double cosine      = Math.Abs(direction1.DotProduct(direction2));
            double cosineAngle = Math.Cos(angle);
            bool   trueOrFalse = (cosine >= cosineAngle);

            return(trueOrFalse);
        }
Example #28
0
        public void Test_XYZTests_DotProduct()
        {
            XYZ bottom = new XYZ(0, 0, 0);
            XYZ top    = new XYZ(20, 30, 0);
            XYZ right  = new XYZ(45, 70, 0);

            Assert.Equal(3000, XYZ.DotProduct(bottom, top, right));
        }
        public double Gochopboi2vector(XYZ u1, XYZ u2)
        {
            double a  = u1.DotProduct(u2);
            double y1 = Math.Sqrt(Math.Pow(u1.X, 2) + Math.Pow(u1.Y, 2) + Math.Pow(u1.Z, 2));
            double y2 = Math.Sqrt(Math.Pow(u2.X, 2) + Math.Pow(u2.Y, 2) + Math.Pow(u2.Z, 2));

            return(Math.Abs(a / (y1 * y2)));
        }
        /***************************************************/
        /****              Public methods               ****/
        /***************************************************/

        public static Plane ArbitraryPlane(this Curve curve)
        {
            XYZ origin = curve.GetEndPoint(0);
            XYZ x      = (curve.GetEndPoint(1) - origin).Normalize();
            XYZ helper = 1 - Math.Abs(x.DotProduct(XYZ.BasisZ)) > BH.oM.Geometry.Tolerance.Angle ? XYZ.BasisZ : XYZ.BasisX;
            XYZ y      = x.CrossProduct(helper).Normalize();

            return(Plane.CreateByOriginAndBasis(origin, x, y));
        }
        /// <summary>
        /// Create the opening associated to an already created door or window.
        /// </summary>
        /// <param name="exporterIFC">The exporter class.</param>
        /// <param name="doc">The document.</param>
        /// <param name="hostObjHnd">The host object IFC handle.</param>
        /// <param name="hostId">The host object element id.</param>
        /// <param name="insertId">The insert element id.</param>
        /// <param name="openingGUID">The GUID for the IfcOpeningElement.</param>
        /// <param name="cutLoop">The 2D outline representing the opening geometry.</param>
        /// <param name="cutDir">The direction of the extrusion representing the opening geometry.</param>
        /// <param name="origUnscaledDepth">The width of the host object that the opening is cutting.</param>
        /// <param name="posHingeSide">True if the 2D outline is on the plane containing the hinge.</param>
        /// <param name="isRecess">True if the IfcOpeningElement should represent a recess.</param>
        /// <returns>The class containing information about the opening.</returns>
        static public DoorWindowOpeningInfo CreateOpeningForDoorWindow(ExporterIFC exporterIFC, Document doc,
            IFCAnyHandle hostObjHnd, ElementId hostId, ElementId insertId, string openingGUID, CurveLoop cutLoop, XYZ cutDir,
            double origUnscaledDepth, bool posHingeSide, bool isRecess)
        {
            // calculate some values.
            double openingHeight = -1.0;
            double openingWidth = -1.0;
            
            Element wallElement = doc.GetElement(hostId);
            Wall wall = (wallElement != null) ? wallElement as Wall : null;
            Curve curve = WallExporter.GetWallAxis(wall);
            if (curve == null)
                return null;

            // Don't export opening if we are exporting parts on a wall, as the parts will already have the openings cut out.
            if (PartExporter.CanExportParts(wall))
                return null;

            ElementId catId = CategoryUtil.GetSafeCategoryId(wall);

            double unScaledDepth = origUnscaledDepth;

            IFCAnyHandle hostObjPlacementHnd = IFCAnyHandleUtil.GetObjectPlacement(hostObjHnd);
            IFCAnyHandle ownerHistory = ExporterCacheManager.OwnerHistoryHandle;

            XYZ relOrig = XYZ.Zero;
            XYZ relZ = XYZ.BasisZ;
            XYZ relX = XYZ.BasisX;

            double openingZNonScaled = -1.0;

            Plane plane = new Plane(cutDir, XYZ.Zero);

            // get height, width before transform
            BoundingBoxXYZ cutLoopBBox = ComputeApproximateCurveLoopBBoxForOpening(cutLoop, null);
            if (cutLoopBBox != null)
            {
                XYZ dist = cutLoopBBox.Max - cutLoopBBox.Min;
                openingZNonScaled = cutLoopBBox.Min.Z;
                openingHeight = Math.Abs(dist.Z);
                openingWidth = Math.Sqrt(dist.X * dist.X + dist.Y * dist.Y);
            }

            Transform openingTrf = ExporterIFCUtils.GetUnscaledTransform(exporterIFC, hostObjPlacementHnd);
            XYZ hostObjYDir = openingTrf.BasisY;
            XYZ hostObjOrig = openingTrf.Origin;
            openingTrf = openingTrf.Inverse;

            // move to wall axis
            CurveLoop tmpCutLoop = GeometryUtil.TransformCurveLoop(cutLoop, openingTrf);

            cutDir = openingTrf.OfVector(cutDir);
            if (curve is Line)
            {
                Plane cutLoopPlane = null;
                try
                {
                    cutLoopPlane = tmpCutLoop.GetPlane();
                }
                catch
                {
                    return null;
                }

                XYZ clOrig = cutLoopPlane.Origin;

                double wantOriginAtY = posHingeSide ? (-unScaledDepth / 2.0) : (unScaledDepth / 2.0);

                if (!MathUtil.IsAlmostEqual(wantOriginAtY, clOrig[1]))
                {
                    XYZ moveVec = new XYZ(0, wantOriginAtY - clOrig[1], 0);
                    tmpCutLoop = GeometryUtil.MoveCurveLoop(tmpCutLoop, moveVec);
                }

                bool cutDirRelToHostObjY = (cutDir[1] > 0.0); // true = same sense, false = opp. sense

                if (posHingeSide != cutDirRelToHostObjY)
                {
                    cutDir = cutDir * -1.0;
                    cutDirRelToHostObjY = !cutDirRelToHostObjY;  // not used beyond this point.
                }
            }
            else if ((cutLoopBBox != null) && (curve is Arc))
            {
                Arc arc = curve as Arc;
                double radius = arc.Radius;

                XYZ curveCtr = arc.Center;

                // check orientation to cutDir, make sure it points to center of arc.

                XYZ origLL = new XYZ(cutLoopBBox.Min.X, cutLoopBBox.Min.Y, curveCtr.Z);
                XYZ origUR = new XYZ(cutLoopBBox.Max.X, cutLoopBBox.Max.Y, curveCtr.Z);
                XYZ origCtr = (origLL + origUR) / 2.0;

                double centerDist = origCtr.DistanceTo(curveCtr);
                XYZ approxMoveDir = (origCtr - curveCtr).Normalize();

                bool cutDirPointingIn = (cutDir.DotProduct(approxMoveDir) < 0.0);
                bool centerInsideArc = (centerDist < radius);
                if (centerInsideArc == cutDirPointingIn)
                {
                    XYZ moveVec = cutDir * -unScaledDepth;
                    origCtr += moveVec;
                    tmpCutLoop = GeometryUtil.MoveCurveLoop(tmpCutLoop, moveVec);
                }

                // not for windows that are too big ... forget about it.  Very rare case.
                double depthFactor = openingWidth / (2.0 * radius);
                double eps = MathUtil.Eps();
                if (depthFactor < 1.0 - eps)
                {
                    double depthFactorSq = depthFactor * depthFactor * 4;
                    double extraDepth = radius * (1.0 - Math.Sqrt(1.0 - depthFactorSq));
                    if (extraDepth > eps)
                    {
                        XYZ moveVec = cutDir * -extraDepth;
                        tmpCutLoop = GeometryUtil.MoveCurveLoop(tmpCutLoop, moveVec);
                        unScaledDepth += extraDepth;
                    }
                }

                // extra fudge on the other side of the window opening.
                depthFactor = origUnscaledDepth / (2.0 * radius);
                if (depthFactor < 1.0 - eps)
                {
                    double extraDepth = radius * (1.0 - Math.Sqrt(1.0 - depthFactor));
                    if (extraDepth > eps)
                        unScaledDepth += extraDepth;
                }
            }

            XYZ cutXDir = XYZ.BasisZ;
            XYZ cutOrig = XYZ.Zero;
            XYZ cutYDir = cutDir.CrossProduct(cutXDir);
            plane = new Plane(cutXDir, cutYDir, cutOrig);

            // now move to origin in this coordinate system.
            // todo: update openingtrf if we are to use it again!
            BoundingBoxXYZ tmpBBox = ComputeApproximateCurveLoopBBoxForOpening(tmpCutLoop, plane);
            if (tmpBBox != null)
            {
                relOrig = tmpBBox.Min;
                XYZ moveVec = relOrig * -1.0;
                tmpCutLoop = GeometryUtil.MoveCurveLoop(tmpCutLoop, moveVec);
            }

            IList<CurveLoop> oCutLoopList = new List<CurveLoop>();
            oCutLoopList.Add(tmpCutLoop);

            double depth = UnitUtil.ScaleLength(unScaledDepth);

            Element doorWindowElement = doc.GetElement(insertId);

            IFCAnyHandle openingRepHnd = RepresentationUtil.CreateExtrudedProductDefShape(exporterIFC, doorWindowElement, catId, 
                oCutLoopList, plane, cutDir, depth);
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(openingRepHnd))
                return null;

            // care only about first loop.
            IFCFile file = exporterIFC.GetFile();
            XYZ scaledOrig = UnitUtil.ScaleLength(relOrig);
            IFCAnyHandle openingPlacement = ExporterUtil.CreateLocalPlacement(file, hostObjPlacementHnd, scaledOrig, relZ, relX);

            string openingObjectType = isRecess ? "Recess": "Opening";
            string origOpeningName = NamingUtil.GetIFCNamePlusIndex(doorWindowElement, 1);
            string openingName = NamingUtil.GetNameOverride(doorWindowElement, origOpeningName);

            IFCAnyHandle openingHnd = IFCInstanceExporter.CreateOpeningElement(file, openingGUID, ownerHistory, openingName, null,
                openingObjectType, openingPlacement, openingRepHnd, null);

            string openingVoidsGUID = GUIDUtil.CreateSubElementGUID(doorWindowElement, (int)IFCDoorSubElements.DoorOpeningRelVoid);
            IFCInstanceExporter.CreateRelVoidsElement(file, openingVoidsGUID, ownerHistory, null, null, hostObjHnd, openingHnd);

            if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
            {
                using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
                {
                    double height = 0.0, width = 0.0;
                    if (ExtrusionExporter.ComputeHeightWidthOfCurveLoop(tmpCutLoop, plane, out height, out width))
                    {
                        extraParams.ScaledHeight = UnitUtil.ScaleLength(height);
                        extraParams.ScaledWidth = UnitUtil.ScaleLength(width);
                    }

                    IList<CurveLoop> curveLoops = new List<CurveLoop>();
                    curveLoops.Add(tmpCutLoop);
                    double area = ExporterIFCUtils.ComputeAreaOfCurveLoops(curveLoops);
                    if (area > 0.0)
                        extraParams.ScaledArea = UnitUtil.ScaleArea(area);

                    extraParams.ScaledLength = depth;
                    PropertyUtil.CreateOpeningQuantities(exporterIFC, openingHnd, extraParams);
                }
            }

            return DoorWindowOpeningInfo.Create(openingHnd, openingHeight, openingWidth);
        }
        /// <summary>
        /// Generates the UV value of a point projected to a plane, given an extrusion direction.
        /// </summary>
        /// <param name="plane">The plane.</param>
        /// <param name="projDir">The projection direction.</param>
        /// <param name="point">The point.</param>
        /// <returns>The UV value.</returns>
        public static UV ProjectPointToPlane(Plane plane, XYZ projDir, XYZ point)
        {
            XYZ zDir = plane.Normal;

            double denom = projDir.DotProduct(zDir);
            if (MathUtil.IsAlmostZero(denom))
                return null;

            XYZ xDir = plane.XVec;
            XYZ yDir = plane.YVec;
            XYZ orig = plane.Origin;

            double distToPlane = ((orig - point).DotProduct(zDir)) / denom;
            XYZ pointProj = distToPlane * projDir + point;
            XYZ pointProjOffset = pointProj - orig;
            UV pointProjUV = new UV(pointProjOffset.DotProduct(xDir), pointProjOffset.DotProduct(yDir));
            return pointProjUV;
        }
Example #33
0
        /// <summary>
        /// Main implementation to export walls.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <param name="geometryElement">
        /// The geometry element.
        /// </param>
        /// <param name="origWrapper">
        /// The IFCProductWrapper.
        /// </param>
        /// <param name="overrideLevelId">
        /// The level id.
        /// </param>
        /// <param name="range">
        /// The range to be exported for the element.
        /// </param>
        /// <returns>
        /// The exported wall handle.
        /// </returns>
        public static IFCAnyHandle ExportWallBase(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement,
           IFCProductWrapper origWrapper, ElementId overrideLevelId, IFCRange range)
        {
            using (IFCProductWrapper localWrapper = IFCProductWrapper.Create(origWrapper))
            {
                ElementId catId = CategoryUtil.GetSafeCategoryId(element);

                Wall wallElement = element as Wall;
                FamilyInstance famInstWallElem = element as FamilyInstance;

                if (wallElement == null && famInstWallElem == null)
                    return null;

                if (wallElement != null && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                    return null;

                // get global values.
                Document doc = element.Document;
                double scale = exporterIFC.LinearScale;

                IFCFile file = exporterIFC.GetFile();
                IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();
                IFCAnyHandle contextOfItemsAxis = exporterIFC.Get3DContextHandle("Axis");
                IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body");
              
                IFCRange zSpan = new IFCRange();
                double depth = 0.0;
                bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                bool exportParts = PartExporter.CanExportParts(wallElement);
                if (exportParts && !PartExporter.CanExportElementInPartExport(wallElement, validRange? overrideLevelId : wallElement.Level.Id, validRange))
                    return null;

                // get bounding box height so that we can subtract out pieces properly.
                // only for Wall, not FamilyInstance.
                if (wallElement != null && geometryElement != null)
                {
                    BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                    if (boundingBox == null)
                        return null;
                    zSpan = new IFCRange(boundingBox.Min.Z, boundingBox.Max.Z);

                    // if we have a top clipping plane, modify depth accordingly.
                    double bottomHeight = validRange ? Math.Max(zSpan.Start, range.Start) : zSpan.Start;
                    double topHeight = validRange ? Math.Min(zSpan.End, range.End) : zSpan.End;
                    depth = topHeight - bottomHeight;
                    if (MathUtil.IsAlmostZero(depth))
                        return null;
                    depth *= scale;
                }

                IFCAnyHandle axisRep = null;
                IFCAnyHandle bodyRep = null;

                bool exportingAxis = false;
                Curve curve = null;

                bool exportedAsWallWithAxis = false;
                bool exportedBodyDirectly = false;
                bool exportingInplaceOpenings = false;

                Curve centerCurve = GetWallAxis(wallElement);

                XYZ localXDir = new XYZ(1, 0, 0);
                XYZ localYDir = new XYZ(0, 1, 0);
                XYZ localZDir = new XYZ(0, 0, 1);
                XYZ localOrig = new XYZ(0, 0, 0);
                double eps = MathUtil.Eps();

                if (centerCurve != null)
                {
                    Curve baseCurve = GetWallAxisAtBaseHeight(wallElement);
                    curve = GetWallTrimmedCurve(wallElement, baseCurve);

                    IFCRange curveBounds;
                    XYZ oldOrig;
                    GeometryUtil.GetAxisAndRangeFromCurve(curve, out curveBounds, out localXDir, out oldOrig);

                    localOrig = oldOrig;
                    if (baseCurve != null)
                    {
                        if (!validRange || (MathUtil.IsAlmostEqual(range.Start, zSpan.Start)))
                        {
                            XYZ newOrig = baseCurve.Evaluate(curveBounds.Start, false);
                            if (!validRange && (zSpan.Start < newOrig[2] - eps))
                                localOrig = new XYZ(localOrig.X, localOrig.Y, zSpan.Start);
                            else
                                localOrig = new XYZ(localOrig.X, localOrig.Y, newOrig[2]);
                        }
                        else
                        {
                            localOrig = new XYZ(localOrig.X, localOrig.Y, range.Start);
                        }
                    }

                    double dist = localOrig[2] - oldOrig[2];
                    if (!MathUtil.IsAlmostZero(dist))
                    {
                        XYZ moveVec = new XYZ(0, 0, dist);
                        curve = GeometryUtil.MoveCurve(curve, moveVec);
                    }
                    localYDir = localZDir.CrossProduct(localXDir);

                    // ensure that X and Z axes are orthogonal.
                    double xzDot = localZDir.DotProduct(localXDir);
                    if (!MathUtil.IsAlmostZero(xzDot))
                        localXDir = localYDir.CrossProduct(localZDir);
                }

                Transform orientationTrf = Transform.Identity;
                orientationTrf.BasisX = localXDir;
                orientationTrf.BasisY = localYDir;
                orientationTrf.BasisZ = localZDir;
                orientationTrf.Origin = localOrig;

                using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                {
                    IFCAnyHandle localPlacement = setter.GetPlacement();

                    Plane plane = new Plane(localXDir, localYDir, localOrig);  // project curve to XY plane.
                    XYZ projDir = XYZ.BasisZ;

                    // two representations: axis, body.         
                    {
                        if ((centerCurve != null) && (GeometryUtil.CurveIsLineOrArc(centerCurve)))
                        {
                            exportingAxis = true;

                            string identifierOpt = "Axis";	// IFC2x2 convention
                            string representationTypeOpt = "Curve2D";  // IFC2x2 convention

                            IFCGeometryInfo info = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, plane, projDir, false);
                            ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, curve, XYZ.Zero, true);
                            IList<IFCAnyHandle> axisItems = info.GetCurves();

                            if (axisItems.Count == 0)
                            {
                                exportingAxis = false;
                            }
                            else
                            {
                                HashSet<IFCAnyHandle> axisItemSet = new HashSet<IFCAnyHandle>();
                                foreach (IFCAnyHandle axisItem in axisItems)
                                    axisItemSet.Add(axisItem);

                                axisRep = RepresentationUtil.CreateShapeRepresentation(exporterIFC, element, catId, contextOfItemsAxis,
                                   identifierOpt, representationTypeOpt, axisItemSet);
                            }
                        }
                    }

                    IList<IFCExtrusionData> cutPairOpenings = new List<IFCExtrusionData>();
                    Document document = element.Document;

                    if (wallElement != null && exportingAxis && curve != null)
                    {
                        SolidMeshGeometryInfo solidMeshInfo = 
                            (range == null) ? GeometryUtil.GetSolidMeshGeometry(geometryElement, Transform.Identity) :
                                GeometryUtil.GetClippedSolidMeshGeometry(geometryElement, range);
                                
                        IList<Solid> solids = solidMeshInfo.GetSolids();
                        IList<Mesh> meshes = solidMeshInfo.GetMeshes();
                        if (solids.Count == 0 && meshes.Count == 0)
                            return null;

                        bool useNewCode = false;
                        if (useNewCode && solids.Count == 1 && meshes.Count == 0)
                        {
                            bool completelyClipped;
                            bodyRep = ExtrusionExporter.CreateExtrusionWithClipping(exporterIFC, wallElement, catId, solids[0], 
                                plane, projDir, range, out completelyClipped);

                            if (completelyClipped)
                                return null;

                            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                            {
                                exportedAsWallWithAxis = true;
                                exportedBodyDirectly = true;
                            }
                            else
                            {
                                exportedAsWallWithAxis = false;
                                exportedBodyDirectly = false;
                            }
                        }
                            
                        if (!exportedAsWallWithAxis)
                        {
                            // Fallback - use native routines to try to export wall.
                            bool isCompletelyClipped;
                            bodyRep = FallbackTryToCreateAsExtrusion(exporterIFC, wallElement, solidMeshInfo,
                                catId, curve, plane, depth, zSpan, range, setter, 
                                out cutPairOpenings, out isCompletelyClipped);
                            if (isCompletelyClipped)
                                return null;
                            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                exportedAsWallWithAxis = true;
                        }
                    }
                
                    using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
                    {
                        ElementId matId = ElementId.InvalidElementId;

                        if (!exportedAsWallWithAxis)
                        {
                            SolidMeshGeometryInfo solidMeshCapsule = null;

                            if (wallElement != null)
                            {
                                if (validRange)
                                {
                                    solidMeshCapsule = GeometryUtil.GetClippedSolidMeshGeometry(geometryElement, range);
                                }
                                else
                                {
                                    solidMeshCapsule = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement);
                                }
                                if (solidMeshCapsule.SolidsCount() == 0 && solidMeshCapsule.MeshesCount() == 0)
                                {
                                    return null;
                                }
                            }
                            else
                            {
                                GeometryElement geomElemToUse = GetGeometryFromInplaceWall(famInstWallElem);
                                if (geomElemToUse != null)
                                {
                                    exportingInplaceOpenings = true;
                                }
                                else
                                {
                                    exportingInplaceOpenings = false;
                                    geomElemToUse = geometryElement;
                                }
                                Transform trf = Transform.Identity;
                                if (geomElemToUse != geometryElement)
                                    trf = famInstWallElem.GetTransform();
                                solidMeshCapsule = GeometryUtil.GetSolidMeshGeometry(geomElemToUse, trf);
                            }

                            IList<Solid> solids = solidMeshCapsule.GetSolids();
                            IList<Mesh> meshes = solidMeshCapsule.GetMeshes();

                            extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                            extraParams.AreInnerRegionsOpenings = true;

                            BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                            if ((solids.Count > 0) || (meshes.Count > 0))
                            {
                                matId = BodyExporter.GetBestMaterialIdForGeometry(solids, meshes);
                                bodyRep = BodyExporter.ExportBody(element.Document.Application, exporterIFC, element, catId,
                                    solids, meshes, bodyExporterOptions, extraParams).RepresentationHnd;
                            }
                            else
                            {
                                IList<GeometryObject> geomElemList = new List<GeometryObject>();
                                geomElemList.Add(geometryElement);
                                BodyData bodyData = BodyExporter.ExportBody(element.Document.Application, exporterIFC, element, catId,
                                    geomElemList, bodyExporterOptions, extraParams);
                                bodyRep = bodyData.RepresentationHnd;
                            }

                            if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                            {
                                extraParams.ClearOpenings();
                                return null;
                            }

                            // We will be able to export as a IfcWallStandardCase as long as we have an axis curve.
                            XYZ extrDirUsed = XYZ.Zero;
                            if (extraParams.HasExtrusionDirection)
                            {
                                extrDirUsed = extraParams.ExtrusionDirection;
                                if (MathUtil.IsAlmostEqual(Math.Abs(extrDirUsed[2]), 1.0))
                                {
                                    if ((solids.Count == 1) && (meshes.Count == 0))
                                        exportedAsWallWithAxis = exportingAxis;
                                    exportedBodyDirectly = true;
                                }
                            }
                        }

                        IFCAnyHandle prodRep = null;
                        IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                        if (exportingAxis)
                            representations.Add(axisRep);

                        representations.Add(bodyRep);
                        prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);

                        string objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                        IFCAnyHandle wallHnd = null;

                        string elemGUID = (validRange) ? ExporterIFCUtils.CreateGUID() : ExporterIFCUtils.CreateGUID(element);
                        string elemName = NamingUtil.GetNameOverride(element, exporterIFC.GetName());
                        string elemDesc = NamingUtil.GetDescriptionOverride(element, null);
                        string elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                        string elemId = NamingUtil.CreateIFCElementId(element);

                        if (exportedAsWallWithAxis)
                        {
                            wallHnd = IFCInstanceExporter.CreateWallStandardCase(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                localPlacement, exportParts ? null : prodRep, elemId);

                            if (exportParts)
                                PartExporter.ExportHostPart(exporterIFC, wallElement, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                            localWrapper.AddElement(wallHnd, setter, extraParams, true);

                            OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, cutPairOpenings, exporterIFC, localPlacement, setter, localWrapper);
                            if (exportedBodyDirectly)
                            {
                                OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, exporterIFC, localPlacement, setter, localWrapper);
                            }
                            else
                            {
                                double scaledWidth = wallElement.Width * scale;
                                ExporterIFCUtils.AddOpeningsToElement(exporterIFC, wallHnd, wallElement, scaledWidth, range, setter, localPlacement, localWrapper);
                            }

                            // export Base Quantities
                            if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
                            {
                                CreateWallBaseQuantities(exporterIFC, wallElement, wallHnd, depth);
                            }
                        }
                        else
                        {
                            wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                localPlacement, exportParts ? null : prodRep, elemId);

                            if (exportParts)
                                PartExporter.ExportHostPart(exporterIFC, wallElement, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                            localWrapper.AddElement(wallHnd, setter, extraParams, true);

                            // Only export one material for 2x2; for future versions, export the whole list.
                            if (exporterIFC.ExportAs2x2 && (matId != ElementId.InvalidElementId) && !exportParts)
                            {
                                CategoryUtil.CreateMaterialAssociation(doc, exporterIFC, wallHnd, matId);
                            }

                            if (exportingInplaceOpenings)
                            {
                                ExporterIFCUtils.AddOpeningsToElement(exporterIFC, wallHnd, famInstWallElem, 0.0, range, setter, localPlacement, localWrapper);
                            }

                            if (exportedBodyDirectly)
                                OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, exporterIFC, localPlacement, setter, localWrapper);
                        }

                        PropertyUtil.CreateInternalRevitPropertySets(exporterIFC, element, localWrapper);

                        ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;

                        if (wallElement != null && !exportParts)
                        {
                            if (!exporterIFC.ExportAs2x2 || exportedAsWallWithAxis) //will move this check into ExportHostObject
                                HostObjectExporter.ExportHostObjectMaterials(exporterIFC, wallElement, localWrapper.GetAnElement(),
                                    geometryElement, localWrapper, wallLevelId, Toolkit.IFCLayerSetDirection.Axis2);
                        }

                        exporterIFC.RegisterSpaceBoundingElementHandle(wallHnd, element.Id, wallLevelId);
                        return wallHnd;
                    }
                }
            }
        }
        /// <summary>
        /// Main implementation to export walls.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <param name="geometryElement">
        /// The geometry element.
        /// </param>
        /// <param name="productWrapper">
        /// The IFCProductWrapper.
        /// </param>
        /// <param name="overrideLevelId">
        /// The level id.
        /// </param>
        /// <param name="range">
        /// The range to be exported for the element.
        /// </param>
        /// <returns>
        /// The exported wall handle.
        /// </returns>
        public static IFCAnyHandle ExportWallBase(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement,
           IFCProductWrapper productWrapper, ElementId overrideLevelId, UV range)
        {
            using (IFCProductWrapper localWrapper = IFCProductWrapper.Create(productWrapper))
            {
                ElementId catId = CategoryUtil.GetSafeCategoryId(element);

                Wall wallElement = element as Wall;
                FamilyInstance famInstWallElem = element as FamilyInstance;

                if (wallElement == null && famInstWallElem == null)
                    return IFCAnyHandle.Create();

                if (wallElement != null && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                    return IFCAnyHandle.Create();

                // get global values.
                Document doc = element.Document;
                double scale = exporterIFC.LinearScale;

                IFCFile file = exporterIFC.GetFile();
                IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();
                IFCAnyHandle contextOfItems = exporterIFC.Get3DContextHandle();

                UV zSpan = UV.Zero;
                double depth = 0.0;
                bool validRange = (!MathUtil.IsAlmostZero(range.V - range.U));

                // get bounding box height so that we can subtract out pieces properly.
                // only for Wall, not FamilyInstance.
                if (wallElement != null && geometryElement != null)
                {
                    BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                    zSpan = new UV(boundingBox.Min.Z, boundingBox.Max.Z);

                    // if we have a top clipping plane, modify depth accordingly.
                    double bottomHeight = validRange ? Math.Max(zSpan[0], range[0]) : zSpan[0];
                    double topHeight = validRange ? Math.Min(zSpan[1], range[1]) : zSpan[1];
                    depth = topHeight - bottomHeight;
                    if (MathUtil.IsAlmostZero(depth))
                        return IFCAnyHandle.Create();
                    depth *= scale;
                }

                IFCAnyHandle axisRep = IFCAnyHandle.Create();
                IFCAnyHandle bodyRep = IFCAnyHandle.Create();

                bool exportingAxis = false;
                Curve curve = null;

                bool exportedAsWallWithAxis = false;
                bool exportedBodyDirectly = false;
                bool exportingInplaceOpenings = false;

                Curve centerCurve = GetWallAxis(wallElement);

                XYZ localXDir = new XYZ(1, 0, 0);
                XYZ localYDir = new XYZ(0, 1, 0);
                XYZ localZDir = new XYZ(0, 0, 1);
                XYZ localOrig = new XYZ(0, 0, 0);
                double eps = MathUtil.Eps();

                if (centerCurve != null)
                {
                    Curve baseCurve = GetWallAxisAtBaseHeight(wallElement);
                    curve = GetWallTrimmedCurve(wallElement, baseCurve);

                    UV curveBounds;
                    XYZ oldOrig;
                    GeometryUtil.GetAxisAndRangeFromCurve(curve, out curveBounds, out localXDir, out oldOrig);

                    localOrig = oldOrig;
                    if (baseCurve != null)
                    {
                        if (!validRange || (MathUtil.IsAlmostEqual(range[0], zSpan[0])))
                        {
                            XYZ newOrig = baseCurve.Evaluate(curveBounds.U, false);
                            if (validRange && (zSpan[0] < newOrig[2] - eps))
                                localOrig = new XYZ(localOrig.X, localOrig.Y, zSpan[0]);
                            else
                                localOrig = new XYZ(localOrig.X, localOrig.Y, newOrig[2]);
                        }
                        else
                        {
                            localOrig = new XYZ(localOrig.X, localOrig.Y, range[0]);
                        }
                    }

                    double dist = localOrig[2] - oldOrig[2];
                    if (!MathUtil.IsAlmostZero(dist))
                    {
                        XYZ moveVec = new XYZ(0, 0, dist);
                        curve = GeometryUtil.MoveCurve(curve, moveVec);
                    }
                    localYDir = localZDir.CrossProduct(localXDir);

                    // ensure that X and Z axes are orthogonal.
                    double xzDot = localZDir.DotProduct(localXDir);
                    if (!MathUtil.IsAlmostZero(xzDot))
                        localXDir = localYDir.CrossProduct(localZDir);
                }

                Transform orientationTrf = Transform.Identity;
                orientationTrf.BasisX = localXDir;
                orientationTrf.BasisY = localYDir;
                orientationTrf.BasisZ = localZDir;
                orientationTrf.Origin = localOrig;

                using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                {
                    IFCAnyHandle localPlacement = setter.GetPlacement();

                    Plane plane = new Plane(localXDir, localYDir, localOrig);  // project curve to XY plane.
                    XYZ projDir = new XYZ(0, 0, 1);

                    // two representations: axis, body.         
                    {
                        if ((centerCurve != null) && (GeometryUtil.CurveIsLineOrArc(centerCurve)))
                        {
                            exportingAxis = true;

                            IFCLabel identifierOpt = IFCLabel.Create("Axis");	// IFC2x2 convention
                            IFCLabel representationTypeOpt = IFCLabel.Create("Curve2D");  // IFC2x2 convention

                            IFCGeometryInfo info = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, plane, projDir, false);
                            ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, curve, XYZ.Zero, true);
                            IList<IFCAnyHandle> axisItems = info.GetCurves();

                            if (axisItems.Count == 0)
                            {
                                exportingAxis = false;
                            }
                            else
                            {
                                HashSet<IFCAnyHandle> axisItemSet = new HashSet<IFCAnyHandle>();
                                foreach (IFCAnyHandle axisItem in axisItems)
                                    axisItemSet.Add(axisItem);

                                axisRep = RepresentationUtil.CreateShapeRepresentation(exporterIFC, catId, contextOfItems,
                                   identifierOpt, representationTypeOpt, axisItemSet);
                            }
                        }
                    }

                    IList<IFCExtrusionData> cutPairOpenings = new List<IFCExtrusionData>();

                    do
                    {
                        if (wallElement == null || !exportingAxis || curve == null)
                            break;

                        bool hasExtrusion = HasElevationProfile(wallElement);
                        if (hasExtrusion)
                        {
                            IList<CurveLoop> loops = GetElevationProfile(wallElement);
                            if (loops.Count == 0)
                                hasExtrusion = false;
                            else
                            {
                                IList<IList<CurveLoop>> sortedLoops = ExporterIFCUtils.SortCurveLoops(loops);
                                if (sortedLoops.Count == 0)
                                    break;

                                // Current limitation: can't handle wall split into multiple disjointed pieces.
                                int numSortedLoops = sortedLoops.Count;
                                if (numSortedLoops > 1)
                                    break;

                                bool ignoreExtrusion = true;
                                bool cantHandle = false;
                                bool hasGeometry = false;
                                for (int ii = 0; (ii < numSortedLoops) && !cantHandle; ii++)
                                {
                                    int sortedLoopSize = sortedLoops[ii].Count;
                                    if (sortedLoopSize == 0)
                                        continue;
                                    if (!ExporterIFCUtils.IsCurveLoopConvexWithOpenings(sortedLoops[ii][0], range, wallElement, out ignoreExtrusion))
                                    {
                                        if (ignoreExtrusion)
                                        {
                                            // we need more information.  Is there something to export?  If so, we'll
                                            // ignore the extrusion.  Otherwise, we will fail.

                                            IFCSolidMeshGeometryInfo solidMeshInfo = ExporterIFCUtils.GetClippedSolidMeshGeometry(exporterIFC, range, geometryElement);
                                            if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0)
                                                continue;
                                            hasExtrusion = false;
                                        }
                                        else
                                        {
                                            cantHandle = true;
                                        }
                                        hasGeometry = true;
                                    }
                                    else
                                    {
                                        hasGeometry = true;
                                    }
                                }

                                if (!hasGeometry)
                                    return IFCAnyHandle.Create();
                                if (cantHandle)
                                    break;
                            }
                        }

                        if (!CanExportWallGeometryAsExtrusion(element, range))
                            break;

                        // extrusion direction.
                        XYZ extrusionDir = GetWallHeightDirection(wallElement);

                        // create extrusion boundary.
                        IList<CurveLoop> boundaryLoops = new List<CurveLoop>();

                        bool alwaysThickenCurve = IsWallBaseRectangular(wallElement, curve);

                        if (!alwaysThickenCurve)
                        {
                            boundaryLoops = GetLoopsFromTopBottomFace(wallElement, exporterIFC);
                            if (boundaryLoops.Count == 0)
                                continue;
                        }
                        else
                        {
                            CurveLoop newLoop = CurveLoop.CreateViaThicken(curve, wallElement.Width, new XYZ(0, 0, 1));
                            if (newLoop == null)
                                break;

                            if (!GeometryUtil.IsIFCLoopCCW(newLoop, new XYZ(0, 0, 1)))
                                newLoop = GeometryUtil.ReverseOrientation(newLoop);
                            boundaryLoops.Add(newLoop);
                        }

                        // origin gets scaled later.
                        XYZ setterOffset = new XYZ(0, 0, setter.Offset + (localOrig[2] - setter.BaseOffset));

                        IFCAnyHandle baseBodyItemHnd = file.CreateExtrudedSolidFromCurveLoop(exporterIFC, catId,
                           boundaryLoops, plane, extrusionDir, depth);
                        if (!baseBodyItemHnd.HasValue)
                            break;

                        IFCAnyHandle bodyItemHnd = AddClippingsToBaseExtrusion(exporterIFC, wallElement,
                           setterOffset, range, zSpan, baseBodyItemHnd, out cutPairOpenings);
                        if (!bodyItemHnd.HasValue)
                            break;

                        HashSet<IFCAnyHandle> bodyItems = new HashSet<IFCAnyHandle>();
                        bodyItems.Add(bodyItemHnd);

                        if (baseBodyItemHnd.Id == bodyItemHnd.Id)
                        {
                            bodyRep = RepresentationUtil.CreateSweptSolidRep(exporterIFC, catId, contextOfItems, bodyItems, IFCAnyHandle.Create());
                        }
                        else
                        {
                            bodyRep = RepresentationUtil.CreateClippingRep(exporterIFC, catId, contextOfItems, bodyItems);
                        }

                        if (bodyRep.HasValue)
                            exportedAsWallWithAxis = true;
                    } while (false);

                    IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData();
                    ElementId matId = ElementId.InvalidElementId;

                    if (!exportedAsWallWithAxis)
                    {
                        IFCSolidMeshGeometryInfo solidMeshInfo;

                        if (wallElement != null)
                        {
                            if (validRange)
                            {
                                solidMeshInfo = ExporterIFCUtils.GetClippedSolidMeshGeometry(exporterIFC, range, geometryElement);
                                if (solidMeshInfo.GetSolids().Count == 0 && solidMeshInfo.GetMeshes().Count == 0)
                                    return IFCAnyHandle.Create();
                            }
                            else
                            {
                                solidMeshInfo = ExporterIFCUtils.GetSplitSolidMeshGeometry(exporterIFC, geometryElement);
                            }
                        }
                        else
                        {
                            GeometryElement geomElemToUse = GetGeometryFromInplaceWall(famInstWallElem);
                            if (geomElemToUse != null)
                            {
                                exportingInplaceOpenings = true;
                            }
                            else
                            {
                                exportingInplaceOpenings = false;
                                geomElemToUse = geometryElement;
                            }
                            Transform trf = Transform.Identity;
                            if (geomElemToUse != geometryElement)
                                trf = famInstWallElem.GetTransform();
                            solidMeshInfo = ExporterIFCUtils.GetSolidMeshGeometry(exporterIFC, geomElemToUse, trf);
                        }

                        IList<Solid> solids = solidMeshInfo.GetSolids();
                        IList<Mesh> meshes = solidMeshInfo.GetMeshes();

                        extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                        extraParams.AreInnerRegionsOpenings = true;

                        if ((solids.Count > 0) || (meshes.Count > 0))
                        {
                            matId = BodyExporter.GetBestMaterialIdForGeometry(solids, meshes);
                            bodyRep = BodyExporter.ExportBody(element.Document.Application, exporterIFC, catId, solids, meshes, true, extraParams);
                        }
                        else
                        {
                            IList<GeometryObject> geomElemList = new List<GeometryObject>();
                            geomElemList.Add(geometryElement);
                            bodyRep = BodyExporter.ExportBody(element.Document.Application, exporterIFC, catId, geomElemList, true, extraParams);
                        }

                        if (!bodyRep.HasValue)
                            return IFCAnyHandle.Create();

                        // We will be able to export as a IfcWallStandardCase as long as we have an axis curve.
                        XYZ extrDirUsed = XYZ.Zero;
                        if (extraParams.HasCustomAxis)
                        {
                            extrDirUsed = extraParams.CustomAxis;
                            if (MathUtil.IsAlmostEqual(Math.Abs(extrDirUsed[2]), 1.0))
                            {
                                if ((solids.Count == 1) && (meshes.Count == 0))
                                    exportedAsWallWithAxis = exportingAxis;
                                exportedBodyDirectly = true;
                            }
                        }
                    }

                    IFCAnyHandle prodRep = IFCAnyHandle.Create();
                    IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                    if (exportingAxis)
                        representations.Add(axisRep);

                    representations.Add(bodyRep);
                    prodRep = file.CreateProductDefinitionShape(IFCLabel.Create(), IFCLabel.Create(), representations);

                    IFCLabel objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                    IFCAnyHandle wallHnd = IFCAnyHandle.Create();

                    IFCLabel elemGUID = (validRange) ? IFCLabel.CreateGUID() : IFCLabel.CreateGUID(element);
                    IFCLabel elemName = NamingUtil.GetNameOverride(element, NamingUtil.CreateIFCName(exporterIFC, -1));
                    IFCLabel elemDesc = NamingUtil.GetDescriptionOverride(element, IFCLabel.Create());
                    IFCLabel elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                    IFCLabel elemId = NamingUtil.CreateIFCElementId(element);

                    if (exportedAsWallWithAxis)
                    {
                        wallHnd = file.CreateWallStandardCase(elemGUID, ownerHistory, elemName, elemDesc, elemObjectType, localPlacement,
                           elemId, prodRep);
                        localWrapper.AddElement(wallHnd, setter, extraParams, true);

                        OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, cutPairOpenings, exporterIFC, localPlacement, setter, localWrapper);
                        if (exportedBodyDirectly)
                        {
                            OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, exporterIFC, localPlacement, setter, localWrapper);
                        }
                        else
                        {
                            double scaledWidth = wallElement.Width * scale;
                            ExporterIFCUtils.AddOpeningsToWall(exporterIFC, wallHnd, wallElement, scaledWidth, range, setter, localPlacement, localWrapper);
                        }

                        // export Base Quantities
                        if (exporterIFC.ExportBaseQuantities)
                        {
                            CreateWallBaseQuantities(exporterIFC, wallElement, wallHnd, depth);
                        }
                    }
                    else
                    {
                        wallHnd = file.CreateWall(elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                           localPlacement, elemId, prodRep);
                        localWrapper.AddElement(wallHnd, setter, extraParams, true);

                        // Only export one material for 2x2; for future versions, export the whole list.
                        if (exporterIFC.ExportAs2x2 && (matId != ElementId.InvalidElementId))
                        {
                            CategoryUtil.CreateMaterialAssociation(doc, exporterIFC, wallHnd, matId);
                        }

                        if (exportingInplaceOpenings)
                        {
                            double scaledWidth = wallElement.Width * scale;
                            ExporterIFCUtils.AddOpeningsToWall(exporterIFC, wallHnd, wallElement, scaledWidth, range, setter, localPlacement, localWrapper);
                        }

                        if (exportedBodyDirectly)
                            OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, exporterIFC, localPlacement, setter, localWrapper);
                    }

                    ExporterIFCUtils.CreateGenericElementPropertySet(exporterIFC, element, localWrapper);

                    ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;

                    if (wallElement != null)
                        ExporterIFCUtils.ExportHostObject(exporterIFC, wallElement, geometryElement, localWrapper);

                    exporterIFC.RegisterSpaceBoundingElementHandle(wallHnd, element.Id, wallLevelId);
                    return wallHnd;
                }
            }
        }
Example #35
0
        /// <summary>
        /// Creates or updates the IfcLocalPlacement associated with the current origin offset.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="bbox">The bounding box.</param>
        /// <param name="ecData">The extrusion creation data which contains the local placement.</param>
        /// <param name="lpOrig">The local placement origin.</param>
        /// <param name="unscaledTrfOrig">The unscaled local placement origin.</param>
        public void CreateLocalPlacementFromOffset(ExporterIFC exporterIFC, BoundingBoxXYZ bbox, IFCExtrusionCreationData ecData, XYZ lpOrig, XYZ unscaledTrfOrig)
        {
            if (ecData == null)
                return;

            IFCAnyHandle localPlacement = ecData.GetLocalPlacement();
            if (!IFCAnyHandleUtil.IsNullOrHasNoValue(localPlacement))
            {
                IFCFile file = exporterIFC.GetFile();

                // If the BBox passes through (0,0, 0), or no bbox, do nothing.
                if (bbox == null ||
                    ((bbox.Min.X < MathUtil.Eps() && bbox.Max.X > -MathUtil.Eps()) &&
                     (bbox.Min.Y < MathUtil.Eps() && bbox.Max.Y > -MathUtil.Eps()) &&
                     (bbox.Min.Z < MathUtil.Eps() && bbox.Max.Z > -MathUtil.Eps())))
                {
                    if (!ecData.ReuseLocalPlacement)
                        ecData.SetLocalPlacement(ExporterUtil.CopyLocalPlacement(file, localPlacement));
                    return;
                }

                if (!MathUtil.IsAlmostZero(unscaledTrfOrig.DotProduct(unscaledTrfOrig)))
                {
                    if (!ecData.ReuseLocalPlacement)
                        ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, lpOrig, null, null));
                    else
                    {
                        IFCAnyHandle relativePlacement = GeometryUtil.GetRelativePlacementFromLocalPlacement(localPlacement);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(relativePlacement))
                        {
                            IFCAnyHandle newRelativePlacement = ExporterUtil.CreateAxis(file, lpOrig, null, null);
                            GeometryUtil.SetRelativePlacement(localPlacement, newRelativePlacement);
                        }
                        else
                        {
                            IFCAnyHandle newOriginHnd = ExporterUtil.CreateCartesianPoint(file, lpOrig);
                            IFCAnyHandleUtil.SetAttribute(relativePlacement, "Location", newOriginHnd);
                        }
                    }
                }
                else if (ecData.ForceOffset)
                    ecData.SetLocalPlacement(ExporterUtil.CreateLocalPlacement(file, localPlacement, null));
                else if (!ecData.ReuseLocalPlacement)
                    ecData.SetLocalPlacement(ExporterUtil.CopyLocalPlacement(file, localPlacement));
            }
        }
    private static bool GetPolygonPlane(List<XYZ> polygon, 
      out XYZ normal, out double dist, out double area)
    {
      normal = XYZ.Zero;
      dist = area = 0.0;
      int n = (null == polygon) ? 0 : polygon.Count;
      bool rc = (2 < n);
      if (3 == n)
      {
        XYZ a = polygon[0];
        XYZ b = polygon[1];
        XYZ c = polygon[2];
        XYZ v = b - a;
        normal = v.CrossProduct(c - a);
        dist = normal.DotProduct(a);
      }
      else if (4 == n)
      {
        XYZ a = polygon[0];
        XYZ b = polygon[1];
        XYZ c = polygon[2];
        XYZ d = polygon[3];

        normal = new XYZ(
        (c.Y - a.Y) * (d.Z - b.Z) + (c.Z - a.Z) * (b.Y - d.Y),
        (c.Z - a.Z) * (d.X - b.X) + (c.X - a.X) * (b.Z - d.Z),
        (c.X - a.X) * (d.Y - b.Y) + (c.Y - a.Y) * (b.X - d.X));

        dist = 0.25 *
          (normal.X * (a.X + b.X + c.X + d.X)
          + normal.Y * (a.Y + b.Y + c.Y + d.Y)
          + normal.Z * (a.Z + b.Z + c.Z + d.Z));
      }
      else if (4 < n)
      {
        XYZ a;
        XYZ b = polygon[n - 2];
        XYZ c = polygon[n - 1];
        XYZ s = XYZ.Zero;

        for (int i = 0; i < n; ++i)
        {
          a = b;
          b = c;
          c = polygon[i];

          normal = new XYZ(
          b.Y * (c.Z - a.Z),
          b.Z * (c.X - a.X),
          b.X * (c.Y - a.Y));

          s += c;
        }
        dist = s.DotProduct(normal) / n;
      }
      if (rc)
      {
        double length = normal.GetLength();
        rc = !normal.IsZeroLength();

        if (rc)
        {
          normal /= length;
          dist /= length;
          area = 0.5 * length;
        }
      }
      return rc;
    }
Example #37
0
        /// <summary>
        /// Creates an extruded solid from a collection of curve loops and a thickness.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="profileName">The name of the extrusion profile.</param>
        /// <param name="origCurveLoops">The profile boundary curves.</param>
        /// <param name="plane">The plane of the boundary curves.</param>
        /// <param name="extrDirVec">The direction of the extrusion.</param>
        /// <param name="scaledExtrusionSize">The thickness of the extrusion, perpendicular to the plane.</param>
        /// <returns>The IfcExtrudedAreaSolid handle.</returns>
        /// <remarks>If the curveLoop plane normal is not the same as the plane direction, only tesellated boundaries are supported.</remarks> 
        public static IFCAnyHandle CreateExtrudedSolidFromCurveLoop(ExporterIFC exporterIFC, string profileName, IList<CurveLoop> origCurveLoops,
            Plane plane, XYZ extrDirVec, double scaledExtrusionSize)
        {
            IFCAnyHandle extrudedSolidHnd = null;
            
            if (scaledExtrusionSize < MathUtil.Eps())
                return extrudedSolidHnd;

            IFCFile file = exporterIFC.GetFile();
	
            // we need to figure out the plane of the curve loops and modify the extrusion direction appropriately.
            // assumption: first curve loop defines the plane.
            int sz = origCurveLoops.Count;
            if (sz == 0)
                return extrudedSolidHnd;

            XYZ planeXDir = plane.XVec;
            XYZ planeYDir = plane.YVec;
            XYZ planeZDir = plane.Normal;
            XYZ planeOrig = plane.Origin;

            double slantFactor = Math.Abs(planeZDir.DotProduct(extrDirVec));
            if (MathUtil.IsAlmostZero(slantFactor))
                return extrudedSolidHnd;

            // Check that curve loops are valid.
            IList<CurveLoop> curveLoops = ExporterIFCUtils.ValidateCurveLoops(origCurveLoops, extrDirVec);
            if (curveLoops.Count == 0)
                return extrudedSolidHnd;

            scaledExtrusionSize /= slantFactor;

            IFCAnyHandle sweptArea = null;
            if (curveLoops.Count == 1)
            {
                sweptArea = CreateRectangleProfileDefIfPossible(exporterIFC, profileName, curveLoops[0], plane, extrDirVec);
                if (sweptArea == null) sweptArea = CreateCircleProfileDefIfPossible(exporterIFC, profileName, curveLoops[0], plane, extrDirVec);
                if (sweptArea == null) sweptArea = CreateIShapeProfileDefIfPossible(exporterIFC, profileName, curveLoops[0], plane, extrDirVec);
            }

            if (sweptArea == null)
            {
                IFCAnyHandle profileCurve = null;
                HashSet<IFCAnyHandle> innerCurves = new HashSet<IFCAnyHandle>();

                // reorient curves if necessary: outer CCW, inners CW.
                foreach (CurveLoop curveLoop in curveLoops)
                {
                    bool isCCW = false;
                    try
                    {
                        isCCW = curveLoop.IsCounterclockwise(planeZDir);
                    }
                    catch
                    {
                        if (profileCurve == null)
                            return null;
                        else
                            continue;
                    }

                    if (profileCurve == null)
                    {
                        if (!isCCW)
                            curveLoop.Flip();
                        profileCurve = ExporterIFCUtils.CreateCurveFromCurveLoop(exporterIFC, curveLoop, plane, extrDirVec);
                        if (IFCAnyHandleUtil.IsNullOrHasNoValue(profileCurve))
                            return extrudedSolidHnd;
                    }
                    else
                    {
                        if (isCCW)
                            curveLoop.Flip();
                        IFCAnyHandle innerCurve = ExporterIFCUtils.CreateCurveFromCurveLoop(exporterIFC, curveLoop, plane, extrDirVec);
                        if (!IFCAnyHandleUtil.IsNullOrHasNoValue(innerCurve))
                            innerCurves.Add(innerCurve);
                    }
                }

                if (innerCurves.Count > 0)
                    sweptArea = IFCInstanceExporter.CreateArbitraryProfileDefWithVoids(file, IFCProfileType.Area, profileName, profileCurve, innerCurves);
                else
                    sweptArea = IFCInstanceExporter.CreateArbitraryClosedProfileDef(file, IFCProfileType.Area, profileName, profileCurve);
            }

            IList<double> relExtrusionDirList = new List<double>();
            relExtrusionDirList.Add(extrDirVec.DotProduct(planeXDir));
            relExtrusionDirList.Add(extrDirVec.DotProduct(planeYDir));
            relExtrusionDirList.Add(extrDirVec.DotProduct(planeZDir));

            XYZ scaledXDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, planeXDir);
            XYZ scaledZDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, planeZDir);
            XYZ scaledOrig = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, planeOrig);
   
            IFCAnyHandle solidAxis = ExporterUtil.CreateAxis(file, scaledOrig, scaledZDir, scaledXDir);
            IFCAnyHandle extrusionDirection = ExporterUtil.CreateDirection(file, relExtrusionDirList);

            extrudedSolidHnd = IFCInstanceExporter.CreateExtrudedAreaSolid(file, sweptArea, solidAxis, extrusionDirection, scaledExtrusionSize);
            return extrudedSolidHnd;
        }
        /// <summary>
        /// Main implementation to export walls.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="element">The element.</param>
        /// <param name="connectedWalls">Information about walls joined to this wall.</param>
        /// <param name="geometryElement">The geometry element.</param>
        /// <param name="origWrapper">The ProductWrapper.</param>
        /// <param name="overrideLevelId">The level id.</param>
        /// <param name="range">The range to be exported for the element.</param>
        /// <returns>The exported wall handle.</returns>
        public static IFCAnyHandle ExportWallBase(ExporterIFC exporterIFC, Element element, IList<IList<IFCConnectedWallData>> connectedWalls,
            GeometryElement geometryElement, ProductWrapper origWrapper, ElementId overrideLevelId, IFCRange range)
        {
            // Check cases where we choose not to export early.
            ElementId catId = CategoryUtil.GetSafeCategoryId(element);

            Wall wallElement = element as Wall;
            FamilyInstance famInstWallElem = element as FamilyInstance;
            FaceWall faceWall = element as FaceWall;

            bool exportingWallElement = (wallElement != null);
            bool exportingFamilyInstance = (famInstWallElem != null);
            bool exportingFaceWall = (faceWall != null);

            if (!exportingWallElement && !exportingFamilyInstance && !exportingFaceWall)
                return null;

            if (exportingWallElement && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                return null;

            IFCRange zSpan = null;
            double depth = 0.0;
            bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

            bool exportParts = PartExporter.CanExportParts(element);
            if (exportParts && !PartExporter.CanExportElementInPartExport(element, validRange ? overrideLevelId : element.LevelId, validRange))
                return null;

            IList<Solid> solids = new List<Solid>();
            IList<Mesh> meshes = new List<Mesh>();
            bool exportingInplaceOpenings = false;

            if (!exportParts)
            {
                if (exportingWallElement || exportingFaceWall)
                {
                    GetSolidsAndMeshes(geometryElement, range, ref solids, ref meshes);
                    if (solids.Count == 0 && meshes.Count == 0)
                        return null;
                }
                else
                {
                    GeometryElement geomElemToUse = GetGeometryFromInplaceWall(famInstWallElem);
                    if (geomElemToUse != null)
                    {
                        exportingInplaceOpenings = true;
                    }
                    else
                    {
                        exportingInplaceOpenings = false;
                        geomElemToUse = geometryElement;
                    }
                    Transform trf = Transform.Identity;
                    if (geomElemToUse != geometryElement)
                        trf = famInstWallElem.GetTransform();

                    SolidMeshGeometryInfo solidMeshCapsule = GeometryUtil.GetSplitSolidMeshGeometry(geomElemToUse, trf);
                    solids = solidMeshCapsule.GetSolids();
                    meshes = solidMeshCapsule.GetMeshes();
                }
            }

            IFCFile file = exporterIFC.GetFile();
            using (IFCTransaction tr = new IFCTransaction(file))
            {
                using (ProductWrapper localWrapper = ProductWrapper.Create(origWrapper))
                {
                    // get bounding box height so that we can subtract out pieces properly.
                    // only for Wall, not FamilyInstance.
                    if (exportingWallElement && geometryElement != null)
                    {
                        // There is a problem in the API where some walls with vertical structures are overreporting their height,
                        // making it appear as if there are clipping problems on export.  We will work around this by getting the
                        // height directly from the solid(s).
                        if (solids.Count > 0 && meshes.Count == 0)
                        {
                            zSpan = GetBoundingBoxOfSolids(solids);
                        }
                        else
                        {
                            BoundingBoxXYZ boundingBox = wallElement.get_BoundingBox(null);
                            if (boundingBox != null)
                                zSpan = GetBoundingBoxZRange(boundingBox);
                        }

                        if (zSpan == null)
                            return null;

                        // if we have a top clipping plane, modify depth accordingly.
                        double bottomHeight = validRange ? Math.Max(zSpan.Start, range.Start) : zSpan.Start;
                        double topHeight = validRange ? Math.Min(zSpan.End, range.End) : zSpan.End;
                        depth = topHeight - bottomHeight;
                        if (MathUtil.IsAlmostZero(depth))
                            return null;
                        depth = UnitUtil.ScaleLength(depth);
                    }
                    else
                    {
                        zSpan = new IFCRange();
                    }

                    Document doc = element.Document;

                    double baseWallElevation = 0.0;
                    ElementId baseLevelId = PlacementSetter.GetBaseLevelIdForElement(element);
                    if (baseLevelId != ElementId.InvalidElementId)
                    {
                        Element baseLevel = doc.GetElement(baseLevelId);
                        if (baseLevel is Level)
                            baseWallElevation = (baseLevel as Level).Elevation;
                    }

                    IFCAnyHandle axisRep = null;
                    IFCAnyHandle bodyRep = null;

                    bool exportingAxis = false;
                    Curve trimmedCurve = null;

                    bool exportedAsWallWithAxis = false;
                    bool exportedBodyDirectly = false;

                    Curve centerCurve = GetWallAxis(wallElement);

                    XYZ localXDir = new XYZ(1, 0, 0);
                    XYZ localYDir = new XYZ(0, 1, 0);
                    XYZ localZDir = new XYZ(0, 0, 1);
                    XYZ localOrig = new XYZ(0, 0, 0);
                    double eps = MathUtil.Eps();

                    if (centerCurve != null)
                    {
                        Curve baseCurve = GetWallAxisAtBaseHeight(wallElement);
                        trimmedCurve = GetWallTrimmedCurve(wallElement, baseCurve);

                        IFCRange curveBounds;
                        XYZ oldOrig;
                        GeometryUtil.GetAxisAndRangeFromCurve(trimmedCurve, out curveBounds, out localXDir, out oldOrig);

                        // Move the curve to the bottom of the geometry or the bottom of the range, which is higher.
                        if (baseCurve != null)
                            localOrig = new XYZ(oldOrig.X, oldOrig.Y, validRange ? Math.Max(range.Start, zSpan.Start) : zSpan.Start);
                        else
                            localOrig = oldOrig;

                        double dist = localOrig[2] - oldOrig[2];
                        if (!MathUtil.IsAlmostZero(dist))
                        {
                            XYZ moveVec = new XYZ(0, 0, dist);
                            trimmedCurve = GeometryUtil.MoveCurve(trimmedCurve, moveVec);
                        }
                        localYDir = localZDir.CrossProduct(localXDir);

                        // ensure that X and Z axes are orthogonal.
                        double xzDot = localZDir.DotProduct(localXDir);
                        if (!MathUtil.IsAlmostZero(xzDot))
                            localXDir = localYDir.CrossProduct(localZDir);
                    }
                    else
                    {
                        BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                        if (boundingBox != null)
                        {
                            XYZ bBoxMin = boundingBox.Min;
                            XYZ bBoxMax = boundingBox.Max;
                            if (validRange)
                                localOrig = new XYZ(bBoxMin.X, bBoxMin.Y, range.Start);
                            else
                                localOrig = boundingBox.Min;

                            XYZ localXDirMax = null;
                            Transform bTrf = boundingBox.Transform;
                            XYZ localXDirMax1 = new XYZ(bBoxMax.X, localOrig.Y, localOrig.Z);
                            localXDirMax1 = bTrf.OfPoint(localXDirMax1);
                            XYZ localXDirMax2 = new XYZ(localOrig.X, bBoxMax.Y, localOrig.Z);
                            localXDirMax2 = bTrf.OfPoint(localXDirMax2);
                            if (localXDirMax1.DistanceTo(localOrig) >= localXDirMax2.DistanceTo(localOrig))
                                localXDirMax = localXDirMax1;
                            else
                                localXDirMax = localXDirMax2;
                            localXDir = localXDirMax.Subtract(localOrig);
                            localXDir = localXDir.Normalize();
                            localYDir = localZDir.CrossProduct(localXDir);

                            // ensure that X and Z axes are orthogonal.
                            double xzDot = localZDir.DotProduct(localXDir);
                            if (!MathUtil.IsAlmostZero(xzDot))
                                localXDir = localYDir.CrossProduct(localZDir);
                        }
                    }

                    IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();

                    Transform orientationTrf = Transform.Identity;
                    orientationTrf.BasisX = localXDir;
                    orientationTrf.BasisY = localYDir;
                    orientationTrf.BasisZ = localZDir;
                    orientationTrf.Origin = localOrig;

                    double scaledFootprintArea = 0;
                    double scaledLength = 0;

                    using (PlacementSetter setter = PlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                    {
                        IFCAnyHandle localPlacement = setter.LocalPlacement;

                        // The local coordinate system of the wall as defined by IFC for IfcWallStandardCase.
                        Plane wallLCS = new Plane(localXDir, localYDir, localOrig);  // project curve to XY plane.
                        XYZ projDir = XYZ.BasisZ;

                        // two representations: axis, body.         
                        {
                            if (!exportParts && (centerCurve != null) && (GeometryUtil.CurveIsLineOrArc(centerCurve)))
                            {
                                exportingAxis = true;

                                string identifierOpt = "Axis";	// IFC2x2 convention
                                string representationTypeOpt = "Curve2D";  // IFC2x2 convention

                                IFCGeometryInfo info = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, wallLCS, projDir, false);
                                ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, trimmedCurve, XYZ.Zero, true);
                                IList<IFCAnyHandle> axisItems = info.GetCurves();

                                if (axisItems.Count == 0)
                                {
                                    exportingAxis = false;
                                }
                                else
                                {
                                    HashSet<IFCAnyHandle> axisItemSet = new HashSet<IFCAnyHandle>();
                                    foreach (IFCAnyHandle axisItem in axisItems)
                                        axisItemSet.Add(axisItem);

                                    IFCAnyHandle contextOfItemsAxis = exporterIFC.Get3DContextHandle("Axis");
                                    axisRep = RepresentationUtil.CreateShapeRepresentation(exporterIFC, element, catId, contextOfItemsAxis,
                                       identifierOpt, representationTypeOpt, axisItemSet);
                                }
                            }
                        }

                        IList<IFCExtrusionData> cutPairOpenings = new List<IFCExtrusionData>();

                        if (!exportParts && exportingWallElement && exportingAxis && trimmedCurve != null)
                        {
                                    bool isCompletelyClipped;
                            bodyRep = TryToCreateAsExtrusion(exporterIFC, wallElement, connectedWalls, solids, meshes, baseWallElevation,
                                catId, centerCurve, trimmedCurve, wallLCS, depth, zSpan, range, setter,
                                        out cutPairOpenings, out isCompletelyClipped, out scaledFootprintArea, out scaledLength);
                                    if (isCompletelyClipped)
                                        return null;
                                    if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                        exportedAsWallWithAxis = true;
                                }

                        using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
                        {
                            BodyData bodyData = null;

                            if (!exportedAsWallWithAxis)
                            {
                                extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                                extraParams.AreInnerRegionsOpenings = true;

                                BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                                
                                // Swept solids are not natively exported as part of CV2.0.  
                                // We have removed the UI toggle for this, so that it is by default false, but keep for possible future use.
                                if (ExporterCacheManager.ExportOptionsCache.ExportAdvancedSweptSolids)
                                    bodyExporterOptions.TryToExportAsSweptSolid = true;

                                ElementId overrideMaterialId = ElementId.InvalidElementId;
                                if (exportingWallElement)
                                    overrideMaterialId = HostObjectExporter.GetFirstLayerMaterialId(wallElement);

                                if (!exportParts)
                                {
                                    if ((solids.Count > 0) || (meshes.Count > 0))
                                    {
                                        bodyRep = BodyExporter.ExportBody(exporterIFC, element, catId, overrideMaterialId,
                                            solids, meshes, bodyExporterOptions, extraParams).RepresentationHnd;
                                    }
                                    else
                                    {
                                        IList<GeometryObject> geomElemList = new List<GeometryObject>();
                                        geomElemList.Add(geometryElement);
                                        bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, overrideMaterialId,
                                            geomElemList, bodyExporterOptions, extraParams);
                                        bodyRep = bodyData.RepresentationHnd;
                                    }

                                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                    {
                                        extraParams.ClearOpenings();
                                        return null;
                                    }
                                }

                                // We will be able to export as a IfcWallStandardCase as long as we have an axis curve.
                                XYZ extrDirUsed = XYZ.Zero;
                                if (extraParams.HasExtrusionDirection)
                                {
                                    extrDirUsed = extraParams.ExtrusionDirection;
                                    if (MathUtil.IsAlmostEqual(Math.Abs(extrDirUsed[2]), 1.0))
                                    {
                                        if ((solids.Count == 1) && (meshes.Count == 0))
                                            exportedAsWallWithAxis = exportingAxis;
                                        exportedBodyDirectly = true;
                                    }
                                }
                            }

                            IFCAnyHandle prodRep = null;
                            if (!exportParts)
                            {
                                IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                                if (exportingAxis)
                                    representations.Add(axisRep);

                                representations.Add(bodyRep);

                                IFCAnyHandle boundingBoxRep = null;
                                if ((solids.Count > 0) || (meshes.Count > 0))
                                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, solids, meshes, Transform.Identity);
                                else
                                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity);

                                if (boundingBoxRep != null)
                                    representations.Add(boundingBoxRep);

                                prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);
                            }

                            ElementId matId = ElementId.InvalidElementId;
                            string objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                            IFCAnyHandle wallHnd = null;

                            string elemGUID = null;
                            int subElementIndex = ExporterStateManager.GetCurrentRangeIndex();
                            if (subElementIndex == 0)
                                elemGUID = GUIDUtil.CreateGUID(element);
                            else if (subElementIndex <= ExporterStateManager.RangeIndexSetter.GetMaxStableGUIDs())
                                elemGUID = GUIDUtil.CreateSubElementGUID(element, subElementIndex + (int)IFCGenericSubElements.SplitInstanceStart - 1);
                            else
                                elemGUID = GUIDUtil.CreateGUID();
                            
                            string elemName = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element));
                            string elemDesc = NamingUtil.GetDescriptionOverride(element, null);
                            string elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                            string elemTag = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element));

                            string ifcType = IFCValidateEntry.GetValidIFCType(element, null);

                            // For Foundation and Retaining walls, allow exporting as IfcFooting instead.
                            bool exportAsFooting = false;
                            if (exportingWallElement)
                            {
                                WallType wallType = wallElement.WallType;

                                if (wallType != null)
                                {
                                    int wallFunction;
                                    if (ParameterUtil.GetIntValueFromElement(wallType, BuiltInParameter.FUNCTION_PARAM, out wallFunction) != null)
                                    {
                                        if (wallFunction == (int)WallFunction.Retaining || wallFunction == (int)WallFunction.Foundation)
                                        {
                                            // In this case, allow potential to export foundation and retaining walls as footing.
                                            string enumTypeValue = null;
                                            IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, wallElement, out enumTypeValue);
                                            if (exportType == IFCExportType.IfcFooting)
                                                exportAsFooting = true;
                                        }
                                    }
                                }
                            }

                            if (exportedAsWallWithAxis)
                            {
                                if (exportAsFooting)
                                {
                                    wallHnd = IFCInstanceExporter.CreateFooting(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, ifcType);
                                }
                                else
                                {
                                    bool exportAsWall = exportParts;
                                    if (!exportAsWall)
                                    {
                                        // (For Reference View export) If the representation returned earlier is of type Tessellation, create IfcWall instead.
                                        foreach (IFCAnyHandle pRep in IFCAnyHandleUtil.GetRepresentations(prodRep))
                                        {
                                            if (String.Compare(IFCAnyHandleUtil.GetRepresentationType(pRep), "Tessellation") == 0)
                                            {
                                                exportAsWall = true;
                                                break;
                                            }
                                        }
                                    }

                                    if (exportAsWall)
                                    {
                                        wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                                localPlacement, null, elemTag, ifcType);
                                    }
                                    else
                                    {
                                        wallHnd = IFCInstanceExporter.CreateWallStandardCase(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                            localPlacement, prodRep, elemTag, ifcType);
                                    }
                                }

                                if (exportParts)
                                    PartExporter.ExportHostPart(exporterIFC, element, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                                localWrapper.AddElement(element, wallHnd, setter, extraParams, true);

                                if (!exportParts)
                                {
                                    OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, cutPairOpenings, null,
                                        exporterIFC, localPlacement, setter, localWrapper);
                                    if (exportedBodyDirectly)
                                    {
                                        Transform offsetTransform = (bodyData != null) ? bodyData.OffsetTransform : Transform.Identity;
                                        OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, offsetTransform,
                                            exporterIFC, localPlacement, setter, localWrapper);
                                    }
                                    else
                                    {
                                        double scaledWidth = UnitUtil.ScaleLength(wallElement.Width);
                                        OpeningUtil.AddOpeningsToElement(exporterIFC, wallHnd, wallElement, null, scaledWidth, range, setter, localPlacement, localWrapper);
                                    }
                                }

                                // export Base Quantities
                                if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
                                {
                                    scaledFootprintArea = MathUtil.AreaIsAlmostZero(scaledFootprintArea) ? extraParams.ScaledArea : scaledFootprintArea;
                                    scaledLength = MathUtil.IsAlmostZero(scaledLength) ? extraParams.ScaledLength : scaledLength;
                                    PropertyUtil.CreateWallBaseQuantities(exporterIFC, wallElement, solids, meshes, wallHnd, scaledLength, depth, scaledFootprintArea);
                                }
                            }
                            else
                            {
                                if (exportAsFooting)
                                {
                                    wallHnd = IFCInstanceExporter.CreateFooting(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, ifcType);
                                }
                                else
                                {
                                    wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, ifcType);
                                }

                                if (exportParts)
                                    PartExporter.ExportHostPart(exporterIFC, element, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                                localWrapper.AddElement(element, wallHnd, setter, extraParams, true);

                                if (!exportParts)
                                {
                                    // Only export one material for 2x2; for future versions, export the whole list.
                                    if (ExporterCacheManager.ExportOptionsCache.ExportAs2x2 || exportingFamilyInstance)
                                    {
                                        matId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(solids, meshes, element);
                                        if (matId != ElementId.InvalidElementId)
                                            CategoryUtil.CreateMaterialAssociation(exporterIFC, wallHnd, matId);
                                    }

                                    if (exportingInplaceOpenings)
                                    {
                                        OpeningUtil.AddOpeningsToElement(exporterIFC, wallHnd, famInstWallElem, null, 0.0, range, setter, localPlacement, localWrapper);
                                    }

                                    if (exportedBodyDirectly)
                                    {
                                        Transform offsetTransform = (bodyData != null) ? bodyData.OffsetTransform : Transform.Identity;
                                        OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, offsetTransform,
                                            exporterIFC, localPlacement, setter, localWrapper);
                                    }
                                }
                            }

                            ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;

                            if ((exportingWallElement || exportingFaceWall) && !exportParts)
                            {
                                HostObject hostObject = null;
                                if (exportingWallElement)
                                    hostObject = wallElement;
                                else
                                    hostObject = faceWall;
                                if (!ExporterCacheManager.ExportOptionsCache.ExportAs2x2 || exportedAsWallWithAxis)
                                    HostObjectExporter.ExportHostObjectMaterials(exporterIFC, hostObject, localWrapper.GetAnElement(),
                                        geometryElement, localWrapper, wallLevelId, Toolkit.IFCLayerSetDirection.Axis2, !exportedAsWallWithAxis);
                            }

                            ExportWallType(exporterIFC, localWrapper, wallHnd, element, matId, exportedAsWallWithAxis, exportAsFooting);

                            SpaceBoundingElementUtil.RegisterSpaceBoundingElementHandle(exporterIFC, wallHnd, element.Id, wallLevelId);

                            tr.Commit();
                            return wallHnd;
                        }
                    }
                }
            }
        }
Example #39
0
        public override Value Evaluate(FSharpList<Value> args)
        {
            var symbol = (FamilySymbol)((Value.Container)args[0]).Item;
            var curves = ((Value.List) args[1]).Item;

            IEnumerable<Tuple<Curve, XYZ>> data;
            if (args[2].IsList)
            {
                var targets = ((Value.List)args[2]).Item;

                if (curves.Count() != targets.Count())
                    throw new Exception("The number of curves and the number of up vectors must be the same.");

                //if we get a list of up vectors, then pair each
                //curve with a corresponding up vector
                data = curves.Zip(targets,
                    (first, second) =>
                        new Tuple<Curve, XYZ>((Curve) ((Value.Container) first).Item,
                            (XYZ) ((Value.Container) second).Item));
            }
            else
            {
                //if we get a single up vector, then pair each
                //curve with that up vector
                data = curves.Select(x=>new Tuple<Curve, XYZ>((Curve)((Value.Container)x).Item,
                            (XYZ)((Value.Container)args[2]).Item));
            }

            var instData = new List<FamilyInstanceCreationData>();

            int count = 0;

            foreach (var pair in data)
            {
                var curve = pair.Item1;
                var target = pair.Item2;

                //calculate the desired rotation
                //we do this by finding the angle between the z axis
                //and vector between the start of the beam and the target point
                //both projected onto the start plane of the beam.

                XYZ zAxis = new XYZ(0, 0, 1);
                XYZ yAxis = new XYZ(0, 1, 0);

                //flatten the beam line onto the XZ plane
                //using the start's z coordinate
                XYZ start = curve.get_EndPoint(0);
                XYZ end = curve.get_EndPoint(1);
                XYZ newEnd = new XYZ(end.X, end.Y, start.Z); //drop end point to plane

                ////use the x axis of the curve's transform
                ////as the normal of the start plane
                //XYZ planeNormal = (curve.get_EndPoint(0) - curve.get_EndPoint(1)).Normalize();

                //catch the case where the end is directly above
                //the start, creating a normal with zero length
                //in that case, use the Z axis
                XYZ planeNormal = newEnd.IsAlmostEqualTo(start) ? zAxis : (newEnd - start).Normalize();

                XYZ target_project = target - target.DotProduct(planeNormal)*planeNormal;
                XYZ z_project = zAxis - zAxis.DotProduct(planeNormal)*planeNormal;

                //double gamma = target_project.AngleTo(z_project);
                double gamma = target.AngleOnPlaneTo(zAxis.IsAlmostEqualTo(planeNormal) ? yAxis : zAxis, planeNormal);

                FamilyInstance instance = null;
                if (this.Elements.Count > count)
                {
                    if (dynUtils.TryGetElement(this.Elements[count], out instance))
                    {
                        if (instance.Symbol != symbol)
                            instance.Symbol = symbol;

                        //update the curve
                        var locCurve = instance.Location as LocationCurve;
                        locCurve.Curve = curve;
                    }
                    else
                    {
                        var beamData = new FamilyInstanceCreationData(curve, symbol, dynRevitSettings.DefaultLevel, StructuralType.Beam)
                            {
                                RotateAngle = gamma
                            };
                        instData.Add(beamData);
                    }
                }
                else
                {
                    var beamData = new FamilyInstanceCreationData(curve, symbol, dynRevitSettings.DefaultLevel, StructuralType.Beam)
                        {
                            RotateAngle = gamma
                        };
                    instData.Add(beamData);
                }

                count++;
            }

            //trim the elements collection
            foreach (var e in this.Elements.Skip(count))
            {
                this.DeleteElement(e);
            }

            FSharpList<Value> results = FSharpList<Value>.Empty;

            if (instData.Any())
            {
                var ids = dynRevitSettings.Doc.Document.Create.NewFamilyInstances2(instData);

                //add our batch-created instances ids'
                //to the elements collection
                ids.ToList().ForEach(x=>Elements.Add(x));
            }

            //add all of the instances
            results = Elements.Aggregate(results, (current, id) => FSharpList<Value>.Cons(Value.NewContainer(dynRevitSettings.Doc.Document.GetElement(id)), current));
            results.Reverse();

            return Value.NewList(results);
        }
Example #40
0
        /// <summary>
        /// Main implementation to export walls.
        /// </summary>
        /// <param name="exporterIFC">
        /// The ExporterIFC object.
        /// </param>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <param name="geometryElement">
        /// The geometry element.
        /// </param>
        /// <param name="origWrapper">
        /// The ProductWrapper.
        /// </param>
        /// <param name="overrideLevelId">
        /// The level id.
        /// </param>
        /// <param name="range">
        /// The range to be exported for the element.
        /// </param>
        /// <returns>
        /// The exported wall handle.
        /// </returns>
        public static IFCAnyHandle ExportWallBase(ExporterIFC exporterIFC, Element element, GeometryElement geometryElement,
           ProductWrapper origWrapper, ElementId overrideLevelId, IFCRange range)
        {
            IFCFile file = exporterIFC.GetFile();
            using (IFCTransaction tr = new IFCTransaction(file))
            {
                using (ProductWrapper localWrapper = ProductWrapper.Create(origWrapper))
                {
                    ElementId catId = CategoryUtil.GetSafeCategoryId(element);

                    Wall wallElement = element as Wall;
                    FamilyInstance famInstWallElem = element as FamilyInstance;
                    FaceWall faceWall = element as FaceWall;
                    
                    if (wallElement == null && famInstWallElem == null && faceWall == null)
                        return null;

                    if (wallElement != null && IsWallCompletelyClipped(wallElement, exporterIFC, range))
                        return null;

                    Document doc = element.Document;
                    double scale = exporterIFC.LinearScale;
                    
                    double baseWallElevation = 0.0;
                    ElementId baseLevelId = ExporterUtil.GetBaseLevelIdForElement(element);
                    if (baseLevelId != ElementId.InvalidElementId)
                    {
                        Element baseLevel = doc.GetElement(baseLevelId);
                        if (baseLevel is Level)
                            baseWallElevation = (baseLevel as Level).Elevation;
                    }
                    
                    IFCAnyHandle ownerHistory = exporterIFC.GetOwnerHistoryHandle();
                    IFCAnyHandle contextOfItemsAxis = exporterIFC.Get3DContextHandle("Axis");
                    IFCAnyHandle contextOfItemsBody = exporterIFC.Get3DContextHandle("Body");

                    IFCRange zSpan = new IFCRange();
                    double depth = 0.0;
                    bool validRange = (range != null && !MathUtil.IsAlmostZero(range.Start - range.End));

                    bool exportParts = PartExporter.CanExportParts(element);
                    if (exportParts && !PartExporter.CanExportElementInPartExport(element, validRange ? overrideLevelId : element.Level.Id, validRange))
                        return null;

                    // get bounding box height so that we can subtract out pieces properly.
                    // only for Wall, not FamilyInstance.
                    if (wallElement != null && geometryElement != null)
                    {
                        BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                        if (boundingBox == null)
                            return null;
                        zSpan = new IFCRange(boundingBox.Min.Z, boundingBox.Max.Z);

                        // if we have a top clipping plane, modify depth accordingly.
                        double bottomHeight = validRange ? Math.Max(zSpan.Start, range.Start) : zSpan.Start;
                        double topHeight = validRange ? Math.Min(zSpan.End, range.End) : zSpan.End;
                        depth = topHeight - bottomHeight;
                        if (MathUtil.IsAlmostZero(depth))
                            return null;
                        depth *= scale;
                    }

                    IFCAnyHandle axisRep = null;
                    IFCAnyHandle bodyRep = null;

                    bool exportingAxis = false;
                    Curve curve = null;

                    bool exportedAsWallWithAxis = false;
                    bool exportedBodyDirectly = false;
                    bool exportingInplaceOpenings = false;

                    Curve centerCurve = GetWallAxis(wallElement);

                    XYZ localXDir = new XYZ(1, 0, 0);
                    XYZ localYDir = new XYZ(0, 1, 0);
                    XYZ localZDir = new XYZ(0, 0, 1);
                    XYZ localOrig = new XYZ(0, 0, 0);
                    double eps = MathUtil.Eps();

                    if (centerCurve != null)
                    {
                        Curve baseCurve = GetWallAxisAtBaseHeight(wallElement);
                        curve = GetWallTrimmedCurve(wallElement, baseCurve);

                        IFCRange curveBounds;
                        XYZ oldOrig;
                        GeometryUtil.GetAxisAndRangeFromCurve(curve, out curveBounds, out localXDir, out oldOrig);

                        localOrig = oldOrig;
                        if (baseCurve != null)
                        {
                            if (!validRange || (MathUtil.IsAlmostEqual(range.Start, zSpan.Start)))
                            {
                                XYZ newOrig = baseCurve.Evaluate(curveBounds.Start, false);
                                if (!validRange && (zSpan.Start < newOrig[2] - eps))
                                    localOrig = new XYZ(localOrig.X, localOrig.Y, zSpan.Start);
                                else
                                    localOrig = new XYZ(localOrig.X, localOrig.Y, newOrig[2]);
                            }
                            else
                            {
                                localOrig = new XYZ(localOrig.X, localOrig.Y, range.Start);
                            }
                        }

                        double dist = localOrig[2] - oldOrig[2];
                        if (!MathUtil.IsAlmostZero(dist))
                        {
                            XYZ moveVec = new XYZ(0, 0, dist);
                            curve = GeometryUtil.MoveCurve(curve, moveVec);
                        }
                        localYDir = localZDir.CrossProduct(localXDir);

                        // ensure that X and Z axes are orthogonal.
                        double xzDot = localZDir.DotProduct(localXDir);
                        if (!MathUtil.IsAlmostZero(xzDot))
                            localXDir = localYDir.CrossProduct(localZDir);
                    }
                    else
                    {
                        BoundingBoxXYZ boundingBox = element.get_BoundingBox(null);
                        if (boundingBox != null)
                        {
                            XYZ bBoxMin = boundingBox.Min;
                            XYZ bBoxMax = boundingBox.Max;
                            if (validRange)
                                localOrig = new XYZ(bBoxMin.X, bBoxMin.Y, range.Start);
                            else
                                localOrig = boundingBox.Min;

                            XYZ localXDirMax = null;
                            Transform bTrf = boundingBox.Transform;
                            XYZ localXDirMax1 = new XYZ(bBoxMax.X, localOrig.Y, localOrig.Z);
                            localXDirMax1 = bTrf.OfPoint(localXDirMax1);
                            XYZ localXDirMax2 = new XYZ(localOrig.X, bBoxMax.Y, localOrig.Z);
                            localXDirMax2 = bTrf.OfPoint(localXDirMax2);
                            if (localXDirMax1.DistanceTo(localOrig) >= localXDirMax2.DistanceTo(localOrig))
                                localXDirMax = localXDirMax1;
                            else
                                localXDirMax = localXDirMax2;
                            localXDir = localXDirMax.Subtract(localOrig);
                            localXDir = localXDir.Normalize();
                            localYDir = localZDir.CrossProduct(localXDir);

                            // ensure that X and Z axes are orthogonal.
                            double xzDot = localZDir.DotProduct(localXDir);
                            if (!MathUtil.IsAlmostZero(xzDot))
                                localXDir = localYDir.CrossProduct(localZDir);
                        }
                    }

                    Transform orientationTrf = Transform.Identity;
                    orientationTrf.BasisX = localXDir;
                    orientationTrf.BasisY = localYDir;
                    orientationTrf.BasisZ = localZDir;
                    orientationTrf.Origin = localOrig;

                    if (overrideLevelId == ElementId.InvalidElementId)
                        overrideLevelId = ExporterUtil.GetBaseLevelIdForElement(element);
                    using (IFCPlacementSetter setter = IFCPlacementSetter.Create(exporterIFC, element, null, orientationTrf, overrideLevelId))
                    {
                        IFCAnyHandle localPlacement = setter.GetPlacement();

                        Plane plane = new Plane(localXDir, localYDir, localOrig);  // project curve to XY plane.
                        XYZ projDir = XYZ.BasisZ;

                        // two representations: axis, body.         
                        {
                            if (!exportParts && (centerCurve != null) && (GeometryUtil.CurveIsLineOrArc(centerCurve)))
                            {
                                exportingAxis = true;

                                string identifierOpt = "Axis";	// IFC2x2 convention
                                string representationTypeOpt = "Curve2D";  // IFC2x2 convention

                                IFCGeometryInfo info = IFCGeometryInfo.CreateCurveGeometryInfo(exporterIFC, plane, projDir, false);
                                ExporterIFCUtils.CollectGeometryInfo(exporterIFC, info, curve, XYZ.Zero, true);
                                IList<IFCAnyHandle> axisItems = info.GetCurves();

                                if (axisItems.Count == 0)
                                {
                                    exportingAxis = false;
                                }
                                else
                                {
                                    HashSet<IFCAnyHandle> axisItemSet = new HashSet<IFCAnyHandle>();
                                    foreach (IFCAnyHandle axisItem in axisItems)
                                        axisItemSet.Add(axisItem);

                                    axisRep = RepresentationUtil.CreateShapeRepresentation(exporterIFC, element, catId, contextOfItemsAxis,
                                       identifierOpt, representationTypeOpt, axisItemSet);
                                }
                            }
                        }

                        IList<IFCExtrusionData> cutPairOpenings = new List<IFCExtrusionData>();
                        Document document = element.Document;

                        IList<Solid> solids = new List<Solid>();
                        IList<Mesh> meshes = new List<Mesh>();

                        if (!exportParts && wallElement != null && exportingAxis && curve != null)
                        {
                            SolidMeshGeometryInfo solidMeshInfo =
                                (range == null) ? GeometryUtil.GetSplitSolidMeshGeometry(geometryElement) :
                                    GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range);

                            solids = solidMeshInfo.GetSolids();
                            meshes = solidMeshInfo.GetMeshes();
                            if (solids.Count == 0 && meshes.Count == 0)
                                return null;

                            bool useNewCode = false;
                            if (useNewCode && solids.Count == 1 && meshes.Count == 0)
                            {
                                bool completelyClipped;
                                bodyRep = ExtrusionExporter.CreateExtrusionWithClipping(exporterIFC, wallElement, catId, solids[0],
                                    plane, projDir, range, out completelyClipped);

                                if (completelyClipped)
                                    return null;

                                if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                {
                                    exportedAsWallWithAxis = true;
                                    exportedBodyDirectly = true;
                                }
                                else
                                {
                                    exportedAsWallWithAxis = false;
                                    exportedBodyDirectly = false;
                                }
                            }

                            if (!exportedAsWallWithAxis)
                            {
                                // Fallback - use native routines to try to export wall.
                                bool isCompletelyClipped;
                                bodyRep = FallbackTryToCreateAsExtrusion(exporterIFC, wallElement, solidMeshInfo, baseWallElevation,
                                    catId, curve, plane, depth, zSpan, range, setter,
                                    out cutPairOpenings, out isCompletelyClipped);
                                if (isCompletelyClipped)
                                    return null;
                                if (!IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                    exportedAsWallWithAxis = true;
                            }
                        }

                        using (IFCExtrusionCreationData extraParams = new IFCExtrusionCreationData())
                        {
                            BodyData bodyData = null;

                            if (!exportedAsWallWithAxis)
                            {
                                SolidMeshGeometryInfo solidMeshCapsule = null;

                                if (wallElement != null || faceWall != null)
                                {
                                    if (validRange)
                                    {
                                        solidMeshCapsule = GeometryUtil.GetSplitClippedSolidMeshGeometry(geometryElement, range);
                                    }
                                    else
                                    {
                                        solidMeshCapsule = GeometryUtil.GetSplitSolidMeshGeometry(geometryElement);
                                    }
                                    if (solidMeshCapsule.SolidsCount() == 0 && solidMeshCapsule.MeshesCount() == 0)
                                    {
                                        return null;
                                    }
                                }
                                else
                                {
                                    GeometryElement geomElemToUse = GetGeometryFromInplaceWall(famInstWallElem);
                                    if (geomElemToUse != null)
                                    {
                                        exportingInplaceOpenings = true;
                                    }
                                    else
                                    {
                                        exportingInplaceOpenings = false;
                                        geomElemToUse = geometryElement;
                                    }
                                    Transform trf = Transform.Identity;
                                    if (geomElemToUse != geometryElement)
                                        trf = famInstWallElem.GetTransform();
                                    solidMeshCapsule = GeometryUtil.GetSplitSolidMeshGeometry(geomElemToUse, trf);
                                }

                                solids = solidMeshCapsule.GetSolids();
                                meshes = solidMeshCapsule.GetMeshes();

                                extraParams.PossibleExtrusionAxes = IFCExtrusionAxes.TryZ;   // only allow vertical extrusions!
                                extraParams.AreInnerRegionsOpenings = true;

                                BodyExporterOptions bodyExporterOptions = new BodyExporterOptions(true);
                                
                                // Swept solids are not natively exported as part of CV2.0.  
                                // We have removed the UI toggle for this, so that it is by default false, but keep for possible future use.
                                if (ExporterCacheManager.ExportOptionsCache.ExportAdvancedSweptSolids)
                                    bodyExporterOptions.TryToExportAsSweptSolid = true;

                                ElementId overrideMaterialId = ElementId.InvalidElementId;
                                if (wallElement != null)
                                    overrideMaterialId = HostObjectExporter.GetFirstLayerMaterialId(wallElement);

                                if (!exportParts)
                                {
                                    if ((solids.Count > 0) || (meshes.Count > 0))
                                    {
                                        bodyRep = BodyExporter.ExportBody(exporterIFC, element, catId, overrideMaterialId,
                                            solids, meshes, bodyExporterOptions, extraParams).RepresentationHnd;
                                    }
                                    else
                                    {
                                        IList<GeometryObject> geomElemList = new List<GeometryObject>();
                                        geomElemList.Add(geometryElement);
                                        bodyData = BodyExporter.ExportBody(exporterIFC, element, catId, overrideMaterialId,
                                            geomElemList, bodyExporterOptions, extraParams);
                                        bodyRep = bodyData.RepresentationHnd;
                                    }

                                    if (IFCAnyHandleUtil.IsNullOrHasNoValue(bodyRep))
                                    {
                                        extraParams.ClearOpenings();
                                        return null;
                                    }
                                }

                                // We will be able to export as a IfcWallStandardCase as long as we have an axis curve.
                                XYZ extrDirUsed = XYZ.Zero;
                                if (extraParams.HasExtrusionDirection)
                                {
                                    extrDirUsed = extraParams.ExtrusionDirection;
                                    if (MathUtil.IsAlmostEqual(Math.Abs(extrDirUsed[2]), 1.0))
                                    {
                                        if ((solids.Count == 1) && (meshes.Count == 0))
                                            exportedAsWallWithAxis = exportingAxis;
                                        exportedBodyDirectly = true;
                                    }
                                }
                            }

                            IFCAnyHandle prodRep = null;
                            if (!exportParts)
                            {
                                IList<IFCAnyHandle> representations = new List<IFCAnyHandle>();
                                if (exportingAxis)
                                    representations.Add(axisRep);

                                representations.Add(bodyRep);

                                IFCAnyHandle boundingBoxRep = null;
                                if ((solids.Count > 0) || (meshes.Count > 0))
                                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, solids, meshes, Transform.Identity);
                                else
                                    boundingBoxRep = BoundingBoxExporter.ExportBoundingBox(exporterIFC, geometryElement, Transform.Identity);

                                if (boundingBoxRep != null)
                                    representations.Add(boundingBoxRep);

                                prodRep = IFCInstanceExporter.CreateProductDefinitionShape(file, null, null, representations);
                            }

                            ElementId matId = ElementId.InvalidElementId;
                            string objectType = NamingUtil.CreateIFCObjectName(exporterIFC, element);
                            IFCAnyHandle wallHnd = null;

                            string elemGUID = (validRange) ? GUIDUtil.CreateGUID() : GUIDUtil.CreateGUID(element);
                            string elemName = NamingUtil.GetNameOverride(element, NamingUtil.GetIFCName(element));
                            string elemDesc = NamingUtil.GetDescriptionOverride(element, null);
                            string elemObjectType = NamingUtil.GetObjectTypeOverride(element, objectType);
                            string elemTag = NamingUtil.GetTagOverride(element, NamingUtil.CreateIFCElementId(element));

                            // For Foundation and Retaining walls, allow exporting as IfcFooting instead.
                            bool exportAsFooting = false;
                            string enumTypeValue = null;

                            if (wallElement != null)
                            {
                                WallType wallType = wallElement.WallType;

                                if (wallType != null)
                                {
                                    int wallFunction;
                                    if (ParameterUtil.GetIntValueFromElement(wallType, BuiltInParameter.FUNCTION_PARAM, out wallFunction) != null)
                                    {
                                        if (wallFunction == (int)WallFunction.Retaining || wallFunction == (int)WallFunction.Foundation)
                                        {
                                            // In this case, allow potential to export foundation and retaining walls as footing.
                                            IFCExportType exportType = ExporterUtil.GetExportType(exporterIFC, wallElement, out enumTypeValue);
                                            if (exportType == IFCExportType.ExportFooting)
                                                exportAsFooting = true;
                                        }
                                    }
                                }
                            }

                            if (exportedAsWallWithAxis)
                            {
                                if (exportAsFooting)
                                {
                                    Toolkit.IFCFootingType footingType = FootingExporter.GetIFCFootingType(element, enumTypeValue);
                                    wallHnd = IFCInstanceExporter.CreateFooting(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, footingType);
                                }
                                else if (exportParts)
                                {
                                    wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, null, elemTag);
                                }
                                else
                                {
                                    wallHnd = IFCInstanceExporter.CreateWallStandardCase(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, prodRep, elemTag);
                                }

                                if (exportParts)
                                    PartExporter.ExportHostPart(exporterIFC, element, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                                localWrapper.AddElement(element, wallHnd, setter, extraParams, true);

                                if (!exportParts)
                                {
                                    OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, cutPairOpenings, null,
                                        exporterIFC, localPlacement, setter, localWrapper);
                                    if (exportedBodyDirectly)
                                    {
                                        Transform offsetTransform = (bodyData != null) ? bodyData.OffsetTransform : Transform.Identity;
                                        OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, offsetTransform,
                                            exporterIFC, localPlacement, setter, localWrapper);
                                    }
                                    else
                                    {
                                        ICollection<IFCAnyHandle> beforeOpenings = localWrapper.GetAllObjects();
                                        double scaledWidth = wallElement.Width * scale;
                                        ExporterIFCUtils.AddOpeningsToElement(exporterIFC, wallHnd, wallElement, scaledWidth, range, setter, localPlacement, localWrapper.ToNative());
                                        ICollection<IFCAnyHandle> afterOpenings = localWrapper.GetAllObjects();
                                        if (beforeOpenings.Count != afterOpenings.Count)
                                        {
                                            foreach (IFCAnyHandle before in beforeOpenings)
                                                afterOpenings.Remove(before);
                                            foreach (IFCAnyHandle potentiallyBadOpening in afterOpenings)
                                            {
                                                PotentiallyCorrectOpeningOrientationAndOpeningType(potentiallyBadOpening, localPlacement, scaledWidth);
                                            }
                                        }
                                    }
                                }

                                // export Base Quantities
                                if (ExporterCacheManager.ExportOptionsCache.ExportBaseQuantities)
                                {
                                    CreateWallBaseQuantities(exporterIFC, wallElement, wallHnd, depth);
                                }
                            }
                            else
                            {
                                if (exportAsFooting)
                                {
                                    Toolkit.IFCFootingType footingType = FootingExporter.GetIFCFootingType(element, enumTypeValue);
                                    wallHnd = IFCInstanceExporter.CreateFooting(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag, footingType);
                                }
                                else
                                {
                                    wallHnd = IFCInstanceExporter.CreateWall(file, elemGUID, ownerHistory, elemName, elemDesc, elemObjectType,
                                        localPlacement, exportParts ? null : prodRep, elemTag);
                                }

                                if (exportParts)
                                    PartExporter.ExportHostPart(exporterIFC, element, wallHnd, localWrapper, setter, localPlacement, overrideLevelId);

                                localWrapper.AddElement(element, wallHnd, setter, extraParams, true);

                                if (!exportParts)
                                {
                                    // Only export one material for 2x2; for future versions, export the whole list.
                                    if (exporterIFC.ExportAs2x2 || famInstWallElem != null)
                                    {
                                        matId = BodyExporter.GetBestMaterialIdFromGeometryOrParameter(solids, meshes, element);
                                        if (matId != ElementId.InvalidElementId)
                                            CategoryUtil.CreateMaterialAssociation(exporterIFC, wallHnd, matId);
                                    }

                                    if (exportingInplaceOpenings)
                                    {
                                        ExporterIFCUtils.AddOpeningsToElement(exporterIFC, wallHnd, famInstWallElem, 0.0, range, setter, localPlacement, localWrapper.ToNative());
                                    }

                                    if (exportedBodyDirectly)
                                    {
                                        Transform offsetTransform = (bodyData != null) ? bodyData.OffsetTransform : Transform.Identity;
                                        OpeningUtil.CreateOpeningsIfNecessary(wallHnd, element, extraParams, offsetTransform,
                                            exporterIFC, localPlacement, setter, localWrapper);
                                    }
                                }
                            }

                            ElementId wallLevelId = (validRange) ? setter.LevelId : ElementId.InvalidElementId;

                            if ((wallElement != null || faceWall != null) && !exportParts)
                            {
                                HostObject hostObject = null;
                                if (wallElement != null)
                                    hostObject = wallElement;
                                else
                                    hostObject = faceWall;
                                if (!exporterIFC.ExportAs2x2 || exportedAsWallWithAxis)
                                    HostObjectExporter.ExportHostObjectMaterials(exporterIFC, hostObject, localWrapper.GetAnElement(),
                                        geometryElement, localWrapper, wallLevelId, Toolkit.IFCLayerSetDirection.Axis2, !exportedAsWallWithAxis);
                            }

                            ExportWallType(exporterIFC, localWrapper, wallHnd, element, matId, exportedAsWallWithAxis, exportAsFooting);

                            exporterIFC.RegisterSpaceBoundingElementHandle(wallHnd, element.Id, wallLevelId);

                            tr.Commit();
                            return wallHnd;
                        }
                    }
                }
            }
        }
        /*
        /// <summary>
        /// Return the average of a list of values.
        /// Prerequisite: the underlying class T must supply
        /// operator*(double) and operator+(const T &).
        /// </summary>
        T Average<T>( List<T> a )
        {
          T result;
          bool first = true;
          foreach( T x in a )
          {
        if( first )
        {
          result = x;
        }
        else
        {
          result += x;
        }
          }
          return result * ( 1.0 / a.Count );
        }

        XYZ Sum( List<XYZ> a )
        {
          XYZ sum = XYZ.Zero;
          foreach( XYZ x in a )
          {
        sum += x;
          }
          return sum;
        }

        XYZ Average( List<XYZ> a )
        {
          return Sum( a ) * (1.0 / a.Count);
        }

        XYZ TriangleCenter( List<XYZ> pts )
        {
          Debug.Assert( 3 == pts.Count, "expected three points in triangle" );
          return Average( pts );
        }
        */
        /// <summary>
        /// Return the plane properties of a given polygon,
        /// i.e. the plane normal, area, and its distance
        /// from the origin. Cf. also GetSignedPolygonArea.
        /// </summary>
        internal static bool GetPolygonPlane(
            List<XYZ> polygon,
            out XYZ normal,
            out double dist,
            out double area)
        {
            normal = XYZ.Zero;
              dist = area = 0.0;
              int n = ( null == polygon ) ? 0 : polygon.Count;
              bool rc = ( 2 < n );
              if( 3 == n )
              {

            // the general case returns a wrong result for the triangle
            // ((-1 -1 -1) (1 -1 -1) (-1 -1 1)), so implement specific
            // code for triangle:

            XYZ a = polygon[0];
            XYZ b = polygon[1];
            XYZ c = polygon[2];
            XYZ v = b - a;
            normal = v.CrossProduct( c - a );
            dist = normal.DotProduct( a );
              }
              else if( 4 == n )
              {

            // more efficient code for 4-sided polygons

            XYZ a = polygon[0];
            XYZ b = polygon[1];
            XYZ c = polygon[2];
            XYZ d = polygon[3];

            normal = new XYZ(
              ( c.Y - a.Y ) * ( d.Z - b.Z ) + ( c.Z - a.Z ) * ( b.Y - d.Y ),
              ( c.Z - a.Z ) * ( d.X - b.X ) + ( c.X - a.X ) * ( b.Z - d.Z ),
              ( c.X - a.X ) * ( d.Y - b.Y ) + ( c.Y - a.Y ) * ( b.X - d.X ) );

            dist = 0.25 *
              ( normal.X * ( a.X + b.X + c.X + d.X )
              + normal.Y * ( a.Y + b.Y + c.Y + d.Y )
              + normal.Z * ( a.Z + b.Z + c.Z + d.Z ) );
              }
              else if( 4 < n )
              {

            // general case for n-sided polygons

            XYZ a;
            XYZ b = polygon[n - 2];
            XYZ c = polygon[n - 1];
            XYZ s = XYZ.Zero;

            for( int i = 0; i < n; ++i )
            {
              a = b;
              b = c;
              c = polygon[i];

              normal = new XYZ(
            normal.X + b.Y * ( c.Z - a.Z ),
            normal.Y + b.Z * ( c.X - a.X ),
            normal.Z + b.X * ( c.Y - a.Y ) );

              s += c;
            }
            dist = s.DotProduct( normal ) / n;
              }
              if( rc )
              {

            // the polygon area is half of the length
            // of the non-normalized normal vector of the plane:

            double length = normal.GetLength();
            rc = !Util.IsZero( length );
            Debug.Assert( rc );

            if( rc )
            {
              normal /= length;
              dist /= length;
              area = 0.5 * length;
            }
              }
              return rc;
        }
        /// <summary>
        /// Offsets an arc along the offset direction from the point on the arc.
        /// </summary>
        /// <param name="arc">The arc.</param>
        /// <param name="offsetPntOnArc">The point on the arc.</param>
        /// <param name="offset">The offset vector.</param>
        /// <returns>The offset Arc.</returns>
        private static Arc OffsetArc(Arc arc, XYZ offsetPntOnArc, XYZ offset)
        {
            if (arc == null || offset == null)
                throw new ArgumentNullException();

            if (offset.IsZeroLength())
                return arc;

            XYZ axis = arc.Normal.Normalize();

            XYZ offsetAlongAxis = axis.Multiply(offset.DotProduct(axis));
            XYZ offsetOrthAxis = offset - offsetAlongAxis;
            XYZ offsetPntToCenter = (arc.Center - offsetPntOnArc).Normalize();

            double signedOffsetLengthTowardCenter = offsetOrthAxis.DotProduct(offsetPntToCenter);
            double newRadius = arc.Radius - signedOffsetLengthTowardCenter; // signedOffsetLengthTowardCenter > 0, minus, < 0, add

            Arc offsetArc = Arc.Create(arc.Center, newRadius, arc.GetEndParameter(0), arc.GetEndParameter(1), arc.XDirection, arc.YDirection);

            offsetArc = GeometryUtil.MoveCurve(offsetArc, offsetAlongAxis) as Arc;

            return offsetArc;
        }
        /// <summary>
        /// Creates an extruded solid from a collection of curve loops and a thickness.
        /// </summary>
        /// <param name="exporterIFC">The ExporterIFC object.</param>
        /// <param name="profileName">The name of the extrusion profile.</param>
        /// <param name="origCurveLoops">The profile boundary curves.</param>
        /// <param name="plane">The plane of the boundary curves.</param>
        /// <param name="extrDirVec">The direction of the extrusion.</param>
        /// <param name="scaledExtrusionSize">The thickness of the extrusion, perpendicular to the plane.</param>
        /// <returns>The IfcExtrudedAreaSolid handle.</returns>
        /// <remarks>If the curveLoop plane normal is not the same as the plane direction, only tesellated boundaries are supported.</remarks> 
        public static IFCAnyHandle CreateExtrudedSolidFromCurveLoop(ExporterIFC exporterIFC, string profileName, IList<CurveLoop> origCurveLoops,
            Plane plane, XYZ extrDirVec, double scaledExtrusionSize)
        {
            IFCAnyHandle extrudedSolidHnd = null;

            if (scaledExtrusionSize < MathUtil.Eps())
                return extrudedSolidHnd;

            IFCFile file = exporterIFC.GetFile();

            // we need to figure out the plane of the curve loops and modify the extrusion direction appropriately.
            // assumption: first curve loop defines the plane.
            int sz = origCurveLoops.Count;
            if (sz == 0)
                return extrudedSolidHnd;

            XYZ planeXDir = plane.XVec;
            XYZ planeYDir = plane.YVec;
            XYZ planeZDir = plane.Normal;
            XYZ planeOrig = plane.Origin;

            double slantFactor = Math.Abs(planeZDir.DotProduct(extrDirVec));
            if (MathUtil.IsAlmostZero(slantFactor))
                return extrudedSolidHnd;

            // Reduce the number of line segments in the curveloops from highly tessellated polylines, if applicable.
            IList<CurveLoop> curveLoops = CoarsenCurveLoops(origCurveLoops);

            // Check that curve loops are valid.
            curveLoops = ExporterIFCUtils.ValidateCurveLoops(curveLoops, extrDirVec);
            if (curveLoops.Count == 0)
                return extrudedSolidHnd;

            scaledExtrusionSize /= slantFactor;

            IFCAnyHandle sweptArea = CreateSweptArea(exporterIFC, profileName, curveLoops, plane, extrDirVec);
            if (IFCAnyHandleUtil.IsNullOrHasNoValue(sweptArea))
                return extrudedSolidHnd;

            IList<double> relExtrusionDirList = new List<double>();
            relExtrusionDirList.Add(extrDirVec.DotProduct(planeXDir));
            relExtrusionDirList.Add(extrDirVec.DotProduct(planeYDir));
            relExtrusionDirList.Add(extrDirVec.DotProduct(planeZDir));

            XYZ scaledXDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, planeXDir);
            XYZ scaledZDir = ExporterIFCUtils.TransformAndScaleVector(exporterIFC, planeZDir);
            XYZ scaledOrig = ExporterIFCUtils.TransformAndScalePoint(exporterIFC, planeOrig);

            IFCAnyHandle solidAxis = ExporterUtil.CreateAxis(file, scaledOrig, scaledZDir, scaledXDir);
            IFCAnyHandle extrusionDirection = ExporterUtil.CreateDirection(file, relExtrusionDirList);

            extrudedSolidHnd = IFCInstanceExporter.CreateExtrudedAreaSolid(file, sweptArea, solidAxis, extrusionDirection, scaledExtrusionSize);
            return extrudedSolidHnd;
        }
        /// <summary>
        /// Determine the elevation boundary profile
        /// polygons of the exterior vertical planar
        /// face of the given wall solid.
        /// </summary>
        /// <param name="polygons">Return polygonal boundary
        /// loops of exterior vertical planar face, i.e.
        /// profile of wall elevation incl. holes</param>
        /// <param name="solid">Input solid</param>
        /// <param name="w">Vector pointing along
        /// wall centre line</param>
        /// <param name="w">Vector pointing towards
        /// exterior wall face</param>
        /// <returns>False if no exterior vertical
        /// planar face was found, else true</returns>
        static bool GetProfile(
            List<List<XYZ>> polygons,
            Solid solid,
            XYZ v,
            XYZ w)
        {
            double d, dmax = 0;
              PlanarFace outermost = null;
              FaceArray faces = solid.Faces;
              foreach( Face f in faces )
              {
            PlanarFace pf = f as PlanarFace;
            if( null != pf
              && Util.IsVertical( pf )
              && Util.IsZero( v.DotProduct( pf.Normal ) ) )
            {
              d = pf.Origin.DotProduct( w );
              if( ( null == outermost )
            || ( dmax < d ) )
              {
            outermost = pf;
            dmax = d;
              }
            }
              }

              if( null != outermost )
              {
            XYZ voffset = _offset * w;
            XYZ p, q = XYZ.Zero;
            bool first;
            int i, n;
            EdgeArrayArray loops = outermost.EdgeLoops;
            foreach( EdgeArray loop in loops )
            {
              List<XYZ> vertices = new List<XYZ>();
              first = true;
              foreach( Edge e in loop )
              {
            IList<XYZ> points = e.Tessellate();
            p = points[0];
            if( !first )
            {
              Debug.Assert( p.IsAlmostEqualTo( q ),
                "expected subsequent start point"
                + " to equal previous end point" );
            }
            n = points.Count;
            q = points[n - 1];
            for( i = 0; i < n - 1; ++i )
            {
              XYZ a = points[i];
              a += voffset;
              vertices.Add( a );
            }
              }
              q += voffset;
              Debug.Assert( q.IsAlmostEqualTo( vertices[0] ),
            "expected last end point to equal"
            + " first start point" );
              polygons.Add( vertices );
            }
              }
              return null != outermost;
        }
        /// <summary>
        /// Returns an integer to indicate if two vectors are parallel, antiparallel or not.
        /// </summary>
        /// <param name="a">The one vector.</param>
        /// <param name="b">The other vector.</param>
        /// <returns>1 parallel, -1 antiparallel, 0 not parallel.</returns>
        public static int VectorsAreParallel2(XYZ a, XYZ b)
        {
            if (a == null || b == null)
                return 0;

            double aa, bb, ab;
            double epsSq = Eps() * Eps();

            aa = a.DotProduct(a);
            bb = b.DotProduct(b);

            if (aa < epsSq || bb < epsSq)
                return 0;

            ab = a.DotProduct(b);
            double cosAngleSq = (ab / aa) * (ab / bb);
            if (cosAngleSq < 1.0 - AngleEps() * AngleEps())
                return 0;

            return ab > 0 ? 1 : -1;
        }
        /// <summary>
        /// Checks if two vectors are orthogonal or not.
        /// </summary>
        /// <param name="a">The one vector.</param>
        /// <param name="b">The other vector.</param>
        /// <returns>True if they are orthogonal, false if not.</returns>
        public static bool VectorsAreOrthogonal(XYZ a, XYZ b)
        {
            if (a == null || b == null)
                return false;

            if (a.IsAlmostEqualTo(XYZ.Zero) || b.IsAlmostEqualTo(XYZ.Zero))
                return true;

            double ab = a.DotProduct(b);
            double aa = a.DotProduct(a);
            double bb = b.DotProduct(b);

            return (ab * ab < aa * AngleEps() * bb * AngleEps()) ? true : false;
        }