xBimTeam / XbimWindowsUI

The home of XbimXplorer and WPF components for your desktop BIM applications.
Other
252 stars 149 forks source link

How to make "BuildScene" faster? #116

Open SpacePurr opened 5 years ago

SpacePurr commented 5 years ago

Hello, XBim-experts! I would like to open a big massive topic about visual changes in model view. More details: question is about method 'ReloadModel' which calls 'BuildScene'. I haven't enough experience in C# and Xbim. I would like to explain my question in element color example. I need to paint (set color) some ifc model's elements and save changes. I do it in 2 steps:

  1. Change StyledItem of element, briefly:
    var ifcProd = SelectedItem as IfcProduct;
    var repItemsLabels = ifcProd.Representation.Representations.LastOrDefault();  
    var body = repItemsLabels.Items.FirstOrDefault();  
    var styledItem = body.StyledByItem.First();  
    //… 

Next I put old color as element property, then I create a new color and something I need.

And I save it:

Model.SaveAs(Path);
  1. Previous step does not influence on model visual view. In addition I use 'BuildScene ' for set color to element. I found it here: https://github.com/xBimTeam/XbimWindowsUI/issues/37

Previous algorithm works perfect: hide elements, make element transparent and set color to elements. But 'ReloadModel' method works very long (5-10 sec) on a big ifc-files (about 1M rows in ifc-file or 30Mb sized). I tried to set color using 'Highlight' method. This way I had to rewrite something in xBim library. Generic.xaml add:

<extensions:ObservableMeshVisual3D x:Name="ColorLayers" EdgeDiameter="0"  VertexRadius="0" />

DrawingControl3D add:

[TemplatePart(Name = TemplateColorLayers, Type = typeof(ObservableMeshVisual3D))]
private const string TemplateColorLayers = "ColorLayers";
protected ObservableMeshVisual3D Highlighted;

public override void OnApplyTemplate ()
{
//some code
ColorLayers = (ObservableMeshVisual3D)GetTemplateChild(TemplateColorLayers);
if (ColorLayers != null)
                ColorLayers.PropertyChanged += ColorLayers_PropertyChanged;
//some code
}
private void ColorLayers_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var pInfo = typeof(MeshVisual3D).GetProperty(e.PropertyName);
            var sourceValue = pInfo.GetValue(ColorLayers, null);
            pInfo.SetValue(TransHighlighted, sourceValue, null);
        }

I created my own collection of elements which will be always highlighted:

public EntitySelection SelItem
        {
            get { return (EntitySelection)GetValue(SelItemProperty); }
            set { SetValue(SelItemProperty, value); }
        }

        public static readonly DependencyProperty SelItemProperty = DependencyProperty.Register("SelItem",
            typeof(EntitySelection), typeof(DrawingControl3D), new PropertyMetadata(OnSelItemChanged));

        private static void OnSelItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

All I took from xBim examples.

Compile new Xbim.Presentation library.

Then I created my own class 'MyDrawingControl3D : DrawingControl3D' in which I implemented the methods based on your methods:

public virtual void MyHighlighSelected(IPersistEntity newVal)
        {
            // 0. prepare
            var mat = new WpfMaterial(
                new XbimColour(
                    "Selection", MySelectionColor.ScR, MySelectionColor.ScG, MySelectionColor.ScB, MySelectionColor.ScA)
                );

            var m = MyGetSelectionGeometry(newVal, mat);

            ColorLayers.Content = m; //Binding other ObservableMesh

        }

Also

private WpfMeshGeometry3D MyGetSelectionGeometry(IPersistEntity newVal, WpfMaterial mat)
        {
//some code
if (SelectionBehaviour == SelectionBehaviours.MultipleSelection)
                {
                    m = WpfMeshGeometry3D.GetGeometry(SelItem, ModelPositions, mat);
                }
//some code
}

In my 'MainViewModel' I called this method for selecting elements:

MyControl.MyHighlighSelected(SelectedItem);

Element was colored and saved, but this way I faces with 3 problems:

  1. 'ModelOpacity' property doesn't work with elements
  2. Common 'HighlightSelected' method doesn't work with elements.
  3. I can see elements color just when I look straight at it, I can't see color when other transparent element stays in front element I colored.

In total I made a conclusion that 'highlight' method isn't suitable for me and I turned back to 'ReloadModel', because except painting, I need hide element and make element transparent. I think 'ReloadModel' method create a scene and works with all elements inside. I have an idea: I can create a new scene and put selected elements inside. Then I can add my scene to main scene used in 'DrawingControl'. But I'm not sure about it. Is it possible?

In total I would to understand can I make previous algorithm faster(ReloadModel => LoadGeometry => BuildScene), because my idea-generator is empty... Thanks.

SpacePurr commented 5 years ago

UPD: I understood that i can't use it for excluding elements(Overloading invisible elements to something). I would like to make this process(ReloadModel => BuildScene) in some separated threads. I wonder it will make process faster.