/// <summary> /// Processes IfcProject attributes. /// </summary> /// <param name="ifcProjectHandle">The IfcProject handle.</param> protected override void Process(IFCAnyHandle ifcProjectHandle) { IFCAnyHandle unitsInContext = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcProjectHandle, "UnitsInContext", false); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(unitsInContext)) { IList <IFCAnyHandle> units = IFCAnyHandleUtil.GetAggregateInstanceAttribute <List <IFCAnyHandle> >(unitsInContext, "Units"); if (units != null) { m_UnitsInContext = new HashSet <IFCUnit>(); foreach (IFCAnyHandle unit in units) { IFCUnit ifcUnit = IFCImportFile.TheFile.IFCUnits.ProcessIFCProjectUnit(unit); if (!IFCUnit.IsNullOrInvalid(ifcUnit)) { m_UnitsInContext.Add(ifcUnit); } } } else { Importer.TheLog.LogMissingRequiredAttributeError(unitsInContext, "Units", false); } } // We need to process the units before we process the rest of the file, since we will scale values as we go along. base.Process(ifcProjectHandle); // process true north - take the first valid representation context that has a true north value. HashSet <IFCAnyHandle> repContexts = IFCAnyHandleUtil.GetAggregateInstanceAttribute <HashSet <IFCAnyHandle> >(ifcProjectHandle, "RepresentationContexts"); if (repContexts != null) { foreach (IFCAnyHandle geomRepContextHandle in repContexts) { if (!IFCAnyHandleUtil.IsNullOrHasNoValue(geomRepContextHandle) && IFCAnyHandleUtil.IsSubTypeOf(geomRepContextHandle, IFCEntityType.IfcGeometricRepresentationContext)) { IFCAnyHandle trueNorthHandle = IFCAnyHandleUtil.GetInstanceAttribute(geomRepContextHandle, "TrueNorth"); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(trueNorthHandle)) { List <double> trueNorthDir = IFCAnyHandleUtil.GetAggregateDoubleAttribute <List <double> >(trueNorthHandle, "DirectionRatios"); if (trueNorthDir != null && trueNorthDir.Count >= 2) { m_TrueNorthDirection = trueNorthDir; break; } } } } } // Special read of IfcPresentationLayerAssignment if the INVERSE flag isn't properly set in the EXPRESS file. if (IFCImportFile.TheFile.SchemaVersion >= IFCSchemaVersion.IFC2x2) { IFCPresentationLayerAssignment.ProcessAllLayerAssignments(); } }
/// <summary> /// Processes IfcProject attributes. /// </summary> /// <param name="ifcProjectHandle">The IfcProject handle.</param> protected override void Process(IFCAnyHandle ifcProjectHandle) { IFCAnyHandle unitsInContext = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcProjectHandle, "UnitsInContext", false); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(unitsInContext)) { IList <IFCAnyHandle> units = IFCAnyHandleUtil.GetAggregateInstanceAttribute <List <IFCAnyHandle> >(unitsInContext, "Units"); if (units != null) { m_UnitsInContext = new HashSet <IFCUnit>(); foreach (IFCAnyHandle unit in units) { IFCUnit ifcUnit = IFCImportFile.TheFile.IFCUnits.ProcessIFCProjectUnit(unit); if (!IFCUnit.IsNullOrInvalid(ifcUnit)) { m_UnitsInContext.Add(ifcUnit); } } } else { Importer.TheLog.LogMissingRequiredAttributeError(unitsInContext, "Units", false); } } // We need to process the units before we process the rest of the file, since we will scale values as we go along. base.Process(ifcProjectHandle); // process true north - take the first valid representation context that has a true north value. HashSet <IFCAnyHandle> repContexts = IFCAnyHandleUtil.GetAggregateInstanceAttribute <HashSet <IFCAnyHandle> >(ifcProjectHandle, "RepresentationContexts"); if (repContexts != null) { foreach (IFCAnyHandle geomRepContextHandle in repContexts) { if (!IFCAnyHandleUtil.IsNullOrHasNoValue(geomRepContextHandle) && IFCAnyHandleUtil.IsSubTypeOf(geomRepContextHandle, IFCEntityType.IfcGeometricRepresentationContext)) { IFCRepresentationContext context = IFCRepresentationContext.ProcessIFCRepresentationContext(geomRepContextHandle); if (TrueNorthDirection == null && context.TrueNorth != null) { // TODO: Verify that we don't have inconsistent true norths. If we do, warn. TrueNorthDirection = new UV(context.TrueNorth.X, context.TrueNorth.Y); } if (WorldCoordinateSystem == null && context.WorldCoordinateSystem != null && !context.WorldCoordinateSystem.IsIdentity) { WorldCoordinateSystem = context.WorldCoordinateSystem; } } } } }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { Units documentUnits = new Units(doc.DisplayUnitSystem == DisplayUnit.METRIC ? UnitSystem.Metric : UnitSystem.Imperial); foreach (IFCUnit unit in UnitsInContext) { if (!IFCUnit.IsNullOrInvalid(unit)) { try { FormatOptions formatOptions = new FormatOptions(unit.Unit); formatOptions.SetSymbolTypeId(unit.Symbol); documentUnits.SetFormatOptions(unit.Spec, formatOptions); } catch (Exception ex) { Importer.TheLog.LogError(unit.Id, ex.Message, false); } } } doc.SetUnits(documentUnits); // We will randomize unused grid names so that they don't conflict with new entries with the same name. // This is only for relink. foreach (ElementId gridId in Importer.TheCache.GridNameToElementMap.Values) { Grid grid = doc.GetElement(gridId) as Grid; if (grid == null) { continue; } // Note that new Guid() is useless - it creates a GUID of all 0s. grid.Name = Guid.NewGuid().ToString(); } base.Create(doc); // IfcProject usually won't create an element, as it contains no geometry. // If it doesn't, use the ProjectInfo element in the document to store its parameters. if (CreatedElementId == ElementId.InvalidElementId) { CreatedElementId = Importer.TheCache.ProjectInformationId; } }
/// <summary> /// Creates or populates Revit elements based on the information contained in this class. /// </summary> /// <param name="doc">The document.</param> protected override void Create(Document doc) { Units documentUnits = new Units(doc.DisplayUnitSystem == DisplayUnit.METRIC ? UnitSystem.Metric : UnitSystem.Imperial); foreach (IFCUnit unit in UnitsInContext) { if (!IFCUnit.IsNullOrInvalid(unit)) { try { FormatOptions formatOptions = new FormatOptions(unit.UnitName); formatOptions.UnitSymbol = unit.UnitSymbol; documentUnits.SetFormatOptions(unit.UnitType, formatOptions); } catch (Exception ex) { IFCImportFile.TheLog.LogError(unit.Id, ex.Message, false); } } } doc.SetUnits(documentUnits); // We will randomize unused grid names so that they don't conflict with new entries with the same name. // This is only for relink. foreach (ElementId gridId in Importer.TheCache.GridNameToElementMap.Values) { Grid grid = doc.GetElement(gridId) as Grid; if (grid == null) { continue; } grid.Name = new Guid().ToString(); } base.Create(doc); }
/// <summary> /// Processes IfcProject attributes. /// </summary> /// <param name="ifcProjectHandle">The IfcProject handle.</param> protected override void Process(IFCAnyHandle ifcProjectHandle) { IFCAnyHandle unitsInContext = IFCImportHandleUtil.GetRequiredInstanceAttribute(ifcProjectHandle, "UnitsInContext", false); if (!IFCAnyHandleUtil.IsNullOrHasNoValue(unitsInContext)) { IList <IFCAnyHandle> units = IFCAnyHandleUtil.GetAggregateInstanceAttribute <List <IFCAnyHandle> >(unitsInContext, "Units"); if (units != null) { m_UnitsInContext = new HashSet <IFCUnit>(); foreach (IFCAnyHandle unit in units) { IFCUnit ifcUnit = IFCImportFile.TheFile.IFCUnits.ProcessIFCProjectUnit(unit); if (!IFCUnit.IsNullOrInvalid(ifcUnit)) { m_UnitsInContext.Add(ifcUnit); } } } else { Importer.TheLog.LogMissingRequiredAttributeError(unitsInContext, "Units", false); } } var application = IFCImportFile.TheFile.Document.Application; var projectUnits = IFCImportFile.TheFile.IFCUnits.GetIFCProjectUnit(SpecTypeId.Length); IFCImportFile.TheFile.VertexTolerance = application.VertexTolerance; IFCImportFile.TheFile.ShortCurveTolerance = application.ShortCurveTolerance; Importer.TheProcessor.PostProcessProject(projectUnits?.ScaleFactor, projectUnits?.Unit); // We need to process the units before we process the rest of the file, since we will scale values as we go along. base.Process(ifcProjectHandle); // process true north - take the first valid representation context that has a true north value. HashSet <IFCAnyHandle> repContexts = IFCAnyHandleUtil.GetAggregateInstanceAttribute <HashSet <IFCAnyHandle> >(ifcProjectHandle, "RepresentationContexts"); bool hasMapConv = false; XYZ geoRef = XYZ.Zero; string geoRefName = null; double trueNorth = 0.0; if (repContexts != null) { foreach (IFCAnyHandle geomRepContextHandle in repContexts) { if (!IFCAnyHandleUtil.IsNullOrHasNoValue(geomRepContextHandle) && IFCAnyHandleUtil.IsSubTypeOf(geomRepContextHandle, IFCEntityType.IfcGeometricRepresentationContext)) { IFCRepresentationContext context = IFCRepresentationContext.ProcessIFCRepresentationContext(geomRepContextHandle); if (TrueNorthDirection == null && context.TrueNorth != null) { // TODO: Verify that we don't have inconsistent true norths. If we do, warn. TrueNorthDirection = new UV(context.TrueNorth.X, context.TrueNorth.Y); } if (WorldCoordinateSystem == null && context.WorldCoordinateSystem != null && !context.WorldCoordinateSystem.IsIdentity) { WorldCoordinateSystem = context.WorldCoordinateSystem; } // Process Map Conversion if any HashSet <IFCAnyHandle> coordOperation = IFCAnyHandleUtil.GetAggregateInstanceAttribute <HashSet <IFCAnyHandle> >(geomRepContextHandle, "HasCoordinateOperation"); if (coordOperation != null) { if (coordOperation.Count > 0) { if (IFCAnyHandleUtil.IsSubTypeOf(coordOperation.FirstOrDefault(), IFCEntityType.IfcMapConversion)) { hasMapConv = true; IFCAnyHandle mapConv = coordOperation.FirstOrDefault(); bool found = false; double eastings = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(mapConv, "Eastings", out found); if (!found) { eastings = 0.0; } double northings = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(mapConv, "Northings", out found); if (!found) { northings = 0.0; } double orthogonalHeight = IFCImportHandleUtil.GetRequiredScaledLengthAttribute(mapConv, "OrthogonalHeight", out found); if (!found) { orthogonalHeight = 0.0; } double xAxisAbs = IFCImportHandleUtil.GetOptionalRealAttribute(mapConv, "XAxisAbscissa", 1.0); double xAxisOrd = IFCImportHandleUtil.GetOptionalRealAttribute(mapConv, "XAxisOrdinate", 0.0); trueNorth = Math.Atan2(xAxisOrd, xAxisAbs); //angleToNorth = -((xAxisAngle > -Math.PI / 2.0) ? xAxisAngle - Math.PI / 2.0 : xAxisAngle + Math.PI * 1.5); double scale = IFCImportHandleUtil.GetOptionalRealAttribute(mapConv, "Scale", 1.0); geoRef = new XYZ(scale * eastings, scale * northings, scale * orthogonalHeight); // Process the IfcProjectedCRS IFCAnyHandle projCRS = IFCAnyHandleUtil.GetInstanceAttribute(mapConv, "TargetCRS"); if (projCRS != null && IFCAnyHandleUtil.IsSubTypeOf(projCRS, IFCEntityType.IfcProjectedCRS)) { geoRefName = IFCImportHandleUtil.GetRequiredStringAttribute(projCRS, "Name", false); string desc = IFCImportHandleUtil.GetOptionalStringAttribute(projCRS, "Description", null); string geodeticDatum = IFCImportHandleUtil.GetOptionalStringAttribute(projCRS, "GeodeticDatum", null); string verticalDatum = IFCImportHandleUtil.GetOptionalStringAttribute(projCRS, "VerticalDatum", null); string mapProj = IFCImportHandleUtil.GetOptionalStringAttribute(projCRS, "MapProjection", null); string mapZone = IFCImportHandleUtil.GetOptionalStringAttribute(projCRS, "MapZone", null); IFCAnyHandle mapUnit = IFCImportHandleUtil.GetOptionalInstanceAttribute(projCRS, "MapUnit"); Document doc = IFCImportFile.TheFile.Document; ProjectInfo projectInfo = doc.ProjectInformation; // We add this here because we want to make sure that external processors (e.g., Navisworks) // get a chance to add a container for the parameters that get added below. In general, // we should probably augment Processor.AddParameter to ensure that CreateOrUpdateElement // is called before anything is attempted to be added. This is a special case, though, // as in Revit we don't actually create an element for the IfcProject. Importer.TheProcessor.CreateOrUpdateElement(Id, GlobalId, EntityType.ToString(), CategoryId.IntegerValue, null); Category category = IFCPropertySet.GetCategoryForParameterIfValid(projectInfo, Id); IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.Name", geoRefName, Id); if (!string.IsNullOrEmpty(desc)) { IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.Description", desc, Id); } if (!string.IsNullOrEmpty(geodeticDatum)) { IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.GeodeticDatum", geodeticDatum, Id); } if (!string.IsNullOrEmpty(verticalDatum)) { IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.VerticalDatum", verticalDatum, Id); } if (!string.IsNullOrEmpty(mapProj)) { IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.MapProjection", mapProj, Id); } if (!string.IsNullOrEmpty(mapZone)) { IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.MapZone", mapZone, Id); } if (!IFCAnyHandleUtil.IsNullOrHasNoValue(mapUnit)) { IFCUnit mapUnitIfc = IFCUnit.ProcessIFCUnit(mapUnit); string unitStr = UnitUtils.GetTypeCatalogStringForUnit(mapUnitIfc.Unit); IFCPropertySet.AddParameterString(doc, projectInfo, category, this, "IfcProjectedCRS.MapUnit", unitStr, Id); double convFactor = UnitUtils.Convert(1.0, mapUnitIfc.Unit, IFCImportFile.TheFile.IFCUnits.GetIFCProjectUnit(SpecTypeId.Length).Unit); eastings = convFactor * eastings; northings = convFactor * northings; orthogonalHeight = convFactor * orthogonalHeight; geoRef = new XYZ(eastings, northings, orthogonalHeight); } } } } } } } ProjectLocation projectLocation = IFCImportFile.TheFile.Document.ActiveProjectLocation; ProjectPosition projectPosition; if (projectLocation != null) { if (hasMapConv) { projectPosition = new ProjectPosition(geoRef.X, geoRef.Y, geoRef.Z, trueNorth); projectLocation.SetProjectPosition(XYZ.Zero, projectPosition); if (!string.IsNullOrEmpty(geoRefName)) { IFCImportFile.TheFile.Document.SiteLocation.SetGeoCoordinateSystem(geoRefName); } } else { // Set initial project location based on the information above. // This may be further modified by the site. trueNorth = 0.0; if (TrueNorthDirection != null) { trueNorth = -Math.Atan2(-TrueNorthDirection.U, TrueNorthDirection.V); } // TODO: Extend this to work properly if the world coordinate system // isn't a simple translation. XYZ origin = XYZ.Zero; if (WorldCoordinateSystem != null) { geoRef = WorldCoordinateSystem.Origin; double angleRot = Math.Atan2(WorldCoordinateSystem.BasisX.Y, WorldCoordinateSystem.BasisX.X); // If it is translation only, or if the WCS rotation is equal to trueNorth, we assume they are the same if (WorldCoordinateSystem.IsTranslation || MathUtil.IsAlmostEqual(angleRot, trueNorth)) { WorldCoordinateSystem = null; } else { // If the trueNorth is not set (=0), set the trueNorth by the rotation of the WCS, otherwise add the angle if (MathUtil.IsAlmostZero(trueNorth)) { trueNorth = angleRot; } else { trueNorth += angleRot; } WorldCoordinateSystem = null; } } projectPosition = new ProjectPosition(geoRef.X, geoRef.Y, geoRef.Z, trueNorth); projectLocation.SetProjectPosition(XYZ.Zero, projectPosition); } } } }