override protected void Process(IFCAnyHandle ifcGeometricSet) { base.Process(ifcGeometricSet); IList <IFCAnyHandle> elements = IFCAnyHandleUtil.GetAggregateInstanceAttribute <List <IFCAnyHandle> >(ifcGeometricSet, "Elements"); if (elements != null) { foreach (IFCAnyHandle element in elements) { if (IFCAnyHandleUtil.IsSubTypeOf(element, IFCEntityType.IfcCurve)) { IFCCurve curve = IFCCurve.ProcessIFCCurve(element); if (curve != null) { Curves.Add(curve); } } else { Importer.TheLog.LogError(Id, "Unhandled entity type in IfcGeometricSet: " + IFCAnyHandleUtil.GetEntityType(element).ToString(), false); } } } }
override protected void Process(IFCAnyHandle solid) { base.Process(solid); IFCAnyHandle directrix = IFCImportHandleUtil.GetRequiredInstanceAttribute(solid, "Directrix", true); Directrix = IFCCurve.ProcessIFCCurve(directrix); IFCAnyHandle referenceSurface = IFCImportHandleUtil.GetRequiredInstanceAttribute(solid, "ReferenceSurface", true); ReferenceSurface = IFCSurface.ProcessIFCSurface(referenceSurface); StartParameter = IFCImportHandleUtil.GetOptionalDoubleAttribute(solid, "StartParam", 0.0); if (StartParameter < MathUtil.Eps()) { StartParameter = 0.0; } double endParameter = IFCImportHandleUtil.GetOptionalDoubleAttribute(solid, "EndParam", -1.0); if (!MathUtil.IsAlmostEqual(endParameter, -1.0)) { if (endParameter < StartParameter + MathUtil.Eps()) { Importer.TheLog.LogError(solid.StepId, "IfcSurfaceCurveSweptAreaSolid swept curve end parameter less than or equal to start parameter, aborting.", true); } EndParameter = endParameter; } }
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); }
private void ProcessIFCCompositeCurveSegment(IFCAnyHandle ifcCurveSegment) { bool found = false; bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcCurveSegment, "SameSense", out found); if (!found) { sameSense = true; } IFCAnyHandle parentCurve = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurveSegment, "ParentCurve", true); IFCCurve ifcParentCurve = IFCCurve.ProcessIFCCurve(parentCurve); if (ifcParentCurve == null) { IFCImportFile.TheLog.LogError(ifcCurveSegment.StepId, "Error processing ParentCurve for IfcCompositeCurveSegment.", false); return; } bool hasCurve = (ifcParentCurve.Curve != null); bool hasCurveLoop = (ifcParentCurve.CurveLoop != null); if (!hasCurve && !hasCurveLoop) { IFCImportFile.TheLog.LogError(ifcCurveSegment.StepId, "Error processing ParentCurve for IfcCompositeCurveSegment.", false); return; } else { // The CurveLoop here is from the parent IfcCurve, which is the IfcCompositeCurve, which will correspond to a CurveLoop. // IfcCompositiveCurveSegment may be either a curve or a curveloop, which we want to append to the parent curveloop. if (CurveLoop == null) { CurveLoop = new CurveLoop(); } } try { if (hasCurve) { AddCurveToLoop(CurveLoop, ifcParentCurve.Curve, !sameSense, true); } else if (hasCurveLoop) { foreach (Curve subCurve in ifcParentCurve.CurveLoop) { AddCurveToLoop(CurveLoop, subCurve, !sameSense, true); } } } catch (Exception ex) { IFCImportFile.TheLog.LogError(ifcParentCurve.Id, ex.Message, true); } }
/// <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 curves to be valid axis curves. /// The Curve may be contained as either a single Curve in the IFCCurve representation item, /// or it could be an open CurveLoop that could be represented as a single curve.</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 a bounded curve, or an open CurveLoop that can be represented // as one curve. IFCCurve ifcCurve = item as IFCCurve; Curve axisCurve = ifcCurve.Curve; if (axisCurve == null) { axisCurve = ifcCurve.ConvertCurveLoopIntoSingleCurve(); } if (axisCurve != null) { return(axisCurve.CreateTransformed(lcs)); } } } } return(null); }
/// <summary> /// Processes an IfcRepresentationItem entity handle. /// </summary> /// <param name="ifcRepresentationItem">The IfcRepresentationItem handle.</param> /// <returns>The IFCRepresentationItem object.</returns> public static IFCRepresentationItem ProcessIFCRepresentationItem(IFCAnyHandle ifcRepresentationItem) { if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcBooleanResult)) { return(IFCBooleanResult.ProcessIFCBooleanResult(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcCurve)) { return(IFCCurve.ProcessIFCCurve(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcFaceBasedSurfaceModel)) { return(IFCFaceBasedSurfaceModel.ProcessIFCFaceBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcGeometricSet)) { return(IFCGeometricSet.ProcessIFCGeometricSet(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcMappedItem)) { return(IFCMappedItem.ProcessIFCMappedItem(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcShellBasedSurfaceModel)) { return(IFCShellBasedSurfaceModel.ProcessIFCShellBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcSolidModel)) { return(IFCSolidModel.ProcessIFCSolidModel(ifcRepresentationItem)); } if (IFCImportFile.TheFile.SchemaVersion >= IFCSchemaVersion.IFC2x2 && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcStyledItem)) { return(IFCStyledItem.ProcessIFCStyledItem(ifcRepresentationItem)); } if (IFCImportFile.TheFile.SchemaVersion >= IFCSchemaVersion.IFC4 && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcTriangulatedFaceSet)) { return(IFCTriangulatedFaceSet.ProcessIFCTriangulatedFaceSet(ifcRepresentationItem)); } if (IFCImportFile.TheFile.SchemaVersion >= IFCSchemaVersion.IFC4Add2 && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcPolygonalFaceSet)) { return(IFCPolygonalFaceSet.ProcessIFCPolygonalFaceSet(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcTopologicalRepresentationItem)) { return(IFCTopologicalRepresentationItem.ProcessIFCTopologicalRepresentationItem(ifcRepresentationItem)); } Importer.TheLog.LogUnhandledSubTypeError(ifcRepresentationItem, IFCEntityType.IfcRepresentationItem, true); return(null); }
private IList <Curve> ProcessIFCCompositeCurveSegment(IFCAnyHandle ifcCurveSegment) { bool found = false; bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcCurveSegment, "SameSense", out found); if (!found) { sameSense = true; } IFCAnyHandle ifcParentCurve = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurveSegment, "ParentCurve", true); IFCCurve parentCurve = null; using (TemporaryVerboseLogging logger = new TemporaryVerboseLogging()) { parentCurve = IFCCurve.ProcessIFCCurve(ifcParentCurve); } if (parentCurve == null) { Importer.TheLog.LogWarning(ifcCurveSegment.StepId, "Error processing ParentCurve (#" + ifcParentCurve.StepId + ") for IfcCompositeCurveSegment; this may be repairable.", false); return(null); } bool hasCurve = (parentCurve.Curve != null); bool hasCurveLoop = (parentCurve.CurveLoop != null); if (!hasCurve && !hasCurveLoop) { Importer.TheLog.LogWarning(ifcCurveSegment.StepId, "Error processing ParentCurve (#" + ifcParentCurve.StepId + ") for IfcCompositeCurveSegment; this may be repairable.", false); return(null); } IList <Curve> curveSegments = new List <Curve>(); if (hasCurve) { curveSegments.Add(parentCurve.Curve); } else if (hasCurveLoop) { foreach (Curve subCurve in parentCurve.CurveLoop) { curveSegments.Add(subCurve); } } return(curveSegments); }
override protected void Process(IFCAnyHandle solid) { base.Process(solid); IFCAnyHandle directrix = IFCImportHandleUtil.GetRequiredInstanceAttribute(solid, "Directrix", true); Directrix = IFCCurve.ProcessIFCCurve(directrix); bool found = false; Radius = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(solid, "Radius", out found); if (!found || !Application.IsValidThickness(Radius)) { Importer.TheLog.LogError(solid.StepId, "IfcSweptDiskSolid radius is invalid, aborting.", true); } double innerRadius = IFCImportHandleUtil.GetOptionalScaledLengthAttribute(solid, "InnerRadius", 0.0); if (Application.IsValidThickness(innerRadius)) { if (!Application.IsValidThickness(Radius - innerRadius)) { Importer.TheLog.LogError(solid.StepId, "IfcSweptDiskSolid inner radius is too large, aborting.", true); } InnerRadius = innerRadius; } StartParameter = IFCImportHandleUtil.GetOptionalDoubleAttribute(solid, "StartParam", 0.0); if (StartParameter < MathUtil.Eps()) { StartParameter = 0.0; } double endParameter = IFCImportHandleUtil.GetOptionalDoubleAttribute(solid, "EndParam", -1.0); if (!MathUtil.IsAlmostEqual(endParameter, -1.0)) { if (endParameter < StartParameter + MathUtil.Eps()) { Importer.TheLog.LogWarning(solid.StepId, "IfcSweptDiskSolid swept curve end parameter less than or equal to start parameter, ignoring both.", true); StartParameter = 0.0; } else { EndParameter = endParameter; } } }
/// <summary> /// Create an IFCCurve object from a handle of type IfcCurve. /// </summary> /// <param name="ifcCurve">The IFC handle.</param> /// <returns>The IFCCurve object.</returns> public static IFCCurve ProcessIFCCurve(IFCAnyHandle ifcCurve) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcCurve)) { IFCImportFile.TheLog.LogNullError(IFCEntityType.IfcCurve); return(null); } IFCEntity curve; if (!IFCImportFile.TheFile.EntityMap.TryGetValue(ifcCurve.StepId, out curve)) { curve = new IFCCurve(ifcCurve); } return(curve as IFCCurve); }
protected override void Process(IFCAnyHandle ifcEdgeCurve) { base.Process(ifcEdgeCurve); IFCAnyHandle edgeGeometry = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcEdgeCurve, "EdgeGeometry", true); EdgeGeometry = IFCCurve.ProcessIFCCurve(edgeGeometry); bool found = false; bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcEdgeCurve, "SameSense", out found); if (found) SameSense = sameSense; else { Importer.TheLog.LogWarning(ifcEdgeCurve.StepId, "Cannot find SameSense attribute, defaulting to true", false); SameSense = true; } }
protected override void Process(IFCAnyHandle ifcCurve) { base.Process(ifcCurve); IFCAnyHandle basisCurve = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurve, "BasisCurve", false); if (basisCurve == null) { return; } IFCAnyHandle dir = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurve, "RefDirection", false); bool found = false; double distance = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(ifcCurve, "Distance", out found); if (!found) { distance = 0.0; } IFCCurve ifcBasisCurve = IFCCurve.ProcessIFCCurve(basisCurve); XYZ dirXYZ = (dir == null) ? ifcBasisCurve.GetNormal() : IFCPoint.ProcessNormalizedIFCDirection(dir); try { if (ifcBasisCurve.Curve != null) { SetCurve(ifcBasisCurve.Curve.CreateOffset(distance, XYZ.BasisZ)); } else { CurveLoop baseCurveLoop = ifcBasisCurve.GetTheCurveLoop(); if (baseCurveLoop != null) { SetCurveLoop(CurveLoop.CreateViaOffset(baseCurveLoop, distance, XYZ.BasisZ)); } } } catch { Importer.TheLog.LogError(ifcCurve.StepId, "Couldn't create offset curve.", false); } }
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."); } } }
/// <summary> /// Processes an IfcRepresentationItem entity handle. /// </summary> /// <param name="ifcRepresentationItem">The IfcRepresentationItem handle.</param> /// <returns>The IFCRepresentationItem object.</returns> public static IFCRepresentationItem ProcessIFCRepresentationItem(IFCAnyHandle ifcRepresentationItem) { if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcBooleanResult)) { return(IFCBooleanResult.ProcessIFCBooleanResult(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcConnectedFaceSet)) { return(IFCConnectedFaceSet.ProcessIFCConnectedFaceSet(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcCurve)) { return(IFCCurve.ProcessIFCCurve(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcFaceBasedSurfaceModel)) { return(IFCFaceBasedSurfaceModel.ProcessIFCFaceBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcGeometricSet)) { return(IFCGeometricSet.ProcessIFCGeometricSet(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcMappedItem)) { return(IFCMappedItem.ProcessIFCMappedItem(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcShellBasedSurfaceModel)) { return(IFCShellBasedSurfaceModel.ProcessIFCShellBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcSolidModel)) { return(IFCSolidModel.ProcessIFCSolidModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcStyledItem)) { return(IFCStyledItem.ProcessIFCStyledItem(ifcRepresentationItem)); } IFCImportFile.TheLog.LogUnhandledSubTypeError(ifcRepresentationItem, IFCEntityType.IfcRepresentationItem, true); return(null); }
protected override void Process(IFCAnyHandle ifcEdgeCurve) { base.Process(ifcEdgeCurve); IFCAnyHandle edgeGeometry = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcEdgeCurve, "EdgeGeometry", true); EdgeGeometry = IFCCurve.ProcessIFCCurve(edgeGeometry); bool found = false; bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcEdgeCurve, "SameSense", out found); if (found) { SameSense = sameSense; } else { Importer.TheLog.LogWarning(ifcEdgeCurve.StepId, "Cannot find SameSense attribute, defaulting to true", false); SameSense = true; } }
override protected void Process(IFCAnyHandle solid) { base.Process(solid); bool found = false; bool agreementFlag = IFCImportHandleUtil.GetRequiredBooleanAttribute(solid, "AgreementFlag", out found); if (found) { AgreementFlag = agreementFlag; } IFCAnyHandle baseSurface = IFCImportHandleUtil.GetRequiredInstanceAttribute(solid, "BaseSurface", true); BaseSurface = IFCSurface.ProcessIFCSurface(baseSurface); if (!(BaseSurface is IFCPlane)) { Importer.TheLog.LogUnhandledSubTypeError(baseSurface, IFCEntityType.IfcSurface, true); } if (IFCAnyHandleUtil.IsValidSubTypeOf(solid, IFCEntityType.IfcPolygonalBoundedHalfSpace)) { IFCAnyHandle position = IFCImportHandleUtil.GetRequiredInstanceAttribute(solid, "Position", false); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(position)) { BaseBoundingCurveTransform = IFCLocation.ProcessIFCAxis2Placement(position); } else { BaseBoundingCurveTransform = Transform.Identity; } IFCAnyHandle boundaryCurveHandle = IFCImportHandleUtil.GetRequiredInstanceAttribute(solid, "PolygonalBoundary", true); BaseBoundingCurve = IFCCurve.ProcessIFCCurve(boundaryCurveHandle); if (BaseBoundingCurve == null || BaseBoundingCurve.GetTheCurveLoop() == null) { Importer.TheLog.LogError(Id, "IfcPolygonalBoundedHalfSpace has an invalid boundary, ignoring.", true); } } }
protected override void Process(IFCAnyHandle ifcCurve) { base.Process(ifcCurve); IFCAnyHandle basisCurve = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcCurve, "BasisCurve", false); if (basisCurve == null) { return; } bool found = false; double distance = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(ifcCurve, "Distance", out found); if (!found) { distance = 0.0; } try { IFCCurve ifcBasisCurve = IFCCurve.ProcessIFCCurve(basisCurve); if (ifcBasisCurve.Curve != null) { Curve = ifcBasisCurve.Curve.CreateOffset(distance, XYZ.BasisZ); } else if (ifcBasisCurve.CurveLoop != null) { CurveLoop = CurveLoop.CreateViaOffset(ifcBasisCurve.CurveLoop, distance, XYZ.BasisZ); } } catch { Importer.TheLog.LogError(ifcCurve.StepId, "Couldn't create offset curve.", false); } }
/// <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); }
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); }
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); }
/// <summary> /// Processes an IfcRepresentationItem entity handle. /// </summary> /// <param name="ifcRepresentationItem">The IfcRepresentationItem handle.</param> /// <returns>The IFCRepresentationItem object.</returns> public static IFCRepresentationItem ProcessIFCRepresentationItem(IFCAnyHandle ifcRepresentationItem) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcRepresentationItem)) { Importer.TheLog.LogNullError(IFCEntityType.IfcRepresentationItem); return(null); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcBooleanResult)) { return(IFCBooleanResult.ProcessIFCBooleanResult(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcCurve)) { return(IFCCurve.ProcessIFCCurve(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcFaceBasedSurfaceModel)) { return(IFCFaceBasedSurfaceModel.ProcessIFCFaceBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcGeometricSet)) { return(IFCGeometricSet.ProcessIFCGeometricSet(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcMappedItem)) { return(IFCMappedItem.ProcessIFCMappedItem(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcShellBasedSurfaceModel)) { return(IFCShellBasedSurfaceModel.ProcessIFCShellBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcSolidModel)) { return(IFCSolidModel.ProcessIFCSolidModel(ifcRepresentationItem)); } if (IFCImportFile.TheFile.SchemaVersion >= IFCSchemaVersion.IFC2x2 && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcStyledItem)) { return(IFCStyledItem.ProcessIFCStyledItem(ifcRepresentationItem)); } if (IFCImportFile.TheFile.SchemaVersion >= IFCSchemaVersion.IFC4 && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcTriangulatedFaceSet)) { return(IFCTriangulatedFaceSet.ProcessIFCTriangulatedFaceSet(ifcRepresentationItem)); } // There is no way to actually determine an IFC4Add2 file vs. a "vanilla" IFC4 file, which is // obsolete. The try/catch here allows us to read these obsolete files without crashing. try { if (IFCImportFile.TheFile.SchemaVersion >= IFCSchemaVersion.IFC4 && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcPolygonalFaceSet)) { return(IFCPolygonalFaceSet.ProcessIFCPolygonalFaceSet(ifcRepresentationItem)); } } catch { } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcTopologicalRepresentationItem)) { return(IFCTopologicalRepresentationItem.ProcessIFCTopologicalRepresentationItem(ifcRepresentationItem)); } Importer.TheLog.LogUnhandledSubTypeError(ifcRepresentationItem, IFCEntityType.IfcRepresentationItem, true); return(null); }
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; }
/// <summary> /// Processes an IfcRepresentationItem entity handle. /// </summary> /// <param name="ifcRepresentationItem">The IfcRepresentationItem handle.</param> /// <returns>The IFCRepresentationItem object.</returns> public static IFCRepresentationItem ProcessIFCRepresentationItem(IFCAnyHandle ifcRepresentationItem) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcRepresentationItem)) { Importer.TheLog.LogNullError(IFCEntityType.IfcRepresentationItem); return(null); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcMappedItem)) { return(IFCMappedItem.ProcessIFCMappedItem(ifcRepresentationItem)); } if (IFCImportFile.TheFile.SchemaVersionAtLeast(IFCSchemaVersion.IFC2x2) && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcStyledItem)) { return(IFCStyledItem.ProcessIFCStyledItem(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcTopologicalRepresentationItem)) { return(IFCTopologicalRepresentationItem.ProcessIFCTopologicalRepresentationItem(ifcRepresentationItem)); } // TODO: Move everything below to IFCGeometricRepresentationItem, once it is created. if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcBooleanResult)) { return(IFCBooleanResult.ProcessIFCBooleanResult(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcCurve)) { return(IFCCurve.ProcessIFCCurve(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcFaceBasedSurfaceModel)) { return(IFCFaceBasedSurfaceModel.ProcessIFCFaceBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcGeometricSet)) { return(IFCGeometricSet.ProcessIFCGeometricSet(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcPoint)) { return(IFCPoint.ProcessIFCPoint(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcShellBasedSurfaceModel)) { return(IFCShellBasedSurfaceModel.ProcessIFCShellBasedSurfaceModel(ifcRepresentationItem)); } if (IFCAnyHandleUtil.IsValidSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcSolidModel)) { return(IFCSolidModel.ProcessIFCSolidModel(ifcRepresentationItem)); } // TODO: Move the items below to IFCGeometricRepresentationItem->IFCTessellatedItem->IfcTessellatedFaceSet. if (IFCImportFile.TheFile.SchemaVersionAtLeast(IFCSchemaVersion.IFC4Obsolete) && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcTriangulatedFaceSet)) { return(IFCTriangulatedFaceSet.ProcessIFCTriangulatedFaceSet(ifcRepresentationItem)); } // There is no way to actually determine an IFC4Add2 file vs. a "vanilla" IFC4 file, which is // obsolete. The try/catch here allows us to read these obsolete files without crashing. try { if (IFCImportFile.TheFile.SchemaVersionAtLeast(IFCSchemaVersion.IFC4) && IFCAnyHandleUtil.IsSubTypeOf(ifcRepresentationItem, IFCEntityType.IfcPolygonalFaceSet)) { return(IFCPolygonalFaceSet.ProcessIFCPolygonalFaceSet(ifcRepresentationItem)); } } catch (Exception ex) { // Once we fail once, downgrade the schema so we don't try again. if (IFCImportFile.HasUndefinedAttribute(ex)) { IFCImportFile.TheFile.DowngradeIFC4SchemaTo(IFCSchemaVersion.IFC4Add1Obsolete); } else { throw ex; } } Importer.TheLog.LogUnhandledSubTypeError(ifcRepresentationItem, IFCEntityType.IfcRepresentationItem, 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."); } }
/// <summary> /// Processes IfcGridAxis attributes. /// </summary> /// <param name="ifcGridAxis">The IfcGridAxis handle.</param> protected override void Process(IFCAnyHandle ifcGridAxis) { base.Process(ifcGridAxis); AxisTag = IFCImportHandleUtil.GetOptionalStringAttribute(ifcGridAxis, "AxisTag", null); if (AxisTag == null) { AxisTag = "Z"; // arbitrary; all Revit Grids have names. } IFCAnyHandle axisCurve = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcGridAxis, "AxisCurve", true); AxisCurve = IFCCurve.ProcessIFCCurve(axisCurve); bool found = false; bool sameSense = IFCImportHandleUtil.GetRequiredBooleanAttribute(ifcGridAxis, "SameSense", out found); SameSense = found ? sameSense : true; // We are going to check if this grid axis is a vertical duplicate of any existing axis. // If so, we will throw an exception so that we don't create duplicate grids. // We will only initialize these values if we actually intend to use them below. IList <Curve> curves = null; int curveCount = 0; ElementId gridId = ElementId.InvalidElementId; if (Importer.TheCache.GridNameToElementMap.TryGetValue(AxisTag, out gridId)) { Grid grid = IFCImportFile.TheFile.Document.GetElement(gridId) as Grid; if (grid != null) { IList <Curve> otherCurves = new List <Curve>(); Curve gridCurve = grid.Curve; if (gridCurve != null) { otherCurves.Add(gridCurve); int matchingGridId = FindMatchingGrid(otherCurves, grid.Id.IntegerValue, ref curves, ref curveCount); if (matchingGridId != -1) { Importer.TheCache.UseGrid(grid); CreatedElementId = grid.Id; return; } } } } IDictionary <string, IFCGridAxis> gridAxes = IFCImportFile.TheFile.IFCProject.GridAxes; IFCGridAxis gridAxis = null; if (gridAxes.TryGetValue(AxisTag, out gridAxis)) { int matchingGridId = FindMatchingGrid(gridAxis, ref curves, ref curveCount); if (matchingGridId != -1) { DuplicateAxisId = matchingGridId; return; } else { // Revit doesn't allow grid lines to have the same name. If it isn't a duplicate, rename it. // Note that this will mean that we may miss some "duplicate" grid lines because of the renaming. AxisTag = MakeAxisTagUnique(AxisTag); } } gridAxes.Add(new KeyValuePair <string, IFCGridAxis>(AxisTag, this)); }
protected override void Process(IFCAnyHandle ifcCurve) { base.Process(ifcCurve); // We are going to attempt minor repairs for small but reasonable gaps between Line/Line and Line/Arc pairs. As such, we want to collect the // curves before we create the curve loop. IList <IFCAnyHandle> segments = IFCAnyHandleUtil.GetValidAggregateInstanceAttribute <List <IFCAnyHandle> >(ifcCurve, "Segments"); if (segments == null) { Importer.TheLog.LogError(Id, "Invalid IfcCompositeCurve with no segments.", true); } double shortCurveTol = IFCImportFile.TheFile.Document.Application.ShortCurveTolerance; // need List<> so that we can AddRange later. List <Curve> curveSegments = new List <Curve>(); Segments.Clear(); ShortGapRepairer shortGapRepairer = new ShortGapRepairer(shortCurveTol); foreach (IFCAnyHandle segment in segments) { IFCCurve currCurve = ProcessIFCCompositeCurveSegment(segment); if (currCurve != null) { Segments.Add(currCurve); IList <Curve> newCurves = currCurve.GetCurves(); if (newCurves != null && newCurves.Count != 0) { curveSegments.AddRange(newCurves); // If we had a gap, we weren't able to correct it before getting new curves. shortGapRepairer.ClearGapInformation(); } else { Line gapRepairLine = shortGapRepairer.AddToGap(currCurve.Id, currCurve.BackupCurveStartLocation, currCurve.BackupCurveEndLocation); if (gapRepairLine != null) { curveSegments.Add(gapRepairLine); } } } } int numSegments = curveSegments.Count; if (numSegments == 0) { Importer.TheLog.LogError(Id, "Invalid IfcCompositeCurve with no segments.", true); } try { // We are going to try to reverse or tweak segments as necessary to make the CurveLoop. // For each curve, it is acceptable if it can be appended to the end of the existing loop, or prepended to its start, // possibly after reversing the curve, and possibly with some tweaking. // NOTE: we do not do any checks yet to repair the endpoints of the curveloop to make them closed. // NOTE: this is not expected to be perfect with dirty data, but is expected to not change already valid data. // curveLoopStartPoint and curveLoopEndPoint will change over time as we add new curves to the start or end of the CurveLoop. XYZ curveLoopStartPoint = curveSegments[0].GetEndPoint(0); XYZ curveLoopEndPoint = curveSegments[0].GetEndPoint(1); double vertexEps = IFCImportFile.TheFile.Document.Application.VertexTolerance; // This is intended to be "relatively large". The idea here is that the user would rather have the information presented // than thrown away because of a gap that is architecturally insignificant. double gapVertexEps = Math.Max(vertexEps, 0.01); // 1/100th of a foot, or 3.048 mm. // canRepairFirst may change over time, as we may potentially add curves to the start of the CurveLoop. bool canRepairFirst = (curveSegments[0] is Line); for (int ii = 1; ii < numSegments; ii++) { XYZ nextStartPoint = curveSegments[ii].GetEndPoint(0); XYZ nextEndPoint = curveSegments[ii].GetEndPoint(1); // These will be set below. bool attachNextSegmentToEnd = false; bool reverseNextSegment = false; double minGap = 0.0; // Scoped to prevent distLoopEndPtToNextStartPt and others from being used later on. { // Find the minimum gap between the current curve segment and the existing curve loop. If it is too large, we will give up. double distLoopEndPtToNextStartPt = curveLoopEndPoint.DistanceTo(nextStartPoint); double distLoopEndPtToNextEndPt = curveLoopEndPoint.DistanceTo(nextEndPoint); double distLoopStartPtToNextEndPt = curveLoopStartPoint.DistanceTo(nextEndPoint); double distLoopStartPtToNextStartPt = curveLoopStartPoint.DistanceTo(nextStartPoint); // Determine the minimum gap between the two curves. If it is too large, we'll give up before trying anything. double minStartGap = Math.Min(distLoopStartPtToNextEndPt, distLoopStartPtToNextStartPt); double minEndGap = Math.Min(distLoopEndPtToNextStartPt, distLoopEndPtToNextEndPt); minGap = Math.Min(minStartGap, minEndGap); // If the minimum distance between the two curves is greater than gapVertexEps (which is the larger of our two tolerances), // we can't fix the issue. if (minGap > gapVertexEps) { string lengthAsString = IFCUnitUtil.FormatLengthAsString(minGap); string maxGapAsString = IFCUnitUtil.FormatLengthAsString(gapVertexEps); throw new InvalidOperationException("IfcCompositeCurve contains a gap of " + lengthAsString + " that is greater than the maximum gap size of " + maxGapAsString + " and cannot be repaired."); } // We have a possibility to add the segment. What we do depends on the gap distance. // If the current curve loop's closest end to the next segment is its end (vs. start) point, set attachNextSegmentToEnd to true. attachNextSegmentToEnd = (MathUtil.IsAlmostEqual(distLoopEndPtToNextStartPt, minGap)) || (MathUtil.IsAlmostEqual(distLoopEndPtToNextEndPt, minGap)); // We need to reverse the next segment if: // 1. We are attaching the next segment to the end of the curve loop, and the next segment's closest end to the current curve loop is its end (vs. start) point. // 2. We are attaching the next segment to the start of the curve loop, and the next segment's closest end to the current curve loop is its start (vs. end) point. reverseNextSegment = (MathUtil.IsAlmostEqual(distLoopEndPtToNextEndPt, minGap)) || (MathUtil.IsAlmostEqual(distLoopStartPtToNextStartPt, minGap)); } if (reverseNextSegment) { curveSegments[ii] = curveSegments[ii].CreateReversed(); MathUtil.Swap <XYZ>(ref nextStartPoint, ref nextEndPoint); } // If minGap is less than vertexEps, we won't need to do any repairing - just fix the orientation if necessary. if (minGap < vertexEps) { if (attachNextSegmentToEnd) { // Update the curve loop end point to be the end point of the next segment after potentially being reversed. curveLoopEndPoint = nextEndPoint; } else { canRepairFirst = curveSegments[ii] is Line; curveLoopStartPoint = nextStartPoint; // Update the curve loop start point to be the start point of the next segment, now at the beginning of the loop, // after potentially being reversed. Curve tmpCurve = curveSegments[ii]; curveSegments.RemoveAt(ii); curveSegments.Insert(0, tmpCurve); } continue; } // The gap is too big for CurveLoop, but smaller than our maximum tolerance - we will try to fix the gap by extending // one of the line segments around the gap. If the gap is between two Arcs, we will try to introduce a short // segment between them, as long as the gap is larger than the short curve tolerance. bool canRepairNext = curveSegments[ii] is Line; bool createdRepairLine = false; if (attachNextSegmentToEnd) { // Update the curve loop end point to be the end point of the next segment after potentially being reversed. XYZ originalCurveLoopEndPoint = curveLoopEndPoint; curveLoopEndPoint = nextEndPoint; if (canRepairNext) { curveSegments[ii] = RepairLineAndReport(Id, originalCurveLoopEndPoint, curveLoopEndPoint, minGap); } else if (curveSegments[ii - 1] is Line) // = canRepairCurrent, only used here. { curveSegments[ii - 1] = RepairLineAndReport(Id, curveSegments[ii - 1].GetEndPoint(0), curveSegments[ii].GetEndPoint(0), minGap); } else { // Can't add a line to fix a gap that is smaller than the short curve tolerance. // This will result in mutliple curve loops. if (minGap < shortCurveTol + MathUtil.Eps()) { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that is too short to be repaired by a connecting segment.", false); } else { try { Line repairLine = Line.CreateBound(originalCurveLoopEndPoint, curveSegments[ii].GetEndPoint(0)); curveSegments.Insert(ii, repairLine); ii++; // Skip the repair line as we've already "added" it and the non-linear segment to our growing loop. numSegments++; createdRepairLine = true; } catch { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that can't be fixed.", false); } } } } else { XYZ originalCurveLoopStartPoint = curveLoopStartPoint; curveLoopStartPoint = nextStartPoint; if (canRepairNext) { curveSegments[ii] = RepairLineAndReport(Id, curveLoopStartPoint, originalCurveLoopStartPoint, minGap); } else if (canRepairFirst) { curveSegments[0] = RepairLineAndReport(Id, curveSegments[ii].GetEndPoint(1), curveSegments[0].GetEndPoint(1), minGap); } else { // Can't add a line to fix a gap that is smaller than the short curve tolerance. // In the future, we may fix this gap by intersecting the two curves and extending one of them. if (minGap < shortCurveTol + MathUtil.Eps()) { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that is too short to be repaired by a connecting segment.", true); } Line repairLine = Line.CreateBound(curveSegments[ii].GetEndPoint(1), originalCurveLoopStartPoint); curveSegments.Insert(0, repairLine); ii++; // Skip the repair line as we've already "added" it and the non-linear curve to our growing loop. numSegments++; } // Either canRepairFirst was already true, or canRepairNext was true and we added it to the front of the loop, // or we added a short repair line to the front of the loop. In any of these cases, the front curve segement of the // loop is now a line segment. if (!canRepairFirst && !canRepairNext && !createdRepairLine) { Importer.TheLog.LogError(Id, "IfcCompositeCurve contains a gap between two non-linear segments that can't be fixed.", true); } canRepairFirst = true; // Move the curve to the front of the loop. Curve tmpCurve = curveSegments[ii]; curveSegments.RemoveAt(ii); curveSegments.Insert(0, tmpCurve); } } SetCurveLoops(curveSegments); } catch (Exception ex) { Importer.TheLog.LogError(Id, ex.Message, true); } }
/// <summary> /// Create an IFCCurve object from a handle of type IfcCurve. /// </summary> /// <param name="ifcCurve">The IFC handle.</param> /// <returns>The IFCCurve object.</returns> public static IFCCurve ProcessIFCCurve(IFCAnyHandle ifcCurve) { if (IFCAnyHandleUtil.IsNullOrHasNoValue(ifcCurve)) { IFCImportFile.TheLog.LogNullError(IFCEntityType.IfcCurve); return null; } IFCEntity curve; if (!IFCImportFile.TheFile.EntityMap.TryGetValue(ifcCurve.StepId, out curve)) curve = new IFCCurve(ifcCurve); return (curve as IFCCurve); }
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(); } } }