Changing transparency of a selected group in ruby

Dear friends,

In following example code, I wish to select all faces that connected to face2 (box in this example) then read and change its opacity. Would you please help me for it…

UI.menu("Plugins").add_item("Box") {
Sketchup.active_model.select_tool(Box.new)
}
class Box
  def activate
    mod = Sketchup.active_model
    sel = mod.selection
    ent = mod.active_entities
#Make a group

    pt1 = [0, 0, 0]
    pt2 = [2, 0, 0]
    pt3 = [2, 10, 0]
    pt4 = [0, 10, 0]
    grp = mod.active_entities.add_group
    face1 = grp.entities.add_face [pt1, pt2, pt3, pt4]    
    face1.pushpull -10
  end
  def deactivate(view)
    view.invalidate
  end
  def onLButtonDown(flags, x, y, view)
    mod = Sketchup.active_model
    sel = mod.selection
  # select face
    input = Sketchup::InputPoint.new
    input.pick view, x, y
    view.model.active_path = input.instance_path.valid? ? input.instance_path : nil
    face2 = input.face

    # Code????

  end  
end

Assuming that your face2 is valid AND it’s a face - i.e. NOT a group as your title suggests ??
Try something like this…

mats=Sketchup.active_model.materials
mat=mats.add("MyMatName") unless mat=mats["MyMatName"] # or another name
mat.alpha=0.5 # or other transparency
faces=[]
edges=face2.edges
edges.each{|e|
  faces << e.faces
}
faces.flatten!
faces.uniq!
faces.each{|f|
  f.material = mat
}

PS: also include all of your code inside your own name-space module…

1 Like

Thank you for your codes but I have 2 problems. 1- cannot change transparency of backside of box. 2- Transparency change from outside not both outside and inside. Next time for codes I will follow your advice.

f.material = mat
f.back_material = mat

?

1 Like

unfortunately f.back_material = mat cannot work.

How doesn’t it work.
A face has a .material and a .back_material - both of which can be changed in code…
Please explain your problem more clearly…

1 Like

following code works.

      faces.each{|f|
      f.material = mat
    }
      faces.each{|f|
      f.back_material = mat
    }

I try to “summarizing” the help from TIG for you :wink:

Your onLButtonDown method should look like this:

def onLButtonDown(flags, x, y, view)
    mod = Sketchup.active_model
    sel = mod.selection
  # select face
    input = Sketchup::InputPoint.new
    input.pick view, x, y
    face2 = input.face
    if face2
      mats=Sketchup.active_model.materials
      mat=mats.add("MyMatName") unless mat=mats["MyMatName"] # or another name
      mat.alpha=0.5 # or other transparency
      faces=[]
      edges=face2.edges
      edges.each{|e|
        faces << e.faces
      }
      faces.flatten!
      faces.uniq!
      faces.each{|f|
        f.material = mat
        f.back_material = mat
      }
    else
      view.model.active_path = input.instance_path.valid? ? input.instance_path : nil
    end
end
1 Like

You are so clever!!! It works but still I have other problem. When we select one side of a box, all other sides of box will be transparency except opposite side. (opposite side is not connected to face directly). How can I change transparency of all sides of box?

Something like this:

References

References:
Face#all_connected-instance_method
Vector3d#parallel-instance_method
Face.normal-instance_method

  def onLButtonDown(flags, x, y, view)
      mod = Sketchup.active_model
      sel = mod.selection
    # select face
      input = Sketchup::InputPoint.new
      input.pick view, x, y
      face2 = input.face
      if face2
        mats=Sketchup.active_model.materials
        mat=mats.add("MyMatName") unless mat=mats["MyMatName"] # or another name
        mat.alpha=0.5 # or other transparency
        connected = face2.all_connected
        faces = connected.grep(Sketchup::Face)
        faces.each{|f|
          #this will make transparent the face2 and opposite face
          if f.normal.parallel?(face2.normal) # you can take out this condition if want all faces transparent
            f.material = mat
            f.back_material = mat
          end  # you can take out this condition if want all faces transparent
        }
      else
        view.model.active_path = input.instance_path.valid? ? input.instance_path : nil
      end
  end

It works really good and my problem completely solved. Thank you so much. Is it possible first we select group and change group transparency or we have to change material of faces as you did?

Administrative note : Please do not quote my full post just above your answer!

  def onLButtonDown(flags, x, y, view)
      mod = Sketchup.active_model # this line not in use in this code
      sel = mod.selection # this line not in use in this code
    # select face
      input = Sketchup::InputPoint.new
      input.pick view, x, y
      face2 = input.face
      
      # prints the instance path to Ruby console. 
      # CHECK THIS OUT yourself what you see in console when you clicks 
      p input.instance_path.to_a

      if face2
        mats=Sketchup.active_model.materials
        mat=mats.add("MyMatName") unless mat=mats["MyMatName"] # or another name
        mat.alpha=0.5 # or other transparency
        path = input.instance_path.to_a
        gr = path.grep(Sketchup::Group).first
        gr.material = mat if gr

          #this is now may obsolete below here:
      # else
          #view.model.active_path = input.instance_path.valid? ? input.instance_path : nil
      end
  end

1 Like

Your codes are really good and simply I can use it in my own plugins. Please forgive me to bother you again. I wish to pick material from face2, change its transparency and color and at the end return it to its original material. Can you help me for it?

Here we are. Try and find out how and why it works.
You must find the “right” face to click to get the color/transparency change effect!

In a return, I would like to ask you to find the description:
of the
view.draw_text instance method,
as well as the
Color class description
in a Ruby API documentation and copy-paste a link for me. :wink:

module Majid866
module Test

class Box
  def activate
    # note the variable start with '@', meaning
    # it is 'exposed' to other methods 
    # within this class instance
    # in other words this is instance variable
    # so we can, and will use it e.g. in onLButtonDown method
    
    mod = Sketchup.active_model
    sel = mod.selection #not used
    ent = mod.active_entities
    #Make a group
    pt1 = [0, 0, 0]
    pt2 = [2, 0, 0]
    pt3 = [2, 10, 0]
    pt4 = [0, 10, 0]
    grp = mod.active_entities.add_group
    @face1 = grp.entities.add_face [pt1, pt2, pt3, pt4]
    
    # add a "built in" Color object to face to be able see differences 
    #   ( face.material method accept it as material ) 
    @face1.material = "HotPink"
    @face1.back_material = "HotPink"
    @face1.pushpull -10
    
    #Define a material with color transparency for later use
    mats = Sketchup.active_model.materials
    @mat = mats.add("MyMaterial") unless @mat = mats["MyMaterial"] # or another name
    #add color
    @mat.color = "Dodgerblue" # or other color
    #add transparency
    @mat.alpha = 0.5 # or other transparency
    
    #define a status of the tool
    @state = 1
    
    #define a "status" text initial value 
    @face_is_what_we_want = "Click on the right face!"
  end
  def deactivate(view)
    view.invalidate
  end
  def onLButtonDown(flags, x, y, view)
    # use some InputPoint methods to see if the cursor on face
    input = Sketchup::InputPoint.new
    input.pick view, x, y
    face2 = input.face
    
    # The InputPoint#face method will return a Sketchup::Face object OR nil
    # boolean check will return false if it is nil, or true if it is some face
    # So, we can test if the cursor is over some face
    # then if we get true then we will deal with it 
    
    # the second condition is checking if the picked face2
    # is the same as we first created in the activate method
    if face2 && face2 == @face1
      
      # Check the status
      case @state
      when 1
        # retrieve and store the material 
        @original_mat = face2.material
        
        # change the face2 material to your above defined material
        face2.material = @mat
        face2.back_material = @mat #optional
        
        # Change a status of the tool, so your next click will
        # "land" in state 2 condition
        @state = 2
      when 2
        face2.material = @original_mat
        face2.back_material = @original_mat #optional
        
        # Change a status of the tool back to 1
        # so you can click and click "forever"
        @state = 1
      end #case
            
      #set the "status" text if we are on a right face
      @face_is_what_we_want = "You are Smart. Click again"
    else
      #set the wrong "status" text if we are on a wrong face
      @face_is_what_we_want = "Ups! Try again to click on the right face!"
    end #if
    view.invalidate
  end
  
  #Print out to screen upper left 
  def draw(view)
      view.draw_text( [10,10], @face_is_what_we_want )
  end
end # Class

end # module Test
end # module Majid866

It would be appropriate to wrap the Box class inside a uniquely named module. As is, the Box class is created directly in the global namespace.

1 Like

It has been told many times… but he do not get it.
I hope he will use this only his own and will wrap in later… anyway I edited.
I wanted to help him to get some basic.

1 Like

Sorry to bother you again. I will follow your advice and will try for improvement. I used your code in following example I supposed in second click, box color will be red (Original color) but it change to white!!! Can you help me to find problem?

module Majid866
UI.menu("Plugins").add_item("Box") {
Sketchup.active_model.select_tool(Box.new)
}
class Box
  def activate
    mod = Sketchup.active_model
    sel = mod.selection
    ent = mod.active_entities
#Make a group

    pt1 = [0, 0, 0]
    pt2 = [2, 0, 0]
    pt3 = [2, 10, 0]
    pt4 = [0, 10, 0]
    @st = 0
    grp = Sketchup.active_model.active_entities.add_group
    face1 = grp.entities.add_face [pt1, pt2, pt3, pt4]    
    face1.pushpull -10
    grp.material = "red"
  end
  def deactivate(view)
    view.invalidate
  end
  
  def onLButtonDown(flags, x, y, view)
    if @st == 0
      input = Sketchup::InputPoint.new
      input.pick view, x, y
      face2 = input.face      
      if face2
        @st += 1
        @original_mat = face2.material  # Should be red if click on box      
        mats = Sketchup.active_model.materials
        mat = mats.add("green") unless mat = mats["green"] # or another name
        mat.alpha = 0.2 # or other transparency
        path = input.instance_path.to_a
        @gr = path.grep(Sketchup::Group).first
        @gr.material = mat if @gr
      end
    else
      @st = 0
      @gr.material = @original_mat # 
    end  
  end
end
end

I know my problem and it was my plan to review all after solving this problem. I plan to use this example in a bigger plugins and it is why I use variables the way that make no sense. for example I know in second click I can select group again but in my final codes, I will make a hole in box and second click cannot find group. Let me keep instance variables for further uses.

You have been applied a material to the group. The faces still have the default “white” material.
Please check it “manually”. I mean draw a box in SU - without Ruby code - put into group, apply material to group and double click to edit. If you select the face you will see what I described above.

Therefore when you are queering the face.material you will get the “white” not red!

If you check my previous code you can see I applied material to face with this “special” purpose!

You are good teacher. I need time to review all codes and have better understanding. After many tries also I find out difference between group material and face material and solve problem by following codes although I didn’t know why but I feel shy to ask you. I am so happy you told me reason. Thank you.

module Majid866
UI.menu("Plugins").add_item("Box") {
Sketchup.active_model.select_tool(Box.new)
}
class Box
  def activate
    mod = Sketchup.active_model
    sel = mod.selection
    ent = mod.active_entities
#Make a group

    pt1 = [0, 0, 0]
    pt2 = [2, 0, 0]
    pt3 = [2, 10, 0]
    pt4 = [0, 10, 0]
    @st = 0
    grp = Sketchup.active_model.active_entities.add_group
    face1 = grp.entities.add_face [pt1, pt2, pt3, pt4]    
    face1.pushpull -10
    grp.material = "red"
  end
  def deactivate(view)
    view.invalidate
  end
  
  def onLButtonDown(flags, x, y, view)
    if @st == 0
      input = Sketchup::InputPoint.new
      input.pick view, x, y
      face2 = input.face      
      if face2
        @st += 1    
        mats = Sketchup.active_model.materials
        mat = mats.add("green") unless mat = mats["green"] # or another name
        mat.alpha = 0.2 # or other transparency
        path = input.instance_path.to_a
        @gr = path.grep(Sketchup::Group).first
        @original_mat = @gr.material
        @gr.material = mat if @gr
      end
    else
      @st = 0
      @gr.material = @original_mat # 
    end  
  end
end
end