How to draw a line from centerpoint of face?

20200603_085604

How to draw a line[z vector] from centerpoint of face?

Assuming you somehow got a reference to the desired face (easy if you created it yourself in your Ruby, otherwise have the user select it before you run your code)

start_point = face.bounds.center
end_point = start_point + [0, 0, z_length]
Sketchup.active_model.active_entities.add_line(start_point, end_point)
3 Likes

Thank you for your reply,

But I would like to ask you one more thing…

Same question but

How to draw a line that is vertical to the face ( not Z vector )

You have reference to ‘face’…
Set up a distance - e.g. length = 6.66
Then v = face.normal gives the line’s direction.
Set its length thus v.length = length
start_point = face.bounds.center
The end could then be set up using end_point = start_point.offset(v)
Now use
Sketchup.active_model.active_entities.add_line(start_point, end_point)

2 Likes

You use a scaled copy of the face’s normal vector instead of the fixed direction [0,0,z] in the previous example. You have to know whether you want the edge to come from the front or back side of the face, though.

offset_vector = Geom::Vector3d.new(face.normal)
offset_vector.length = required_length
# offset_vector.reverse # if for the back side of the face
end_point = start_point.offset(offset_vector)
Sketchup.active_model.active_entities.add_line(start_point, end_point)

Basically the same as @TIG showed but with allowance for back side. It isn’t really needed in this situation because face.normal returns a newly created vector, not a reference to the face’s actual vector (you can’t directly manipulate a face’s normal itself anyway), but I showed how to make a safe copy if you are working with a vector you got from some other source so that you don’t alter the original when setting its length.

1 Like

It is successfully working! (Pic 1)

but,

When I make a group before draw a line, It is not working well (Pic 2)

The position of the line is not quite right.

What kind of problem?


model = Sketchup.active_model
entities = model.active_entities
selection = Sketchup.active_model.selection

faces =
selection.each do |e|
faces << e if e.is_a? Sketchup::Face

end

faces.each do |face|
#group = entities.add_group(face)
start_point = face.bounds.center
offset_vector = Geom::Vector3d.new(face.normal)
offset_vector.length = 1000
end_point = start_point.offset(offset_vector)
Sketchup.active_model.active_entities.add_line(start_point, end_point)
end


For the 3rd time … Will you please post code correctly, … not images of code.

I’m sorry for same mistakes

code is

model = Sketchup.active_model
entities = model.active_entities
selection = Sketchup.active_model.selection

faces =
selection.each do |e|
faces << e if e.is_a? Sketchup::Face

end

faces.each do |face|
group = entities.add_group(face)
start_point = face.bounds.center
offset_vector = Geom::Vector3d.new(face.normal)
offset_vector.length = 1000
end_point = start_point.offset(offset_vector)
Sketchup.active_model.active_entities.add_line(start_point, end_point)
end

This is not correctly posted. Please read the wiki (again).

Now I got to know the method of posting code

model = Sketchup.active_model
entities = model.active_entities
selection = Sketchup.active_model.selection

faces = []
selection.each do |e|
faces << e if e.is_a? Sketchup::Face

end

faces.each do |face|
group = entities.add_group(face)
start_point = face.bounds.center
offset_vector = Geom::Vector3d.new(face.normal)
offset_vector.length = 1000
end_point = start_point.offset(offset_vector)
Sketchup.active_model.active_entities.add_line(start_point, end_point)
end

You are getting mixed coordinates by putting the face into a group before creating the edge. I’d recommend creating both first and then adding them simultaneously when you create the group (note that the edge is the return value from add_line). Put them into the same array and then pass that as argument to add_group.

entities.add_group([face, edge])

You code formatting is better, but please learn how to indent [2 spaces] so it’s easier to read…
selection.each do |e|
faces << e if e.is_a? Sketchup::Face
end
Would be better as

selection.each do |e|
  faces << e if e.is_a? Sketchup::Face
end

Although I’d prefer:

faces = selection.grep(Sketchup::Face)

That said… if you group a face its ‘transformation’ is affected, because it’s now inside another context.
You can get the transformation of the container [group] and apply that to the center-point before adding the new edge.
But in this case I think you could do it in another easier way - as @slbaumgartner outlined.

1 Like
model = Sketchup.active_model
entities = model.active_entities
selection = Sketchup.active_model.selection

faces = selection.grep(Sketchup::Face)
edges = entities.grep(Sketchup::Edge)

faces.each do |face|
  group = entities.add_group([face, edge])
  start_point = face.bounds.center
  offset_vector = Geom::Vector3d.new(face.normal)
  offset_vector.length = 100
  end_point = start_point.offset(offset_vector)
  Sketchup.active_model.active_entities.add_line(start_point, end_point)
end

Ruby says: wrong argument type (expected Sketchup::Entity)

If I necessarily need to group before creating the edge for my tool

Is there any other way?

In the snippet you attached, nowhere is edge assigned a value, so add_group is complaining that nil is not a Sketchup::Entity. You need to move the code that creates the edge up to before the add_group statement, and assign edge to the return value from the add_line statement. The statement that sets edges is irrelevant in two regards: first, it will only find edges that already exist at that time, and second your later code makes no use of edges.

1 Like

You’ve referenced ALL edges but never used it.
You also have a reference set up to the active_entities which is then not used, similar with ‘model’.
But the bad bit is that you add a reference into the add_group() named ‘edge’ which is not predefined.
So it will break !
Consider this simplistic tidied example…

model = Sketchup.active_model
entities = model.active_entities
selection = model.selection
faces = selection.grep(Sketchup::Face)
faces.each{|face|
  start_point = face.bounds.center
  offset_vector = face.normal
  offset_vector.length = 100
  end_point = start_point.offset(offset_vector)
  edge = entities.add_line(start_point, end_point)
  group = entities.add_group([face, edge])
}

Of course if the new edge interacts with geometry in the active context it might merge.
So to try and separate things as soon as possible… Like this improved version, which adds the edge into the group so it’s always separated…

model = Sketchup.active_model
entities = model.active_entities
selection = model.selection
faces = selection.grep(Sketchup::Face)
faces.each{|face|
  group = entities.add_group(face)
  start_point = face.bounds.center
  offset_vector = face.normal
  offset_vector.length = 100
  end_point = start_point.offset(offset_vector)
  edge = group.entities.add_line(start_point, end_point)
}

PS: Do you really want the ‘normal’ edge 100" long ?
To make it say metric try 100.mm or 100.cm or 1.m ??

2 Likes

model = Sketchup.active_model
entities = model.active_entities
selection = model.selection
material = Sketchup.active_model.materials[0]
materials = model.materials
faces = selection.grep(Sketchup::Face)
faces.each{|face|
  group = entities.add_group(face)
  entities = group.entities
  before = entities.grep(Sketchup::Face)
  face.pushpull( 10000.mm )
  new_faces = entities.grep(Sketchup::Face) - before
  upper_face = new_faces.find {|f| f.normal == face.normal.reverse }
unless upper_face.nil?
  upper_face.material = "Red"
  start_point = upper_face.bounds.center
  offset_vector = upper_face.normal
  offset_vector.length = 10000.mm
  end_point = start_point.offset(offset_vector)
end
  edge = group.entities.add_line(start_point, end_point)
}

It is successfully working! (Pic 1)

But,

When I copy a group(face) before running the process, It is not working well (Pic 2)

I need to copy a group(face) Because I want to leave the original face

model = Sketchup.active_model
entities = model.active_entities
selection = model.selection
material = Sketchup.active_model.materials[0]
materials = model.materials
faces = selection.grep(Sketchup::Face)
faces.each{|face|
  group = entities.add_group(face)
  group2 = group.copy
  entities2 = group2.entities
  before = entities2.grep(Sketchup::Face)
  face.pushpull( 10000.mm )
  new_faces = entities2.grep(Sketchup::Face) - before
  upper_face = new_faces.find {|f| f.normal == face.normal.reverse }
unless upper_face.nil?
  upper_face.material = "Red"
  start_point = upper_face.bounds.center
  offset_vector = upper_face.normal
  offset_vector.length = 10000.mm
  end_point = start_point.offset(offset_vector)
end
  edge = group2.entities.add_line(start_point, end_point)
}

It says Cannot convert argument to Geom::Point3d

You need to pushpull the copy of face found in group2, that is, before[0] not the original face (which is only in group). Same as in the GUI, modifying a copy of a group breaks its relationship to any other copies, leaving them unchanged.

As written, the pushpull affects group but not group2, so new_faces is empty. That means upper_face is nil (nothing to find). You then test for upper_face.nil? but the code to add_line is executed regardless of whether or not upper_face is nil. The statement to add_line should be inside the unless block because start_point and end_point aren’t set unless that block was executed.

The issues here and in your previous attempts all stem from basic issues with your understanding of Ruby, not really with the SketchUp Ruby API. Learn to place puts or p output statements at key places and you will find errors more quickly.

1 Like

model = Sketchup.active_model
entities = model.active_entities
selection = model.selection
faces = selection.grep(Sketchup::Face)
faces.each{|face|
  group = entities.add_group(face)
  group2 = group.copy
  entities2 = group2.entities
  entities2 = face.parent.entities
  before = entities2.grep(Sketchup::Face)
  before[0].pushpull( 10000.mm )
  new_faces = entities2.grep(Sketchup::Face) - before
  upper_face = new_faces.find {|f| f.normal == face.normal.reverse }
unless upper_face.nil?
  upper_face.material = "Red"
  start_point = upper_face.bounds.center
  offset_vector = upper_face.normal
  offset_vector.length = 10000.mm
  end_point = start_point.offset(offset_vector)
end
  edge = group2.entities.add_line(start_point, end_point)
}

I did pushpull “before[0]”

But then why the edge goes into group1? not group2

I’ve been watching ruby basic videos, but there is delay

Sorry for the beginners question

You define

entities2 = group2.entities

and immediately overwrite it with

entities2 = face.parent.entities

which is the equivalent of

entities2 = group.entities

NOT what you want…

Please read what you type and see/expect the result of each and every line of code…
Here you do something, then immediately undo it, and you are confused when the first step is overwritten by the second…
The code only does what you tell it !

1 Like

It’s working now

model = Sketchup.active_model
entities = model.active_entities
selection = model.selection
faces = selection.grep(Sketchup::Face)
faces.each{|face|
  group = entities.add_group(face)
  group2 = group.copy
  entities2 = group2.entities
  before = entities2.grep(Sketchup::Face)
  before[0].pushpull( 10000.mm )
  new_faces = entities2.grep(Sketchup::Face) - before
  upper_face = new_faces.find {|f| f.normal == before[0].normal.reverse }
unless upper_face.nil?
  upper_face.material = "Red"
  start_point = upper_face.bounds.center
  offset_vector = upper_face.normal
  offset_vector.length = 10000.mm
  end_point = start_point.offset(offset_vector)
end
  edge = group2.entities.add_line(start_point, end_point)
}