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…

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.

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!