public void Add(byte[] mesh, short productTypeId, int productLabel, int geometryLabel, XbimMatrix3D? transform = null, short modelId = 0, 
     ITextureMapping textureMappingMethod = null)
 {
     var frag = new XbimMeshFragment(PositionCount, TriangleIndexCount, productTypeId, productLabel, geometryLabel, modelId);
     Read(mesh, transform);
     if (textureMappingMethod != null)
     {
         AddTextureMapping(textureMappingMethod.GetTextureMap(this._unfrozenPositions, this._unfrozenNormals, this._unfrozenTriangleIndices));
     }
     frag.EndPosition = PositionCount - 1;
     frag.EndTriangleIndex = TriangleIndexCount - 1;
     _meshes.Add(frag);
 }
Exemple #2
0
        /// <summary>
        /// This version uses the new Geometry representation
        /// </summary>
        /// <param name="model"></param>
        /// <param name="modelTransform">The transform to place the models geometry in the right place</param>
        /// <param name="opaqueShapes"></param>
        /// <param name="transparentShapes"></param>
        /// <param name="isolateInstances">List of instances to be isolated</param>
        /// <param name="hideInstances">List of instances to be hidden</param>
        /// <param name="excludeTypes">List of type to exclude, by default excplict openings and spaces are excluded if exclude = null</param>
        /// <param name="selectContexts">Contexts for displaying</param>
        /// <returns></returns>
        public XbimScene <WpfMeshGeometry3D, WpfMaterial> BuildScene(IModel model, XbimMatrix3D modelTransform,
                                                                     ModelVisual3D opaqueShapes, ModelVisual3D transparentShapes, List <IPersistEntity> isolateInstances = null,
                                                                     List <IPersistEntity> hideInstances = null, List <IIfcGeometricRepresentationContext> selectContexts = null,
                                                                     List <Type> excludeTypes            = null)
        {
            var excludedTypes    = model.DefaultExclusions(excludeTypes);
            var onlyInstances    = isolateInstances?.Where(i => i.Model == model).ToDictionary(i => i.EntityLabel);
            var hiddenInstances  = hideInstances?.Where(i => i.Model == model).ToDictionary(i => i.EntityLabel);
            var selectedContexts = selectContexts?.Where(i => i.Model == model).ToDictionary(i => i.EntityLabel);

            var scene = new XbimScene <WpfMeshGeometry3D, WpfMaterial>(model);
            var timer = new Stopwatch();

            timer.Start();
            using (var geomStore = model.GeometryStore)
            {
                using (var geomReader = geomStore.BeginRead())
                {
                    var materialsByStyleId      = new Dictionary <int, WpfMaterial>();
                    var repeatedShapeGeometries = new Dictionary <int, MeshGeometry3D>();
                    var meshesByStyleId         = new Dictionary <int, WpfMeshGeometry3D>();
                    var tmpOpaquesGroup         = new Model3DGroup();
                    var tmpTransparentsGroup    = new Model3DGroup();

                    //get a list of all the unique style ids then build their style and mesh
                    var sstyleIds = geomReader.StyleIds;
                    foreach (var styleId in sstyleIds)
                    {
                        var wpfMaterial = GetWpfMaterial(model, styleId);
                        materialsByStyleId.Add(styleId, wpfMaterial);

                        var mg = GetNewStyleMesh(wpfMaterial, tmpTransparentsGroup, tmpOpaquesGroup);
                        meshesByStyleId.Add(styleId, mg);
                    }

                    var shapeInstances = GetShapeInstancesToRender(geomReader, excludedTypes);
                    var tot            = 1;
                    if (ProgressChanged != null)
                    {
                        // only enumerate if there's a need for progress update
                        tot = shapeInstances.Count();
                    }
                    var prog         = 0;
                    var lastProgress = 0;

                    // !typeof (IfcFeatureElement).IsAssignableFrom(IfcMetaData.GetType(s.IfcTypeId)) /*&&
                    // !typeof(IfcSpace).IsAssignableFrom(IfcMetaData.GetType(s.IfcTypeId))*/);
                    foreach (var shapeInstance in shapeInstances
                             .Where(s => null == onlyInstances || onlyInstances.Count == 0 || onlyInstances.Keys.Contains(s.IfcProductLabel))
                             .Where(s => null == hiddenInstances || hiddenInstances.Count == 0 || !hiddenInstances.Keys.Contains(s.IfcProductLabel))
                             .Where(s => null == selectedContexts || selectedContexts.Count == 0 || selectedContexts.Keys.Contains(s.RepresentationContext)))
                    {
                        // logging
                        var currentProgress = 100 * prog++ / tot;
                        if (currentProgress != lastProgress && ProgressChanged != null)
                        {
                            ProgressChanged(this, new ProgressChangedEventArgs(currentProgress, "Creating visuals"));
                            lastProgress = currentProgress;
                        }

                        // work out style
                        var styleId = shapeInstance.StyleLabel > 0
                            ? shapeInstance.StyleLabel
                            : shapeInstance.IfcTypeId * -1;

                        if (!materialsByStyleId.ContainsKey(styleId))
                        {
                            // if the style is not available we build one by ExpressType
                            var material2 = GetWpfMaterialByType(model, shapeInstance.IfcTypeId);
                            materialsByStyleId.Add(styleId, material2);

                            var mg = GetNewStyleMesh(material2, tmpTransparentsGroup, tmpOpaquesGroup);
                            meshesByStyleId.Add(styleId, mg);
                        }

                        //GET THE ACTUAL GEOMETRY
                        MeshGeometry3D wpfMesh;
                        //see if we have already read it
                        if (UseMaps && repeatedShapeGeometries.TryGetValue(shapeInstance.ShapeGeometryLabel, out wpfMesh))
                        {
                            var mg = new GeometryModel3D(wpfMesh, materialsByStyleId[styleId]);
                            mg.SetValue(FrameworkElement.TagProperty,
                                        new XbimInstanceHandle(model, shapeInstance.IfcProductLabel, shapeInstance.IfcTypeId));
                            mg.BackMaterial = mg.Material;
                            mg.Transform    =
                                XbimMatrix3D.Multiply(shapeInstance.Transformation,
                                                      modelTransform)
                                .ToMatrixTransform3D();
                            if (materialsByStyleId[styleId].IsTransparent)
                            {
                                tmpTransparentsGroup.Children.Add(mg);
                            }
                            else
                            {
                                tmpOpaquesGroup.Children.Add(mg);
                            }
                        }
                        else //we need to get the shape geometry
                        {
                            IXbimShapeGeometryData shapeGeom = geomReader.ShapeGeometry(shapeInstance.ShapeGeometryLabel);

                            if (UseMaps && shapeGeom.ReferenceCount > 1) //only store if we are going to use again
                            {
                                wpfMesh = new MeshGeometry3D();
                                switch ((XbimGeometryType)shapeGeom.Format)
                                {
                                case XbimGeometryType.PolyhedronBinary:
                                    wpfMesh.Read(shapeGeom.ShapeData);
                                    break;

                                case XbimGeometryType.Polyhedron:
                                    wpfMesh.Read(((XbimShapeGeometry)shapeGeom).ShapeData);
                                    break;
                                }

                                repeatedShapeGeometries.Add(shapeInstance.ShapeGeometryLabel, wpfMesh);
                                var mg = new GeometryModel3D(wpfMesh, materialsByStyleId[styleId]);
                                mg.SetValue(FrameworkElement.TagProperty,
                                            new XbimInstanceHandle(model, shapeInstance.IfcProductLabel, shapeInstance.IfcTypeId));
                                mg.BackMaterial = mg.Material;
                                mg.Transform    = XbimMatrix3D.Multiply(shapeInstance.Transformation, modelTransform).ToMatrixTransform3D();

                                //manual Texturemapping
                                if (materialsByStyleId[styleId].HasTexture &&
                                    mg.Geometry is MeshGeometry3D mesh3D)
                                {
                                    ITextureMapping tMapping;
                                    if (materialsByStyleId[styleId].IfcTextureCoordinate != null)
                                    {
                                        tMapping = TextureMappingFactory.CreateTextureMapping(materialsByStyleId[styleId].IfcTextureCoordinate);
                                    }
                                    else
                                    {
                                        Logger.LogWarning(0, "No IfcTextureCoordinate is defined for style " + styleId + ". Spherical mapping is used.");
                                        tMapping = new SphericalTextureMap();
                                    }
                                    mesh3D.TextureCoordinates.Concat(tMapping.GetTextureMap(mesh3D.Positions, mesh3D.Normals, mesh3D.TriangleIndices));
                                }

                                if (materialsByStyleId[styleId].IsTransparent)
                                {
                                    tmpTransparentsGroup.Children.Add(mg);
                                }
                                else
                                {
                                    tmpOpaquesGroup.Children.Add(mg);
                                }
                            }
                            else //it is a one off, merge it with shapes of same style
                            {
                                var targetMergeMeshByStyle = meshesByStyleId[styleId];

                                // replace target mesh beyond suggested size
                                // https://docs.microsoft.com/en-us/dotnet/framework/wpf/graphics-multimedia/maximize-wpf-3d-performance
                                //
                                if (targetMergeMeshByStyle.PositionCount > 20000
                                    ||
                                    targetMergeMeshByStyle.TriangleIndexCount > 60000
                                    )
                                {
                                    targetMergeMeshByStyle.EndUpdate();
                                    var replace = GetNewStyleMesh(materialsByStyleId[styleId], tmpTransparentsGroup, tmpOpaquesGroup);
                                    meshesByStyleId[styleId] = replace;
                                    targetMergeMeshByStyle   = replace;
                                }
                                // end replace

                                if (shapeGeom.Format != (byte)XbimGeometryType.PolyhedronBinary)
                                {
                                    continue;
                                }
                                var             transform     = XbimMatrix3D.Multiply(shapeInstance.Transformation, modelTransform);
                                ITextureMapping textureMethod = null;
                                if (materialsByStyleId[styleId].HasTexture)
                                {
                                    if (materialsByStyleId[styleId].IfcTextureCoordinate != null)
                                    {
                                        textureMethod = TextureMappingFactory.CreateTextureMapping(materialsByStyleId[styleId].IfcTextureCoordinate);
                                    }
                                    else
                                    {
                                        Logger.LogWarning(0, "No texture mapping method defined for style " + styleId + ". Spherical mapping is used.");
                                        textureMethod = new SphericalTextureMap();
                                    }
                                }
                                targetMergeMeshByStyle.Add(
                                    shapeGeom.ShapeData,
                                    shapeInstance.IfcTypeId,
                                    shapeInstance.IfcProductLabel,
                                    shapeInstance.InstanceLabel, transform,
                                    (short)model.UserDefinedId,
                                    textureMethod);
                            }
                        }
                    }

                    foreach (var wpfMeshGeometry3D in meshesByStyleId.Values)
                    {
                        wpfMeshGeometry3D.EndUpdate();
                    }
                    if (tmpOpaquesGroup.Children.Any())
                    {
                        var mv = new ModelVisual3D {
                            Content = tmpOpaquesGroup
                        };
                        opaqueShapes.Children.Add(mv);
                    }
                    if (tmpTransparentsGroup.Children.Any())
                    {
                        var mv = new ModelVisual3D {
                            Content = tmpTransparentsGroup
                        };
                        transparentShapes.Children.Add(mv);
                    }
                }
            }
            Logger.LogDebug("Time to load visual components: {0:F3} seconds", timer.Elapsed.TotalSeconds);

            ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(0, "Ready"));
            return(scene);
        }