Adding two Point3d, is that impossible?
-
Hi,
this seems an absurd question and goes beyond any common sense but here it is, how do I add two Point3d?
Something like this:a = Geom::Point3d.new(1,1,1) b = Geom::Point3d.new(0,1,1) c = a + b
Now this spits out a Error: #<ArgumentError: Cannot convert argument to Sketchup::Vector3d>
Which would seems like that it's only possible to add a Vector3d to a point3d, which is pretty nonsense to me.Sketchup documentation says there's a Point3d.+ operator with Point3d as arguments, but then fails to report a snippet with an actual point3 + point3d, which adds to my confusion:
*Point3d.+SketchUp 6.0+
The '+' operator is a fast way to add to the current x, y and z values of a point, or to set the values of a point by adding to other points together.**Arguments:
point2
A Point3d object.**
Returns:point
a Point3d object
pt2 = pt + vec
pt = pt + [10,10,10]* -
pointA + pointB
does not work !
c = pointA.vector_to(pointB)
works, but that returns a vector.
To convert that vector to a point you can use:
pointC = Geom::Point3d.new(c.to_a)
Or to find the mid-point you can use:
pointC = Geom::Point3d.linear_combination(0.5, pointA, 0.5, pointB)
-
@ziocleto said:
Hi,
this seems an absurd question and goes beyond any common sense but here it is, how do I add two Point3d?
Something like this:a = Geom::Point3d.new(1,1,1) b = Geom::Point3d.new(0,1,1) c = a + b
Now this spits out a Error: #<ArgumentError: Cannot convert argument to Sketchup::Vector3d>
Which would seems like that it's only possible to add a Vector3d to a point3d, which is pretty nonsense to me.Perhaps
c = Geom;;Point3d.new(a.x+b.x,a.y+b.y,a.z+b.z)
is what you are looking for?
-
I know this error was reported, but it must be low on the fix list.
-
@sdmitch said:
Perhaps
c = Geom;;Point3d.new(a.x+b.x,a.y+b.y,a.z+b.z) >
is what you are looking for?
Even simpler:
p = p1 + p2.to_a
-
Thanks, that confirms my fears.
Yes I can do all sort of workarounds but as a language geek sort of person I fail to understand how you would prefer to implement Point3d.+(Vector3d) or Point3d.+(Array) and not the clearly more obvious: Point3d.+(Point3d)
I can only think it's one of those bugs somebody put in there in the first place and that's created a massive headache or negligence for people to fix it...
-
@ziocleto said:
I fail to understand how you would prefer to implement Point3d.+(Vector3d) or Point3d.+(Array) and not the clearly more obvious: Point3d.+(Point3d)
While agreeing that it seems strange that the SketchUp developers have never addressed this question, I would quibble that adding points is not clearly more obvious. It depends on what you are trying to do. If you are thinking about geometric operations, adding two points doesn't make much sense whereas offsetting from a point by adding a vector is essential.
-
@slbaumgartner said:
While agreeing that it seems strange that the SketchUp developers have never addressed this question, I would quibble that adding points is not clearly more obvious. It depends on what you are trying to do. If you are thinking about geometric operations, adding two points doesn't make much sense whereas offsetting from a point by adding a vector is essential.
Well it goes against 99.99% of what any other graphics engines or math classes do.
Adding 2 points it's pretty basic stuff in any math related algorithm, via all sort of architectures, CPUs, GPUs, abacus, you name itThe strong typization of Point3d and Vector3d is also very questionable as normally having the same memory footprint and data behaviour those 2 types pretty much means the same thing from an algorithm point of view, in fact they are heavily parallelized in any architecture to achieve better performances.
A Vector3d is a Point3d basically, but you can have different functions to perform vector-like operation (normally a normalised direction), but having 2 classes instead of a different set of functions is weird... very...
-
@ziocleto said:
The strong typization of Point3d and Vector3d is also very questionable as ... they are heavily parallelized in any architecture to achieve better performances.
And this why the SketchUp API authors made both classes "compatible" with a basic 3 element array, ... and also extended the Ruby base Array class to be compatible with them.
The
TypeError
exception raised with theGeom::Point3d
argument to it's addition method, is IMHO not nefarious, nor by design. It's just a sloppy mistake in the C-side API code,.. and because it has a workaround, always remains somewhat lower in the to do list. It just never percolates to the top of the list in any major cycle.@ziocleto said:
A Vector3d is a Point3d basically, but you can have different functions to perform vector-like operation (normally a normalised direction), but having 2 classes instead of a different set of functions is weird... very...
Well each programming language has it's quirks. Ruby is a class based language, and this is the way things are usually done, when objects have differing behavior.
However, normally there is a superclass that has the common functionality. And the differing classes are defined as subclasses of this common superclass. This is called inheritance because the subclasses inherit all their ancestors methods.
This is fundamental in Ruby.
The books & learned PhDs who preach against inheritance as being evil, and profess that composition solves all problems, are creatures of other programming languages like Java. Their arguments do not apply to Ruby. Ruby is optimized for inheritance, and explicitly designed for it.These two classes [
Geom::Point3d
andGeom::Vector3d
,] do share some methods in common. And could have been defined both as subclasses ofArray
.But they were not.
But Ruby is also a multi-paradigm language. It has other functionality constructs besides inheritance. (Singleton, Delegation, etc.)
In Ruby, common functionality can also be shared with the use of mixin library modules. This is called composition. It creates a single place in the code, for the shared functionality, and makes code maintenance easier. This common functionality, can also be shared with any other class or module, without respect to any inheritance chain(s).
But if composition was done, it was not exposed to the Ruby-side of the API. (Both classes in question look like simple subclasses of
Object
.)But things still work, because Ruby does not enforce any particular functionality over any other.
Lastly, many of the base API classes were first exposed back around SketchUp v4, by programmers who were not that knowledgeable about Ruby philosophy. You'll see some method names that violate Rubyish conventions and are influenced by Javascript and C (especially in the names of observer class callback methods.) Ruby was relatively new back then, as well.
So, in closing, I would say that given what the API documentation says, that this issue was not intentional. (I can ping Thomas and see what he thinks.)
-
Yes we do agree that not having a Point3d+.(Point3d) is 99% just sloppiness, which I can fully understand.
I've worked on some big code projects in my days and yes, eventually even if you have a team of gurus some sloppiness is un-avoidable, for all sort of reasons.I would like to discuss the more general language side of the matter (the whole API architecture) but I don't think I'll ever have time to spend on it!
-
@dan rathbun said:
@ziocleto said:
The strong typization of Point3d and Vector3d is also very questionable as ...
And this why the SketchUp API authors made both classes "compatible" with a basic 3 element array, ...
OH.. also.. there is another way they could have gone for this particular method.
And that is duck-typing the argument, instead of class-typing it.
Ruby example (they are really implemented on the C-side):
<span class="syntaxdefault">def </span><span class="syntaxkeyword">+(</span><span class="syntaxdefault">arg</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> raise</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">TypeError</span><span class="syntaxkeyword">,</span><span class="syntaxstring">"invalid argument type"</span><span class="syntaxkeyword">,</span><span class="syntaxdefault">caller</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> unless<br /> </span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> arg</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">respond_to</span><span class="syntaxkeyword">?(;</span><span class="syntaxdefault">x</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">&&<br /></span><span class="syntaxdefault"> arg</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">respond_to</span><span class="syntaxkeyword">?(;</span><span class="syntaxdefault">y</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">&&<br /></span><span class="syntaxdefault"> arg</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">respond_to</span><span class="syntaxkeyword">?(;</span><span class="syntaxdefault">z</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">||<br /></span><span class="syntaxdefault"> </span><span class="syntaxkeyword">(</span><span class="syntaxdefault"> arg</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">respond_to</span><span class="syntaxkeyword">?(;[])</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">&&</span><span class="syntaxdefault"> </span><span class="syntaxcomment"># be sure it has 3 members<br /></span><span class="syntaxdefault"> arg</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Numeric</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> rescue false </span><span class="syntaxkeyword">&&<br /></span><span class="syntaxdefault"> arg</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">1</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Numeric</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> rescue false </span><span class="syntaxkeyword">&&<br /></span><span class="syntaxdefault"> arg</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">2</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">is_a</span><span class="syntaxkeyword">?(</span><span class="syntaxdefault">Numeric</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> rescue false </span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment"># rescue modifiers trap IndexError exceptions<br /><br /></span><span class="syntaxdefault"> </span><span class="syntaxcomment"># the method body<br /><br /></span><span class="syntaxdefault">end</span>
If you are only concerned with Ruby 2.0+, then you can use a refinement module to correct the method for you code only.
Advertisement