0

I have a script that places two sets of meshes into a list. When I want to export the result, I load all the objects into a scene and then I export the scene. One being a set of slanted cylinders, and the other a set of vertical cylinders.

Each slanted cylinder is translated and transformed so that it is pointing towards the next (closest) vertical cylinder, but for some reason when the final scene is exported the slanted cylinders appear below the vertical cylinders.

the slanted beams/braces that are present are supposed to start at the top of each cylinder and move across to the next closest cylinder.

**How can I make it so the slanted cylinders are merged together instead of appearing below the vertical cylinders? **

Here is my implementation;

import trimesh
import numpy as np

connection_points = read_blue_points_file("blue_points.txt")
cylinders = []
beams = []
scene = trimesh.Scene()

# Sort the array by the X coordinate
connection_points = connection_points[connection_points[:, 0].argsort()]
print(connection_points)

# Create Cylinders
for point in connection_points:
    height = point[2]
    cylinder = trimesh.primitives.Cylinder(radius=0.5, height=height, transform=None, sections=32, mutable=True)
    cylinder.apply_translation((point[0],point[1],0))
    cylinder.collide = False
    cylinders.append(cylinder)

for index, point in enumerate(connection_points):
    if index < len(connection_points) - 1:
        current_cylinder = point
        next_cylinder = connection_points[index + 1]

    Angle = find_angle_between_points(current_cylinder, next_cylinder)
    Direction = current_cylinder - next_cylinder

    rotation_matrix = trimesh.transformations.rotation_matrix(angle = Angle , direction = Direction)
    distance = distance_between_points(current_cylinder, next_cylinder)
    beam = trimesh.primitives.Cylinder(Radius = 0.1, height = distance/2, transform=rotation_matrix, Sections=32, mutable=True)
    beam.apply_translation(next_cylinder)
    beams.append(beam)
        def read_blue_points_file(filename):
      """Reads a text file of blue points and returns an array of points."""
    
      points = []
      with open(filename, "r") as f:
        for line in f:
          point = [float(x) for x in line.split(",")]
          points.append(point)
    
      return np.array(points)
def find_angle_between_points(point1, point2):
    # Calculate the angle between the two vectors
    angle = np.arccos(np.dot(point1, point2) / (np.linalg.norm(point1) * np.linalg.norm(point2)))

    return math.degrees(angle)
#input two XYZ points, return distance between points
def distance_between_points(point1, point2):

  # Convert the points to numpy arrays.
  point1 = np.array(point1)
  point2 = np.array(point2)

  # Calculate the difference between the two points.
  difference = np.subtract(point2, point1)

  # Calculate the norm of the difference vector.
  norm = np.linalg.norm(difference)

  # Return the distance.
  return norm

Text File of List of points

Current Result

GIo
  • 3
  • 3
  • Welcome Glo! Are you able to post a minimal working example maybe with say 5 points hard coded? – gremto Jun 16 '23 at 10:01
  • Hi, I posted an image labeled as "current result" under the code I provided. – GIo Jun 16 '23 at 16:17
  • Thanks Glo, the image is helpful, but it would be more useful to be able to run the code in order to help you resolve the problem. – gremto Jun 16 '23 at 17:16
  • Sorry! I Didn't realize what you were asking, I updated the provided code to be a little more helpful – GIo Jun 16 '23 at 17:26
  • No probs, do you have the code for find_angle_between_points() and distance_between_points() or are they part of an import? – gremto Jun 16 '23 at 18:53
  • Yes, I've updated the provided code to include those two – GIo Jun 16 '23 at 19:05
  • Hi Glo, I think your angle calculation might not be doing what you actually need: at the moment you're calculating the angle between the vectors defined by OP1 and OP2 (where O is the origin and P1 and P2 refer to points 1 and 2). I think what you really need is the rotation matrix to transform your original cylinder to the orientation defined by vector P1P2 if that makes sense? It looks like there's a useful utility to help you anyway using trimesh.geometry.align_vectors() – gremto Jun 17 '23 at 09:58
  • Also I think the translation should be something more like "current_cylinder - Direction*0.5" so it moves the beam to between the current and next cylinders – gremto Jun 17 '23 at 17:44

1 Answers1

0

With the above mentioned tweaks, here's some output I used to check it- note I might have flipped it vertically- but should be enough for you to get yours working:

enter image description here

Updated code as follows:

import trimesh
import numpy as np

#input two XYZ points, return distance between points
def distance_between_points(point1, point2):

    # Convert the points to numpy arrays.
    point1 = np.array(point1)
    point2 = np.array(point2)

    # Calculate the difference between the two points.
    difference = np.subtract(point2, point1)

    # Calculate the norm of the difference vector.
    norm = np.linalg.norm(difference)

    # Return the distance.
    return norm

def find_angle_between_points(point1, point2):
    # Calculate the angle between the two vectors

    print("P1 ", point1)
    print("P2 ", point2)

    angle = np.arccos(np.dot(point1, point2-point1) / (np.linalg.norm(point1) * np.linalg.norm(point2-point1)))
    print("NormP1 ", np.linalg.norm(point1))
    print("NormP2 ", np.linalg.norm(point2))


    return np.degrees(angle)
def read_blue_points_file(filename):
      """Reads a text file of blue points and returns an array of points."""
    
      points = []
      with open(filename, "r") as f:
        for line in f:
          point = [float(x) for x in line.split(",")]
          points.append(point)
    
      return np.array(points)


def main():

    print("IN MAIN")
    connection_points = read_blue_points_file("blue_points.txt")
    cylinders = []
    beams = []
    scene = trimesh.Scene()
    # Sort the array by the X coordinate
    connection_points = connection_points[connection_points[:, 0].argsort()]
    print(connection_points)
    # Create Cylinders
    for point in connection_points:
        height = point[2]
        cylinder = trimesh.primitives.Cylinder(radius=0.5, height=height, transform=None, sections=32, mutable=True)
        cylinder.apply_translation((point[0],point[1],height/2))
        cylinder.collide = False
        cylinders.append(cylinder)

    for index, point in enumerate(connection_points):
        if index < len(connection_points) - 1:
            current_cylinder = point
            next_cylinder = connection_points[index + 1]

            Angle = find_angle_between_points(current_cylinder, next_cylinder)
            Direction = current_cylinder - next_cylinder
            print("direction", Direction)
            print("angle ", Angle)

            rotation_matrix = trimesh.geometry.align_vectors([0, 0, 1], Direction, return_angle=False)

            print("r matrix ", rotation_matrix)
            distance = distance_between_points(current_cylinder, next_cylinder)
            print(distance)

            beam = trimesh.primitives.Cylinder(radius = 0.1, height = distance, transform=rotation_matrix, sections=32, mutable=True)

            beam.apply_translation(current_cylinder - Direction*0.5)
            beams.append(beam)

    scene.add_geometry(cylinders)
    scene.add_geometry(beams)
    scene.export("op.stl")

if __name__ == '__main__':
    main()
gremto
  • 228
  • 2
  • 7