Ejemplo n.º 1
0
        // Append vertices and return shift
        private void AppendVertices(Representation r, IfcSceneExportSummary summary, IEnumerable <XbimPoint3D> points)
        {
            PtArray ptArray = new PtArray();

            foreach (var p in points)
            {
                // Append to vertices and apply scale
                p.AppendTo(ptArray.Xyz, summary.Scale);
            }

            r.Points.Add(ptArray);
        }
Ejemplo n.º 2
0
        // Creates a transform
        private Dto.Scene.Transform CreateTransform(IfcSceneExportSummary s, XbimShapeInstance shape)
        {
            // Context transformation (relative offset shift => make final transform relative to context shift)
            var contextWcs = s.TransformOf(shape.RepresentationContext) ?? XbimMatrix3D.Identity;

            switch (s.AppliedSettings.Transforming)
            {
            case SceneTransformationStrategy.Matrix:
                return((shape.Transformation * contextWcs).ToRotation(s.Scale));

            case SceneTransformationStrategy.Quaternion:
                return((shape.Transformation * contextWcs).ToQuaternion(s.Scale));

            default:
                throw new NotImplementedException($"Missing implementation for '{s.AppliedSettings.Transforming}'");
            }
        }
Ejemplo n.º 3
0
        // Creates a new representation context
        private Representation GetOrCreateRepresentation(IfcSceneExportSummary s, XbimShapeInstance shape, TesselationPackage pkg)
        {
            var(context, contextWcs) = s.RepresentationContext(shape.RepresentationContext);
            var representation = pkg.Representations.FirstOrDefault(r => r.Context.Equals(context.Name));
            // left expansion & concatenation in xbim !
            var aabb = shape.BoundingBox.ToABox(s.Scale, p => (shape.Transformation * contextWcs).Transform(p));

            if (null == representation)
            {   // Create new representation
                representation = new Representation
                {
                    Context     = context.Name,
                    BoundingBox = new BoundingBox {
                        ABox = aabb
                    }
                };
                pkg.Representations.Add(representation);
            }
            else
            {   // Union bounding boxes
                representation.BoundingBox.ABox = representation.BoundingBox.ABox.UnionWith(aabb);
            }
            return(representation);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Runs tessselation with Xbim scene context
        /// </summary>
        /// <param name="model">The model to be exported</param>
        /// <param name="summary">The scene export summary</param>
        /// <param name="monitor">The progress emitter instance</param>
        /// <returns>An enumerable of tesselated product representations</returns>
        public IEnumerable <IfcProductSceneRepresentation> Tesselate(IModel model, IfcSceneExportSummary summary, CancelableProgressing monitor)
        {
            ReadGeometryStore(model, monitor);

            short[] excludeTypeId = ExcludeExpressType.Select(t => model.Metadata.ExpressTypeId(t.ExpressName)).ToArray();
            Array.Sort(excludeTypeId);

            // Start reading the geometry store built before
            using (var gReader = model.GeometryStore.BeginRead())
            {
                int totalCount   = gReader.ShapeGeometries.Count();
                int currentCount = 0;
                // Product label vs. Component and candidate shape labels
                var packageCache = new SortedDictionary <int, TesselationPackage>();
                // Compute contexts
                ComputeContextTransforms(gReader, summary, ContextsCreateFromSettings(gReader, summary));

                monitor?.NotifyProgressEstimateUpdate(totalCount);

                foreach (var geometry in gReader.ShapeGeometries)
                {
                    if (monitor?.State.IsAboutCancelling ?? false)
                    {
                        monitor.State.MarkCanceled();
                        break;
                    }

                    currentCount++;

                    monitor?.State.UpdateDone(currentCount, "Running tesselation...");
                    monitor?.NotifyOnProgressChange();

                    if (geometry.ShapeData.Length <= 0)
                    {
                        // No geometry
                        continue;
                    }

                    var shapes = gReader.ShapeInstancesOfGeometry(geometry.ShapeLabel)
                                 .Where(i => 0 > Array.BinarySearch(excludeTypeId, i.IfcTypeId) &&
                                        i.RepresentationType == XbimGeometryRepresentationType.OpeningsAndAdditionsIncluded);

                    if (!shapes.Any())
                    {
                        // No shape instances
                        continue;
                    }

                    using (var ms = new MemoryStream(((IXbimShapeGeometryData)geometry).ShapeData))
                    {
                        using (var br = new BinaryReader(ms))
                        {
                            XbimShapeTriangulation tr = br.ReadShapeTriangulation();
                            foreach (XbimShapeInstance shape in shapes)
                            {
                                if (monitor?.State.IsAboutCancelling ?? false)
                                {
                                    monitor.State.MarkCanceled();
                                    break;
                                }

                                var product = model.Instances[shape.IfcProductLabel] as IIfcProduct;

                                // Try first to find the referenced component
                                TesselationPackage pkg;
                                if (!packageCache.TryGetValue(shape.IfcProductLabel, out pkg))
                                {
                                    // New component ToDo shape tuple built from component and todo ShapeGeometryLabel
                                    pkg = new TesselationPackage(gReader.ShapeInstancesOfEntity(product));
                                    packageCache[shape.IfcProductLabel] = pkg;
                                }

                                var ctx = summary.ContextOf(shape.RepresentationContext);
                                if (null == ctx)
                                {
                                    Logger?.LogWarning($"Shape of representation #{shape.RepresentationContext} of product #{product.EntityLabel} out of context scope. Skipped.");
                                    continue;
                                }

                                // Check for representation
                                var representation = GetOrCreateRepresentation(summary, shape, pkg);

                                if (!pkg.IsShapeGeometryDone(geometry))
                                {
                                    AppendVertices(representation, summary, tr.Vertices);
                                }

                                // TODO Use "bias" definition to adjust biased local offsets
                                var body = new FaceBody
                                {
                                    Material = new RefId {
                                        Nid = shape.StyleLabel > 0 ? shape.StyleLabel : shape.IfcTypeId * -1
                                    },
                                    Transform = CreateTransform(summary, shape),
                                    PtSet     = (uint)representation.Points.Count - 1,
                                };

                                foreach (var face in tr.Faces)
                                {
                                    if (face.Indices.Count % 3 != 0)
                                    {
                                        throw new NotSupportedException("Expecting triangular meshes only");
                                    }

                                    // Translate Xbim face definition
                                    var bodyFace = new Face
                                    {
                                        IsPlanar = face.IsPlanar,
                                        Mesh     = new Mesh
                                        {
                                            Type   = FacetType.TriMesh,
                                            Orient = Orientation.Ccw
                                        }
                                    };

                                    switch (face.NormalCount)
                                    {
                                    case 0:
                                        // No normals at all
                                        break;

                                    case 1:
                                        // Single normal
                                        bodyFace.IsPlanar = true;
                                        face.Normals[0].Normal.AppendTo(bodyFace.Mesh.Normal);
                                        break;

                                    default:
                                        // No planar face
                                        if (face.NormalCount != face.Indices.Count)
                                        {
                                            throw new NotSupportedException($"Incorrect count of normals per face mesh (expecting {face.Indices.Count}, have {face.NormalCount}");
                                        }

                                        foreach (var n in face.Normals.Select(n => n.Normal))
                                        {
                                            n.AppendTo(bodyFace.Mesh.Normal);
                                        }

                                        break;
                                    }

                                    bodyFace.Mesh.Vertex.AddRange(face.Indices.Select(i => (uint)i));
                                    body.Faces.Add(bodyFace);
                                }

                                // Add body to known component
                                representation.Bodies.Add(body);
                                // Remove geometry label from todo list
                                pkg.RemoveDone(shape);

                                // If no shape instances left
                                if (pkg.IsDone)
                                {
                                    yield return(pkg.ToSceneRepresentation(shape.IfcProductLabel));

                                    packageCache.Remove(shape.IfcProductLabel);
                                }
                            }
                        }
                    }
                }

                // Return most recent
                if (packageCache.Count > 0)
                {
                    Logger?.LogWarning($"Detected {packageCache.Count} unfinished geometry entries. Missing shapes.");
                    foreach (var e in packageCache)
                    {
                        // Announce missing components even if unfinished due to some reason
                        Logger?.LogWarning($"IfcProduct #{e.Key} misses {e.Value.CountOpenInstances} shape(s).");
                        yield return(e.Value.ToSceneRepresentation(e.Key));
                    }
                }
            }

            monitor?.NotifyOnProgressChange("Done tesselation.");
        }
Ejemplo n.º 5
0
        // Compute contexts and related transformation
        private void ComputeContextTransforms(IGeometryStoreReader gReader, IfcSceneExportSummary s, IDictionary <int, SceneContext> contextTable)
        {
            foreach (var cr in gReader.ContextRegions)
            {
                SceneContext sc;
                if (contextTable.TryGetValue(cr.ContextLabel, out sc))
                {
                    XbimVector3D offset = XbimVector3D.Zero;
                    XbimVector3D mean   = XbimVector3D.Zero;
                    foreach (var r in cr)
                    {
                        mean += r.Centre.ToVector();
                        sc.Regions.Add(r.ToRegion(s.Scale));
                    }
                    mean *= 1.0 / cr.Count;

                    switch (s.AppliedSettings.Positioning)
                    {
                    case ScenePositioningStrategy.UserCorrection:
                        // Center at user's center
                        offset = s.AppliedSettings.UserModelCenter.ToXbimVector3DMeter(s.Model.ModelFactors);
                        break;

                    case ScenePositioningStrategy.MostPopulatedRegionCorrection:
                        // Center at most populated
                        offset = cr.MostPopulated().Centre.ToVector();
                        break;

                    case ScenePositioningStrategy.MostExtendedRegionCorrection:
                        // Center at largest
                        offset = cr.Largest().Centre.ToVector();
                        break;

                    case ScenePositioningStrategy.MeanTranslationCorrection:
                        // Use mean correction
                        offset = mean;
                        break;

                    case ScenePositioningStrategy.SignificantPopulationCorrection:
                        var        population = cr.Sum(r => r.Population);
                        XbimRegion rs         = null;
                        double     max        = double.NegativeInfinity;
                        foreach (var r in cr)
                        {
                            // Compute weighted extent by relative population
                            double factor = r.Size.Length * r.Population / population;
                            if (max < factor)
                            {
                                rs  = r;
                                max = factor;
                            }
                        }
                        offset = rs.Centre.ToVector();
                        break;

                    case ScenePositioningStrategy.NoCorrection:
                        // No correction
                        Logger?.LogInformation($"No translation correction applied by settings to context '{cr.ContextLabel}'");
                        break;

                    default:
                        throw new NotImplementedException($"Missing implementation for '{s.AppliedSettings.Positioning}'");
                    }

                    if (s.AppliedSettings.Transforming == SceneTransformationStrategy.Matrix)
                    {
                        // If Matrix or Global use rotation matrix representation
                        sc.Wcs = new XbimMatrix3D(offset).ToRotation(s.Scale);
                    }
                    else
                    {
                        // Otherwise use Quaternion representation
                        sc.Wcs = new XbimMatrix3D(offset).ToQuaternion(s.Scale);
                    }

                    // Set correction to negative offset shift (without scale since in model space units)
                    s.SetRepresentationContext(cr.ContextLabel, sc, new XbimMatrix3D(offset * -1));
                }
                else
                {
                    Logger?.LogWarning("Excluding context label '{0}'. Not mentioned by settings.", cr.ContextLabel);
                }
            }
        }
Ejemplo n.º 6
0
 private IDictionary <int, SceneContext> ContextsCreateFromSettings(IGeometryStoreReader gReader, IfcSceneExportSummary s)
 {
     // Retrieve all context with geometry and match those to pregiven in settings
     return(gReader.ContextIds
            .Select(label => s.Model.Instances[label])
            .OfType <IIfcRepresentationContext>()
            .Select(c => (c.EntityLabel, s.AppliedSettings.UserRepresentationContext.FirstOrDefault(sc => StringComparer.OrdinalIgnoreCase.Equals(sc.Name, c.ContextIdentifier))))
            .Where(t => t.Item2 != null)
            .ToDictionary(t => t.EntityLabel, t => t.Item2));
 }
Ejemplo n.º 7
0
        // Runs the scene model export
        private IfcSceneExportSummary DoSceneModelTransfer(IModel model, IfcSceneExportSettings settings, CancelableProgressing progressing)
        {
            // Generate new summary
            var summary = new IfcSceneExportSummary(model, settings);

            // Transfer materials
            var materials = StylesToMaterial(model).ToDictionary(m => m.Id.Nid);

            summary.Scene.Materials.AddRange(materials.Values);

            Logger?.LogInformation("Starting model tesselation of {0}", model.Header.Name);
            // Retrieve enumeration of components having a geomety within given contexts
            var sceneRepresentations = TesselatorInstance.Tesselate(model, summary, progressing);

            Logger?.LogInformation("Starting model export of {0}", model.Header.Name);
            // Run transfer and log parents
            var parents = new HashSet <int>();

            foreach (var sr in sceneRepresentations)
            {
                var p = model.Instances[sr.EntityLabel] as IIfcProduct;
                if (progressing?.State.IsAboutCancelling ?? false)
                {
                    Logger?.LogInformation("Canceled model export of '{0}'", model.Header.FileName);
                    progressing.State.MarkCanceled();
                    break;
                }

                Component c;
                if (!summary.ComponentCache.TryGetValue(p.EntityLabel, out c))
                {
                    int?optParent;
                    c = CreateComponent(p, Enumerable.Empty <Classifier>(), out optParent);
                    summary.ComponentCache.Add(p.EntityLabel, c);
                    summary.Scene.Components.Add(c);

                    if (optParent.HasValue)
                    {
                        parents.Add(optParent.Value);
                    }
                }

                c.Representations.AddRange(sr.Representations);
            }

            // Check for remaining components (i.e. missing parents without geometry)
            parents.RemoveWhere(id => summary.ComponentCache.ContainsKey(id));
            Queue <int> missingInstance = new Queue <int>(parents);

            while (missingInstance.Count > 0)
            {
                if (progressing?.State.IsAboutCancelling ?? false)
                {
                    if (!progressing.State.IsCanceled)
                    {
                        Logger?.LogInformation("Canceled model export of '{0}'", model.Header.FileName);
                        progressing.State.MarkCanceled();
                    }
                    break;
                }

                if (model.Instances[missingInstance.Dequeue()] is IIfcProduct product)
                {
                    Component c;
                    if (!summary.ComponentCache.TryGetValue(product.EntityLabel, out c))
                    {
                        int?optParent;
                        c = CreateComponent(product, Enumerable.Empty <Classifier>(), out optParent);
                        summary.ComponentCache.Add(product.EntityLabel, c);

                        if (optParent.HasValue && !summary.ComponentCache.ContainsKey(optParent.Value))
                        {
                            // Enqueue missing parents
                            missingInstance.Enqueue(optParent.Value);
                        }

                        summary.Scene.Components.Add(c);
                    }
                }
            }

            // Add default materials where required
            summary.Scene.Materials.AddRange(
                DefaultMaterials(
                    model,
                    summary.Scene.Components
                    .SelectMany(c => c.Representations)
                    .SelectMany(r => r.Bodies)
                    .Select(b => b.Material)
                    .Where(m => 0 > m.Nid)
                    .Distinct()
                    )
                );

            return(summary);
        }