ArcCurve start and end points in global coordinate system

Hi,
I’m working on an architectural project and i’m using the same SketchUp model for the wiring. I know some people advise against this but the pain of updating two models seems worse than the problems of doing it all in SketchUp. Anyway, it all seems fine but I’m trying to automate some task with Rubi Api to do things like name my components. That all works great. But I would also like to determine which components a cable (always drawn as an ArcCurve) is connecting. This way I can make the Ids given to the components be reflected in the names given to the cables. So radiator TRV cable “R-A1-7” (Radiator, Block A, floor 1, Id=7) will be given the name “TC-A1-7”. So the 7 matches.

My code finds the cables and the components but I’m struggling to find the end points of the ArcCurve in the global coordinate system as well as the centre of the bounding box of the components.

What I want is a function that given an ArcCurve, or a Group with a single ArcCurve in it will answer the end points positions in the world. Also the same for a ComponentInstance, but answering its bounds.centre, also in the world coordinate system.

current I check every componentInstance (that’s been identified as a relevant component) like this:
componentInstance.bounds.center.distance(location)
passing in location from each end of my curve
arcCurve.vertices[0].position
and
arcCurve.vertices[-1].position

but the points are all over the place.

Is there an existing example project that does something vaguely similar someone could point me towards?

Thanks!

Euan

For any Curve (or subclass ArcCurve) start point, in the parent’s local coordinates …

def curve_start_point(curve)
  curve.first_edge.start.position
end

For any Curve (or subclass ArcCurve) end point, in the parent’s local coordinates …

def curve_end_point(curve)
  curve.last_edge.end.position
end

Assuming that “child” is a group in the top level model entities context, and “point” is a curve end point in that groups’s child coordinates, … to convert to world (model) coordinates …

def model_coordinates(point, child)
  point.transform(child.transformation)
end

See:

If the component instances are also within the model’s top level entities then their bounds corners should be expressed in model coordinates.

Hi Dan,
thanks for your reply.
If child is not at the top level, would it work for me to have something like this:

def model_coordinates(point, child)
point.transform(child.transformation)
parent = child.parent
while !parent.nil?
  point.transform(child.transformation)
  parent = parent.parent
end
end

really appreciate your help.
thanks,
Euan

Be carefull. The SketchUp core has a weird thing to do with coordinates. If you are within an editing context (ie, you’ve double clicked to enter a group,) the API methods return values in world coordinates.

So you’ll want to be at the top level outside all nesting levels when you run your naming utility.

model.close_active until model.entities == model.active_entities

See also:

No this will not work. Mainly because (ignoring the coding errors) … because #parent returns the owner of the geometric entities collection (ie, a definition or the model) and not an instance or group that has a transformation. (FYI, a group is a special component instance and so also has a component definition.)

If you’ve multi-nested things you will need to know the InstancePath to the particular cable or component instance.
The only API method that can give you this is Sketchup::Model#active_path meaning the target must be open for edit.

So it’d make it easier on yourself if you use a known container say for the Cabling and/or target instances.

This method is not always correct. e.g. I draw an edge from point A to point B, then draw another edge from point C to point B, and weld these two edges to a curve. In this case, eighter start point or the end point from the methods above may get the wrong result.

:thinking: The Entities #weld method “randomly” determine which will be the start and end of the welded edges…
In your example there are two “start” point of original edges at the welded curve “end” and “other end” …so I’m not sure what you mean by “wrong result”?

In my opinion Dan’s methods are good. :wink:

:bulb: Perhaps, you can test this quick snippet also.

def curve_start_end_vector(curve)
  [curve.first_edge.line[1],
   curve.last_edge.line[1] ]
end

def curve_start_end_point(curve)
  verts = curve.vertices
  [verts.first.position, verts.last.position]
end

def print_welded_ends
  mod = Sketchup.active_model
  ents = mod.active_entities
  sel = mod.selection
  return if sel.empty?
  edges = sel.grep(Sketchup::Edge)
  return unless edges.first.is_a?(Sketchup::Edge)
  mod.start_operation("Print welded ends",true)
  curves = ents.weld(edges)
  curves.each{|curve|
    start_pt, end_pt = curve_start_end_point(curve)
    start_vec, end_vec = curve_start_end_vector(curve)
    ents.add_text("Start", start_pt, start_vec)
    ents.add_text("End", end_pt, end_vec)
  }
  mod.commit_operation
end
print_welded_ends

I know your codes would give the correct result, what I mean is that curve.first_edge.start.position may not represent the start position of a curve, and curve.last_edge.end.position may not represent the end position of a curve.

I see now, what you mean, you are right.

Tested with Dan’s method:

"Failed" method
def curve_start_end_vector(curve)
  [curve.first_edge.line[1],
   curve.last_edge.line[1] ]
end

def curve_start_point(curve)
  curve.first_edge.start.position
end

def curve_end_point(curve)
  curve.last_edge.end.position
end

def print_welded_ends
  mod = Sketchup.active_model
  ents = mod.active_entities
  sel = mod.selection
  return if sel.empty?
  edges = sel.grep(Sketchup::Edge)
  return unless edges.first.is_a?(Sketchup::Edge)
  mod.start_operation("Print welded ends2",true)
  curves = ents.weld(edges)
  curves.each{|curve|
    start_vec, end_vec = curve_start_end_vector(curve)
    ents.add_text("Start", curve_start_point(curve), start_vec)
    ents.add_text("End", curve_end_point(curve), end_vec)
  }
  mod.commit_operation
end
print_welded_ends

image

_
In this case mine code above in Post #7 method is better :wink:
Result:
image

1 Like

If it does not work the wat that the documentation says it should, then it is likely a bug.
Please open an issue in the tracker.

I can’t report anything about it. It is not buggy, just there is no information. I made my own assumption, whether it is true or not. :blush: :innocent:

(The issue tracker operators are already scared by the number of reported issues… perhaps that’s certainly not why it’s not decreasing. :grinning:)