Is there a simple way to change component axis rotation in ruby? It’s very simple in sketchup but I need to do that in order to retrieve the right dimensions of the wall with ruby.
I have read and trying a lot but nothing works
One “very simple” method to do it involving 4 times interaction of the USER:
- Right click on a desired component to select Change Axes
- Pick point for origin of axes
- Pick direction for red axis
- Pick direction for green axis
Actually you need to write a methods to determine the object, a point and at least two axes in a question.
Then you have to create a transformation and apply to the object then apply the inverse of this transformation to the object entities.
Perhaps you can start to check this:
.
.
Also, you can check if this one already fulfills your needs:
s4u-reset-axis
(Be careful because the developer is lying about the price of this extension on EWH)
thanks @dezmo
¿I did the first part but how can I aply the inverse to the object entiies?
a = Sketchup.active_model.selection[0]
targetPoint = a.bounds.center
vector = Geom::Vector3d.new(0,0,1)
degreesToRotate = 45.degrees
t=Geom::Transformation.rotation(targetPoint,vector,degreesToRotate)
a.transform!(t)
this doesn’t works
for ent in a.definition.entities
a.transform!(t.inverse)
end
``
Thanks a lot @dezmo I’m sure it will helps me.
@rtches Here is an example modified from @thomthom’s Skippy library
(which is used by the his Axes Tools.)
I modified it to try to determine what the new origin and 3 axis should be.
Test fully and modify further as needed.
Here is a test model:
instance_axes_reset.skp (21.7 KB)
module SomeAuthor::SomePlugin
extend self
def reset_axes(
instance = Sketchup.active_model.selection.first
)
return nil unless instance && instance.respond_to?(:definition)
model = instance.model
definition = instance.definition
# Get a new axes for the instance's definition:
new_axes = get_new_axes(definition)
# Adjust all the definition's entities to the new internal axes:
model.start_operation("Adjust Axes", true)
###
# Transform all of the definition's entities to the new axes:
definition.entities.transform_entities(
new_axes.inverse,
definition.entities.to_a
)
# Adjust the instance transformations:
definition.instances.each do |instance|
instance.transformation *= new_axes
end
#
###
model.commit_operation
return instance
end
def get_new_axes(definition)
entities = definition.entities
edges = entities.grep(Sketchup::Edge)
pts = edges.flat_map(&:vertices).uniq.map(&:position)
# Determine a new origin point for the new axes:
origin = get_new_origin(pts)
# Determine a new axes for the entities based upon edges
# that use the vertex at the new origin point.
edges.keep_if do |e|
e.vertices.any? {|v| v.position == origin }
end
# Map the edges to the points of their other vertex:
pts = edges.map do |e|
e.other_vertex(
e.vertices.find {|v| v.position == origin }
).position
end
# Now map those pts to normalized vectors along the edges:
vecs = pts.map {|pt| origin.vector_to(pt).normalize }
# Get an array of offset points from the normalized vectors:
pts = vecs.map {|vec| origin.offset(vec) }
# Sort by the z value:
pts.sort! {|a,b| a.z <=> b.z }
# Keep the 2 vectors with the smallest z values:
vecs.keep_if {|vec| pts[0..1].include?(origin.offset(vec)) }
# Sort these 2 vectors by their angle to the X_AXIS:
vecs.sort! {|a,b| a.angle_between(X_AXIS) <=> b.angle_between(X_AXIS) }
# The first vector in the sorted array will use as xaxis:
xaxis = vecs.first
# The zaxis will be a vector perpendicular to both other vectors.
# We use the cross product to find it:
zaxis = xaxis.cross(vecs[1])
# We do not know if vecs[1] is perpendicular in the XY plane to
# the xaxis. (Ie, the edges found may not be at right angles.)
# So we again produce another perpendicular vector by cross product:
yaxis = zaxis.cross(xaxis)
return Geom::Transformation::axes(origin, xaxis, yaxis, zaxis)
end
def get_new_origin(pts)
# Sort by the z value:
pts.sort! {|a,b| a.z <=> b.z }
# Keep only those whose z value is minimal:
z_min = pts.first.z
pts.keep_if {|pt| pt.z == z_min }
# Look for the point closest to X_AXIS (with smallest y value):
# Sort by the y value:
pts.sort! {|a,b| a.y <=> b.y }
y_min = pts[0].y
# Keep only points whose y is minimum:
pts.keep_if {|pt| pt.y == y_min }
if pts.size == 1
# Use it:
pts.first
else
# There are duplicate points equidistant from X_AXIS, so
# use the one furthest to the "right" with highest x value:
pts.sort! {|a,b| a.x <=> b.x }
pts.last
end
end
end # extension namespace module
@DanRathbun Brilliant!
My main goal is to make an extension that attach to the IFC classification of each element a PSet containing the quantity take off information as specified by Building SMART. When I collaborate with other teams their IFCs have such a PSet because Revit or Archicad add them but mine doesn’t.
Example with IfcWall
https://standards.buildingsmart.org/MVD/RELEASE/IFC4/ADD2_TC1/RV1_2/HTML/schema/ifcsharedbldgelements/lexical/ifcwall.htm
At the moment I have achieved this:
What IFC Manager adds to the component:
What my pluging is adding now hence my aim to get the correct axes.
When I export the model to IFC that information goes with the model and IFC viewers (Bim Vision, Bim Collabs Zoom, Trimble Connect, etc) show them as properties.
Thanks again @DanRathbun also @dezmo and @thomthom for your contributions.
Uh… huh. Thanks for the context (but it is a bit more information than is really needed for this specific topic.)
So just for a bit more advice, be aware of issues with getting the volume of scaled instances.
To discuss volume further, respond in topic:
How do you reliably get a group/component instances volume?
Thanks @DanRathbun I suffered it but in order to export to IFC I try to simplify geometry before.