For several days I have tried to solve this problem:
Is it possible to pushpull a circle on an existing face?
model = Sketchup.active_model
ents = @model.active_entities
ents.each do |o|
ptsf = [[-1000,0,0], [-1000,1000,0], [-2000,1000,0], [-2000,0,0]]
# pushpull circle on face - not working
centerpoint = [-1500,500,0]
vector = [0,0,1]
radius = 300
circle = ents.add_circle centerpoint, vector, radius
face = ents.add_face circle
It creates the Error: #<NoMethodError: undefined method `pushpull’ for nil:NilClass>
This gives certainly Error: #<NoMethodError: undefined method 'active_entities' for nil:NilClass>.
Do not use instance variables when you don’t need them or don’t know how to use them. The @ determines the type of variable and an instance variable is only meant to be used within a class instance (and declared in the initializemethod). If you do not use classes, you do not need it.
Recommended is to use round parentheses around the arguments of every method call. It is not required, but good style, makes it easier to recognize what is a method and avoids special cases where the precendence of subsequent method calls is ambiguous when they are only separated by spaces.
After reading an error message like this, the subsequent step is to become curious why the object on which pushpull has been called is nil. Therefore you need to break before doing the pushpull and inspect the value of the referenceface (e.g. with puts('face', face.inspect)).
Apparently ents.add_face circle has returned nil. This happens when a face in the same place already exists. The circle face already exists because it has been created automatically out of the square when you inserted the circle edges that partition the square into two faces.
This is a tricky part of trying to use the API like you would model manually. The add_circle method creates edges and returns them, but it triggers also automatic merging and splitting which causes SketchUp to create a circle face, but it is not returned as a reference.
But in order to continue your script, you need a reference and you need to be sure that you find the reference for the right entity (you cannot rely on guessing, programming must always be unambiguous).
Methods with side effects (automatic merging and splitting) are a bit indeterministic.
A work-around is to compare a snapshot of the existing entities before and after your operation and find the reference to the circle face this way. When thinking of work-arounds we need to ensure that there are no risky assumptions that may not always be true. This approach works here
when we can assume that exactly one circle face is created successfully (e.g. we must know no there are no existing edges that causes it to split into two or more circle sections with additional split edges).
we know there is no concurrency like a parallel process that interferes and add/remove entities between our snapshots.
An alternative is therefore to avoid operations that cause merging and splitting. When using the API, it is better to think in a different paradigm, not how to modify geometry like you would do with the mouse, but how to compute all the vertex positions of the final geometry. All experienced SketchUp developers prefer to compute the points using virtual geometry and trigonometry or vector math (Geom::Point3d, Math.sin or Geom::Transformation.rotation) and then add a face for these circle points using add_face.
A possibly irrelevant question: do you realize that coordinates in SketchUp Ruby API code are taken to be inches unless you explicitly specify units (e.g. 1000.mm) regardless of the model units you have set? The to_l method will convert value into a Length in the model’s units, but will rescale it to keep the equivalent to the original inches (e.g. 10.to_l => 25.4cm) I ask because the values in your snippet are suspiciously large (thousands) if taken to be inches.
This might not matter in your specific case, but you should also be aware that in SketchUp a “circle” is actually a regular polygon with some attached metadata that remembers the mathematical parameters of the true circle. The metadata is created during the add_circle method. There is no way to generate or attach it to a polygon after the fact. So, don’t expect to treat the result of building it via @Aerilius excellent suggestion to respond to circle-related (ArcCurve) methods.
That works because you didn’t first draw the ptsf face, so the circle is just that with no face in it. It lets the add_face succeed because there is no prior duplicate face (try breaking up the code right after the add_circle call and you will see this is true).
cv_arr = 
circle.each do |c|
cv_arr << c.vertices
What you are wanting to do, is “iterate the circle edges, and collect all the edge vertice arrays, flatten the array of nested arrays, then uniquify the array because there will be two references to every vertex in the array” …