Hole cutting components - gluing behavior odd

Hi,

It seems odd to me that faces are distorted when a component is glued to a face that is not on the same plane as the component.

A much preferred method would be like this:

Or an alternative, but less preferred method (cut perpendicular to face):

As far as I know, there is no easy (or difficult) way to obtain this affect. Especially when you take into account that not all hole cutting components are rectangular.

Is this a bug? Or is this the intended behavior? Maybe if this is intended, a feature could be added such as ‘gluing_type’.

It isn’t normal behavior. I’ve had this happen to me before and wanted to report it as some bug. But after saving and reopening the file to report, there was nothing there anymore showing the distortion. The issue had healed itself by saving the file. And I wasn’t able to reproduce the distortion to report. But it’s certainly not a feature.

Hmmm… I missed that part. The ‘healing’ that occurs, is that the component is actually moved to match the plane of the face. Interesting!!! Not bad if that’s what you actually wanted.

It seems that a validity check is done when saving.

Should this be reported as a bug? Feature request?

I can’t see any use for this feature, although others might, who knows.
As for it being a bug, if it happens enough to others as well and it can be reproduced, certainly. Then yes, report it.

Hm… that’s indeed a bug in the Ruby API which doesn’t validate the planes before committing the operation.

1 Like

So… It seems to me that there should be a way to check if gluing the component will cause it to move. Or maybe even a feature to test a face, or an array of faces, and see if their planes are valid to glue the component to? It seems there is no possible way of getting the hole-cutting face of a component. I understand it’s not really a face, but its seems like there should be a way to figure out where the cutting will take place, or has taken place.

The cut will be the outer perimeter of the closed edge loop lying flat on the “ground plane” of the component (Z == 0).

So you can validate yourself by checking if the ground plane orientation of the component matches the plane of the face.

Can you post a sample line of code, showing how to do that.

GluedTo.skp (49.8 KB)

model = Sketchup.active_model
entities = model.active_entities

face = entities.grep(Sketchup::Face).first
instances = entities.grep(Sketchup::ComponentInstance)

# Assumes the instances are in the same Entities collection as the faces.
instances.each { |instance|
  point = instance.transformation.origin
  # The classify_point check is a very naive check to see if the origin of
  # the instance is actually on the face and not just on the plane.
  # You might have to tweak that to your conditions - like allowing the point
  # to be on the vertices and edges.
  if point.on_plane?(face.plane) && face.classify_point(point) == Sketchup::Face::PointInside
    puts "Gluing #{instance} to #{face}"
    instance.glued_to = face
  end
}

Thanks Thomas. That is useful to see if the origin is on plane, but still doesn’t address the real problem.

It might help to explain what I’m trying to do:

  1. Find all face my component intersects with (I know how to do this)
  2. Get the points of the cutting loop for the component. This would be the points for the ‘loop’ that cuts out the surface of the face.
  3. Create a new component with a cutting loop only.
  4. Place and Glue an instance of the newly created component on each face, adjusting each instance to match the plane of the face.

Number two is the only thing I have no way of doing.

You might want to see my Face Cutter Extension, to see what I’m trying to accomplish.

Only consider those faces in the active_entities context, AND sharing the instance,transformation(origin) point when checked, AND which have

face.normal == instance.transformation.zaxis

At least then you’ll avoid non-planar faces getting glued_to…

I see. Check first to see if the origin is on the face. then check the zaxis.
Now that part is solved.

I still have no way of know the dimentions of the cut hole. Currently I just create additional instances of the component. This works alright except for two things.

  1. For complex components you end up with a lot of geometry.
  2. The glass gets less translucent because of the additional copies.

In my building creator extension I can control the shape and size so know where to cut the hole, but with user supplied components there’s no way to know.

This is actually glued to a component.

You CAN get any component’s cutting outline…
See my HolePunchTool for some clues…

1 Like

Thanks @TIG,

That is exactly what I needed. Your get_oultine method is sweet. It looks like it probably doesn’t fall into the simple category. :wink:

Thanks also @thomthom, for your help.

I think I have all my questions answered, but I’m not marking a solution because the original question was about a bug that hasn’t been addressed.

One more question (this should be the last). If I check a component and the Z-axis is aligned with the plane of the face, but the component origin is not on the face, how can I calculate the distance between the face and the origin? On a normal wall this would be the wall thickness. And one more: how do I transform the component to move that distance? Basically I need to move the component to be on the face.

Sketchup::Face#plane()
returns a plane array for use with other API methods.

Geom::Point3d#project_to_plane()
returns a new point, upon the plane argument, closest to the point object itself.

Geom::Point3d#vector_to()
returns a new vector object between the point argument and the point itself.

The distance will be returned by the vector object’s length() instance method.
(But you do not really need it to move the component. You can test a vector if it is NOT of zero length via it’s valid?() instance method. See the example below that does this and only creates an undoable operation if the test is true.)

Geom::Transformation::new(vector)
or
Geom::Transformation::translation(vector) (likely a wrapper for the constructor call above)
returns a transformation object that can be used as an argument for a group or component’s move!() or transform!() methods.


Where face is your face object, and inst is your component instance:

origin = inst.transformation.origin
target = origin.project_to_plane( face.plane )
vector = origin.vector_to( target )
if vector.is_a?(Geom::Vector3d) && vector.valid?
  model.start_operation("Fix Component position",true)
    inst.transform!( Geom::Transformation::new(vector) )
  model.commit_operation
else
  # display a messagebox ?
end
1 Like

Thanks, That helps tremendously.

1 Like