Well, how are your fence models oriented? Do you have multiple different models, each with its own orientation “baked in”, or do they all have the same initial orientation when they’re loaded and are they then rotated afterwards (using e.g. a call to set_hpr)? The latter would be easier to deal with.

Also, is the order in which the two points of a fence segment are given consistent? What I mean is, when looking straight at the model, is one point (e.g. fence_segment[0]) always to the left and the other point to the right of the fence? If not, it might be hard to tell whether the shear factor for a particular fence needs to be negative or positive.

Ideally you have one fence segment, which goes into the X direction, and then you rotate it after applying the shear.

Otherwise, you’re making things unnecessarily difficult for yourself. The easiest then would be to apply the inverse of the rotation to align it in the X direction, then apply the shear matrix, then re-apply the original rotation matrix. The transforms can be combined using matrix multiplication.

If I’m not much mistaken, if you model your fence such that one end of it is at the origin (i.e. the zero-position), and then you always place your fence such that its origin is at point A, then you will always know which end is associated with point A and which with point B. This should allow you to calculate a shear-factor based on those two points without worrying about which way around the fence is.

What behaviour are you seeing when you try that approach?

What rdb described should, I think, work, so my inclination is to suspect that there is another problem that’s preventing it from doing so.

Looking at that image, it seems that the shear factor is correct when the x-coordinate of point 1 is smaller than that of point 2, so it may be worth trying to negate the shear factor (multiply by -1) in the other case.

However, I do wonder if the heading angle is always correctly calculated. How do you calculate the “2D slope”?

Same results as before.
Thank you Thaumaturge for your help I really appreciate it.
I solved by adding a condition if x_point_1 is smaller than other points will make the shear factor a positive otherwise negative.
as Epihaius said.

Since the fences in your screenshots have different sizes, maybe you apply this scale in your actual project?
Scaling the model by 2 in height could explain the problem you are seeing.
It might be necessary then to apply the scale first, then the shear and finally the rotation and position. To do that, 3 different matrices need to be multiplied in that order:

slope = fence_line.get_slope()
model_angle = 180 - math.degrees(math.atan(slope))
for fence_segment in line :
fence_length = bounds[1][0] - bounds[0][0]
ratio = fence_segment.get_length() / fence_length
x = (fence_segment[0]['x'] + fence_segment[1]['x']) / 2
y = (fence_segment[0]['y'] + fence_segment[1]['y']) / 2
z_min = min(fence_segment[0]['z'], fence_segment[1]['z'])
fence_segment_model.setPos(x, -y, z_min)
fence_segment_model.setH(model_angle)
if fence_segment[0][2] != fence_segment[1][2]:
height = fence_segment[1][2] - fence_segment[0][2]
shear_factor = height / fence_segment.get_length()
if fence_line[0][0] < fence_line[1][0]:
shear_factor *= -1.
shear_mat = Mat4.shear_mat(0., shear_factor, 0.)
shear_mat.transpose_in_place()
scale_mat = Mat4.scale_mat(ratio, 1, 2)
# the final matrix combines scale, shear, rotation and position
# by multiplying corresponding matrices in a specific order
mat = scale_mat * shear_mat * fence_segment_model.get_mat()
fence_segment_model.set_mat(mat)
offset = abs(shear_factor) * fence_segment.get_length() * .31
fence_segment_model.set_z(fence_segment_model.get_z() + offset)
else:
fence_segment_model.set_scale(ratio, 1, 2)

If you use the above code exactly as written, does it look better then?