How to create a copy of face and add to its parent?

For every face which has front and back material I want to create one extra face with back material.
How can I create a copy of face ? This is what I’ve tried so far

def create_face(entities, face)
	pts = []
	count = 0
	normal = face.normal.reverse
	face.edges.each {|edge|
		p = edge.start.position
		pts[count] = [p.x + normal.x * 0.01, p.y + normal.y * 0.01, p.z + normal.z * 0.01]
		count = count + 1
		p = edge.end.position
		pts[count] = [p.x + normal.x * 0.01, p.y + normal.y * 0.01, p.z + normal.z * 0.01]
		count = count + 1
	f = entities.add_face(pts)
	f.material = face.back_material
	face.back_material = f.back_material = nil
	if f.normal == face.normal

I think there is better way to do it.
P.S. This code does not seem to be correct as it is creating triangles which were not there in original model.

Collect the face.outer_loop.vertices - they will always rotate ccw about the face normal except if the face was created flat at z==0 when it faces down against the logic of its vertices.
Inner loops’ (inner_loops=face.loops-[face.outer_loop]) vertices [around holes] will rotate cw [opposite the outer loop’s] - and remembered that you need to make the ‘hole’ faces first then the main face, and then delete the ‘hole’ faces.
You can get each point into a points array using vertex.position for each vertex
Set a vector from the face normal.
[or whatever dim]
Then offset these points in turn
Now use the points to make the face [with holes done initially if needed]

When the new face is made apply the materials as you show - although if there is any uv-mapping of the material’s texture you should also consider getting the original settings and mapping those to the newly added material’s texture too…

Alternatively, if the face is in the model.active_entities context [it’ll bugsplat otherwise!] you can replicate the face exactly as it is, by grouping it [its edges and materials come over into the group], norm=face.normal.reverse, then norm.length=0.001, then using group=entities.add_group(face) then get its origin with tr=group.transformation and origin=tr.origin
copy=entities.add_instance(group.definition, origin.offset(norm))

1 Like

Is this part of an exporter process? If so - then I’d recommend that you duplicate the faces in output file format. Modifying the model during export is not ideal and not something the user would expect. (Apologies if this isn’t what you are doing - but I’ve seen it done a number of times so I have to ask.)

Yes it will be part of export process. I was planning to duplicate the back faces with geometry and materials. Then export obj with single side.
How can I duplicate the faces in obj export ?
Duplication of the face can be achieved if I export it double sided but I need to duplicate the vertices also.

I’m wondering if a cleaner solution wouldn’t be to edit the obj model after export using some open source library. If I get this correctly it’s not really the source geometry you want to (persistently) modify, but the exported information you want to apply some special criteria to.

Also beware that a single SketchUp drawing context doesn’t allow for two faces to take up the same space. Same applies to vertices. To achieve something similar in SketchUp you need to separate these into different drawing contexts.

You could:

  • Start an operation
  • Group everything
  • Copy the group so you have two instances in the same place
  • Make one deeply unique
  • Iterate it recursively and reverse all its faces (just make sure not to iterate the same definition twice)
  • Export
  • Abort the operation.

However it is really a hack to start and abort operations this way. I try to avoid it.

When you write the data for a face in the OBJ file, write out a second set of face data there.

If you make changes to the SU model to solve output data it’ll probably be much slower - and the user is not expecting their model to be modified during an export.

1 Like