private IList <CurveLoop> GetTransformedCurveLoopsFromSimpleProfile(IFCSimpleProfile simpleSweptArea, Transform unscaledLcs, Transform scaledLcs)
        {
            IList <CurveLoop> loops = new List <CurveLoop>();

            // It is legal for simpleSweptArea.Position to be null, for example for IfcArbitraryClosedProfileDef.
            Transform unscaledSweptAreaPosition =
                (simpleSweptArea.Position == null) ? unscaledLcs : unscaledLcs.Multiply(simpleSweptArea.Position);

            Transform scaledSweptAreaPosition =
                (simpleSweptArea.Position == null) ? scaledLcs : scaledLcs.Multiply(simpleSweptArea.Position);

            CurveLoop currLoop = simpleSweptArea.OuterCurve;

            if (currLoop == null || currLoop.Count() == 0)
            {
                Importer.TheLog.LogError(simpleSweptArea.Id, "No outer curve loop for profile, ignoring.", false);
                return(null);
            }
            loops.Add(IFCGeometryUtil.CreateTransformed(currLoop, Id, unscaledSweptAreaPosition, scaledSweptAreaPosition));

            if (simpleSweptArea.InnerCurves != null)
            {
                foreach (CurveLoop innerCurveLoop in simpleSweptArea.InnerCurves)
                {
                    loops.Add(IFCGeometryUtil.CreateTransformed(innerCurveLoop, Id, unscaledSweptAreaPosition, scaledSweptAreaPosition));
                }
            }

            return(loops);
        }
示例#2
0
        /// <summary>
        /// 获得 CurveLoop 的所有点
        /// </summary>
        /// <param name="loop"></param>
        /// <returns></returns>
        public static IList <XYZ> ToPointsList(this CurveLoop loop)
        {
            int        n       = loop.Count();
            List <XYZ> polygon = new List <XYZ>();

            foreach (Curve e in loop)
            {
                IList <XYZ> pts = e.Tessellate();

                n = polygon.Count;

                if (0 < n)
                {
                    //Debug.Assert(pts[0].IsAlmostEqualTo(polygon[n - 1]),
                    //  "expected last edge end point to equal next edge start point");

                    polygon.RemoveAt(n - 1);
                }
                polygon.AddRange(pts);
            }
            n = polygon.Count;

            //Debug.Assert(polygon[0].IsAlmostEqualTo(polygon[n - 1]),
            //  "expected first edge start point to equal last edge end point");

            polygon.RemoveAt(n - 1);

            return(polygon);
        }
示例#3
0
        /// <summary>
        ///     Converts the CurveArray to the CurveLoop.
        /// </summary>
        /// <param name="curves"></param>
        /// <returns></returns>
        public static CurveLoop ToCurveLoop <T>(this IEnumerable <T> curves) where T : Curve
        {
            var newCurves = curves.ToList();

            if (curves == null || newCurves.Count == 0)
            {
                throw new NullReferenceException(nameof(newCurves));
            }

            var results = new CurveLoop();
            var endPt   = newCurves[0]?.GetEndPoint(1);

            results.Append(newCurves[0]);

            newCurves[0] = null;

            // If computing count equals curveLoop count, it should break.
            // Because, the curveLoop cannot find valid curve to append.
            var count = 0;

            while (count < newCurves.Count && results.Count() < newCurves.Count)
            {
                for (var i = 0; i < newCurves.Count; i++)
                {
                    if (newCurves[i] == null)
                    {
                        continue;
                    }

                    var p0 = newCurves[i].GetEndPoint(0);

                    var p1 = newCurves[i].GetEndPoint(1);

                    if (p0.IsAlmostEqualTo(endPt))
                    {
                        endPt = p1;

                        results.Append(newCurves[i]);

                        newCurves[i] = null;
                    }

                    // The curve should be reversed.
                    else if (p1.IsAlmostEqualTo(endPt))
                    {
                        endPt = p0;

                        results.Append(newCurves[i].CreateReversed());

                        newCurves[i] = null;
                    }
                }

                count++;
            }

            return(results);
        }
示例#4
0
        /// <summary>
        /// Attempt to create a single curve from a curve loop composed of linear segments.
        /// </summary>
        /// <param name="curveLoop">The curve loop.</param>
        /// <param name="pointXYZs">The original points from which the curve loop was created.</param>
        /// <returns>The curve, if the curve loop is linear, or null.</returns>
        /// <remarks>Note that the routine does not actually check that the curveLoop is composed
        /// of line segments, or that the point array matches the curve loop in any way.</remarks>
        public static Curve CreateCurveFromPolyCurveLoop(CurveLoop curveLoop, IList <XYZ> pointXYZs)
        {
            if (curveLoop == null)
            {
                return(null);
            }

            int numCurves = curveLoop.Count();

            if (numCurves == 0)
            {
                return(null);
            }

            if (numCurves == 1)
            {
                Curve originalCurve = curveLoop.First();
                if (originalCurve != null)
                {
                    return(originalCurve.Clone());
                }
                return(null);
            }

            if (pointXYZs == null)
            {
                return(null);
            }
            int numPoints = pointXYZs.Count;

            // If we are here, we are sure that the number of points must be at least 3.
            XYZ firstPoint   = pointXYZs[0];
            XYZ secondPoint  = pointXYZs[1];
            XYZ vectorToTest = (secondPoint - firstPoint).Normalize();

            bool allAreCollinear = true;

            for (int ii = 2; ii < numPoints; ii++)
            {
                XYZ vectorTmp = (pointXYZs[ii] - firstPoint).Normalize();
                if (!vectorTmp.IsAlmostEqualTo(vectorToTest))
                {
                    allAreCollinear = false;
                    break;
                }
            }

            if (allAreCollinear)
            {
                return(Line.CreateBound(firstPoint, pointXYZs[numPoints - 1]));
            }

            return(null);
        }
        private static bool CurveLoopIsARectangle(CurveLoop curveLoop, out IList<int> cornerIndices)
        {
            cornerIndices = new List<int>(4);

            // looking for four orthogonal lines in one curve loop.
            int sz = curveLoop.Count();
            if (sz < 4)
                return false;

            IList<Line> lines = new List<Line>();
            foreach (Curve curve in curveLoop)
            {
                if (!(curve is Line))
                    return false;

                lines.Add(curve as Line);
            }

            sz = lines.Count;
            int numAngles = 0;

            // Must have 4 right angles found, and all other lines collinear -- if not, not a rectangle.
            for (int ii = 0; ii < sz; ii++)
            {
                double dot = lines[ii].Direction.DotProduct(lines[(ii + 1) % sz].Direction);
                if (MathUtil.IsAlmostZero(dot))
                {
                    if (numAngles > 3)
                        return false;
                    cornerIndices.Add(ii);
                    numAngles++;
                }
                else if (MathUtil.IsAlmostEqual(dot, 1.0))
                {
                    XYZ line0End1 = lines[ii].GetEndPoint(1);
                    XYZ line1End0 = lines[(ii + 1) % sz].GetEndPoint(0);
                    if (!line0End1.IsAlmostEqualTo(line1End0))
                        return false;
                }
                else
                    return false;
            }

            return (numAngles == 4);
        }
示例#6
0
        /// <summary>
        /// Returns the surface which defines the internal shape of the face
        /// </summary>
        /// <param name="lcs">The local coordinate system for the surface.  Can be null.</param>
        /// <returns>The surface which defines the internal shape of the face</returns>
        public override Surface GetSurface(Transform lcs)
        {
            if (SweptCurve == null)
            {
                Importer.TheLog.LogError(Id, "Cannot find the profile curve of this revolved face.", true);
            }

            IFCSimpleProfile simpleProfile = SweptCurve as IFCSimpleProfile;

            if (simpleProfile == null)
            {
                Importer.TheLog.LogError(Id, "Can't handle profile curve of type " + SweptCurve.GetType() + ".", true);
            }

            CurveLoop outerCurve   = simpleProfile.OuterCurve;
            Curve     profileCurve = (outerCurve != null) ? outerCurve.First <Curve>() : null;

            if (profileCurve == null)
            {
                Importer.TheLog.LogError(Id, "Cannot create the profile curve of this revolved surface.", true);
            }

            if (outerCurve.Count() > 1)
            {
                Importer.TheLog.LogError(Id, "Revolved surface has multiple profile curves, ignoring all but first.", false);
            }

            Curve revolvedSurfaceProfileCurve = profileCurve.CreateTransformed(Position);

            if (!RevolvedSurface.IsValidProfileCurve(AxisPosition.Origin, AxisPosition.BasisZ, revolvedSurfaceProfileCurve))
            {
                Importer.TheLog.LogError(Id, "Profile curve is invalid for this revolved surface.", true);
            }

            if (lcs == null)
            {
                return(RevolvedSurface.Create(AxisPosition.Origin, AxisPosition.BasisZ, revolvedSurfaceProfileCurve));
            }

            Curve transformedRevolvedSurfaceProfileCurve = revolvedSurfaceProfileCurve.CreateTransformed(lcs);

            return(RevolvedSurface.Create(lcs.OfPoint(AxisPosition.Origin), lcs.OfVector(AxisPosition.BasisZ), transformedRevolvedSurfaceProfileCurve));
        }
        public bool FirstPointIsInsideFace(
            CurveLoop CL,
            PlanarFace PFace)
        {
            Transform Trans = PFace.ComputeDerivatives(
                new UV(0, 0));

            if (CL.Count() == 0)
            {
                return(false);
            }
            XYZ Pt = Trans.Inverse.OfPoint(
                CL.ToList()[0].GetEndPoint(0));
            IntersectionResult Res = null;
            bool outval            = PFace.IsInside(
                new UV(Pt.X, Pt.Y), out Res);

            return(outval);
        }
        /// <summary>
        /// Get the local surface transform at a given point on the surface.
        /// </summary>
        /// <param name="pointOnSurface">The point.</param>
        /// <returns>The transform.</returns>
        /// <remarks>This does not include the translation component.</remarks>
        public override Transform GetTransformAtPoint(XYZ pointOnSurface)
        {
            if (!(SweptCurve is IFCSimpleProfile))
            {
                // LOG: ERROR: warn that we only support simple profiles.
                return(null);
            }

            CurveLoop outerCurveLoop = (SweptCurve as IFCSimpleProfile).OuterCurve;

            if (outerCurveLoop == null || outerCurveLoop.Count() != 1)
            {
                // LOG: ERROR
                return(null);
            }

            Curve outerCurve = outerCurveLoop.First();

            if (outerCurve == null)
            {
                // LOG: ERROR
                return(null);
            }

            IntersectionResult result = outerCurve.Project(pointOnSurface);

            if (result == null)
            {
                // LOG: ERROR
                return(null);
            }

            double parameter = result.Parameter;

            Transform atPoint = outerCurve.ComputeDerivatives(parameter, false);

            atPoint.set_Basis(0, atPoint.BasisX.Normalize());
            atPoint.set_Basis(1, atPoint.BasisY.Normalize());
            atPoint.set_Basis(2, atPoint.BasisZ.Normalize());
            atPoint.Origin = pointOnSurface;

            return(atPoint);
        }
        /// <returns>true if the curve loop is clockwise, false otherwise.</returns>
        private static bool SafeIsCurveLoopClockwise(CurveLoop curveLoop, XYZ dir)
        {
            if (curveLoop == null)
                return false;

            if (curveLoop.IsOpen())
                return false;

            if ((curveLoop.Count() == 1) && !(curveLoop.First().IsBound))
                return false;

            return !curveLoop.IsCounterclockwise(dir);
        }
        private IList<GeometryObject> SplitSweptDiskIntoValidPieces(CurveLoop trimmedDirectrixInWCS, IList<CurveLoop> profileCurveLoops, SolidOptions solidOptions)
        {
           // If we have 0 or 1 curves, there is nothing we can do here.
           int numCurves = trimmedDirectrixInWCS.Count();
           if (numCurves < 2)
              return null;

           // We will attempt to represent the original description in as few pieces as possible.  
           IList<Curve> directrixCurves = new List<Curve>();
           foreach (Curve directrixCurve in trimmedDirectrixInWCS)
           {
              if (directrixCurve == null)
              {
                 numCurves--;
                 if (numCurves < 2)
                    return null;
                 continue;
              }
              directrixCurves.Add(directrixCurve);
           }

           IList<GeometryObject> sweptDiskPieces = new List<GeometryObject>();

           // We will march along the directrix one curve at a time, trying to build a bigger piece of the sweep.  At the point that we throw an exception,
           // we will take the last biggest piece and start over.
           CurveLoop currentCurveLoop = new CurveLoop();
           Solid bestSolidSoFar = null;
           double pathAttachmentParam = directrixCurves[0].GetEndParameter(0);

           for (int ii = 0; ii < numCurves; ii++)
           {
              currentCurveLoop.Append(directrixCurves[ii]);
              try
              {
                 Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops,
                    solidOptions);
                 bestSolidSoFar = currentSolid;
              }
              catch
              {
                 if (bestSolidSoFar != null)
                 {
                    sweptDiskPieces.Add(bestSolidSoFar);
                    bestSolidSoFar = null;
                 }
              }

              // This should only happen as a result of the catch loop above.  We want to protect against the case where one or more pieces of the sweep 
              // are completely invalid.
              while (bestSolidSoFar == null && (ii < numCurves))
              {
                 try
                 {
                    currentCurveLoop = new CurveLoop();
                    currentCurveLoop.Append(directrixCurves[ii]);
                    profileCurveLoops = CreateProfileCurveLoopsForDirectrix(directrixCurves[ii], out pathAttachmentParam);

                    Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops,
                       solidOptions);
                    bestSolidSoFar = currentSolid;
                    break;
                 }
                 catch
                 {
                    ii++;
                 }
              }
           }

           return sweptDiskPieces;
        }
        /// <summary>
        /// Get the curve from the Axis representation of the given IfcProduct, transformed to the current local coordinate system.
        /// </summary>
        /// <param name="creator">The IfcProduct that may or may not contain a valid axis curve.</param>
        /// <param name="lcs">The local coordinate system.</param>
        /// <returns>The axis curve, if found, and valid.</returns>
        /// <remarks>In this case, we only allow bounded lines and arcs to be valid axis curves, as per IFC2x3 convention.
        /// The Curve may be contained as either a single Curve in the IFCCurve representation item, or it could be an
        /// open CurveLoop with one item.</remarks>
        private Curve GetAxisCurve(IFCProduct creator, Transform lcs)
        {
            // We need an axis curve to clip the extrusion profiles; if we can't get one, fail
            IFCProductRepresentation productRepresentation = creator.ProductRepresentation;

            if (productRepresentation == null)
            {
                return(null);
            }

            IList <IFCRepresentation> representations = productRepresentation.Representations;

            if (representations == null)
            {
                return(null);
            }

            foreach (IFCRepresentation representation in representations)
            {
                // Go through the list of representations for this product, to find the Axis representation.
                if (representation == null || representation.Identifier != IFCRepresentationIdentifier.Axis)
                {
                    continue;
                }

                IList <IFCRepresentationItem> items = representation.RepresentationItems;
                if (items == null)
                {
                    continue;
                }

                // Go through the list of representation items in the Axis representation, to look for the IfcCurve.
                foreach (IFCRepresentationItem item in items)
                {
                    if (item is IFCCurve)
                    {
                        // We will accept either a bounded Curve of type Line or Arc,
                        // or an open CurveLoop with one curve that satisfies the same condition.
                        IFCCurve ifcCurve  = item as IFCCurve;
                        Curve    axisCurve = ifcCurve.Curve;
                        if (axisCurve == null)
                        {
                            CurveLoop axisCurveLoop = ifcCurve.CurveLoop;
                            if (axisCurveLoop != null && axisCurveLoop.IsOpen() && axisCurveLoop.Count() == 1)
                            {
                                axisCurve = axisCurveLoop.First();
                                if (!(axisCurve is Line || axisCurve is Arc))
                                {
                                    axisCurve = null;
                                }
                            }
                        }

                        if (axisCurve != null)
                        {
                            return(axisCurve.CreateTransformed(lcs));
                        }
                    }
                }
            }

            return(null);
        }
示例#12
0
        public Result Execute(
            ExternalCommandData commandData,
            ref string message,
            ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument    uidoc = uiapp.ActiveUIDocument;
            Application   app   = uiapp.Application;
            Document      doc   = uidoc.Document;

            ICollection <ElementId> selectedElementsId = uidoc.Selection.GetElementIds();

            List <View> selectedViews = new List <View>();

            foreach (ElementId eid in selectedElementsId)
            {
                View current = doc.GetElement(eid) as View;
                selectedViews.Add(current);
            }



            int    count = 0;
            string error = "";

            var form = new Forms.FormPickFromDropDown();

            using (Transaction t = new Transaction(doc, "Resize viewport"))
            {
                if (selectedViews.Count > 1)
                {
                    form.ViewSectionList = new ObservableCollection <View>(selectedViews.OrderBy(x => x.Name));

                    form.ShowDialog();
                }
                else
                {
                    TaskDialog.Show("Error", "Please select some Section Views first.");
                    return(Result.Cancelled);
                }


                if (form.DialogResult == false)
                {
                    return(Result.Cancelled);
                }

                View sourceView = form.SelectedViewSection;

                BoundingBoxXYZ sourceViewBB = sourceView.CropBox;

                ViewCropRegionShapeManager vcrSource = sourceView.GetCropRegionShapeManager();
                CurveLoop sourceLoop = vcrSource.GetCropShape()[0];

                t.Start();
                foreach (ElementId eid in selectedElementsId)
                {
                    View destinationView = doc.GetElement(eid) as View;
                    try
                    {
                        //The origin of the cropbox (from Transform) is not the same for different Sections. Use CropRegionShapeManager instead

                        //destinationView.CropBox.Transform.Origin = sourceViewBB.Transform.Origin;
                        //destinationView.CropBox = sourceViewBB;
                        ViewCropRegionShapeManager destinationVcr = destinationView.GetCropRegionShapeManager();
                        destinationVcr.SetCropShape(sourceLoop);
                        //if the crop is rectangular
                        if (sourceLoop.Count() == 4)
                        {
                            destinationVcr.RemoveCropRegionShape();                             //Reset Crop after it has been set
                        }
                        count++;
                    }
                    catch
                    {
                        error += $"Error processing view: {destinationView.Name}\n";
                    }
                }

                t.Commit();
            }



            TaskDialog.Show("Result", $"{count}/{selectedElementsId.Count} viewport updated. \n{error}");

            return(Result.Succeeded);
        }
        private IList <GeometryObject> SplitSweptDiskIntoValidPieces(CurveLoop trimmedDirectrixInWCS, IList <CurveLoop> profileCurveLoops, SolidOptions solidOptions)
        {
            // If we have 0 or 1 curves, there is nothing we can do here.
            int numCurves = trimmedDirectrixInWCS.Count();

            if (numCurves < 2)
            {
                return(null);
            }

            // We will attempt to represent the original description in as few pieces as possible.
            IList <Curve> directrixCurves = new List <Curve>();

            foreach (Curve directrixCurve in trimmedDirectrixInWCS)
            {
                if (directrixCurve == null)
                {
                    numCurves--;
                    if (numCurves < 2)
                    {
                        return(null);
                    }
                    continue;
                }
                directrixCurves.Add(directrixCurve);
            }

            IList <GeometryObject> sweptDiskPieces = new List <GeometryObject>();

            // We will march along the directrix one curve at a time, trying to build a bigger piece of the sweep.  At the point that we throw an exception,
            // we will take the last biggest piece and start over.
            CurveLoop currentCurveLoop    = new CurveLoop();
            Solid     bestSolidSoFar      = null;
            double    pathAttachmentParam = directrixCurves[0].GetEndParameter(0);

            for (int ii = 0; ii < numCurves; ii++)
            {
                currentCurveLoop.Append(directrixCurves[ii]);
                try
                {
                    Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops,
                                                                                       solidOptions);
                    bestSolidSoFar = currentSolid;
                }
                catch
                {
                    if (bestSolidSoFar != null)
                    {
                        sweptDiskPieces.Add(bestSolidSoFar);
                        bestSolidSoFar = null;
                    }
                }

                // This should only happen as a result of the catch loop above.  We want to protect against the case where one or more pieces of the sweep
                // are completely invalid.
                while (bestSolidSoFar == null && (ii < numCurves))
                {
                    try
                    {
                        currentCurveLoop = new CurveLoop();
                        currentCurveLoop.Append(directrixCurves[ii]);
                        profileCurveLoops = CreateProfileCurveLoopsForDirectrix(directrixCurves[ii], out pathAttachmentParam);

                        Solid currentSolid = GeometryCreationUtilities.CreateSweptGeometry(currentCurveLoop, 0, pathAttachmentParam, profileCurveLoops,
                                                                                           solidOptions);
                        bestSolidSoFar = currentSolid;
                        break;
                    }
                    catch
                    {
                        ii++;
                    }
                }
            }

            return(sweptDiskPieces);
        }
示例#14
0
 public static int NumberOfCurves(this CurveLoop curveLoop)
 {
     return(curveLoop.Count());
 }
示例#15
0
        CurveLoop GetOuterLoopOfRoomFromCreateViaOffset(
            View view,
            IList <IList <BoundarySegment> > sloops)
        {
            Document doc = view.Document;

            CurveLoop      loop = null;
            IList <double> wallthicknessList = new List <double>();

            foreach (IList <BoundarySegment> sloop in sloops)
            {
                loop = new CurveLoop();

                foreach (BoundarySegment s in sloop)
                {
                    loop.Append(s.GetCurve());

                    ElementType type = doc.GetElement(
                        s.ElementId) as ElementType;

                    Element e = doc.GetElement(s.ElementId);

                    double thickness = (e is Wall)
            ? (e as Wall).Width
            : 0; // Room separator; any other exceptions need including??

                    wallthicknessList.Add(thickness
                                          * _wall_width_factor);
                }
                // Skip out after first sloop - ignore
                // rooms with holes and disjunct parts
                break;
            }

            int    n       = loop.Count();
            string slength = string.Join(",",
                                         loop.Select <Curve, string>(
                                             c => c.Length.ToString("#.##")));

            int    m          = wallthicknessList.Count();
            string sthickness = string.Join(",",
                                            wallthicknessList.Select <double, string>(
                                                d => d.ToString("#.##")));

            Debug.Print(
                "{0} curves with lengths {1} and {2} thicknesses {3}",
                n, slength, m, sthickness);

            CreateModelCurves(view, loop);

            bool flip_normal = true;

            XYZ normal = flip_normal ? -XYZ.BasisZ : XYZ.BasisZ;

            CurveLoop room_outer_loop = CurveLoop.CreateViaOffset(
                loop, wallthicknessList, normal);

            CreateModelCurves(view, room_outer_loop);

            //CurveLoop newloop = new CurveLoop();

            //foreach( Curve curve in loop2 )
            //{

            //  IList<XYZ> points = curve.Tessellate();

            //  for( int ip = 0; ip < points.Count - 1; ip++ )
            //  {
            //    Line l = Line.CreateBound(
            //      points[ ip ], points[ ip + 1 ] );

            //    newloop.Append( l );
            //  }
            //}

            return(room_outer_loop);
        }
示例#16
0
        private static bool GetCalloutCornerPoints(Document doc, ElementId calloutId, out XYZ firstPoint, out XYZ secondPoint)
        {
            bool result = false;

            firstPoint  = new XYZ(0, 0, 0);
            secondPoint = new XYZ(0, 0, 0);
            try
            {
                double minX = double.MaxValue;
                double minY = double.MaxValue;
                double minZ = double.MaxValue;
                double maxX = double.MinValue;
                double maxY = double.MinValue;
                double maxZ = double.MinValue;

                ViewCropRegionShapeManager cropRegion = View.GetCropRegionShapeManagerForReferenceCallout(doc, calloutId);
#if RELEASE2016 || RELEASE2017
                IList <CurveLoop> curveLoops = cropRegion.GetCropShape();
                foreach (CurveLoop cLoop in curveLoops)
                {
                    foreach (Curve curve in cLoop)
                    {
                        XYZ point = curve.GetEndPoint(0);
                        if (point.X < minX)
                        {
                            minX = point.X;
                        }
                        if (point.Y < minY)
                        {
                            minY = point.Y;
                        }
                        if (point.Z < minZ)
                        {
                            minZ = point.Z;
                        }
                        if (point.X > maxX)
                        {
                            maxX = point.X;
                        }
                        if (point.Y > maxY)
                        {
                            maxY = point.Y;
                        }
                        if (point.Z > maxZ)
                        {
                            maxZ = point.Z;
                        }
                    }
                }

                if (curveLoops.Count() > 0)
                {
                    firstPoint  = new XYZ(minX, minY, minZ);
                    secondPoint = new XYZ(maxX, maxY, maxZ);
                    result      = true;
                }
#else
                CurveLoop curveLoop = cropRegion.GetCropRegionShape();
                foreach (Curve curve in curveLoop)
                {
                    XYZ point = curve.GetEndPoint(0);
                    if (point.X < minX)
                    {
                        minX = point.X;
                    }
                    if (point.Y < minY)
                    {
                        minY = point.Y;
                    }
                    if (point.Z < minZ)
                    {
                        minZ = point.Z;
                    }
                    if (point.X > maxX)
                    {
                        maxX = point.X;
                    }
                    if (point.Y > maxY)
                    {
                        maxY = point.Y;
                    }
                    if (point.Z > maxZ)
                    {
                        maxZ = point.Z;
                    }
                }

                if (curveLoop.Count() > 0)
                {
                    firstPoint  = new XYZ(minX, minY, minZ);
                    secondPoint = new XYZ(maxX, maxY, maxZ);
                    result      = true;
                }
#endif
            }
            catch (Exception ex)
            {
                errorMessage.AppendLine("Failed to get corner points of callout.\n" + ex.Message);
                //MessageBox.Show("Failed to get corner points of callout\n" + ex.Message, "Get Corner Points of Callout", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
            return(result);
        }
示例#17
0
        /// <summary>
        /// Trims the CurveLoop contained in an IFCCurve by the start and optional end parameter values.
        /// </summary>
        /// <param name="id">The id of the IFC entity containing the directrix, for messaging purposes.</param>
        /// <param name="ifcCurve">The IFCCurve entity containing the CurveLoop to be trimmed.</param>
        /// <param name="startVal">The starting trim parameter.</param>
        /// <param name="origEndVal">The optional end trim parameter.  If not supplied, assume no end trim.</param>
        /// <returns>The original curve loop, if no trimming has been done, otherwise a trimmed copy.</returns>
        private static CurveLoop TrimCurveLoop(int id, IFCCurve ifcCurve, double startVal, double?origEndVal)
        {
            CurveLoop origCurveLoop = ifcCurve.GetTheCurveLoop();

            if (origCurveLoop == null || origCurveLoop.Count() == 0)
            {
                return(null);
            }

            // Trivial case: unbound curve.
            Curve possiblyUnboundCurve = origCurveLoop.First();

            if (!possiblyUnboundCurve.IsBound)
            {
                if (!origEndVal.HasValue)
                {
                    Importer.TheLog.LogError(id, "Can't trim unbound curve with no given end parameter.", true);
                }

                CurveLoop boundCurveLoop = new CurveLoop();
                Curve     boundCurve     = possiblyUnboundCurve.Clone();
                boundCurve.MakeBound(startVal, origEndVal.Value * ifcCurve.ParametericScaling);
                boundCurveLoop.Append(boundCurve);
                return(boundCurveLoop);
            }

            IList <double> curveLengths = new List <double>();
            IList <Curve>  loopCurves   = new List <Curve>();

            double totalParamLength = 0.0;

            bool allLines = true;

            foreach (Curve curve in origCurveLoop)
            {
                if (!(curve is Line))
                {
                    allLines = false;
                }

                double curveLength = curve.GetEndParameter(1) - curve.GetEndParameter(0);
                double currLength  = ScaleCurveLengthForSweptSolid(curve, curveLength);
                loopCurves.Add(curve);
                curveLengths.Add(currLength);
                totalParamLength += currLength;
            }

            double endVal = origEndVal.HasValue ? origEndVal.Value : totalParamLength;
            double eps    = MathUtil.Eps();

            if (!CheckIfTrimParametersAreNeeded(id, ifcCurve, startVal, endVal, totalParamLength))
            {
                return(origCurveLoop);
            }

            // Special cases:
            // if startval = 0 and endval = 1 and we have a polyline, then this likely means that the importing application
            // incorrectly set the extents to be the "whole" curve, when really this is just a portion of the curves
            // (the parametrization is described above).
            // As such, if the totalParamLength is not 1 but startVal = 0 and endVal = 1, we will warn but not trim.
            // This is not a hypothetical case: it occurs in several AllPlan 2017 files at least.
            if (allLines)
            {
                if ((!MathUtil.IsAlmostEqual(totalParamLength, 1.0)) && (MathUtil.IsAlmostZero(startVal) && MathUtil.IsAlmostEqual(endVal, 1.0)))
                {
                    Importer.TheLog.LogWarning(id, "The Start Parameter for the trimming of this curve was set to 0, and the End Parameter was set to 1.  " +
                                               "Most likely, this is an error in the sending application, and the trim extents are being ignored.  " +
                                               "If this trim was intended, please contact Autodesk.", true);
                    return(origCurveLoop);
                }
            }

            int    numCurves       = loopCurves.Count;
            double currentPosition = 0.0;
            int    currCurve       = 0;

            IList <Curve> newLoopCurves = new List <Curve>();

            if (startVal > MathUtil.Eps())
            {
                for (; currCurve < numCurves; currCurve++)
                {
                    if (currentPosition + curveLengths[currCurve] < startVal + eps)
                    {
                        currentPosition += curveLengths[currCurve];
                        continue;
                    }

                    Curve newCurve = loopCurves[currCurve].Clone();
                    if (!MathUtil.IsAlmostEqual(currentPosition, startVal))
                    {
                        double startParam = UnscaleSweptSolidCurveParam(loopCurves[currCurve], startVal - currentPosition);
                        double endParam   = newCurve.GetEndParameter(1);
                        AdjustParamsIfNecessary(newCurve, ref startParam, ref endParam);
                        newCurve.MakeBound(startParam, endParam);
                    }

                    newLoopCurves.Add(newCurve);
                    break;
                }
            }

            if (endVal < totalParamLength - eps)
            {
                for (; currCurve < numCurves; currCurve++)
                {
                    if (currentPosition + curveLengths[currCurve] < endVal - eps)
                    {
                        currentPosition += curveLengths[currCurve];
                        newLoopCurves.Add(loopCurves[currCurve]);
                        continue;
                    }

                    Curve newCurve = loopCurves[currCurve].Clone();
                    if (!MathUtil.IsAlmostEqual(currentPosition + curveLengths[currCurve], endVal))
                    {
                        double startParam = newCurve.GetEndParameter(0);
                        double endParam   = UnscaleSweptSolidCurveParam(loopCurves[currCurve], endVal - currentPosition);
                        AdjustParamsIfNecessary(newCurve, ref startParam, ref endParam);
                        newCurve.MakeBound(startParam, endParam);
                    }

                    newLoopCurves.Add(newCurve);
                    break;
                }
            }

            CurveLoop trimmedCurveLoop = new CurveLoop();

            foreach (Curve curve in newLoopCurves)
            {
                trimmedCurveLoop.Append(curve);
            }
            return(trimmedCurveLoop);
        }
        /// <summary>
        /// Determines if a curveloop can be exported as an I-Shape profile.
        /// </summary>
        /// <param name="exporterIFC">The exporter.</param>
        /// <param name="profileName">The name of the profile.</param>
        /// <param name="curveLoop">The curve loop.</param>
        /// <param name="origPlane">The plane of the loop.</param>
        /// <param name="projDir">The projection direction.</param>
        /// <returns>The IfcIShapeProfileDef, or null if not possible.</returns>
        /// <remarks>This routine works with I-shaped curveloops projected onto origPlane, in either orientation;
        /// it does not work with H-shaped curveloops.</remarks>
        private static IFCAnyHandle CreateIShapeProfileDefIfPossible(ExporterIFC exporterIFC, string profileName, CurveLoop curveLoop, Plane origPlane,
            XYZ projDir)
        {
            IFCFile file = exporterIFC.GetFile();

            if (curveLoop.IsOpen())
                return null;

            if (curveLoop.Count() != 12 && curveLoop.Count() != 16)
                return null;

            // All curves must be lines, except for 4 optional fillets; get direction vectors and start points.
            XYZ xDir = origPlane.XVec;
            XYZ yDir = origPlane.YVec;

            // The list of vertices, in order.  startVertex below is the upper-right hand vertex, in UV-space.
            IList<UV> vertices = new List<UV>();
            // The directions in UV of the line segments. directions[ii] is the direction of the line segment starting with vertex[ii].
            IList<UV> directions = new List<UV>();
            // The lengths in UV of the line segments.  lengths[ii] is the length of the line segment starting with vertex[ii].
            IList<double> lengths = new List<double>();
            // turnsCCW[ii] is true if directions[ii+1] is clockwise relative to directions[ii] in UV-space.
            IList<bool> turnsCCW = new List<bool>();

            IList<Arc> fillets = new List<Arc>();
            IList<int> filletPositions = new List<int>();

            int idx = 0;
            int startVertex = -1;
            int startFillet = -1;
            UV upperRight = null;
            double lowerBoundU = 1e+30;
            double upperBoundU = -1e+30;

            foreach (Curve curve in curveLoop)
            {
                if (!(curve is Line))
                {
                    if (!(curve is Arc))
                        return null;
                    fillets.Add(curve as Arc);
                    filletPositions.Add(idx);   // share the index of the next line segment.
                    continue;
                }

                Line line = curve as Line;

                XYZ point = line.GetEndPoint(0);
                UV pointProjUV = GeometryUtil.ProjectPointToPlane(origPlane, projDir, point);
                if (pointProjUV == null)
                    return null;
                pointProjUV = UnitUtil.ScaleLength(pointProjUV);

                if ((upperRight == null) || ((pointProjUV.U > upperRight.U - MathUtil.Eps()) && (pointProjUV.V > upperRight.V - MathUtil.Eps())))
                {
                    upperRight = pointProjUV;
                    startVertex = idx;
                    startFillet = filletPositions.Count;
                }

                if (pointProjUV.U < lowerBoundU)
                    lowerBoundU = pointProjUV.U;
                if (pointProjUV.U > upperBoundU)
                    upperBoundU = pointProjUV.U;

                vertices.Add(pointProjUV);

                XYZ direction3d = line.Direction;
                UV direction = new UV(direction3d.DotProduct(xDir), direction3d.DotProduct(yDir));
                lengths.Add(UnitUtil.ScaleLength(line.Length));

                bool zeroU = MathUtil.IsAlmostZero(direction.U);
                bool zeroV = MathUtil.IsAlmostZero(direction.V);
                if (zeroU && zeroV)
                    return null;

                // Accept only non-rotated I-Shapes.
                if (!zeroU && !zeroV)
                    return null;

                direction.Normalize();
                if (idx > 0)
                {
                    if (!MathUtil.IsAlmostZero(directions[idx - 1].DotProduct(direction)))
                        return null;
                    turnsCCW.Add(directions[idx - 1].CrossProduct(direction) > 0);
                }

                directions.Add(direction);
                idx++;
            }

            if (directions.Count != 12)
                return null;

            if (!MathUtil.IsAlmostZero(directions[11].DotProduct(directions[0])))
                return null;
            turnsCCW.Add(directions[11].CrossProduct(directions[0]) > 0);

            bool firstTurnIsCCW = turnsCCW[startVertex];

            // Check proper turning of lines.
            // The orientation of the turns should be such that 8 match the original orientation, and 4 go in the opposite direction.
            // The opposite ones are:
            // For I-Shape:
            // if the first turn is clockwise (i.e., in -Y direction): 1,2,7,8.
            // if the first turn is counterclockwise (i.e., in the -X direction): 2,3,8,9.
            // For H-Shape:
            // if the first turn is clockwise (i.e., in -Y direction): 2,3,8,9.
            // if the first turn is counterclockwise (i.e., in the -X direction): 1,2,7,8.

            int iShapeCCWOffset = firstTurnIsCCW ? 1 : 0;
            int hShapeCWOffset = firstTurnIsCCW ? 0 : 1;

            bool isIShape = true;
            bool isHShape = false;

            for (int ii = 0; ii < 12 && isIShape; ii++)
            {
                int currOffset = 12 + (startVertex - iShapeCCWOffset);
                int currIdx = (ii + currOffset) % 12;
                if (currIdx == 1 || currIdx == 2 || currIdx == 7 || currIdx == 8)
                {
                    if (firstTurnIsCCW == turnsCCW[ii])
                        isIShape = false;
                }
                else
                {
                    if (firstTurnIsCCW == !turnsCCW[ii])
                        isIShape = false;
                }
            }

            if (!isIShape)
            {
                // Check if it is orientated like an H - if neither I nor H, fail.
                isHShape = true;

                for (int ii = 0; ii < 12 && isHShape; ii++)
                {
                    int currOffset = 12 + (startVertex - hShapeCWOffset);
                    int currIdx = (ii + currOffset) % 12;
                    if (currIdx == 1 || currIdx == 2 || currIdx == 7 || currIdx == 8)
                    {
                        if (firstTurnIsCCW == turnsCCW[ii])
                            return null;
                    }
                    else
                    {
                        if (firstTurnIsCCW == !turnsCCW[ii])
                            return null;
                    }
                }
            }

            // Check that the lengths of parallel and symmetric line segments are equal.
            double overallWidth = 0.0;
            double overallDepth = 0.0;
            double flangeThickness = 0.0;
            double webThickness = 0.0;

            // I-Shape:
            // CCW pairs:(0,6), (1,5), (1,7), (1,11), (2,4), (2,8), (2,10), (3, 9)
            // CW pairs: (11,5), (0,4), (0,6), (0,10), (1,3), (1,7), (1,9), (2, 8)
            // H-Shape is reversed.
            int cwPairOffset = (firstTurnIsCCW == isIShape) ? 0 : 11;

            overallWidth = lengths[(startVertex + cwPairOffset) % 12];
            flangeThickness = lengths[(startVertex + 1 + cwPairOffset) % 12];

            if (isIShape)
            {
                if (firstTurnIsCCW)
                {
                    overallDepth = vertices[startVertex].V - vertices[(startVertex + 7) % 12].V;
                    webThickness = vertices[(startVertex + 9) % 12].U - vertices[(startVertex + 3) % 12].U;
                }
                else
                {
                    overallDepth = vertices[startVertex].V - vertices[(startVertex + 5) % 12].V;
                    webThickness = vertices[(startVertex + 2) % 12].U - vertices[(startVertex + 8) % 12].U;
                }
            }
            else
            {
                if (!firstTurnIsCCW)
                {
                    overallDepth = vertices[startVertex].U - vertices[(startVertex + 7) % 12].U;
                    webThickness = vertices[(startVertex + 9) % 12].V - vertices[(startVertex + 3) % 12].V;
                }
                else
                {
                    overallDepth = vertices[startVertex].U - vertices[(startVertex + 5) % 12].U;
                    webThickness = vertices[(startVertex + 2) % 12].V - vertices[(startVertex + 8) % 12].V;
                }
            }

            if (!MathUtil.IsAlmostEqual(overallWidth, lengths[(startVertex + 6 + cwPairOffset) % 12]))
                return null;
            if (!MathUtil.IsAlmostEqual(flangeThickness, lengths[(startVertex + 5 + cwPairOffset) % 12]) ||
                !MathUtil.IsAlmostEqual(flangeThickness, lengths[(startVertex + 7 + cwPairOffset) % 12]) ||
                !MathUtil.IsAlmostEqual(flangeThickness, lengths[(startVertex + 11 + cwPairOffset) % 12]))
                return null;
            double innerTopLeftLength = lengths[(startVertex + 2 + cwPairOffset) % 12];
            if (!MathUtil.IsAlmostEqual(innerTopLeftLength, lengths[(startVertex + 4 + cwPairOffset) % 12]) ||
                !MathUtil.IsAlmostEqual(innerTopLeftLength, lengths[(startVertex + 8 + cwPairOffset) % 12]) ||
                !MathUtil.IsAlmostEqual(innerTopLeftLength, lengths[(startVertex + 10 + cwPairOffset) % 12]))
                return null;
            double iShaftLength = lengths[(startVertex + 3 + cwPairOffset) % 12];
            if (!MathUtil.IsAlmostEqual(iShaftLength, lengths[(startVertex + 9 + cwPairOffset) % 12]))
                return null;

            // Check fillet validity.
            int numFillets = fillets.Count();
            double? filletRadius = null;

            if (numFillets != 0)
            {
                if (numFillets != 4)
                    return null;

                // startFillet can have any value from 0 to 4; if it is 4, need to reset it to 0.

                // The fillet positions relative to the upper right hand corner are:
                // For I-Shape:
                // if the first turn is clockwise (i.e., in -Y direction): 2,3,8,9.
                // if the first turn is counterclockwise (i.e., in the -X direction): 3,4,9,10.
                // For H-Shape:
                // if the first turn is clockwise (i.e., in -Y direction): 3,4,9,10.
                // if the first turn is counterclockwise (i.e., in the -X direction): 2,3,8,9.
                int filletOffset = (isIShape == firstTurnIsCCW) ? 1 : 0;
                if (filletPositions[startFillet % 4] != ((2 + filletOffset + startVertex) % 12) ||
                    filletPositions[(startFillet + 1) % 4] != ((3 + filletOffset + startVertex) % 12) ||
                    filletPositions[(startFillet + 2) % 4] != ((8 + filletOffset + startVertex) % 12) ||
                    filletPositions[(startFillet + 3) % 4] != ((9 + filletOffset + startVertex) % 12))
                    return null;

                double tmpFilletRadius = fillets[0].Radius;
                for (int ii = 1; ii < 4; ii++)
                {
                    if (!MathUtil.IsAlmostEqual(tmpFilletRadius, fillets[ii].Radius))
                        return null;
                }

                if (!MathUtil.IsAlmostZero(tmpFilletRadius))
                    filletRadius = UnitUtil.ScaleLength(tmpFilletRadius);
            }

            XYZ planeNorm = origPlane.Normal;
            for (int ii = 0; ii < numFillets; ii++)
            {
                bool filletIsCCW = (fillets[ii].Normal.DotProduct(planeNorm) > MathUtil.Eps());
                if (filletIsCCW == firstTurnIsCCW)
                    return null;
            }

            if (MathUtil.IsAlmostZero(overallWidth) || MathUtil.IsAlmostZero(overallDepth) ||
                MathUtil.IsAlmostZero(flangeThickness) || MathUtil.IsAlmostZero(webThickness))
                return null;

            // We have an I-Shape Profile!
            IList<double> newCtr = new List<double>();
            newCtr.Add((vertices[0].U + vertices[6].U) / 2);
            newCtr.Add((vertices[0].V + vertices[6].V) / 2);

            IFCAnyHandle location = IFCInstanceExporter.CreateCartesianPoint(file, newCtr);

            IList<double> refDir = new List<double>();

            if (isIShape)
            {
                refDir.Add(1.0);
                refDir.Add(0.0);
            }
            else
            {
                refDir.Add(0.0);
                refDir.Add(1.0);
            }

            IFCAnyHandle refDirectionOpt = ExporterUtil.CreateDirection(file, refDir);

            IFCAnyHandle positionHnd = IFCInstanceExporter.CreateAxis2Placement2D(file, location, null, refDirectionOpt);

            return IFCInstanceExporter.CreateIShapeProfileDef(file, IFCProfileType.Area, profileName, positionHnd,
                overallWidth, overallDepth, webThickness, flangeThickness, filletRadius);
        }
示例#19
0
        public Polygon2D GetStairAreaPolygon(UIDocument currentDocument, Stairs stair, string key)
        {
            ICollection <ElementId> allRunsIds = stair.GetStairsRuns();
            ElementId currentId = allRunsIds.ElementAt(0);

            if (key.Equals(RevitObjectManager.BASE_LEVEL_KEY))
            {
                foreach (ElementId currentBaseId in allRunsIds)
                {
                    StairsRun currentStairsRun  = currentDocument.Document.GetElement(currentBaseId) as StairsRun;
                    StairsRun selectedStairsRun = currentDocument.Document.GetElement(currentId) as StairsRun;

                    if (currentStairsRun.BaseElevation < selectedStairsRun.BaseElevation)
                    {
                        currentId = currentBaseId;
                    }
                }
            }
            else if (key.Equals(RevitObjectManager.TOP_LEVEL_KEY))
            {
                foreach (ElementId currentTopId in allRunsIds)
                {
                    StairsRun currentStairsRun  = currentDocument.Document.GetElement(currentTopId) as StairsRun;
                    StairsRun selectedStairsRun = currentDocument.Document.GetElement(currentId) as StairsRun;

                    if (currentStairsRun.TopElevation > selectedStairsRun.TopElevation)
                    {
                        currentId = currentTopId;
                    }
                }
            }

            List <Vector2D> areaNodes      = new List <Vector2D>();
            StairsRun       finalStairsRun = currentDocument.Document.GetElement(currentId) as StairsRun;
            CurveLoop       stairPath      = finalStairsRun.GetStairsPath();
            Curve           firstStairPathCurve;

            if (stairPath.Count() > 1)
            {
                if ((finalStairsRun.StairsRunStyle.Equals(StairsRunStyle.Winder) || finalStairsRun.StairsRunStyle.Equals(StairsRunStyle.Spiral)) &&
                    key.Equals(RevitObjectManager.TOP_LEVEL_KEY))
                {
                    firstStairPathCurve = stairPath.ElementAt(stairPath.Count() - 1);
                }
                else
                {
                    firstStairPathCurve = stairPath.ElementAt(0);
                }
            }
            else
            {
                firstStairPathCurve = stairPath.ElementAt(0);
            }

            double stairsRunsWidth = ConvertFeetToMeters(finalStairsRun.ActualRunWidth * STAIRS_AREA_SHRINK_FACTOR);

            if (stairsRunsWidth < DEFAULT_AREA_RADIUS)
            {
                stairsRunsWidth = DEFAULT_AREA_RADIUS;
            }

            double pathsLength = ConvertFeetToMeters(firstStairPathCurve.Length * STAIRS_AREA_SHRINK_FACTOR);

            if (pathsLength < DEFAULT_AREA_RADIUS)
            {
                pathsLength = DEFAULT_AREA_RADIUS;
            }

            Vector2D pathsStart    = GeometryFactory.CreateVector2D(ConvertFeetToMeters(firstStairPathCurve.GetEndPoint(0).X), ConvertFeetToMeters(firstStairPathCurve.GetEndPoint(0).Y), MEASUREMENTUNITFACTOR);
            Vector2D pathsEnd      = GeometryFactory.CreateVector2D(ConvertFeetToMeters(firstStairPathCurve.GetEndPoint(1).X), ConvertFeetToMeters(firstStairPathCurve.GetEndPoint(1).Y), MEASUREMENTUNITFACTOR);
            Vector2D pathDirection = pathsEnd.Difference(pathsStart);
            Vector2D pathDirectionPerpenticular = pathDirection.Rotate((-1) * Math.PI / 2).GetAsNormalized();

            Vector2D firstNode = pathsStart.Add(pathDirectionPerpenticular.Multiply(stairsRunsWidth / 2));

            areaNodes.Add(firstNode);
            Vector2D pointToAdd = firstNode.Add(pathDirection);

            areaNodes.Add(pointToAdd);
            pointToAdd = pointToAdd.Add(pathDirectionPerpenticular.Multiply((-1) * stairsRunsWidth));
            areaNodes.Add(pointToAdd);
            pointToAdd = pointToAdd.Add(pathDirection.Multiply(-1));
            areaNodes.Add(pointToAdd);
            areaNodes.Add(firstNode);

            Polygon2D areaPolygon = GeometryFactory.CreatePolygon2D(areaNodes.ToArray(), finalStairsRun.Name);

            return(areaPolygon);
        }