예제 #1
0
        private double?GetTrimParameter(IFCData trim, IFCCurve basisCurve, IFCTrimmingPreference trimPreference, bool secondAttempt)
        {
            bool preferParam = !(trimPreference == IFCTrimmingPreference.Cartesian);

            if (secondAttempt)
            {
                preferParam = !preferParam;
            }
            double vertexEps = MathUtil.VertexEps;

            IFCAggregate trimAggregate = trim.AsAggregate();

            foreach (IFCData trimParam in trimAggregate)
            {
                if (!preferParam && (trimParam.PrimitiveType == IFCDataPrimitiveType.Instance))
                {
                    IFCAnyHandle trimParamInstance = trimParam.AsInstance();
                    XYZ          trimParamPt       = IFCPoint.ProcessScaledLengthIFCCartesianPoint(trimParamInstance);
                    if (trimParamPt == null)
                    {
                        IFCImportFile.TheLog.LogWarning(basisCurve.Id, "Invalid trim point for basis curve.", false);
                        continue;
                    }

                    try
                    {
                        IntersectionResult result = basisCurve.Curve.Project(trimParamPt);
                        if (result.Distance < vertexEps)
                        {
                            return(result.Parameter);
                        }

                        IFCImportFile.TheLog.LogWarning(basisCurve.Id, "Cartesian value for trim point not on the basis curve.", false);
                    }
                    catch
                    {
                        IFCImportFile.TheLog.LogWarning(basisCurve.Id, "Cartesian value for trim point not on the basis curve.", false);
                    }
                }
                else if (preferParam && (trimParam.PrimitiveType == IFCDataPrimitiveType.Double))
                {
                    double trimParamDouble = trimParam.AsDouble();
                    if (basisCurve.Curve.IsCyclic)
                    {
                        trimParamDouble = IFCUnitUtil.ScaleAngle(trimParamDouble);
                    }
                    return(trimParamDouble);
                }
            }

            // Try again with opposite preference.
            if (!secondAttempt)
            {
                return(GetTrimParameter(trim, basisCurve, trimPreference, true));
            }

            return(null);
        }
예제 #2
0
 private bool NeedToReverseBaseCurve(Curve baseCurve,
                                     double param1, double param2, IFCTrimmingPreference trimPreference)
 {
     // In the very specific case where the trim preference is Cartesian,
     // and the trim parameters are reversed, we can try again by reversing
     // the base curve, if it is not cyclic.
     // This is an error on the input that we see in some files.
     return(baseCurve != null &&
            param1 > param2 + MathUtil.Eps() &&
            trimPreference == IFCTrimmingPreference.Cartesian &&
            !baseCurve.IsCyclic);
 }
예제 #3
0
        private void GetTrimParameters(int id, IFCData trim1, IFCData trim2,
                                       Curve baseCurve, IFCTrimmingPreference trimPreference,
                                       out double param1, out double param2)
        {
            double?condParam1 = GetTrimParameter(id, trim1, baseCurve, trimPreference, false);

            if (!condParam1.HasValue)
            {
                throw new InvalidOperationException("#" + id + ": Couldn't apply first trimming parameter of IfcTrimmedCurve.");
            }
            param1 = condParam1.Value;

            double?condParam2 = GetTrimParameter(id, trim2, baseCurve, trimPreference, false);

            if (!condParam2.HasValue)
            {
                throw new InvalidOperationException("#" + id + ": Couldn't apply second trimming parameter of IfcTrimmedCurve.");
            }
            param2 = condParam2.Value;

            if (MathUtil.IsAlmostEqual(param1, param2))
            {
                // If we had a cartesian parameter as the trim preference, check if the parameter values are better.
                if (trimPreference == IFCTrimmingPreference.Cartesian)
                {
                    condParam1 = GetTrimParameter(id, trim1, baseCurve, IFCTrimmingPreference.Parameter, true);
                    if (!condParam1.HasValue)
                    {
                        throw new InvalidOperationException("#" + id + ": Couldn't apply first trimming parameter of IfcTrimmedCurve.");
                    }
                    param1 = condParam1.Value;

                    condParam2 = GetTrimParameter(id, trim2, baseCurve, IFCTrimmingPreference.Parameter, true);
                    if (!condParam2.HasValue)
                    {
                        throw new InvalidOperationException("#" + id + ": Couldn't apply second trimming parameter of IfcTrimmedCurve.");
                    }
                    param2 = condParam2.Value;
                }
                else
                {
                    throw new InvalidOperationException("#" + id + ": Ignoring 0 length curve.");
                }
            }
        }
      /// <summary>
      /// Creates a handle representing an IfcTrimmedCurve and assigns it to the file.
      /// </summary>
      /// <param name="file">The file.</param>
      /// <param name="basisCurve">The base curve.</param>
      /// <param name="trim1">The cartesian point, parameter, or both of end 1.</param>
      /// <param name="trim2">The cartesian point, parameter, or both of end 2.</param>
      /// <param name="senseAgreement">True if the end points match the orientation of the curve.</param>
      /// <param name="masterRepresentation">An enum stating which trim parameters are available.</param>
      /// <returns>The handle.</returns>
      public static IFCAnyHandle CreateTrimmedCurve(IFCFile file, IFCAnyHandle basisCurve,
          HashSet<IFCData> trim1, HashSet<IFCData> trim2, bool senseAgreement,
          IFCTrimmingPreference masterRepresentation)
      {
         IFCAnyHandleUtil.ValidateSubTypeOf(basisCurve, false, IFCEntityType.IfcCurve);

         IFCAnyHandle trimmedCurve = CreateInstance(file, IFCEntityType.IfcTrimmedCurve);
         IFCAnyHandleUtil.SetAttribute(trimmedCurve, "BasisCurve", basisCurve);
         IFCAnyHandleUtil.SetAttribute(trimmedCurve, "Trim1", trim1);
         IFCAnyHandleUtil.SetAttribute(trimmedCurve, "Trim2", trim2);
         IFCAnyHandleUtil.SetAttribute(trimmedCurve, "SenseAgreement", senseAgreement);
         IFCAnyHandleUtil.SetAttribute(trimmedCurve, "MasterRepresentation", masterRepresentation);
         return trimmedCurve;
      }
예제 #5
0
        protected override void Process(IFCAnyHandle ifcCurve)
        {
            base.Process(ifcCurve);

            bool found = false;

            bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcCurve, "SenseAgreement", out found);

            if (!found)
            {
                sameSense = true;
            }

            IFCAnyHandle basisCurve    = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurve, "BasisCurve", true);
            IFCCurve     ifcBasisCurve = IFCCurve.ProcessIFCCurve(basisCurve);

            if (ifcBasisCurve == null || (ifcBasisCurve.IsEmpty()))
            {
                // LOG: ERROR: Error processing BasisCurve # for IfcTrimmedCurve #.
                return;
            }
            if (ifcBasisCurve.Curve == null)
            {
                // LOG: ERROR: Expected a single curve, not a curve loop for BasisCurve # for IfcTrimmedCurve #.
                return;
            }

            IFCData trim1 = ifcCurve.GetAttribute("Trim1");

            if (trim1.PrimitiveType != IFCDataPrimitiveType.Aggregate)
            {
                // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #.
                return;
            }

            IFCData trim2 = ifcCurve.GetAttribute("Trim2");

            if (trim2.PrimitiveType != IFCDataPrimitiveType.Aggregate)
            {
                // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #.
                return;
            }

            // Note that these are the "unprocessed" values.  These can be used for, e.g., adding up the IFC parameter length
            // of the file, to account for export errors.  The "processed" values can be determined from the Revit curves.
            Trim1 = GetRawTrimParameter(trim1);
            Trim2 = GetRawTrimParameter(trim2);

            IFCTrimmingPreference trimPreference = IFCEnums.GetSafeEnumerationAttribute <IFCTrimmingPreference>(ifcCurve, "MasterRepresentation", IFCTrimmingPreference.Parameter);

            double param1 = 0.0, param2 = 0.0;
            Curve  baseCurve = ifcBasisCurve.Curve;

            try
            {
                GetTrimParameters(ifcBasisCurve.Id, trim1, trim2, baseCurve, trimPreference, out param1, out param2);
                if (NeedToReverseBaseCurve(baseCurve, param1, param2, trimPreference))
                {
                    Importer.TheLog.LogWarning(Id, "Invalid Param1 > Param2 for non-cyclic IfcTrimmedCurve using Cartesian trimming preference, reversing.", false);
                    baseCurve = baseCurve.CreateReversed();
                    GetTrimParameters(ifcBasisCurve.Id, trim1, trim2, baseCurve, trimPreference, out param1, out param2);
                }
            }
            catch (Exception ex)
            {
                Importer.TheLog.LogError(ifcCurve.StepId, ex.Message, false);
                return;
            }

            if (MathUtil.IsAlmostEqual(param1, param2))
            {
                Importer.TheLog.LogError(Id, "Param1 = Param2 for IfcTrimmedCurve #, ignoring.", false);
                return;
            }

            Curve curve = null;

            if (baseCurve.IsCyclic)
            {
                double period = baseCurve.Period;
                if (!sameSense)
                {
                    MathUtil.Swap(ref param1, ref param2);
                }

                // We want to make sure both values are within period of one another.
                param1 = MathUtil.PutInRange(param1, 0, period);
                param2 = MathUtil.PutInRange(param2, 0, period);
                if (param2 < param1)
                {
                    param2 = MathUtil.PutInRange(param2, param1 + period / 2, period);
                }

                // This is effectively an unbound curve.
                double numberOfPeriods = (param2 - param1) / period;
                if (MathUtil.IsAlmostEqual(numberOfPeriods, Math.Round(numberOfPeriods)))
                {
                    Importer.TheLog.LogWarning(Id, "Start and end parameters indicate a zero-length closed curve, assuming unbound is intended.", false);
                    curve = baseCurve;
                }
                else
                {
                    curve = baseCurve.Clone();
                    if (!SafelyBoundCurve(curve, param1, param2))
                    {
                        return;
                    }
                }
            }
            else
            {
                if (param1 > param2 - MathUtil.Eps())
                {
                    Importer.TheLog.LogWarning(Id, "Param1 > Param2 for IfcTrimmedCurve #, reversing.", false);
                    MathUtil.Swap(ref param1, ref param2);
                    sameSense = !sameSense;
                }

                Curve copyCurve = baseCurve.Clone();

                double length = param2 - param1;
                if (length <= IFCImportFile.TheFile.ShortCurveTolerance)
                {
                    string lengthAsString = IFCUnitUtil.FormatLengthAsString(length);
                    Importer.TheLog.LogError(Id, "curve length of " + lengthAsString + " is invalid, ignoring.", false);
                    return;
                }

                if (!SafelyBoundCurve(copyCurve, param1, param2))
                {
                    return;
                }

                if (sameSense)
                {
                    curve = copyCurve;
                }
                else
                {
                    curve = copyCurve.CreateReversed();
                }
            }

            CurveLoop curveLoop = new CurveLoop();

            curveLoop.Append(curve);
            SetCurveLoop(curveLoop);
        }
예제 #6
0
        protected override void Process(IFCAnyHandle ifcCurve)
        {
            base.Process(ifcCurve);

            bool found = false;

            bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcCurve, "SenseAgreement", out found);

            if (!found)
            {
                sameSense = true;
            }

            IFCAnyHandle basisCurve    = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurve, "BasisCurve", true);
            IFCCurve     ifcBasisCurve = IFCCurve.ProcessIFCCurve(basisCurve);

            if (ifcBasisCurve == null || (ifcBasisCurve.Curve == null && ifcBasisCurve.CurveLoop == null))
            {
                // LOG: ERROR: Error processing BasisCurve # for IfcTrimmedCurve #.
                return;
            }
            if (ifcBasisCurve.Curve == null)
            {
                // LOG: ERROR: Expected a single curve, not a curve loop for BasisCurve # for IfcTrimmedCurve #.
                return;
            }

            IFCData trim1 = ifcCurve.GetAttribute("Trim1");

            if (trim1.PrimitiveType != IFCDataPrimitiveType.Aggregate)
            {
                // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #.
                return;
            }
            IFCData trim2 = ifcCurve.GetAttribute("Trim2");

            if (trim2.PrimitiveType != IFCDataPrimitiveType.Aggregate)
            {
                // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #.
                return;
            }

            IFCTrimmingPreference trimPreference = IFCEnums.GetSafeEnumerationAttribute <IFCTrimmingPreference>(ifcCurve, "MasterRepresentation", IFCTrimmingPreference.Parameter);

            double param1 = 0.0, param2 = 0.0;

            try
            {
                GetTrimParameters(trim1, trim2, ifcBasisCurve, trimPreference, out param1, out param2);
            }
            catch (Exception ex)
            {
                Importer.TheLog.LogError(ifcCurve.StepId, ex.Message, false);
                return;
            }

            Curve baseCurve = ifcBasisCurve.Curve;

            if (baseCurve.IsCyclic)
            {
                if (!sameSense)
                {
                    MathUtil.Swap(ref param1, ref param2);
                }

                if (param2 < param1)
                {
                    param2 = MathUtil.PutInRange(param2, param1 + Math.PI, 2 * Math.PI);
                }

                if (param2 - param1 > 2.0 * Math.PI - MathUtil.Eps())
                {
                    Importer.TheLog.LogWarning(ifcCurve.StepId, "IfcTrimmedCurve length is greater than 2*PI, leaving unbound.", false);
                    Curve = baseCurve;
                    return;
                }

                Curve = baseCurve.Clone();

                try
                {
                    Curve.MakeBound(param1, param2);
                }
                catch (Exception ex)
                {
                    if (ex.Message.Contains("too small"))
                    {
                        Curve = null;
                        Importer.TheLog.LogError(Id, "curve length is invalid, ignoring.", false);
                        return;
                    }
                    else
                    {
                        throw ex;
                    }
                }
            }
            else
            {
                if (MathUtil.IsAlmostEqual(param1, param2))
                {
                    Importer.TheLog.LogError(Id, "Param1 = Param2 for IfcTrimmedCurve #, ignoring.", false);
                    return;
                }

                if (param1 > param2 - MathUtil.Eps())
                {
                    Importer.TheLog.LogWarning(Id, "Param1 > Param2 for IfcTrimmedCurve #, reversing.", false);
                    MathUtil.Swap(ref param1, ref param2);
                    return;
                }

                Curve copyCurve = baseCurve.Clone();

                double length = param2 - param1;
                if (length <= IFCImportFile.TheFile.Document.Application.ShortCurveTolerance)
                {
                    string lengthAsString = IFCUnitUtil.FormatLengthAsString(length);
                    Importer.TheLog.LogError(Id, "curve length of " + lengthAsString + " is invalid, ignoring.", false);
                    return;
                }

                copyCurve.MakeBound(param1, param2);
                if (sameSense)
                {
                    Curve = copyCurve;
                }
                else
                {
                    Curve = copyCurve.CreateReversed();
                }
            }

            CurveLoop = new CurveLoop();
            CurveLoop.Append(Curve);
        }
      private double? GetTrimParameter(IFCData trim, IFCCurve basisCurve, IFCTrimmingPreference trimPreference, bool secondAttempt)
      {
         bool preferParam = !(trimPreference == IFCTrimmingPreference.Cartesian);
         if (secondAttempt)
            preferParam = !preferParam;
         double vertexEps = IFCImportFile.TheFile.Document.Application.VertexTolerance;

         IFCAggregate trimAggregate = trim.AsAggregate();
         foreach (IFCData trimParam in trimAggregate)
         {
            if (!preferParam && (trimParam.PrimitiveType == IFCDataPrimitiveType.Instance))
            {
               IFCAnyHandle trimParamInstance = trimParam.AsInstance();
               XYZ trimParamPt = IFCPoint.ProcessScaledLengthIFCCartesianPoint(trimParamInstance);
               if (trimParamPt == null)
               {
                  Importer.TheLog.LogWarning(basisCurve.Id, "Invalid trim point for basis curve.", false);
                  continue;
               }

               try
               {
                  IntersectionResult result = basisCurve.Curve.Project(trimParamPt);
                  if (result.Distance < vertexEps)
                     return result.Parameter;

                  Importer.TheLog.LogWarning(basisCurve.Id, "Cartesian value for trim point not on the basis curve.", false);
               }
               catch
               {
                  Importer.TheLog.LogWarning(basisCurve.Id, "Cartesian value for trim point not on the basis curve.", false);
               }
            }
            else if (preferParam && (trimParam.PrimitiveType == IFCDataPrimitiveType.Double))
            {
               double trimParamDouble = trimParam.AsDouble();
               if (basisCurve.Curve.IsCyclic)
                  trimParamDouble = IFCUnitUtil.ScaleAngle(trimParamDouble);
               else
                  trimParamDouble = IFCUnitUtil.ScaleLength(trimParamDouble);
               return trimParamDouble;
            }
         }

         // Try again with opposite preference.
         if (!secondAttempt)
            return GetTrimParameter(trim, basisCurve, trimPreference, true);

         return null;
      }
      private void GetTrimParameters(IFCData trim1, IFCData trim2, IFCCurve basisCurve, IFCTrimmingPreference trimPreference,
          out double param1, out double param2)
      {
         double? condParam1 = GetTrimParameter(trim1, basisCurve, trimPreference, false);
         if (!condParam1.HasValue)
            throw new InvalidOperationException("#" + basisCurve.Id + ": Couldn't apply first trimming parameter of IfcTrimmedCurve.");
         param1 = condParam1.Value;

         double? condParam2 = GetTrimParameter(trim2, basisCurve, trimPreference, false);
         if (!condParam2.HasValue)
            throw new InvalidOperationException("#" + basisCurve.Id + ": Couldn't apply second trimming parameter of IfcTrimmedCurve.");
         param2 = condParam2.Value;

         if (MathUtil.IsAlmostEqual(param1, param2))
         {
            // If we had a cartesian parameter as the trim preference, check if the parameter values are better.
            if (trimPreference == IFCTrimmingPreference.Cartesian)
            {
               condParam1 = GetTrimParameter(trim1, basisCurve, IFCTrimmingPreference.Parameter, true);
               if (!condParam1.HasValue)
                  throw new InvalidOperationException("#" + basisCurve.Id + ": Couldn't apply first trimming parameter of IfcTrimmedCurve.");
               param1 = condParam1.Value;

               condParam2 = GetTrimParameter(trim2, basisCurve, IFCTrimmingPreference.Parameter, true);
               if (!condParam2.HasValue)
                  throw new InvalidOperationException("#" + basisCurve.Id + ": Couldn't apply second trimming parameter of IfcTrimmedCurve.");
               param2 = condParam2.Value;
            }
            else
               throw new InvalidOperationException("#" + basisCurve.Id + ": Ignoring 0 length curve.");
         }
      }
예제 #9
0
        private void ProcessIFCTrimmedCurve(IFCAnyHandle ifcCurve)
        {
            bool found = false;

            bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcCurve, "SenseAgreement", out found);

            if (!found)
            {
                sameSense = true;
            }

            IFCAnyHandle basisCurve    = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurve, "BasisCurve", true);
            IFCCurve     ifcBasisCurve = IFCCurve.ProcessIFCCurve(basisCurve);

            if (ifcBasisCurve == null || (ifcBasisCurve.Curve == null && ifcBasisCurve.CurveLoop == null))
            {
                // LOG: ERROR: Error processing BasisCurve # for IfcTrimmedCurve #.
                return;
            }
            if (ifcBasisCurve.Curve == null)
            {
                // LOG: ERROR: Expected a single curve, not a curve loop for BasisCurve # for IfcTrimmedCurve #.
                return;
            }

            IFCData trim1 = ifcCurve.GetAttribute("Trim1");

            if (trim1.PrimitiveType != IFCDataPrimitiveType.Aggregate)
            {
                // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #.
                return;
            }
            IFCData trim2 = ifcCurve.GetAttribute("Trim2");

            if (trim2.PrimitiveType != IFCDataPrimitiveType.Aggregate)
            {
                // LOG: ERROR: Invalid data type for Trim1 attribute for IfcTrimmedCurve #.
                return;
            }

            string trimPreferenceAsString        = IFCAnyHandleUtil.GetEnumerationAttribute(ifcCurve, "MasterRepresentation");
            IFCTrimmingPreference trimPreference = IFCTrimmingPreference.Parameter;

            if (trimPreferenceAsString != null)
            {
                trimPreference = (IFCTrimmingPreference)Enum.Parse(typeof(IFCTrimmingPreference), trimPreferenceAsString, true);
            }

            double param1 = 0.0, param2 = 0.0;

            try
            {
                GetTrimParameters(trim1, trim2, ifcBasisCurve, trimPreference, out param1, out param2);
            }
            catch (Exception ex)
            {
                IFCImportFile.TheLog.LogError(ifcCurve.StepId, ex.Message, false);
                return;
            }

            Curve baseCurve = ifcBasisCurve.Curve;

            if (baseCurve.IsCyclic)
            {
                if (!sameSense)
                {
                    MathUtil.Swap(ref param1, ref param2);
                }

                if (param2 < param1)
                {
                    param2 = MathUtil.PutInRange(param2, param1 + Math.PI, 2 * Math.PI);
                }

                if (param2 - param1 > 2.0 * Math.PI - MathUtil.Eps())
                {
                    // LOG: WARNING: #Id: IfcTrimmedCurve length is greater than 2*PI, leaving unbound.
                    Curve = baseCurve;
                    return;
                }

                Curve = baseCurve.Clone();
                Curve.MakeBound(param1, param2);
            }
            else
            {
                if (MathUtil.IsAlmostEqual(param1, param2))
                {
                    // LOG: ERROR: Param1 = Param2 for IfcTrimmedCurve #, ignoring.
                    return;
                }

                if (param1 > param2 - MathUtil.Eps())
                {
                    // LOG: WARNING: Param1 > Param2 for IfcTrimmedCurve #, reversing.
                    MathUtil.Swap(ref param1, ref param2);
                    return;
                }

                Curve copyCurve = baseCurve.Clone();
                copyCurve.MakeBound(param1, param2);
                if (sameSense)
                {
                    Curve = copyCurve;
                }
                else
                {
                    Curve = copyCurve.CreateReversed();
                }
            }
        }