Grasshopper create view in Tekla

Hello,

I’m thinking about the way to automaticaly adjust views to parametric model.

In my case I have an object that is changing it’s place along roadline. I would like to automatically create top view and views for cross and longitudinal section and every time I move my object, the views will follow the object.
Right now to do this I have to create top view (basic xy view) and sections by 3 point view and then I can use it for drawing. But anytime I move my object, I have to manually set views for cross sections.

Any suggestions? Is it possible to do?

Hi Aleksander,

You might be able to do something with a C# scripting component and the Tekla API if that’s something you’re comfortable with - there are some examples in the View class: View Class | Tekla Developer Center

Cheers,

-b

Thank you @sebastian.lindholm. I never tried C#, but I will dive into it.

@sebastian.lindholm I’m attempting to create a C# component for creating a 3D view, but I’m completely new to programming and struggling to get it working. Here is my code, but I’ve realized that in version 2022, there is no Tekla.Structures.Model.UI namespace, so classes like ViewCoordinateSystem or ViewDepthDown/Up won’t work in Tekla 2022. Am I right? Is there any other approach then?

using System;
using System.Collections;
using System.Collections.Generic;

using Rhino;
using Rhino.Geometry;

using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;

using Tekla.Structures;
using Tekla.Structures.Model.UI;
using Tekla.Structures.Geometry3d;

/// <summary>
/// This class will be instantiated on demand by the Script component.
/// </summary>
public class Script_Instance : GH_ScriptInstance
{
#region Utility functions
  /// <summary>Print a String to the [Out] Parameter of the Script component.</summary>
  /// <param name="text">String to print.</param>
  private void Print(string text) { /* Implementation hidden. */ }
  /// <summary>Print a formatted String to the [Out] Parameter of the Script component.</summary>
  /// <param name="format">String format.</param>
  /// <param name="args">Formatting parameters.</param>
  private void Print(string format, params object[] args) { /* Implementation hidden. */ }
  /// <summary>Print useful information about an object instance to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj) { /* Implementation hidden. */ }
  /// <summary>Print the signatures of all the overloads of a specific method to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj, string method_name) { /* Implementation hidden. */ }
#endregion

#region Members
  /// <summary>Gets the current Rhino document.</summary>
  private readonly RhinoDoc RhinoDocument;
  /// <summary>Gets the Grasshopper document that owns this script.</summary>
  private readonly GH_Document GrasshopperDocument;
  /// <summary>Gets the Grasshopper script component that owns this script.</summary>
  private readonly IGH_Component Component;
  /// <summary>
  /// Gets the current iteration count. The first call to RunScript() is associated with Iteration==0.
  /// Any subsequent call within the same solution will increment the Iteration count.
  /// </summary>
  private readonly int Iteration;
#endregion

  /// <summary>
  /// This procedure contains the user code. Input parameters are provided as regular arguments,
  /// Output parameters as ref arguments. You don't have to assign output parameters,
  /// they will have a default value.
  /// </summary>
  private void RunScript(bool activateScript, Point3d minPoint, Point3d maxPoint, ref object A)
  {
    if (activateScript)
    {
      // Tworzenie nowego obiektu klasy ViewExample
      ViewExample example = new ViewExample();
      // Wywołanie metody ViewExample1, która tworzy widok
      example.ViewExample1(minPoint, maxPoint);
    }
    // Nie zwracamy żadnego wyniku, ponieważ operacja jest wykonywana na poziomie aplikacji Tekla i nie jest zwracana do Grasshoppera
    A = null;
  }

  // Klasa ViewExample
  public class ViewExample
  {
    // Metoda tworząca nowy widok w Tekla Structures
    public void ViewExample1(Point3d minPoint, Point3d maxPoint)
    {
      // Tworzenie nowego obiektu klasy View
      Tekla.Structures.Model.UI.View view = new Tekla.Structures.Model.UI.View();
      view.Name = "Example View 2";

      // Ustawienie osi widoku
      View.ViewCoordinateSystem.AxisX = new Vector(-1.97216, -0.332543, 0);
      View.ViewCoordinateSystem.AxisY = new Vector(-0.332543, 1.97216, 0);

      // Ustawienie obszaru roboczego widoku
      view.WorkArea.MinPoint = new Tekla.Structures.Geometry3d.Point(minPoint.X, minPoint.Y, minPoint.Z);
      view.WorkArea.MaxPoint = new Tekla.Structures.Geometry3d.Point(maxPoint.X, maxPoint.Y, maxPoint.Z);

      // Ustawienie głębokości widoku
      view.ViewDepthUp = 1000;
      view.ViewDepthDown = 1000;

      // Wstawienie widoku
      view.Insert();
    }
  }

  // <Custom additional code> 

  // </Custom additional code> 
}

Hi Aleksander,

The Tekla.STructures.Model.UI namespace should be part of the Tekla.Structures.Model.dll assembly.

So if you add a reference to this file you can then use the classes that are part of that namespace;

C:\Program Files\Tekla Structures\2022.0\bin\Tekla.Structures.Model.dll

Cheers,

-b

Thanks for the reply Sebastian. So as you said I added a reference and still can’t achievie what I want.
First of all view creates proper workarea, but this workarea is flat and ViewDepthUp and Down are not applying. I can see right values in View Properties tab, but I have to press Modify button to apply changes.
Secondly i can’t force my view to rotate or make any change when manipulating Vector parameters inside View.ViewCoordinateSystem.AxisX/Y row.
Can you take a glance at my script?

Here is my code:

using System;
using System.Collections;
using System.Collections.Generic;

using Rhino;
using Rhino.Geometry;

using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;

using Tekla.Structures;
using Tekla.Structures.Model.UI;
using Tekla.Structures.Geometry3d;

/// <summary>
/// This class will be instantiated on demand by the Script component.
/// </summary>
public class Script_Instance : GH_ScriptInstance
{
#region Utility functions
  /// <summary>Print a String to the [Out] Parameter of the Script component.</summary>
  /// <param name="text">String to print.</param>
  private void Print(string text) { /* Implementation hidden. */ }
  /// <summary>Print a formatted String to the [Out] Parameter of the Script component.</summary>
  /// <param name="format">String format.</param>
  /// <param name="args">Formatting parameters.</param>
  private void Print(string format, params object[] args) { /* Implementation hidden. */ }
  /// <summary>Print useful information about an object instance to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj) { /* Implementation hidden. */ }
  /// <summary>Print the signatures of all the overloads of a specific method to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj, string method_name) { /* Implementation hidden. */ }
#endregion

#region Members
  /// <summary>Gets the current Rhino document.</summary>
  private readonly RhinoDoc RhinoDocument;
  /// <summary>Gets the Grasshopper document that owns this script.</summary>
  private readonly GH_Document GrasshopperDocument;
  /// <summary>Gets the Grasshopper script component that owns this script.</summary>
  private readonly IGH_Component Component;
  /// <summary>
  /// Gets the current iteration count. The first call to RunScript() is associated with Iteration==0.
  /// Any subsequent call within the same solution will increment the Iteration count.
  /// </summary>
  private readonly int Iteration;
#endregion

  /// <summary>
  /// This procedure contains the user code. Input parameters are provided as regular arguments,
  /// Output parameters as ref arguments. You don't have to assign output parameters,
  /// they will have a default value.
  /// </summary>
  private void RunScript(bool activateScript, Point3d minPoint, Point3d maxPoint, ref object A)
  {
    if (activateScript)
    {
      // Tworzenie nowego obiektu klasy ViewExample
      ViewExample example = new ViewExample();
      // Wywołanie metody ViewExample1, która tworzy widok
      example.ViewExample1(minPoint, maxPoint);
    }
    // Nie zwracamy żadnego wyniku, ponieważ operacja jest wykonywana na poziomie aplikacji Tekla i nie jest zwracana do Grasshoppera
    A = null;
  }

  // Klasa ViewExample
  public class ViewExample
  {
    // Metoda tworząca nowy widok w Tekla Structures
    public void ViewExample1(Point3d minPoint, Point3d maxPoint)
    {
      // Tworzenie nowego obiektu klasy View
      Tekla.Structures.Model.UI.View View = new Tekla.Structures.Model.UI.View();
      View.Name = "Example View 2";

      // Ustawienie osi widoku
      View.ViewCoordinateSystem.AxisX = new Vector(0.5, 0, 0); //-1.97216, -0.332543, 0
      View.ViewCoordinateSystem.AxisY = new Vector(0, 1, 0); //-0.332543, 1.97216, 0

      // Ustawienie obszaru roboczego widoku
      View.WorkArea.MinPoint = new Tekla.Structures.Geometry3d.Point(minPoint.X, minPoint.Y, minPoint.Z);
      View.WorkArea.MaxPoint = new Tekla.Structures.Geometry3d.Point(maxPoint.X, maxPoint.Y, maxPoint.Z);

      // Ustawienie głębokości widoku
      View.ViewDepthUp = 10000;
      View.ViewDepthDown = 2000;

      View.Insert();
      View.Modify();
    }
  }

  // <Custom additional code> 

  // </Custom additional code> 
}
1 Like

Hi, not sure, I haven’t used the View class, but trying the example in the API reference seems to work as intended for me.

You code will always Insert() a new view rather than updating the existing one, this might be an issue. Rather you could use the ViewHandler as in the second example on that page to list all views, and check the view.Names until you find your view and then update and Modify() that one. Only if no view with your name is found you can instead insert a new one.

About rotation I found this post in the Tekla forums, not sure if it’s relevant:
https://forum.tekla.com/topic/35767-create-view-around-a-component/?do=findComment&comment=165432

Cheers,

-b

Well I tried with ViewHandler and modifying one view, and it’s way smarter than creating new view every time :smiley:

In my second attempt with Rhino 8, there are some differences, but modifying vectors and view rotation is working now. I replaced Vector with Tekla.Structures.Geometry3d.Vector.

Unfortunately, setting up the view depth is still not working. I tried using RedrawWorkplane and RedrawView from the ViewHandler class, but I can’t make any changes.

I attach video and gh. script.


C#_Modify_View.gh (12.6 KB)

Hmm, now I can’t get this example to play nice at all on my system, but I can see you’re almost there :sweat_smile:

Maybe try adding

new Tekla.Structures.Model.Model().CommitChanges();

after

activeView.Modify();

At least for model objects this is needed after Modify() in order to redraw them in the UI.

Cheers,

-b

Tried adding this code, but unfortunately it’s still not working :frowning:

// r "C:\\Program Files\\Tekla Structures\\2024.0\\bin\\Tekla.Structures.dll"
// r "C:\\Program Files\\Tekla Structures\\2024.0\\bin\\Tekla.Structures.Model.dll"
// r "C:\\Program Files\\Tekla Structures\\2024.0\\bin\\Tekla.Structures.Geometry3d.Compatibility.dll"

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;

using Rhino;
using Rhino.Geometry;

using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;

using Tekla.Structures;
using Tekla.Structures.Model.UI;
using Tekla.Structures.Geometry3d;

public class Script_Instance : GH_ScriptInstance
{
    #region Notes
    /* 
      Members:
        RhinoDoc RhinoDocument
        GH_Document GrasshopperDocument
        IGH_Component Component
        int Iteration

      Methods (Virtual & overridable):
        Print(string text)
        Print(string format, params object[] args)
        Reflect(object obj)
        Reflect(object obj, string method_name)
    */
    #endregion

    private void RunScript(
	bool activateScript,
	Point3d minPoint,
	Point3d maxPoint,
	ref object A)
    {
        if (activateScript)
        {
            // Tworzenie nowego obiektu klasy ViewExample
            ViewExample example = new ViewExample();
            // Wywołanie metody ViewExample1, która modyfikuje aktywny widok
            example.ModifyActiveView(minPoint, maxPoint);
        }
        // Nie zwracamy żadnego wyniku, ponieważ operacja jest wykonywana na poziomie aplikacji Tekla i nie jest zwracana do Grasshoppera
        A = null;
    }

    // Klasa ViewExample
    public class ViewExample
    {
        // Metoda modyfikująca aktywny widok w Tekla Structures
        public void ModifyActiveView(Point3d minPoint, Point3d maxPoint)
        {
            // Użycie ViewHandler do uzyskania aktywnego widoku
            ViewHandler viewHandler = new ViewHandler();
            Tekla.Structures.Model.UI.View activeView = ViewHandler.GetActiveView();
            
            if (activeView != null)
            {
                // Ustawienie osi widoku
                activeView.ViewCoordinateSystem.AxisX = new Tekla.Structures.Geometry3d.Vector(1, 0, 0); // -1.97216, -0.332543, 0
                activeView.ViewCoordinateSystem.AxisY = new Tekla.Structures.Geometry3d.Vector(0, 1, 0); // -0.332543, 1.97216, 0
                
                // Ustawienie głębokości widoku
               activeView.ViewDepthUp = 40000;
               activeView.ViewDepthDown = 2000;

               // Ustawienie obszaru roboczego widoku
                activeView.WorkArea.MinPoint = new Tekla.Structures.Geometry3d.Point(minPoint.X, minPoint.Y, minPoint.Z);
                activeView.WorkArea.MaxPoint = new Tekla.Structures.Geometry3d.Point(maxPoint.X, maxPoint.Y, maxPoint.Z);

                activeView.Modify();
                new Tekla.Structures.Model.Model().CommitChanges();

            }
            else
            {
                throw new InvalidOperationException("No active view found.");
            }
        }
    }
}