Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Snap object in mouse input

    PYTHON Development
    0
    25
    15.9k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 09/01/2013 at 12:13, xxxxxxxx wrote:

      NiklasR we are successful!🤝  Thank you for your precious help 🍺🍺

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 12/01/2013 at 03:43, xxxxxxxx wrote:

        i have modified the  **op_next  **with Linkbox but... no work...
        The object is not recognized...

        I've never had much luck with the linkbox 😂

        MY_LINKBOX = 100014

        def CreateLayout(self) :
                self.GroupBegin(id=1000, flags=c4d.BFH_SCALEFIT, cols=1, rows=1)
                self.GroupBorderSpace(10, 10, 10, 10)
                self.element = self.AddStaticText(id=1001, flags=c4d.BFH_MASK, initw=120, name="Inserire Oggetto:", borderstyle=c4d.BORDER_NONE)
                self.linkBox = self.AddCustomGui(MY_LINKBOX, c4d.CUSTOMGUI_LINKBOX, "", c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 0, 0)
                self.GroupEnd()
                return True

        def MouseInput(self, doc, data, bd, win, msg) :
                mx = msg[c4d.BFM_INPUT_X]
                my = msg[c4d.BFM_INPUT_Y]
         
                device = 0
                if msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSELEFT:
                    device = c4d.KEY_MLEFT
                elif msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSERIGHT:
                     device = c4d.KEY_MRIGHT
                else:
                    return True

        op = doc.GetActiveObject()
                op_next = self.linkBox.GetLink()
                if not op_next:
        return True

        win.MouseDragStart(button=device, mx=int(mx), my=int(my), flags=c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE)
                result, dx, dy, channel = win.MouseDrag()
                while result==c4d.MOUSEDRAGRESULT_CONTINUE:
                    mx += dx
                    my += dy

        cursorpos = bd.SW(c4d.Vector(mx,my,500))     #screen to world conversion

        cam_pos = bd.GetSceneCamera(doc).GetAbsPos()
                    collider = c4d.utils.GeRayCollider()
                    collider.Init(op_next)

        length = 500000
                    direction = -(cam_pos - cursorpos).GetNormalized()

        did_intersect = collider.Intersect(cam_pos, direction, length)
                    if did_intersect:
                        position = collider.GetNearestIntersection()["hitpos"]
                        print "Intersection at", position
                    else:
                        print "No intersection."
                        position = cursorpos

        doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                    op.SetAbsPos(position)
                    op.Message(c4d.MSG_UPDATE)

        c4d.DrawViews(c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_ANIMATION)
                    result, dx, dy, channel = win.MouseDrag()

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 12/01/2013 at 07:22, xxxxxxxx wrote:

          try :

          op_next = self.linkBox.GetLink(c4d.documents.GetActiveDocument(), c4d.Obase)
          
          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 12/01/2013 at 09:11, xxxxxxxx wrote:

            Originally posted by xxxxxxxx

            try :

            op_next = self.linkBox.GetLink(c4d.documents.GetActiveDocument(), c4d.Obase)

            "object has no attribute 'linkBox'"....  
            I am beginning to think that linkbox they hate me 😂

            Thanks littledevil, you are a generous person, always ready to help all friends in this forum 👍

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 12/01/2013 at 10:37, xxxxxxxx wrote:

              could be some kind of call order problem. try something like this

              class myclass(c4d.Something) :
              	def __init__(self) :
              		self.linkBox = None
              	
              	def CreateLayout(self, *args) :
              		self.linkBox = Something
              	
              	def AnotherMethod(self) :
              		if (not self.linkBox) :
              			return False
              		else:
              			x = self.linkBox.Do(blah)
              

              MouseInput might be called the first time before CreateLayout has been called and as you 
              haven't defined linkBox as a variable in the class constructor it does not yet exist at that point.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 12/01/2013 at 12:08, xxxxxxxx wrote:

                littledevil, i have pasted the entire code. 
                You can control it and correct it?
                I would like to understand where I'm wrong ...
                Thanks for your help 🍺

                import os
                import sys
                import c4d
                from c4d import plugins, utils, bitmaps, gui, documents
                 
                PLUGIN_ID = 10000008 # THIS id IS FOR TESTING PUPOSES ONLY!!!
                 
                #for GeLoadString values must match with the header file
                IDS_ESTENSIONE = 100000
                MY_LINKBOX = 100015
                  
                  
                class SettingsDialog(gui.SubDialog) :
                 
                 
                    def CreateLayout(self) :
                        self.GroupBegin(id=1000, flags=c4d.BFH_SCALEFIT, cols=1, rows=1)
                        self.GroupBorderSpace(10, 10, 10, 10)
                        self.element = self.AddStaticText(id=1001, flags=c4d.BFH_MASK, initw=120, name="Inserire Oggetto:", borderstyle=c4d.BORDER_NONE)
                 **        self.linkBox = self.AddCustomGui(MY_LINKBOX, c4d.CUSTOMGUI_LINKBOX, "", c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, 0, 0)**
                  
                		
                		
                        self.GroupEnd()
                        return True
                    def InitValues(self) :
                        
                        return True
                 
                    def Command(self, id, msg) :
                 
                        return True
                 
                class Caleidos(plugins.ToolData) :
                  
                    def __init__(self) :
                        self.data = 0
                  
                    def KeyboardInput(self, doc, data, bd, win, msg) :
                        key = msg.GetLong(c4d.BFM_INPUT_CHANNEL)
                        cstr = msg.GetString(c4d.BFM_INPUT_ASC)
                        if key==c4d.KEY_ESC:
                            #do what you want            
                            #return True to signal that the key is processed
                            return True
                        return False
                 
                 
                    def MouseInput(self, doc, data, bd, win, msg) :
                	
                		if msg.GetLong(c4d.BFM_INPUT_CHANNEL)==c4d.BFM_INPUT_MOUSELEFT:
                			print "Begin Mouse Left Pressed"
                			while True:
                			
                				bc = c4d.BaseContainer()
                				if gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, bc) :
                					if bc.GetLong(c4d.BFM_INPUT_CHANNEL)==c4d.BFM_INPUT_MOUSELEFT:
                						print "Mouse Left Pressed"
                			
                						mx = msg[c4d.BFM_INPUT_X]
                						my = msg[c4d.BFM_INPUT_Y]
                				 
                						device = 0
                						if msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSELEFT:
                							device = c4d.KEY_MLEFT
                						elif msg[c4d.BFM_INPUT_CHANNEL]==c4d.BFM_INPUT_MOUSERIGHT:
                							 device = c4d.KEY_MRIGHT
                						else:
                							return True
                  
                							
                						doc.GetActiveObject()
                						doc.StartUndo() 
                						myobject = **self.linkBox.GetLink()**
                  
                  
                						op = myobject
                						op_next = doc.GetActiveObject()
                						
                						win.MouseDragStart(button=device, mx=int(mx), my=int(my), flags=c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE)
                						result, dx, dy, channel = win.MouseDrag()
                						while result==c4d.MOUSEDRAGRESULT_CONTINUE:
                							mx += dx
                							my += dy            
                  
                							cursorpos = bd.SW(c4d.Vector(mx,my,500))     #screen to world conversion
                							cam_pos = bd.GetSceneCamera(doc).GetAbsPos()
                							collider = c4d.utils.GeRayCollider()
                							collider.Init(op_next)
                							length = 500000
                							direction = -(cam_pos - cursorpos).GetNormalized()
                							did_intersect = collider.Intersect(cam_pos, direction, length)
                							if did_intersect:
                								position = collider.GetNearestIntersection()["hitpos"]
                								print "Intersection at", position
                							else:
                								print "No intersection."
                								position = cursorpos
                							doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                							op.SetAbsPos(position)
                							op.Message(c4d.MSG_UPDATE)  
                							c4d.DrawViews(c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_ANIMATION)
                							result, dx, dy, channel = win.MouseDrag()
                   						if not bc.GetBool(c4d.BFM_INPUT_VALUE) : break
                			print "End Mouse Left Pressed"
                    def AllocSubDialog(self, bc) :
                        return SettingsDialog(self.data) #always return new instance(self.data)
                 
                 
                  
                if __name__ == "__main__":
                    bmp = bitmaps.BaseBitmap()
                    dir, file = os.path.split(__file__)
                    fn = os.path.join(dir, "res", "Icon.tif")
                    bmp.InitWith(fn)
                    plugins.RegisterToolPlugin(id=PLUGIN_ID, str="Caleidos",info=0, icon=bmp, help="Statusbar Text",dat=Caleidos())
                  
                
                
                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 12/01/2013 at 13:03, xxxxxxxx wrote:

                  this obviously won't work. i think you do not really understand what self means in python.
                  it is similar to this in c# or java. it is a referecne to the actual instance of the class from which
                  the code is being executed from. you are doing more or less this :

                  class clsA() :
                  	def __init__(self, x) :
                  		self.X = x
                    
                  class clsB() :
                  	def someMethod() :
                  		# raises a runtime error as class b does not have a memeber called X
                  		print self.X
                  

                  you have either make your dialog class instance a globally available variable (but this
                  could be considered as really bad style) :

                  class clsA() :
                      def __init__(self, x) :
                          self.X = x
                    
                  class clsB() :
                      def do (self, classAinstance) :
                          print classAinstance.X
                         
                  def main() :
                      A = clsA()
                      B = clsB()
                      B.do(A)
                  

                  or you have to make an instance of your GeDialog class a memeber of your
                  ToolData class.

                  class ToolDataClass() :
                      def __init__(self) :
                          self.dialog = None
                          self.data = None
                      
                      def doSomething(self) :
                          if (self.dialog) :
                              print self.Dialog.linkBox.GetLink(document, c4d.Obase)
                          else:
                              print 'dialog has not been raised yet.'
                          
                      def AllocSubDialog(self, bc) :
                          self.Dialog = SettingsDialog(self.data)
                          return self.Dialog
                  

                  edit : fixed a typo,  should be if (self.dialog) : of course and not if(self.data) :

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 12/01/2013 at 14:28, xxxxxxxx wrote:

                    Originally posted by xxxxxxxx

                    or you have to make an instance of your GeDialog class a memeber of your
                    ToolData class.

                    class ToolDataClass() :
                        def __init__(self) :
                            self.dialog = None
                            self.data = None
                        
                        def doSomething(self) :
                            if (self.dialog) :
                                print self.Dialog.linkBox.GetLink(document, c4d.Obase)
                            else:
                                print 'dialog has not been raised yet.'
                            
                        def AllocSubDialog(self, bc) :
                            self.Dialog = SettingsDialog(self.data)
                            return self.Dialog
                    

                    edit : fixed a typo,  should be if (self.dialog) : of course and not if(self.data) :

                    Work!!! I succeeded! littledevil Thanks!!!!!!! 🤝

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 19/07/2013 at 09:28, xxxxxxxx wrote:

                      Originally posted by xxxxxxxx

                      You need to use the c4d.utils.GeRayCollider class to find an intersection on the surface of the
                      destination-object, intersected by the line defined by the mouse-position in global space and
                      the camera position.

                      op = doc.GetActiveObject()
                            op_next = op.GetNext()
                            if not op_next:
                                return True

                      # Convert op_next to a polygon object.
                            # Simplified here, just for demonstration purpose.
                            op_next = op_next.GetCache()
                            if not op_next or not op_next.CheckType(c4d.Opolygon) :
                                print "Cache is not existent or is not a polygon object."
                                return True
                           
                            win.MouseDragStart(button=device, mx=int(mx), my=int(my), flags=c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE)
                            result, dx, dy, channel = win.MouseDrag()
                            while result==c4d.MOUSEDRAGRESULT_CONTINUE:
                                mx += dx
                                my += dy            
                       
                                cursorpos = bd.SW(c4d.Vector(mx,my,500))     #screen to world conversion
                                if(axis == 1) :
                                    cursorpos.x = 0
                                elif(axis == 2) :
                                    cursorpos.y = 0                          #Constrain drawing along an axis based on the comboButton's value
                                elif(axis == 3) :
                                    cursorpos.z = 0

                      cam_pos = bd.GetSceneCamera(doc).GetAbsPos()
                                collider = c4d.utils.GeRayCollider()
                                collider.Init(op_next)

                      length = 500000
                                direction = -(cam_pos - cursorpos).GetNormalized()

                      did_intersect = collider.Intersect(cam_pos, direction, length)
                                if did_intersect:
                                    position = collider.GetNearestIntersection()['hitpos']
                                    print "Intersection at", position
                                else:
                                    print "No intersection."
                                    position = cursorpos

                      doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
                                op.SetAbsPos(position)
                                op.Message(c4d.MSG_UPDATE)

                      c4d.DrawViews(c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_ANIMATION)
                                result, dx, dy, channel = win.MouseDrag()

                      -Nik

                      an example for snap on point object? thanks 🙂

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 30/08/2013 at 07:08, xxxxxxxx wrote:

                        Originally posted by xxxxxxxx

                        What do you mean with "the snap does not work"? You are not even trying to snap the
                        object, just setting it to the cursor position.

                        joint.SetAbsPos(cursorpos)

                        If you want to to snap to a grid with a spacing of 50 units (just for the sake of example), you
                        need to adjust the position vector.

                        def snap_value(value, step) :
                              rest = value % step
                              on_grid = value - rest

                        if rest / float(step) >= 0.5:
                                  on_grid += step

                        return on_grid

                        def snap_grid(vector, gridsize) :
                              vector = c4d.Vector(vector)
                              vector.x = snap_value(vector.x, gridsize)
                              vector.y = snap_value(vector.y, gridsize)
                              vector.z = snap_value(vector.z, gridsize)
                              return vector

                        # ...

                        gridsize = 50
                          position = snap_grid(cursorpos)
                          joint.SetAbsPos(position)

                        See the full code here.

                        -Niklas

                        HI NiklasR How do you adjust the cursor position for snap points ? 🙂

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 08/09/2013 at 16:07, xxxxxxxx wrote:

                          Originally posted by xxxxxxxx

                          an example for snap on point object? thanks 🙂

                          Assuming you have a coordinate in 3D space, you can just use the nearest mesh point and maybe
                          check if the point is within the snap radius.

                              import c4d
                          
                              
                          
                              def snap_point(point, radius, obj) :
                          
                                  """
                          
                                  Calculate the snapping point from a coordinate in 3D space
                          
                                  to a point object within the defined \*radius\*. Requires
                          
                                  the \*point\* in global space.
                          
                                  """
                          
                              
                          
                                  mg = obj.GetMg()
                          
                                  points = obj.GetAllPoints()
                          
                                  point = ~mg \* point
                          
                                  radius \*\*= 2
                          
                              
                          
                                  nearest = None
                          
                                  for p in points:
                          
                                      delta = (p - point).GetLengthSquared()
                          
                                      if delta <= radius and (not nearest or nearest[1] > delta) :
                          
                                          nearest = p, delta
                          
                              
                          
                                  if nearest:
                          
                                      point = nearest[0]
                          
                                  return point
                          
                              
                          
                              def main() :
                          
                                  p = c4d.Vector(102, 99, 97)
                          
                                  print snap_point(p, 10, op)
                          
                              
                          
                              main()
                          
                            
                          
                          
                          Best regards,
                          
                          -Niklas
                          
                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 08/09/2013 at 16:10, xxxxxxxx wrote:

                            Originally posted by xxxxxxxx

                            HI NiklasR How do you adjust the cursor position for snap points ? 🙂

                            You can not "adjust" the cursor position, the cursor is where the mouse points it to. There is also
                            a snapping mode for snapping to object points, so what exactly do you need?

                            Cheers,
                            -Niklas

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post