Community
Navisworks API
Welcome to Autodesk’s Navisworks API Forums. Share your knowledge, ask questions, and explore popular Navisworks API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Issues with Persistent Markups and Saved Viewpoints in Navisworks Plugin

5 REPLIES 5
Reply
Message 1 of 6
Tarek.AhmedWFZ5H
420 Views, 5 Replies

Issues with Persistent Markups and Saved Viewpoints in Navisworks Plugin

Tarek.AhmedWFZ5H
Participant
Participant

I'm developing a Navisworks plugin that tracks the mouse movement to get the elevation of the hovered point and displays it as text at the current mouse location. On click, the elevation text is intended to stick and remain at the clicked location. I'm facing a couple of issues and would appreciate some guidance:

  1. Persistent Markups:

    • When I click to create a Text2D in the overlay render, it works initially. However, every subsequent click replaces the previously created text with a new one, rather than allowing multiple markups to be displayed.
    • To address this, I attempted to save the markup data in a private list field and rerender all the entries from this list on every click. I'm unsure if this is the recommended approach. Is there a better way to handle multiple markups without them being overridden?
  2. Saved Viewpoints:

    • I created a saved viewpoint, but the markups are not saved with the viewpoint. While the markups appear on my screen, they disappear when I switch to another saved viewpoint and return.
    • How can I ensure that the markups are saved with the viewpoints and persist when switching between different saved viewpoints?

 

This is the class that implements the ToolPlugin 

 

public class ElevationInspectorTool : ToolPlugin
    {
        private Point3D _pickedPoint;
        private int _x;
        private int _y;
        private bool _isMouseClicked;
        private readonly List<Markup> _markups = new List<Markup>();

        public void ClearMarkups()
        {
            _markups.Clear();
        }

        public override bool MouseMove(View view, KeyModifiers modifiers, int x, int y, double timeOffset)
        {
            // get current selection
            PickItemResult itemResult = view.PickItemFromPoint(x, y);

            if (itemResult != null)
            {
                _pickedPoint = itemResult.Point;
                _x = x;
                _y = y;

                Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
            }

            return false;
        }

        public override bool MouseDown(View view, KeyModifiers modifiers, ushort button, int x, int y, double timeOffset)
        {
            _isMouseClicked = true;

            Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);

            _markups.Add(new Markup()
            {
                TextFontInfo = new TextFontInfo("typeFace", 20, 10, false, false),
                Text = $"Elev :{Math.Round(_pickedPoint.Z, 2)}m",
                Location = new Point2D(_x, _y),
                OffsetX = 0,
                OffsetY = 0,
                Color = Color.Green,
                ColorAlphaValue = 1.0,
            });


            return false;
        }

        public override void OverlayRender(View view, Graphics graphics)
        {
            if (_pickedPoint != null)
            {
                if (_isMouseClicked)
                {
                    if (_markups.Count == 1)
                    {
                        var savedViewPoint = ViewPointSaver.SaveCurrentView(view.Document, "Test");
                        view.Document.SavedViewpoints.CurrentSavedViewpoint = savedViewPoint;
                    }

                    graphics.BeginWindowContext();

                    foreach (var markup in _markups)
                    {
                        graphics.Color(markup.Color, markup.ColorAlphaValue);
                        graphics.Text2D(markup.TextFontInfo, markup.Text, markup.Location, markup.OffsetX, markup.OffsetY);
                    }

                    graphics.EndWindowContext();

                    _isMouseClicked = false;
                }
                else
                {
                    graphics.BeginWindowContext();

                    foreach (var markup in _markups)
                    {
                        graphics.Color(markup.Color, markup.ColorAlphaValue);
                        graphics.Text2D(markup.TextFontInfo, markup.Text, markup.Location, markup.OffsetX, markup.OffsetY);
                    }

                    graphics.Color(Color.Red, 1.0);
                    graphics.Text2D(new TextFontInfo("typeFace", 20, 10, false, false), $"Elev :{Math.Round(_pickedPoint.Z, 2)}m", new Point2D(_x, _y), 0, 0);

                    graphics.EndWindowContext();
                }

            }
        }
    }

 

 

This is the method that saves the view point

 

public static SavedViewpoint SaveCurrentView(Document document, string name)
        {
            var existingSavedViewPoint = document.SavedViewpoints.Value.FirstOrDefault(v => v.DisplayName == name);

            int count = 1;
            string suggestedName = name;
            while (existingSavedViewPoint != null)
            {
                suggestedName = $"{name}-{count:D2}";
                existingSavedViewPoint = document.SavedViewpoints.Value.FirstOrDefault(v => v.DisplayName == suggestedName);
                count++;
            }

            SavedViewpoint savedViewPoint = new SavedViewpoint
            {
                DisplayName = suggestedName
            };

            document.SavedViewpoints.AddCopy(savedViewPoint);

            // after adding the view point retrive it again from the saved view points.
            var createdSavedViewPoint = document.SavedViewpoints.Value.First(v => v.DisplayName == savedViewPoint.DisplayName) as SavedViewpoint;

            document.SavedViewpoints.ReplaceFromCurrentView(createdSavedViewPoint);

            return createdSavedViewPoint = document.SavedViewpoints.Value.First(v => v.DisplayName == savedViewPoint.DisplayName) as SavedViewpoint;
        }

 

 

Any advice or suggestions on these issues would be greatly appreciated. Thank you!

0 Likes

Issues with Persistent Markups and Saved Viewpoints in Navisworks Plugin

I'm developing a Navisworks plugin that tracks the mouse movement to get the elevation of the hovered point and displays it as text at the current mouse location. On click, the elevation text is intended to stick and remain at the clicked location. I'm facing a couple of issues and would appreciate some guidance:

  1. Persistent Markups:

    • When I click to create a Text2D in the overlay render, it works initially. However, every subsequent click replaces the previously created text with a new one, rather than allowing multiple markups to be displayed.
    • To address this, I attempted to save the markup data in a private list field and rerender all the entries from this list on every click. I'm unsure if this is the recommended approach. Is there a better way to handle multiple markups without them being overridden?
  2. Saved Viewpoints:

    • I created a saved viewpoint, but the markups are not saved with the viewpoint. While the markups appear on my screen, they disappear when I switch to another saved viewpoint and return.
    • How can I ensure that the markups are saved with the viewpoints and persist when switching between different saved viewpoints?

 

This is the class that implements the ToolPlugin 

 

public class ElevationInspectorTool : ToolPlugin
    {
        private Point3D _pickedPoint;
        private int _x;
        private int _y;
        private bool _isMouseClicked;
        private readonly List<Markup> _markups = new List<Markup>();

        public void ClearMarkups()
        {
            _markups.Clear();
        }

        public override bool MouseMove(View view, KeyModifiers modifiers, int x, int y, double timeOffset)
        {
            // get current selection
            PickItemResult itemResult = view.PickItemFromPoint(x, y);

            if (itemResult != null)
            {
                _pickedPoint = itemResult.Point;
                _x = x;
                _y = y;

                Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
            }

            return false;
        }

        public override bool MouseDown(View view, KeyModifiers modifiers, ushort button, int x, int y, double timeOffset)
        {
            _isMouseClicked = true;

            Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);

            _markups.Add(new Markup()
            {
                TextFontInfo = new TextFontInfo("typeFace", 20, 10, false, false),
                Text = $"Elev :{Math.Round(_pickedPoint.Z, 2)}m",
                Location = new Point2D(_x, _y),
                OffsetX = 0,
                OffsetY = 0,
                Color = Color.Green,
                ColorAlphaValue = 1.0,
            });


            return false;
        }

        public override void OverlayRender(View view, Graphics graphics)
        {
            if (_pickedPoint != null)
            {
                if (_isMouseClicked)
                {
                    if (_markups.Count == 1)
                    {
                        var savedViewPoint = ViewPointSaver.SaveCurrentView(view.Document, "Test");
                        view.Document.SavedViewpoints.CurrentSavedViewpoint = savedViewPoint;
                    }

                    graphics.BeginWindowContext();

                    foreach (var markup in _markups)
                    {
                        graphics.Color(markup.Color, markup.ColorAlphaValue);
                        graphics.Text2D(markup.TextFontInfo, markup.Text, markup.Location, markup.OffsetX, markup.OffsetY);
                    }

                    graphics.EndWindowContext();

                    _isMouseClicked = false;
                }
                else
                {
                    graphics.BeginWindowContext();

                    foreach (var markup in _markups)
                    {
                        graphics.Color(markup.Color, markup.ColorAlphaValue);
                        graphics.Text2D(markup.TextFontInfo, markup.Text, markup.Location, markup.OffsetX, markup.OffsetY);
                    }

                    graphics.Color(Color.Red, 1.0);
                    graphics.Text2D(new TextFontInfo("typeFace", 20, 10, false, false), $"Elev :{Math.Round(_pickedPoint.Z, 2)}m", new Point2D(_x, _y), 0, 0);

                    graphics.EndWindowContext();
                }

            }
        }
    }

 

 

This is the method that saves the view point

 

public static SavedViewpoint SaveCurrentView(Document document, string name)
        {
            var existingSavedViewPoint = document.SavedViewpoints.Value.FirstOrDefault(v => v.DisplayName == name);

            int count = 1;
            string suggestedName = name;
            while (existingSavedViewPoint != null)
            {
                suggestedName = $"{name}-{count:D2}";
                existingSavedViewPoint = document.SavedViewpoints.Value.FirstOrDefault(v => v.DisplayName == suggestedName);
                count++;
            }

            SavedViewpoint savedViewPoint = new SavedViewpoint
            {
                DisplayName = suggestedName
            };

            document.SavedViewpoints.AddCopy(savedViewPoint);

            // after adding the view point retrive it again from the saved view points.
            var createdSavedViewPoint = document.SavedViewpoints.Value.First(v => v.DisplayName == savedViewPoint.DisplayName) as SavedViewpoint;

            document.SavedViewpoints.ReplaceFromCurrentView(createdSavedViewPoint);

            return createdSavedViewPoint = document.SavedViewpoints.Value.First(v => v.DisplayName == savedViewPoint.DisplayName) as SavedViewpoint;
        }

 

 

Any advice or suggestions on these issues would be greatly appreciated. Thank you!

Labels (2)
5 REPLIES 5
Message 2 of 6

sai_aluka
Community Visitor
Community Visitor

Hey did you have any luck with the issue ?

0 Likes

Hey did you have any luck with the issue ?

Message 3 of 6

alexisDVJML
Collaborator
Collaborator
    1. Persistent Markups:

      • When I click to create a Text2D in the overlay render, it works initially. However, every subsequent click replaces the previously created text with a new one, rather than allowing multiple markups to be displayed.
      • To address this, I attempted to save the markup data in a private list field and rerender all the entries from this list on every click. I'm unsure if this is the recommended approach. Is there a better way to handle multiple markups without them being overridden?

        Correct approach.
        However:
        • if you want them to persist between session, you will have to save them "somewhere" in the document. Easier would be to save as user properties in the root of the .nwf or at the first level of the tree (see below re: associating them with Saved Viewpoints)
        • I don't understand your logic in OverlayRender. Personnally I would use different colors for the persistent one and the on mouse move one

    2. Saved Viewpoints:

      • I created a saved viewpoint, but the markups are not saved with the viewpoint. While the markups appear on my screen, they disappear when I switch to another saved viewpoint and return.
      • How can I ensure that the markups are saved with the viewpoints and persist when switching between different saved viewpoints?

        AFAIK there is no proprietary user data for a SavedViewPoint.
        What you could do is save your Markup as Comment(s) in the SavedViewPoint, using a prefix magic key to differentiate from user comments (ex: {Markup}) and/or use JSON or your own format for the comment content.
        Then you will need to intercept Navisworks event for a change of active SavedViewPoint, extract these comments to refill your Markup List that is used by your renderer.

        Hope this helps.
Main Scientist, Full Stack Developer & When Time Permits Director of IDIGO ► On your marks, Set, Go
0 Likes

    1. Persistent Markups:

      • When I click to create a Text2D in the overlay render, it works initially. However, every subsequent click replaces the previously created text with a new one, rather than allowing multiple markups to be displayed.
      • To address this, I attempted to save the markup data in a private list field and rerender all the entries from this list on every click. I'm unsure if this is the recommended approach. Is there a better way to handle multiple markups without them being overridden?

        Correct approach.
        However:
        • if you want them to persist between session, you will have to save them "somewhere" in the document. Easier would be to save as user properties in the root of the .nwf or at the first level of the tree (see below re: associating them with Saved Viewpoints)
        • I don't understand your logic in OverlayRender. Personnally I would use different colors for the persistent one and the on mouse move one

    2. Saved Viewpoints:

      • I created a saved viewpoint, but the markups are not saved with the viewpoint. While the markups appear on my screen, they disappear when I switch to another saved viewpoint and return.
      • How can I ensure that the markups are saved with the viewpoints and persist when switching between different saved viewpoints?

        AFAIK there is no proprietary user data for a SavedViewPoint.
        What you could do is save your Markup as Comment(s) in the SavedViewPoint, using a prefix magic key to differentiate from user comments (ex: {Markup}) and/or use JSON or your own format for the comment content.
        Then you will need to intercept Navisworks event for a change of active SavedViewPoint, extract these comments to refill your Markup List that is used by your renderer.

        Hope this helps.
Main Scientist, Full Stack Developer & When Time Permits Director of IDIGO ► On your marks, Set, Go
Message 4 of 6
cation234ctci
in reply to: alexisDVJML

cation234ctci
Participant
Participant

This is exactly what I was trying to do recently: combining an overlay markup and a saved viewpoint.

 

1. Markup: A customized class. You definitely write your own and handle a list of them.

 

2. SavedViewpoint: Even though you could save and retrieve SaveViewPoints from nwd file, it is not flexible. Instead, try using GetCamera() and SetCamera(string) method of Viewpoint class. What you are manipulating with these two methods is a simple JSON string, so if you could save your markups as JSON as well, you could write markup and viewpoint info to disk for later usage. Actually I save them to a SQLite db file.

 

Reference for Viewpoint camera JSON (I didn't write this): https://twentytwo.space/2021/06/02/navisworks-api-viewpoint-part-2/

 

Here's what I've achieved: when I drop a markup on a model item, the current viewpoint is saved and a thumbnail is generated. By double clicking the thumbnail, I can restore the view.

 

This is exactly what I was trying to do recently: combining an overlay markup and a saved viewpoint.

 

1. Markup: A customized class. You definitely write your own and handle a list of them.

 

2. SavedViewpoint: Even though you could save and retrieve SaveViewPoints from nwd file, it is not flexible. Instead, try using GetCamera() and SetCamera(string) method of Viewpoint class. What you are manipulating with these two methods is a simple JSON string, so if you could save your markups as JSON as well, you could write markup and viewpoint info to disk for later usage. Actually I save them to a SQLite db file.

 

Reference for Viewpoint camera JSON (I didn't write this): https://twentytwo.space/2021/06/02/navisworks-api-viewpoint-part-2/

 

Here's what I've achieved: when I drop a markup on a model item, the current viewpoint is saved and a thumbnail is generated. By double clicking the thumbnail, I can restore the view.

 

Message 5 of 6

alexisDVJML
Collaborator
Collaborator

Very Nice 👏

Quick questions:
- you say you use SQLite db, are you using the embedded SQLite db associated with each Naviswork ,nwf. I found it very convenient to store small hidden infos for our plugin. No need to link my application with a SQLite library and this db is actually embedded into the .nwf  [extracted on open, so can even be viewed/manually edited with an app like "DB Browser for SQLite) and stored back on save I think]
- do you handle updating the snapshots? wondering if these snapshots could be generated dynamically or even replaced with an extra navisworks view??

Main Scientist, Full Stack Developer & When Time Permits Director of IDIGO ► On your marks, Set, Go
0 Likes

Very Nice 👏

Quick questions:
- you say you use SQLite db, are you using the embedded SQLite db associated with each Naviswork ,nwf. I found it very convenient to store small hidden infos for our plugin. No need to link my application with a SQLite library and this db is actually embedded into the .nwf  [extracted on open, so can even be viewed/manually edited with an app like "DB Browser for SQLite) and stored back on save I think]
- do you handle updating the snapshots? wondering if these snapshots could be generated dynamically or even replaced with an extra navisworks view??

Main Scientist, Full Stack Developer & When Time Permits Director of IDIGO ► On your marks, Set, Go
Message 6 of 6
cation234ctci
in reply to: alexisDVJML

cation234ctci
Participant
Participant

Hi Alexis, regarding your questions:

 

Since the nwd files in my company are updated frequently, I choose external SQLite files for data storage, so yeah I have to link additional SQLite library. The embedded DB of nwd file is very cool, I even find them amazing, but so far I haven't done any work with it.

 

The snapshots are generated with the function: Bitmap View.GenerateImage(ImageGenerationStyle style, int width, int height), and by calling Viewpoint.GetCamera() again, a snapshot is updated. I believe the Export Image button on the Viewpoint tab of Navisworks ribbon is using the same View.GenerateImage function.

 

The Viewpoint.GetCamera() is so convenient that I can, in fact, associate multiple viewpoints with one markup. By "extra Naviswork view", I assume you are talking about something like the Split View on the View tab. I believe it is possible, but it will be way more complicated than handling simple GetCamera JSON string.

 

Hi Alexis, regarding your questions:

 

Since the nwd files in my company are updated frequently, I choose external SQLite files for data storage, so yeah I have to link additional SQLite library. The embedded DB of nwd file is very cool, I even find them amazing, but so far I haven't done any work with it.

 

The snapshots are generated with the function: Bitmap View.GenerateImage(ImageGenerationStyle style, int width, int height), and by calling Viewpoint.GetCamera() again, a snapshot is updated. I believe the Export Image button on the Viewpoint tab of Navisworks ribbon is using the same View.GenerateImage function.

 

The Viewpoint.GetCamera() is so convenient that I can, in fact, associate multiple viewpoints with one markup. By "extra Naviswork view", I assume you are talking about something like the Split View on the View tab. I believe it is possible, but it will be way more complicated than handling simple GetCamera JSON string.

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Rail Community


 

Autodesk Design & Make Report