Esempio n. 1
0
 /// <summary>
 /// A new indexed star lookup wrapping a single body definition.
 /// </summary>
 /// <param name="body">The body to index</param>
 /// <param name="offset">An optional offset in vertex array</param>
 public FacetStars(FaceBody body, PtOffsetArray ptOffsetArray)
 {
     _index        = new Dictionary <uint, List <Facet> >();
     Body          = body;
     PtOffsetArray = ptOffsetArray;
     Ingest(body);
 }
Esempio n. 2
0
        private void TestRunWith(PtArray ptArray, FaceBody body, FacetStarVisitor.InvestigationStrategy strategy)
        {
            var facetStar = new FacetStars(body, new PtOffsetArray(ptArray, SHIFT));

            Assert.AreEqual(8, facetStar.Vertices.Count(), "8 vertices");
            Assert.AreEqual(8, facetStar.Count, "8 stars");
            // Use no visitor's index cache
            var visitor = new FacetStarVisitor(facetStar, (i) => false, strategy);
            var faces   = new List <MeshPtOffsetArray>();
            var facets  = new HashSet <Facet>();

            foreach (Facet f in visitor)
            {
                switch (visitor.Strategy)
                {
                case FacetStarVisitor.InvestigationStrategy.SameFaceFirst:
                    if (!f.Meshed.Equals(faces.LastOrDefault()))
                    {
                        foreach (var known in faces.Take(faces.Count - 1))
                        {
                            Assert.AreNotEqual(known, f.Meshed, "Face shouldn't be processed before");
                        }

                        faces.Add(f.Meshed);
                        Assert.IsTrue(visitor.IsNewFace);
                    }
                    else
                    {
                        Assert.IsFalse(visitor.IsNewFace);
                    }
                    break;
                }

                facets.Add(f);
                Assert.AreEqual(SHIFT, f.Shift);
                Assert.IsTrue(f.IsTriangle(), "Is Triangle");
                Assert.IsTrue(f.IsValid(), "Is Valid");
            }

            Assert.IsFalse(visitor.HasNextCandidate, "All facets have been processed");
            Assert.AreEqual(12, facets.Count, "12 facets");
        }
Esempio n. 3
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.");
        }