How to move, rotate, keep distance equal

Is there an extension or any tips how to do it?

I want the rectangles to be copied and rotated, but keep the exact distance between these the same, like the midle one. without needing to calculate anything.

The image below is what i tried to do. The left one is my input. The third one is what i tried and rotate them piece by piece.

Then i tried this: copy / 12 the rectangles in the midpoint of the rectangle. Then rotate by hand 45°/12 every piece. But the distance between is different. Is there a magic mathmatical formula to do this?

i think you are looking for curic space

SketchUp is quite capable of doing the calculation for you.
It is also tedious to manually create the positions and fully depends on the dimensions of the rectangle and the radius of rotation.

Copy/rotate the rectangle (a component!) as you did.
Then stitch the created rectangles head<>tail to eachother. To get the total length that they all need while rotated. This should be subtracted from the overall length between first and last rectangle.
The resulting edge from the subtraction can then be divided by 12 to get the required constant length betwee the subsequent rectangles, head<>tail.
It’s all a matter of shifting rectangles but ShetchUp does all the calculations.

I think they need the distance between the geometry of the rectangle to be the same, not the center to center distance… like it those were railing pickets and the minimum to code was 4", they could rotate however you want so long as the distance between the rectangles was the same 4" (or less).

OK. Thanks for the clarification. I was in the process of setting up a dynamic component that could distribute copies of a component and rotate them to the correct angle but was based on the distance between the origins of the components not the space between. I scrapped it and removed my post since I was going down the wrong path.

With the help of Gemini AI I have the ruby ​​code to create copies of the rectangle and set the rotation of each one to the desired angle, but it still needs to be completed with the possibility of setting the gap between the two closest points of the rotated rectangles.

  • ruby code - test at your own risk!
module MS_Tools
  module RotatedArray
    def self.create_array
      model = Sketchup.active_model
      selection = model.selection

      if selection.empty? || selection.length > 1
        UI.messagebox("Selectează o singură componentă sau un singur grup!")
        return
      end

      entity = selection.first
      unless entity.is_a?(Sketchup::ComponentInstance) || entity.is_a?(Sketchup::Group)
        UI.messagebox("Elementul selectat trebuie să fie o Componentă sau un Grup.")
        return
      end

      prompts = ["Număr copii:", "Unghi rotire / pas (grade):", "Distanță liberă (cm):"]
      defaults = [10, 5.0, 50.0]
      input = UI.inputbox(prompts, defaults, "Multiplicare și Rotire Incrementală")

      return unless input

      num_copies = input[0].to_i
      angle_deg = input[1].to_f
      clearance = input[2].to_f.cm

      step_angle_rad = angle_deg.degrees

      model.start_operation('Multiplicare Rotită Exactă', true)

      parent = entity.parent
      
      # Salvăm instanțele create pentru a le calcula colțurile exacte
      instances = [entity]
      
      current_y = 0.0
      base_trans = entity.transformation

      num_copies.times do |i|
        prev_inst = instances.last
        prev_tr = prev_inst.transformation

        # Unghiul pentru noua piesă
        new_angle = step_angle_rad * (i + 1)

        # Matrice de rotire pură pentru noua piesă
        t_rot = Geom::Transformation.rotation(ORIGIN, Z_AXIS, new_angle)

        # Aflăm punctele (colțurile) piesei anterioare în spațiul mondial (World Coordinates)
        prev_points = get_instance_corners(prev_inst)

        # Calculăm decalajul Y necesar încât min_dist(prev_points, new_points) == clearance
        # Facem un calcul exact pe axa Y:
        # Punctele noii piese înainte de translația Y (doar rotite):
        temp_tr = base_trans * t_rot
        untranslated_new_pts = get_points_with_transform(entity, temp_tr)

        # Găsim Y-ul minim astfel încât distanța minimă între orice punct din prev și new să fie clearance
        # Deoarece mișcarea e pe Y, căutăm deplasarea dy pe Y
        dy = calculate_required_y_shift(prev_points, untranslated_new_pts, clearance)

        current_y += dy

        final_tr = base_trans * Geom::Transformation.translation(Geom::Vector3d.new(0, dy, 0)) * (Geom::Transformation.rotation(ORIGIN, Z_AXIS, new_angle))
        
        # Păstrăm poziționarea cumulativă corectă
        if entity.is_a?(Sketchup::ComponentInstance)
          new_inst = parent.entities.add_instance(entity.definition, final_tr)
        else
          new_inst = parent.entities.add_group(entity.definition.entities.to_a)
          new_inst.transformation = final_tr
        end

        instances << new_inst
      end

      model.commit_operation
    end

    private

    def self.get_instance_corners(inst)
      bb = inst.definition.bounds
      tr = inst.transformation
      corners = []
      8.times { |idx| corners << bb.corner(idx).transform(tr) }
      corners
    end

    def self.get_points_with_transform(entity, tr)
      bb = entity.definition.bounds
      corners = []
      8.times { |idx| corners << bb.corner(idx).transform(tr) }
      corners
    end

    def self.calculate_required_y_shift(pts_below, pts_above_untranslated, target_dist)
      # Căutăm translația pe Y (shift_y) astfel încât distanța minimă 3D între colțuri să fie exact target_dist
      # Pentru că translația pe Y modifică distanța direct, calculăm offset-ul necesar între cele mai apropiate puncte.
      
      max_required_y = 0.0

      pts_below.each do |p1|
        pts_above_untranslated.each do |p2|
          # p2_translated = p2 + [0, shift_y, 0]
          # Vrem |p2_translated - p1| >= target_dist
          dx = p2.x - p1.x
          dz = p2.z - p1.z
          
          # Distanța în planul XZ între cele două puncte
          xz_dist_sq = dx*dx + dz*dz
          
          if target_dist*target_dist > xz_dist_sq
            dy_needed = Math.sqrt(target_dist*target_dist - xz_dist_sq) - (p2.y - p1.y)
            max_required_y = dy_needed if dy_needed > max_required_y
          else
            # Dacă distanța pe XZ e deja mai mare decât target_dist, p2 trebuie doar să fie deasupra lui p1 pe Y
            dy_needed = (p1.y - p2.y)
            max_required_y = dy_needed if dy_needed > max_required_y
          end
        end
      end

      max_required_y
    end
  end
end

MS_Tools::RotatedArray.create_array

In Blender, with the help of the Array modifier and the Align and Distribute extension, I can create the entire process to have that equal gap between elements.

Then the model can be exported for SketchUp.

Array, rotate and equal gaps in SketchUp, using Ruby code by Gemini AI (in post above), CLF Loose to groups and Curic Space (v1.1.2) extensions.