How do I close / create a face?

HI all,

I’ve just started with Ruby for sketchup. I’m creating a rotary encoder which works fine, but the faces won’t close when created by Ruby.

I’m creating an outer and inner arcs with

	edgearray = entities.add_arc centre, xaxis, normal, $r1/25.4, start_a, end_a, facets
	edge = edgearray[0]
	arccurve = edge.curve
	end_angle = arccurve.end_angle

	#################################################		
	edgearray = entities.add_arc centre, xaxis, normal, $r2/25.4, start_a, end_a, facets
	edge = edgearray[0]
	arccurve = edge.curve

and closing the face with

	##################################################		
	# Now create the closing lines at the start of arc
	point1 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment )) * (Math::PI / 180)) * $r2 / 25.4, Math.sin(((360.0 / segments) *( segment)) * (Math::PI / 180)) * $r2 / 25.4,0) # Outer arc
	point2 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment )) * (Math::PI / 180)) * $r1 / 25.4, Math.sin(((360.0 / segments) *( segment)) * (Math::PI / 180)) * $r1 / 25.4,0) # Inner arc
	line = entities.add_line point1,point2
	##################################################
	# Now create the closing lines at the end of arc
	point1 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r2 / 25.4, Math.sin(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r2 / 25.4,0) # Outer arc
	point2 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r1 / 25.4, Math.sin(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r1 / 25.4,0) # Inner arc
	line = entities.add_line point1,point2

Everything joins up nicely, but no faces. If I then manually draw a line over the scripted line, the face completes, but I need to do it iin code as there’s literally thousands of faces.

Thanks in advance

Pick one of the drawn Edges and call find_faces.

http://www.sketchup.com/intl/en/developer/docs/ourdoc/edge#find_faces

Thanks Jim.
I’ve been working with the code, but having some difficulty with the arcs. Any ideas on how to use this method with arcs?

An arc is actually a series of Edges in SketchUp. Get ahold of one of the Edges and use find_faces on it.

Thanks slbaumgartner,

I’ve been trying the example (Homepage | SketchUp Developer), and trying to select just one line.

What I’m trying to achieve is this:

If I try to select just one of the joining the arcs, I get ‘Error: #<TypeError: wrong argument type Sketchup::Edge (expected Array)>’.
When I draw a box around it, I get a face from that box, but not the arc.

I’m pulling my hair out here!

I wasn’t able to post the second image, but this is what my code creates

You haven’t given us all of the code…
But can I suggest you step back… and make a method to draw two arcs at a given spec (entities, center, axis, normal, rad1, rad2, start_angle, end_angle) and draw two additional edges between the arcs’ start-vertices and end-vertices.: you have the arrays of all arc-edges and the two end edges, just use edge.find_face on that last edge… Temporary grouping ensures no geometry clashes…
Here my example:

module TIG
    def self.arcface(ents=nil, cent=ORIGIN, axis=X_AXIS, norm=Z_AXIS, rad1=1.0, rad2=2.0, stara=0.0, enda=180.degrees)
        ents=Sketchup.active_model.active_entities unless ents
        grop=ents.add_group()
        ents=grop.entities
        arc1=ents.add_arc(cent, axis, norm, rad1, stara, enda)
        arc2=ents.add_arc(cent, axis, norm, rad2, stara, enda)
        vx10=arc1[0].start
        vx20=arc2[0].start
        edg1=ents.add_line(vx10, vx20)
        vx12=arc1[-1].end
        vx22=arc2[-1].end
        edg2=ents.add_line(vx12, vx22)
        edg2.find_faces
        face=ents.grep(Sketchup::Face)
        grop.explode
        return face
    end
end

To use it = TIG.arcfaces(list_of_parameters)
Pass nil if a default is OK…
Just call the method with different parameters to make different arc-sets.
The method returns the face that was added…
So it you want to pushpull it later you can [remember because of the arcs’ configurations and the resulting face a -ve distance will be ‘up’]…
Repeat as desired with different radii etc…

2 Likes

Thanks TIG, that’s awesome!

The one thing that I can’t work out though is the bigger arcs - they’re either 2 or 3 segments and ‘notchy’. i can’t think of a better way to put it!

The small arcs work a treat.

I’m not asking that you do all of my work for me, but I just can’t see how to the number of entities higher to fix the larger arcs.

I can’t for whatever reason post all of the code as this editor seems to confuse ends / comments with markup.

Thanks mate,
Shane

Sorry, I’ve worked out how to post the full code.

module TIG
	def self.arcface(ents=nil, cent=ORIGIN, axis=X_AXIS, norm=Z_AXIS, rad1=1.0, rad2=2.0, stara=0.0, enda=180.degrees)
		ents=Sketchup.active_model.active_entities unless ents
		grop=ents.add_group()
		ents=grop.entities
		arc1=ents.add_arc(cent, axis, norm, rad1, stara, enda)
		arc2=ents.add_arc(cent, axis, norm, rad2, stara, enda)
		vx10=arc1[0].start
		vx20=arc2[0].start
		edg1=ents.add_line(vx10, vx20)
		vx12=arc1[-1].end
		vx22=arc2[-1].end
		edg2=ents.add_line(vx12, vx22)
		edg2.find_faces
		face=ents.grep(Sketchup::Face)
		grop.explode
		return face
	end
end

########################################################################
#
# This script will create the layout for my absolute rotary encoder
# This will be used in the construction of my telescope.
# Written by Shane Frost
# 13 Nov 2014
#
# TODO
# Add gray code
# Add options
# Add mounting tabs
#
########################################################################

# Begin by declaring the variables
ring = 1
rings = 10
$r1 = 250
segments = 2.0
facets = 40
x = 0
y = 0
mountOffset = 15

#######################################################
# Add Inner circle
centre_point = Geom::Point3d.new(x,y,0)
normal_vector = Geom::Vector3d.new(x,y,1)
radius = ($r1 - mountOffset) / 25.4

entities = Sketchup.active_model.entities
edgearray = entities.add_circle centre_point, normal_vector, radius, 360
first_edge = edgearray[0]
arccurve = first_edge.curve

# Loop through the rings.
while ring < rings + 1 do
	
	#Increment the radius by 10mm and reset the segment back to the first
	$r2 = $r1 + 10
	segment = 0
	AngleVal = 360.0 / segments
	
	#Loop through the segments of the ring
	while segment < segments do
		# Create an segment arc, normal to the Z axis
		centre = Geom::Point3d.new
		normal = Geom::Vector3d.new 0,0,1
		xaxis = Geom::Vector3d.new 1,0,0
		start_a = Math::PI * 2 / segments * segment
		end_a =  Math::PI * 2 / segments * (segment +1)
		model = Sketchup.active_model
		entities = model.entities
		edgearray = entities.add_arc centre, xaxis, normal, $r1/25.4, start_a, end_a, facets
		edge = edgearray[0]
		arccurve = edge.curve
		end_angle = arccurve.end_angle

		#################################################		
		edgearray = entities.add_arc centre, xaxis, normal, $r2/25.4, start_a, end_a, facets
		edge = edgearray[0]
		arccurve = edge.curve
		
		##################################################		
		# Now create the closing lines at the start of arc
		point1 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment )) * (Math::PI / 180)) * $r2 / 25.4, Math.sin(((360.0 / segments) *( segment)) * (Math::PI / 180)) * $r2 / 25.4,0) # Outer arc
		point2 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment )) * (Math::PI / 180)) * $r1 / 25.4, Math.sin(((360.0 / segments) *( segment)) * (Math::PI / 180)) * $r1 / 25.4,0) # Inner arc
		line = entities.add_line point1,point2
		##################################################
		# Now create the closing lines at the end of arc
		point1 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r2 / 25.4, Math.sin(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r2 / 25.4,0) # Outer arc
		point2 = Geom::Point3d.new(Math.cos(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r1 / 25.4, Math.sin(((360.0 / segments) *( segment + 1)) * (Math::PI / 180)) * $r1 / 25.4,0) # Inner arc
		line = entities.add_line point1,point2
		
		##################################################
		# Find the faces
		# Thanks to TIG from Sketchup Forums!	
		TIG.arcface(ents=nil, cent=ORIGIN, axis=X_AXIS, norm=Z_AXIS, rad1=$r1/25.4, rad2=$r2/25.4, stara=start_a, enda=end_a)
		
		segment += 2 #Increment the segment
	end
	
	# Now increment the required variables before moving to the next ring.
	ring += 1
	$r1 += 10
	segments += segments
	facets -= 2
end

#######################################################
# Finish off by closing the outside of the disc.
centre_point = Geom::Point3d.new(x,y,0)
normal_vector = Geom::Vector3d.new(x,y,1)
radius = $r2 / 25.4
entities = Sketchup.active_model.entities
edgearray = entities.add_circle centre_point, normal_vector, radius, 360
first_edge = edgearray[0]
arccurve = first_edge.curve

No matter how it looks, all arcs in SketchUp are actually series of straight Edge segments: Entities#add_arc has an optional sixth argument that sets the number of segments in the arc. Increasing it from the default will make the curves look smoother.

1 Like

Thanks slbaumgartner, you are of course correct! I’ve added a parameter for the number of faces and all is well with the world.

My many thanks to jim_foltz, TIG & slbaumgartner for your invaluable assistance.

I will throw the finished code on github for anybody that wishes to use it.

Yes the default is used if you don’t pass a final ‘numsegs’.
The modified method would be something like:

module TIG
    def self.arcface(ents=nil, cent=ORIGIN, axis=X_AXIS, norm=Z_AXIS, rad1=1.0, rad2=2.0, stara=0.0, enda=180.degrees, nums=12)
        ents=Sketchup.active_model.active_entities unless ents
        grop=ents.add_group()
        ents=grop.entities
        arc1=ents.add_arc(cent, axis, norm, rad1, stara, enda, nums)
        arc2=ents.add_arc(cent, axis, norm, rad2, stara, enda, nums)
        vx10=arc1[0].start
................

It defaults to 12 segments if nil is passed to the method.
Before calling the method you can calculate the integer equivalent to say 1 for each degree of swept arc and give your arc that numseg [OR 2 if <2] ?

That’s a great idea TIG.

Cheers.

def arc()
	ents=Sketchup.active_model.active_entities unless ents
	grop=ents.add_group()
	ents=grop.entities
	cent=[0, 0, 0]
	axis=[0,0,-1]
	norm=[1, 0, 0]
	rad=30
	stara=90.degrees
	enda=270.degrees
	accr=100
	arc1=ents.add_arc(cent, axis, norm, rad, stara, enda, accr)

	vx10=arc1[0].start
	vx12=arc1[-1].end
	edg1=ents.add_line(vx10, vx12)

	edg1.find_faces
	face=ents.grep(Sketchup::Face)
	grop.explode
	return face 
end

def torus()
	model = Sketchup.active_model
	entities = model.active_entities
	face=arc()
	cent=[0, 30, 0]
	axis_1=[0,-1,0]
	normal_1=[0, 0, 1]
	edg2=entities.add_arc cent, axis_1, normal_1, 30, 0.degrees, 180.degrees, 100
 	st=face.followme(edg2)
	return st
end

I am trying to make a torus (google it) I repurposed your code but for some reason the arc function does not return a face, so that follome can work, what am I missing?

The Ruby method Enumerable#grep returns an Array containing the matches, so your variable face is an Array containing the Face. This causes a undefined method error in torus because Array does not have a followme method! At some point you need to extract the face from the Array (and as a precaution should probably test whether grep returned an empty Array or and Array with more than one Face - which could happen if your model has previously drawn Faces!) Edit: in this case since you work within a new Group, you won’t find any Faces you didn’t just draw…

If you change arc() to arc()[0] you get this:

Thats great! Thank you for your input, I don’t have much of a ruby background but I’m churning along, thanks again!