Snap object in mouse input
-
On 09/01/2013 at 11:48, xxxxxxxx wrote:
What about trying it yourself?
Slight tip: The dictionary returned by GeRayCollider.GetNearestIntersection() contains information
like what polygon was interesected. You can then compute the normal of that polygon and rotate
the destination object accordingly.@ littledevil :
Well, we don't want the closes point on the surface, do we? I'm sorry, I don't see why the green
line is the one we would like to use instead of the red line.. :// I also don't get how you would
come to that green line, I don't see any relation to the camera position or view-direction or similar.Hope that doesn't sound offending or so, because that was not my intention. I always
appreciate constructive criticism or questions.
Best,
-Niklas -
On 09/01/2013 at 12:13, xxxxxxxx wrote:
NiklasR we are successful! Thank you for your precious help
-
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 Truedef 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 Trueop = doc.GetActiveObject()
op_next = self.linkBox.GetLink()
if not op_next:
return Truewin.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 += dycursorpos = 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 = cursorposdoc.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() -
On 12/01/2013 at 07:22, xxxxxxxx wrote:
try :
op_next = self.linkBox.GetLink(c4d.documents.GetActiveDocument(), c4d.Obase)
-
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 meThanks littledevil, you are a generous person, always ready to help all friends in this forum
-
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. -
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 helpimport 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())
-
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) :
-
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!!!!!!!
-
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 = 0cam_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 = cursorposdoc.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
-
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 - restif rest / float(step) >= 0.5:
on_grid += stepreturn 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 ?
-
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
-
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