Draw a text dot...?


#1

I would like to display a temporary text dot while I’m looping through some code… I found

Rhino.Display.DisplayPipeline.DrawDot Method (Point3d, String)

but I don’t know how to implement it… This doesn’t need to be dynamic, just display at a certain point and then disappear again… Right now I’m just adding the text dot to the document and deleting it again, but I would like to know how to do this only in the display…

Edit: as an auxiliary question, to add a text dot to the document, we have

sc.doc.Objects.AddTextDot(td,attrs)

and I can attribute a color other than the active layer color by using

attrs=Rhino.DocObjects.ObjectAttributes()
attrs.ObjectColor=System.Drawing.Color.Somecolor

But how do I attribute a text color to the dot? It seems it should be possible…

DisplayPipeline.DrawDot Method (Point3d, String, Color, Color)

(the second color being the text color)

Thanks, --Mitch


(Menno Deij - van Rijswijk) #2

This can be used from a DisplayConduit. If you derive your class from DisplayConduit and override the method DrawForeground, you get a DisplayPipeline object to call drawing routines on.


#3

Example to use DisplayConduit for Mesh:

If needed ofcourse :wink:

Easily edited for other use like this.


#4

All that looks far too complicated for the 3 brain cells I have left…

–Mitch


#5

Here’s an Example in Vb.net

Imports System
Imports System.Collections.Generic
Imports Rhino
Imports Rhino.Commands
Imports Rhino.Geometry
Imports Rhino.Input
Imports Rhino.Input.Custom
Imports Rhino.Display
Imports System.Drawing

Namespace TextDotTest

    <System.Runtime.InteropServices.Guid("5550f864-5075-4ed4-9fa3-97b0c60bbd7e")> _
    Public Class TextDotTestCommand
        Inherits Command

        Shared _instance As TextDotTestCommand

        Public Sub New()
            ' Rhino only creates one instance of each command class defined in a
            ' plug-in, so it is safe to store a refence in a static field.
            _instance = Me
        End Sub

        '''<summary>The only instance of this command.</summary>
        Public Shared ReadOnly Property Instance() As TextDotTestCommand
            Get
                Return _instance
            End Get
        End Property

        '''<returns>The command name as it appears on the Rhino command line.</returns>
        Public Overrides ReadOnly Property EnglishName() As String
            Get
                Return "TextDotTestCommand"
            End Get
        End Property

        Protected Overrides Function RunCommand(ByVal doc As RhinoDoc, ByVal mode As RunMode) As Result

            Dim MyTextDot As New TextDot("Text", New Point3d(0, 0, 0))

            Dim conduit = New DrawBlueMeshConduit(MyTextDot)
            conduit.Enabled = True

            doc.Views.Redraw()

            Dim inStr As String = ""
            Rhino.Input.RhinoGet.GetString("press <Enter> to continue", True, inStr)

            conduit.Enabled = False
            doc.Views.Redraw()

            Return Result.Success
        End Function
    End Class

    Class DrawBlueMeshConduit
        Inherits DisplayConduit
        Private _TextDot As TextDot = Nothing
        Private _bbox As BoundingBox

        Public Sub New(ByVal TextDot As TextDot)
            _TextDot = TextDot
            If _TextDot IsNot Nothing AndAlso _TextDot.IsValid Then
                _bbox = _TextDot.GetBoundingBox(True)
            End If
        End Sub

        Protected Overrides Sub CalculateBoundingBox(ByVal e As CalculateBoundingBoxEventArgs)
            MyBase.CalculateBoundingBox(e)
            e.BoundingBox.Union(_bbox)
        End Sub

        Protected Overrides Sub PreDrawObjects(ByVal e As DrawEventArgs)
            MyBase.PreDrawObjects(e)
            Dim vp = e.Display.Viewport
            e.Display.DrawDot(_TextDot.Point, _TextDot.Text, Color.Black, Color.White)
        End Sub
    End Class

End Namespace

Cheers


(Dale Fugier) #6

And a Rhino.Python sample:

import scriptcontext
import rhinoscriptsyntax as rs
import Rhino

class DrawTextDotsConduit(Rhino.Display.DisplayConduit):
    def __init__(self, points):
        self.points = points
        self.bbox = Rhino.Geometry.BoundingBox()
        for point in points:
            self.bbox.Union(point)
    def CalculateBoundingBox(self, e):
        e.IncludeBoundingBox(self.bbox)
    def DrawOverlay(self, e):
        for point in self.points:
            e.Display.DrawDot(point, point.ToString())

def DrawTextDots():
    points = rs.GetPoints()
    if points:
        conduit = DrawTextDotsConduit(points)
        conduit.Enabled = True
        scriptcontext.doc.Views.Redraw()
        rs.GetString("Press <Enter> to continue")
        conduit.Enabled = False
        scriptcontext.doc.Views.Redraw()
 
if __name__=="__main__":
    DrawTextDots()

#7

Well, I really don’t understand all of what is happening here, mostly due to my lack of understanding of classes.

I don’t know how to get my text - created outside the conduit - into it and have it draw… I seem to be able to get the argument inside the Class, but not into the DrawOverlay def…

Also what I really don’t understand is what the bounding box stuff in there is supposed to be doing or why it is needed.

The following runs, but nothing is drawn… I must need a 4th brain cell to figure this out…

import scriptcontext as sc
import rhinoscriptsyntax as rs
import Rhino

class DrawTextDotsConduit(Rhino.Display.DisplayConduit):
    def __init__(self,point,dirName):
        self.point = point
        self.dirName = dirName
        self.bbox = Rhino.Geometry.BoundingBox()
        self.bbox.Union(point)
    def CalculateBoundingBox(self, e):
        e.IncludeBoundingBox(self.bbox)
    def DrawOverlay(self, e):
       e.Display.DrawDot(point, dirName)

def LookInDirection():
    compass=["North","Northwest","West","Southwest","South","Southeast","East","Northeast"]
    zVec=Rhino.Geometry.Vector3d(0,0,1)
    tarPt=Rhino.Geometry.Point3d(0,0,0)
    camPt=Rhino.Geometry.Point3d(0,-100,50)
    ang_inc=45.0
    xFormR=rs.XformRotation2(ang_inc,zVec,tarPt)
    rs.ViewCameraTarget(camera=camPt,target=tarPt)
    for i in range(8):
        conduit = DrawTextDotsConduit(tarPt,compass[i])
        conduit.Enabled = True
        sc.doc.Views.Redraw()
        rs.GetString("Looking {}, press <Enter> for next view".format(compass[i]))
        conduit.Enabled = False
        camPt=rs.PointTransform(camPt,xFormR)
        rs.RotateView(rs.CurrentView(),1,ang_inc)
        sc.doc.Views.Redraw()

if __name__=="__main__":
    LookInDirection()

Test file: dirTest.3dm (445.6 KB)


#8

Can’t seem to find the error.
If I first run your dale’s command it works.
Then I run helvetosaurs. Nothing. only the rotation.
If i then run dale’s again. Then it won’t show anymore…

Is it a bug?


(Willem Derks) #9

Hi Mitch,

Useful challenge! I found this online to have a basic explanation of classes:
http://www.jesshamrick.com/2011/05/18/an-introduction-to-classes-and-inheritance-in-python/

After trying myself I found that you need to adres the variables point and dirName within the class as self.point and self.dirName

def DrawOverlay(self, e):
   e.Display.DrawDot(self.point, self.dirName)

-Willem


#10

Thats it Willem :smile:

working here now:

import scriptcontext as sc
import rhinoscriptsyntax as rs
import Rhino

class DrawTextDotsConduit(Rhino.Display.DisplayConduit):
    def __init__(self,point,dirName):
        self.point = point
        self.dirName = dirName
        self.bbox = Rhino.Geometry.BoundingBox()
        self.bbox.Union(point)
    def CalculateBoundingBox(self, e):
        e.IncludeBoundingBox(self.bbox)
    def DrawOverlay(self, e):
       e.Display.DrawDot(self.point, self.dirName)

def LookInDirection():
    compass=["North","Northwest","West","Southwest","South","Southeast","East","Northeast"]
    zVec=Rhino.Geometry.Vector3d(0,0,1)
    tarPt=Rhino.Geometry.Point3d(0,0,0)
    camPt=Rhino.Geometry.Point3d(0,-100,50)
    ang_inc=45.0
    xFormR=rs.XformRotation2(ang_inc,zVec,tarPt)
    rs.ViewCameraTarget(camera=camPt,target=tarPt)
    for i in range(8):
        conduit = DrawTextDotsConduit(tarPt,compass[i])
        conduit.Enabled = True
        sc.doc.Views.Redraw()
        rs.GetString("Looking {}, press <Enter> for next view".format(compass[i]))
        conduit.Enabled = False
        camPt=rs.PointTransform(camPt,xFormR)
        rs.RotateView(rs.CurrentView(),1,ang_inc)
        sc.doc.Views.Redraw()

if __name__=="__main__":
    LookInDirection() 

#11

Hmm, is it drawing something on your end? Here it doesn’t…

Ah, wait, if I close Rhino and reopen, it does work! Thanks for the input!

I had also noticed when running Dale’s sample is that if something goes wrong with the script and it bails out early, the conduit seems to get stuck as “enabled” and the previous display always shows… in this case nothing… How do you “destroy” a stuck conduit?

As far as Python Classes go - I did have a class with Classes once… :smile: But it’s been like 3 years, and having not used them since, I have forgotten all… Have to get out my textbook again… Well, this is as good a time as any for my __init__ in classes…

–Mitch


#12

What’s cool about this is that you can have a dot with a custom type color - not possible with a normal dot… Unfortunately, not (yet) transparent - passing an ARGB color with A=0 does not create transparency - but I can imagine it’s coming…

    def DrawOverlay(self, e):
       dcolor=System.Drawing.Color.FromArgb(255,70,70,70)
       tcolor=System.Drawing.Color.FromArgb(255,255,0,0)
       e.Display.DrawDot(self.point, self.dirName, dcolor, tcolor)

Also, with the conduit-drawn dots, you cannot (yet) control the size/typeface as you can with “real” object dots.

Going to have to experiment with drawing 2D and 3D text objects now… Both work! In fact drawing 2D text is better than a dot for my current application…

–Mitch


#13

It’s also a good solution to show a result and let the user Accept or Decline the adjustment on an object. (for my workfield atleast) :stuck_out_tongue:


#14

So my 2D text conduit is working pretty well… :thumbsup: Thanks to all!

Small excerpt

–Mitch


(Willem Derks) #15

Hi Mitch, All

FWIW:

I found some of the documentation about Display.Pipeline:
http://4.rhino3d.com/5/rhinocommon/?topic=html/N_Rhino_Display.htm

Notice how you can also Pre/PostDrawObjects, That was very usefull for me as I am drawing points obscured by objects in front (when applicable) with DrawOverlay they were always visible.

-Willem