Camera Rays wanted
-
Quick and dirty one-liner for the Ruby Console:
model=Sketchup.active_model;c=model.active_view.camera;model.entities.add_cpoint(c.eye);model.entities.add_cline(c.eye,c.direction)
-
oh wait.... that might not be what you asked for... hmm... ok... need to sober up.
-
@thomthom said:
oh wait.... that might not be what you asked for... hmm... ok... need to sober up.
Close though. It adds a construction line from the camera through the center of the camera view (c.direction), so it has the basic pieces.
I want a line through wherever I click with the cursor, or wherever the cursor is when I press a hotkey. I think that should be doable.
Worst case, I would select an existing (maybe temporary) endpoint, but a click in empty space should provide sufficient information.
How do I get the direction from the camera to the cursor or to a cursor click? Ideally, it's starting to sound like I would need to create a new tool that accepts the mouse click.
But a quick-and-dirty should be doable for a selected emdpoint. How to I get the direction from the camera to a selected point?
-
It does not entirely make sense based on the description of what you need it for. But you just want a tool that draws a line from the camere eye to a point you click on? Here is a one-liner that will do jsut that. I even made it use inferencing and draw the inference dots onto the screen for you. Let me know if this is not what you had in mind. OH, and one note about the script. The line that is drawn is not visible until you shift the camera because it is shooting exactly out of the location of the camera, in the direction the camera is looking. So run the code, then lick where you want and orbit to see the line that was drawn. If you need this script to be more easily accessible, I can put it into a menu.
class Clf_august_lines;def onMouseMove(flags, x, y, view);@ip = view.inputpoint(x,y);view.invalidate;end;def onLButtonUp(flags, x, y, view);Sketchup.active_model.active_entities.add_line(@ip.position, view.camera.eye);end;def draw(view);@ip.draw view;end;end;Sketchup.active_model.select_tool(Clf_august_lines.new)
And remember, this is a single line of code and should be pasted into the ruby console.
Chris
-
Thanks Chris,
@chris fullmer said:
It does not entirely make sense based on the description of what you need it for.
I had a hunch that my description of how to use it to visualize where the polyline should go, based on projecting between the camera and the background/watermark, might be a little confusing. I kept getting confused just trying to visualize it enough to place guide planes to draw on.
@unknownuser said:
But you just want a tool that draws a line from the camere eye to a point you click on?
Actually, I asked for a construction line, not "a line". But a line to an existing something was a fall-back and I'll take what I can get.
Thomthom's version creates a
cline
usingcamera.eye
for a point andcamera.direction
for a vector.At first I thought that I might be able to just change
add_line
toadd_cline
. My thought was thatview.inputpoint(x,y).position
might be a vector because it takes screen coordinatesx,y
, but a line cannot be drawn using a vector and a point as arguments, it will need two two points, so for@ip.position
to be a point, thenview.inputpoint(x,y)
must return the 3D position of whatever is under the mouse at screen positionx,y
.A
cline
would definitely be preferable, so I would need a function that returns anx,y
screen direction from the camera from a 3D postion returned byview.inputpoint
. Or maybe there's a method forview
that does that in one step. Thinking about it another second or two, a method ofview
usingx,y
makes sense, and then I would not need an object under the cursor just to throw away itsz
position.I'll look up
view
methods (unless you have it at your fingertips?)@unknownuser said:
Here is a one-liner that will do just that.
Thank you. I'll give it a try.
@unknownuser said:
I even made it use inferencing and draw the inference dots onto the screen for you.
Is that the
onMouseMove
function? I don't grok the@
, is an operator or a convention or what?@unknownuser said:
Let me know if this is not what you had in mind.
Not having tested it yet, it looks like it's getting most of the way there. It does not look like it draws a ray into empty space but rather requires something to exist under the mouse, but either I can recode that or just put in a bunch of temporary lines and use their endpoints.
@unknownuser said:
OH, and one note about the script. The line that is drawn is not visible until you shift the camera because it is shooting exactly out of the location of the camera, in the direction the camera is looking. So run the code, then lick where you want and orbit to see the line that was drawn.
The need to orbit makes lots of sense. That's where I would be using the results.
@unknownuser said:
If you need this script to be more easily accessible, I can put it into a menu.
There are examples of adding functions to menus in the
Examples/*.rb
provided by Google and elsewhere. You can leave this as "an exercise for the student" unless you get inspired. If I get stuck, I'll ask. I'm sure there are lots of folks who can help with that piece.@unknownuser said:
And remember, this is a single line of code and should be pasted into the ruby console.
I've saved it as [ruby:3qi7vzlz]Plugins/ray[/ruby:3qi7vzlz], no [ruby:3qi7vzlz].rb[/ruby:3qi7vzlz] suffix. I think I can just type "[ruby:3qi7vzlz]load ray[/ruby:3qi7vzlz]" or "[ruby:3qi7vzlz]run ray[/ruby:3qi7vzlz]" in the console. I also added line breaks and indents so I can follow it. I couldn't remember if Ruby requires semi-colons at statement/commend line ends, but I seem to recall that they are optional, Ruby being a very Tim Toady (TIMTOWTDI) kind of language, so I left them in.
If my comments above make sense to you, or anyone, and you get inspired or just feel like playing (if it's play for you) please feel free.
I probably won't be picking this up for a few days. I'm flying to Denver on Sunday (with Saturday being the day before Mother's Day, there are NO seats available) in hopes of getting to Colorado Springs before my Mother passes. She appears to have had a stroke this morning and was already not well.
Thanks again, Chris and Thomthom, and I will be checking back later.
August
-
You can substitute
add_line
withadd_cline
as they both take two points.
[Glad to see Chris is using my single-line snippet method - although yourload'ray'
idea is good] -
Thanks TIG,
@tig said:
You can substitute
add_line
withadd_cline
as they both take two points.
[Glad to see Chris is using my single-line snippet method - although yourload'ray'
idea is good]Thank you.
I finally remembered that (obviously) I needed quotes around the file name. I changed the filename to
ray.txt
so that I can open it quicker for editing instead of always having to pick my text editor from a menu.After the string (the above or Chris's or Thomthom's long single-line snippet) is in the console window, then changing to the new tool is a simple matter of clicking on the Ruby Console, pressing Up Arrow and hitting return. The tool is active until I select another tool.
That's a pretty easy UI for being able to use a temporary tool. The minimum size of the Ruby Console does tend to get in the way a bit.
I've attached an image that has both
_line
s and_cline
s.When I asked for "construction lines" I had in mind the kind of "infinite" lines you get from the Tape Measure tool. ThomThom's
_cline
s are like that, with the addition of a construction point at the camera location. Substituting_cline
for_line
in Chris's version produces clines' that are finite at both ends.There is a big difference in the operation between
_line
s and_cline
s. Using_line
s, if there is no object, the inference will be to the ground plane below the horizon or to the red/blue plane or the green/blue plane above the horizon. If there is an object,_line
s can reference a surface.In essence, the inference point is wherever the Rectangle tool might try to place a corner or where the Rotate tool might try to place its center.
Using
_cline
s, the inferences can only be to the axes or to the edges of an object,_cline
s do not appear to be able to reference a surface.So that limits the
_line
version to the nearest "octant" (half a quadrant) and limits the_cline
version even more.I can work with either at this point, simply by placing surfaces or edges out past my working target area/space that can be used for inferences.
In the long run, for other situations where I have wanted a tool like this (e.g., some tricky PhotoMatch problems like tree trunks), I'll probably want infinite
_cline
s (at least one way, but it seems I have a choice between 2-way infinite or two-ended).I think that's going to mean getting an
x,y
,c.eye
-to-screen vector fromview
as I suggested previously. A point and anx,y
vector worked in Thomthom's quick version so that should allow me to generate_cline
s whether or not there is an edge to inference.Thanks again for all the help. Banging around on this is a nice distraction.
August
-
If you give the second argument for
add_cline
as avector
it will be infinite in that direction, so
vector = point1.vector_to(point2) add_cline(point1,vector)
makes a cline that starts at point1 but be infinite otherwise, whereas
add_cline(point1,poin2)
will be a cline between those two points.
To make it infinite in both directions use
cl=entities,add_cline(point1,vector) cl.start=nil
or to make it infinite from an end point towards the 'start' use
cl=add_cline(point1,poin2) cl.start=nil
... -
@tig said:
If you give the second argument ... starts at point1 but be infinite otherwise, ... make it infinite in both directions ... or to make it infinite from an end point towards the 'start' ...
Thanks TIG,
Chris' methodology will give me the two points, your info about using
nil
will let me get an infinite line (so it doesn't matter aboutview
), and I have a workable UI without worrying about menus.That gives me lots of stuff to experiment with plus an expectation that I'll be back to my drawing project quickly.
So I'll take a moment to get back to what this is for. I did not explain it well the first time and Chris was probably not the only person who was confused, so I'll try again.
In a way, it's like trying to design a 3D trompe l'oeil construction. All that matters in one sense is that everything be on the required lines-of-sight. The construction lines give me that.
I have a 2D sketch of what I want my result to look like when it is integrated into my 3D model. I'm trying to duplicate the curves of that sketch as sweeping 3D curves where nothing is on a flat surface (except in the sense that any two adjacent segments define a surface).
Is is turning out to be very hard to construct. I have to keep swapping back to the original viewpoint (thanks for Scenes!) and changes do not always go the direction or have the magnitude that I expect. Sometimes a little nudge with the mouse moves something way off into the distance.
With this tool, I will be able to draw a polyline that goes from ray to ray, and as long as it hits all rays in the correct sequence, it will look the same from the specific camera viewpoint. Thus I can slide the vertices of that polyline along the rays to get whatever form I want that is reasonable from other perspectives while leaving it the same from the camera's view. That should simplify the process by an order of magnitude or more. I'm thinking I can use Color By Layer to tell the lines apart.
Again, thanks to Thomthom, Chris, and TIG for all your help.
August
-
Foo, I'm not getting the
vector
defined properly.I'm modifying Chris' code using TIG's suggestion. Chris provides two points to
.add_cline
and I'm taking those two points and trying to make avector
from them, and then make acline
from thecamera.eye
point and thevector
.Chris' original was:
def onLButtonUp(flags, x, y, view); Sketchup.active_model.active_entities.add_line(@ip.position, view.camera.eye); end;
And I changed that to:
def onLButtonUp(flags, x, y, view); vector = view.camera.eye.vector_to(@ip.position); Sketchup.active_model.active_entities.add_cline(view.camera.eye, vector); end;
Only something is wrong. The first time I click I get a visible
cline
(i.e., it's not going through the camera.eye) and after that I get:Error; #<ArgumentError; Cannot create unit vector from zero length vector> D;/Program Files/Google/Google SketchUp 7/Plugins/LoS;10;in `add_cline' D;/Program Files/Google/Google SketchUp 7/Plugins/LoS;10;in `onLButtonUp' D;/Program Files/Google/Google SketchUp 7/Plugins/LoS;10
(
LoS
is the new, modified version, Line-of-Sight.)Obviously I'm thinking that
@ip.position
is a point, and this error is suggesting that it's not. I don't know the magic in the@
and I suspect that's the source of the problem.But if I can create a
line
or acline
between those two points, why can't I create avector
using them?Obviously I'm missing something, but what?
Thanks,
AugustP.S. The forum [code] block indents lines that start with two spaces properly, but does not indent lines that start with four spaces. How do I fix that so the [code] block displays properly?
-
Without seeing all of the code... you need to set @ip=nil before it's set by the picking - then you should not get the error messages.
I can see nothing wrong with the way you are setting the vector.
Try adding some extra code toentities.add_cpoint(camera.eye)
andentities.add_cpoint(@ip.position)
so you can check these are getting taken properly.
Are you setting the 'camera' and then moving the view point to pick @ip ? You need to get the camera immediately after you click on @ip, otherwise you'll get an old camera.eye being used ?? -
Add a little validation of the vector to ensure it's not of zero length.
def onLButtonUp(flags, x, y, view); vector = view.camera.eye.vector_to(@ip.position) Sketchup.active_model.active_entities.add_cline(view.camera.eye, vector) if vector.valid? end
-
I was getting that same error August. And I am not sure why, hopefully one of their suggestions will fix it. I have little to no experience with conctruction geometry (apart from construction points I guess).
Chris
-
@tig said:
... you need to set @ip=nil before it's set by the picking ... You need to get the camera immediately after you click on @ip, otherwise you'll get an old camera.eye being used ??
Ah Ha! That explains why sometimes I seem to only get one line. It must be using the old @ip and therefor I'm getting the same line constructed with each click, no matter where it is. In this scenario, I seem to get one line with each re-invocation of the tool.
Separately, but similarly, the visible line that does not go through the current camera eye, must be using the older camera eye.
Definitely some issues to explore.
All my links to Ruby reference sources are stuck on my dead computer and I had not begun to use them enough to have them in my head. Can someone point me to where @ip is well described?
Thanks,
August -
The 'line tool' example rb script is perhaps as good as any to start with - you should have that already...
-
@chris fullmer said:
... I have little to no experience with conctruction geometry ...
Pick my jaw off the floor! Given how much of your code, Chris, I use in contructing my own geometry, to use a totally geeky metaphor , that strikes me like Yoda saying he's not very good with a light saber. Sorry.
-
@tig said:
The 'line tool' example rb script is perhaps as good as any to start with - you should have that already...
Thanks. Your suggestion about validating the vector should be useful too. I'll have it kick off a msgbox.
Forgive me if my attention to this is sporadic. I do appreciate all the help.
August
-
As an aside, it occured to me that this thread is an example of the meaning of my signature quote from Dickens. Thanks again to everyone. I'm very encouraged that this will come together quickly from here.
-
@august said:
...All my links to Ruby reference sources are stuck on my dead computer and I had not begun to use them enough to have them in my head. Can someone point me to where @ip is well described?
Thanks TIG,
There are definitely more examples of @ip and @xxxx in the Google-supplied examples. But they didn't help. Your previous suggestion about setting @ip=nil has not helped (so far), at least with the things that I've been wrestling with, and I think I may have a clue why.
Major Ruby Thinking Glitch
I think I've found a major conceptual glitch in my understanding SketchUp Ruby "under the hood" -- and maybe this will help others, at least newbies, too. The following outlines my Ruby learning process to get there. Later I'll try to post full examples for testing to demonstrate what I think is really going on and why the results have seemed to make no sense and the suggested fixes have not worked.
I finally figured out that I was asking the wrong question. I don't need to understand "
@ip
" as much as I first need to understand "@
".After some hours of digging (both of my Ruby books are missing somewhere in "the disaster that once was my home office" but I finally found a good online reference), I have learned that
@ip
is an instance variable.I had originally been trying to follow Chris' usage:
@ip = view.inputpoint(x,y);
That line is used in the working snippet that Chris posted earlier in this thread that defines the "
clf_auguat_lines
" class.I've been assuming that
@ip
would hold an inputpoint.The SketchUp Ruby API doc says that view.inputpoint(x,y) returns
nil
, but clearlynil
is not assigned to the@ip
variable or the script would not do anything.The other OO languages I'm most familiar with, FrameMaker FrameScript and Acrobat JavaScript, allow a method to return an instance of a class and that can be assigned to a variable. Their doc would have said "Returns point object" instead of "Returns nil".
Also, somewhere along the way I got the mistaken idea that Ruby had typeless variables. I guess I assumed that because you don't declare variables. But Ruby has implicit declarations based on the first letter of the variable name and value assigments happen very differently depending on the type of variable being assigned.
I have been assuming that @ip is an inputpoint object created by:
@ip = view.inputpoint(x,y);
From that assumption, I've been further assuming that @ip.position would return a Point3D object.
But it appears that it doesn't, at least not exactly. I had been reading the code as if it would create the Point3D object as soon as
@ip.position
was executed, but instead it appears to hold off evaluating it until the last possible moment. It appears to not create a Point3D at all "if it doesn't have to".The code:
eye = view.camera.eye; Sketchup.active_model.active_entities.add_line(eye,@ip.position);
will, embedded in Chris' snippet, draws a
line
wherever you click. But the code:eye = view.camera.eye; vector = eye.vector_to(@ip.position); Sketchup.active_model.active_entities.add_cline(eye,vector);
will only draw a
cline
if you click on a place that is a valid reference for acline
. Anywhere else, you get an error about a zero-length vector.That has been totally confusing me until the idea of postponed evaluation occurred to me.
What it says to me is that SketcnUp Ruby is not creating a
vector
object by using "eye
" as one Point3D and@ip.position
as a second Point3D. It does not create the second Point3D right away (I'm guessing).Instead, the
vector
is not actually evaluated until theadd_cline
is being executed, and because it'sadd_cline
and notadd_line
, if the@ip.position
is not valid for acline
, you get an error about an invalid vector.I'm stretching here, so I'm hoping someone who knows this much better than I do can follow my logic and tell me if I'm on track or missing the point.
Am I making sense? Is there a better way to make sense out of this?
Thanks,
August -
This is driving me crazy and now I've spent nearly another full day on it. Arrgh!
I can draw Camera Ray
line
s just fine. But notcline
s unless there is an object to reference.I can get one, single unreferenced
cline
. Once acline
fails to get an input point because of a lack of a reference object, I cannot get another valid@ip
for aline
, only forcline
s that have reference objects. Doesn't matter if I reload the file, I have to restart SU to clear this state.I thought I could draw the line first, and then use its endpoints to create the vector (that works) and the
cline
(that doesn't work).To demonstrate, I have two files. The only difference between them is that in the first one, some code is commented out: the single line of code that creates a
cline
from a point and a vector and some following messages to report on it.Both versions create a
vector
from the originalline
and that appears to work fine.Here's the version that creates plain old ordinary edge lines. I call it
rayL.txt
:class Clf_august_lines; def onMouseMove(flags, x, y, view); @ip = view.inputpoint(x,y); view.invalidate; end; def onLButtonUp(flags, x, y, view); line1 = Sketchup.active_model.active_entities\ .add_line(view.camera.eye, @ip.position); if (line1) UI.messagebox "line1 SUCCESS\n view.camera.eye = " + view.camera.eye.to_s + "\n @ip.position = " + @ip.position.to_s else else UI.messagebox "line1 Failure\n view.camera.eye = " + view.camera.eye.to_s + "\n @ip.position = " + @ip.position.to_s end vector1 = line1.start.position\ .vector_to(line1.end.position); if (vector1) UI.messagebox "vector 1 = " + vector1.to_s else UI.messagebox "vector1 Failure" end #cline1 = Sketchup.active_model.active_entities\ #.add_cline(line1.start.position, vector1); # if (cline1) # UI.messagebox "cline1 = " + cline1.to_s # line1.erase! # else # UI.messagebox "cline1 Failure" # end end; def draw(view); @ip.draw view; end; end; Sketchup.active_model.select_tool\ (Clf_august_lines.new)
And here's the version that creates a
line
, then uses that line's endpoints to create avector
, which works in both versions, and then creates acline
from one endpoint of the line and the vector. It is thiscline
which initiates the problem.I call this one
rayLC.txt
because it attempts to create aline
and then acline
:class Clf_august_lines; def onMouseMove(flags, x, y, view); @ip = view.inputpoint(x,y); view.invalidate; end; def onLButtonUp(flags, x, y, view); line1 = Sketchup.active_model.active_entities\ .add_line(view.camera.eye, @ip.position); if (line1) UI.messagebox "line1 SUCCESS\n view.camera.eye = " + view.camera.eye.to_s + "\n @ip.position = " + @ip.position.to_s else UI.messagebox "line1 Failure!\n view.camera.eye = " + view.camera.eye.to_s + "\n @ip.position = " + @ip.position.to_s end vector1 = line1.start.position\ .vector_to(line1.end.position); if (vector1) UI.messagebox "vector 1 = " + vector1.to_s else UI.messagebox "vector1 Failure" end cline1 = Sketchup.active_model.active_entities\ .add_cline(line1.start.position, vector1); if (cline1) UI.messagebox "cline1 = " + cline1.to_s # line1.erase! else UI.messagebox "cline1 Failure" end end; def draw(view); @ip.draw view; end; end; Sketchup.active_model.select_tool\ (Clf_august_lines.new)
If I open a new SU drawing and
load 'rayL.txt'
, it will draw lines whereever I click. But unless there is an object for them to reference, they stop at the bounding planes of the near quadrant.If I then either
load 'rayLC.txt'
or open a new SU file and load it, I can drawcline
s that reference existing objects, e.g.,Sang
, and there is no problem.But when I attempt to draw a
cline
that does not reference an existing object, I can create just that one, singlecline
and then all subsequent attmpts to createcline
s will fail because @ip.position is stuck at thecamera.eye
position orline1.start.position
.Even if I
load rayL.txt
again to create just lines, they fail, referencing Sang, the origin, or whatever. After onecline
,@ip.position
is stuck oncamera.eye
.I have tried TIG's suggestion of inserting @ip = nil but everywhere I have tried it produces error messages.
This doesn't seem like it should be this hard.
I have been poring over the SketchUp Ruby doc about
view
andinputpoint
etc. and unfortunatley it all seems written for those who already get it. It also says things like theinputpoint
should "normally" be obtained using [ruby:11qtfq9b]pick[/ruby:11qtfq9b], but I've followed those examples and not even gotten a working start. At least this one based on Chris Fullmer's version works sometimes.It appears to be one of three things:
- It really is this hard.
- I'm overlooking something very basic.
- There is a bug in creating
cline
s from a point and a vector.
Can someone help me figure out which it is, and/or possibly suggest a workaround?
Thanks,
August
Advertisement