Misplaced arcs after rotation

Hi everyone,
@Nick_Boyts @solamour
Can anyone explain me why I’m getting this bizarre issue?

After rotating the basic arc outer_arc within the ‘while’ loop. I noticed as I explain in the image below that all generated arcs, except the remainder arc, are offset by an angle = 67.499 degrees (which is the rotation angle used in the code and equal to: outer_arc.SweepAngle - out_circ_overlap_angle ). Consequently, they are misplaced even though their Start angles and Sweep angles are correct…(I used the following inputs in my script: circle radius = 9.125m , circular bar diameter = 25mm)

here my code:

arc_rotation
import sys
import clr
import math
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference('RevitNodes')
import Revit
from Revit.Elements import Element

element = IN[0]
cover = IN[1]
circular_bar_type = IN[2]
vertical_bar_type = IN[3]
H_s = IN[4]
V_s = IN[5]

geo = element.Geometry()
surfaces = geo[0].Explode()

s_area = []

for i in surfaces:
    s_area.append(i.Area)
    
S_area = ["%0.2f"%(round(i,2)) for i in s_area]
    
surf = []
surf_area = set()

for s, a in zip(surfaces, S_area):
    if a not in surf_area and S_area.count(a) == 2:
        surf.append(s)
        surf_area.add(a)
#getting circular curves        
out_cir_crv = surf[1].GetIsoline(1, 0).Explode()[0]

#getting vertical curves
out_V_crv = surf[1].GetIsoline(0, 1).Explode()[0]

# overlap lengths
circ_overlap_length = circular_bar_type.GetParameterValueByName("Diamètre de barre")*50/1000
V_overlap_length = vertical_bar_type.GetParameterValueByName("Diamètre de barre")*50/1000

# cover from side face to circular rebar centerline
cir_cover = cover

# cover from side face to vertical rebar centerline
V_cover = 2* cir_cover-cover + V_overlap_length/100

# circular curves for outer and inner sides
out_cir_crv = out_cir_crv.Offset(-cir_cover)
out_cir_crv = out_cir_crv.Translate(0, 0, cover + 1.5 * V_overlap_length/50 + vertical_bar_type.GetParameterValueByName("Diamètre de cintrage de crochet standard")/2000)

# total circular rebars length for outer and inner sides
out_circ_path = out_cir_crv.Length + circ_overlap_length

out_arc_length = out_cir_crv.Length

# total circular rebars length for outer and inner sides
out_circ_path = round(out_cir_crv.Length + circ_overlap_length, 2 )

out_Arc = []
#define arc with 12.00 m length
Pt1 = out_cir_crv.StartPoint
Pt2 = out_cir_crv.PointAtSegmentLength(6.00)
Pt3 = out_cir_crv.PointAtSegmentLength(12.00)
outer_arc = Arc.ByThreePoints(Pt1, Pt2, Pt3)

#compute the overlap length
out_circ_overlap_angle = circ_overlap_length * 360 / out_arc_length

#rebars count
n = int(-(((out_cir_crv.Length) / (outer_arc.Length - circ_overlap_length)) // -1))

# the case where the circumference < 12.00 m
if out_cir_crv.Length <= 12.00:
    out_Arc.append(out_circ_path)
    
#the case where circumference > 12.00 m     
else:
    k = 0
    while k < 600:
        k += 1
        outer_arc = outer_arc.Rotate(out_cir_crv.CenterPoint, Vector.ZAxis(), outer_arc.SweepAngle - out_circ_overlap_angle)
        #checking the last rebar condition
        if outer_arc.StartAngle +  outer_arc.SweepAngle> 360:
            outer_arc = Arc.ByCenterPointRadiusAngle(out_cir_crv.CenterPoint, out_cir_crv.Radius, outer_arc.StartAngle, out_circ_overlap_angle, Vector.ZAxis())
            outer_arc_length = round(outer_arc.Length, 3)
            if outer_arc_length == int(outer_arc_length):
                outer_arc_length = int(outer_arc_length)
            out_Arc.append(outer_arc)
            break
        out_Arc.append(outer_arc)


OUT = out_Arc

Be kind to check my dyn and Revit files below

Shaft_test.rvt (7.4 MB)
shaft_test_12m.dyn (19.5 KB)

Thanks.

We need to see the graph logic for modifying the arcs.

1 Like

@Nick_Boyts

Here the graph

Thanks.

We need to understand your process in order to suggest what might being going wrong. We need to see the python code and the full context of your graph. I don’t see where the second image connects to the first. It would also be helpful if you explained in more detail what it is you’re attempting to do.

1 Like

I’ve edited my reply. Probably, therefore, you have not seen the graph I added.

I’m attempting to rotate and copy an arc of a 12.00 m length around 360 degrees and getting the remaining arc at the end if its length is less than 12m.
Thanks.

1 Like

Sorry, I missed that.

I think you’re better off just mathematically determining how many full arcs you can fit and then calculating the remainder for the final arc length. In most cases like this, mathematically “predetermining” your sequences is simpler and more effective than a while loop.


(Offset used just to show arc placement.)

@Nick_Boyts

I forgot to mention that the arcs are overlapped with a distance d= 50 x bar diameter

I know that I can predetermine the number of full arcs, then calculate the remainder for the last arc. I used the same approach as you before, but in this case, I prefer to use a Python script instead of a graph and employ a while loop for rotation.

My issue arises from the first arc, which creates the offset when it is rotated, and I do not know how to eliminate this offset.

Thanks.

Is the math just not working out then? Are you sure the rotation method you’re using is in degrees and not radians?

Also, I noticed you define the same variable twice in a row. Is that correct?

# circular curves for outer and inner sides
out_cir_crv = out_cir_crv.Offset(-cir_cover)
out_cir_crv = out_cir_crv.Translate(0, 0, cover + 1.5 * V_overlap_length/50 + vertical_bar_type.GetParameterValueByName("Diamètre de cintrage de crochet standard")/2000)

You can certainly still use python. My point is that predefining the lengths and rotations makes everything else easier. The overlap is secondary to the bar placement. If you get your bars placed with their regular spacing, you can then extend the curves to overlap however you want.

Break down your steps and show intermediate outputs to confirm that everything is working as expected.

1 Like

@Nick_Boyts

The mathematical calculations are correct, as you can see in the image below, the numbers of arcs, their lengths, as well as their start and end angles, are correct. The only exception is the final end angle, which exceeds 360 degrees that I have updated it in the code to obtain the correct remaining length.

image

Here is the updated part of the code where I’ve added the start and end angles to output them as shown in the image above.

out_Arc = []
st_angles = ["Start_angles"]
end_angles = ["End_angles"]
#define arc with 12.00 m length
Pt1 = out_cir_crv.StartPoint
Pt2 = out_cir_crv.PointAtSegmentLength(6.00)
Pt3 = out_cir_crv.PointAtSegmentLength(12.00)
outer_arc = Arc.ByThreePoints(Pt1, Pt2, Pt3)

#compute the overlap length
out_circ_overlap_angle = circ_overlap_length * 360 / out_arc_length

#rebars count
n = int(-(((out_cir_crv.Length) / (outer_arc.Length - circ_overlap_length)) // -1))

# the case where the circumference < 12.00 m
if out_cir_crv.Length <= 12.00:
    out_Arc.append(out_circ_path)
    
#the case where circumference > 12.00 m     
else:
    k = 0
    while k < 600:
        k += 1
        outer_arc = outer_arc.Rotate(out_cir_crv.CenterPoint, Vector.ZAxis(), outer_arc.SweepAngle - out_circ_overlap_angle)
        st_angles.append(outer_arc.StartAngle)
        end_angles.append(outer_arc.StartAngle + outer_arc.SweepAngle)
        #checking the last rebar condition
        if outer_arc.StartAngle +  outer_arc.SweepAngle> 360:
            outer_arc = Arc.ByCenterPointRadiusAngle(out_cir_crv.CenterPoint, out_cir_crv.Radius, outer_arc.StartAngle, out_circ_overlap_angle, Vector.ZAxis())
            outer_arc_length = round(outer_arc.Length, 3)
            if outer_arc_length == int(outer_arc_length):
                outer_arc_length = int(outer_arc_length)
            out_Arc.append(outer_arc)
            break
        out_Arc.append(outer_arc)

out = ["updated end angle for the remainder arc"]
out.append(out_Arc[-1].SweepAngle)
OUT = out_Arc, st_angles, end_angles, out

To resolve this issue, I need to rotate back all arcs except the remainder arc with the offset angle of 67.499 degrees , but I’m struggling with how to do that.!?

I redefined this variable to initiate the distribution of the first circular bar over the hook of the vertical bar…

Thanks.

Hi @REDO10 , @Nick_Boyts ,

I feel like your complicating your approach since you don’t actually need angles to create arcs, you could (and in my opinion should) use segment lengths to create your arcs:

PS: Now that I’m looking at it, a List.ReplaceItemAtIndex for replacing the “-OVERLAP” part by a 0 is perhaps easier to understand instead of the List.DropItems and List.Join([0,…]). The functionality wouldn’t change though.

Code block code
RADIUS = 20;
ARC_LENGTH = 12;
OVERLAP = 1;

//Segment lenghts calculation (without taking overlap into account)
CIRCUMFERENCE = (2 * (Math.PI)) * RADIUS;
EFFECTIVE_ARC_LENGTH = ARC_LENGTH - OVERLAP;
SEGMENT_LENGTHS = (0..CIRCUMFERENCE..EFFECTIVE_ARC_LENGTH);

//Arc start lengths
SEGMENT_LENGTHS_WITH_OVERLAP = List.DropItems(SEGMENT_LENGTHS, 1) - OVERLAP;
START_LENGTHS = List.Join([0, SEGMENT_LENGTHS_WITH_OVERLAP]);

//Arc end lengths
SEGMENT_LENGTHS_WITH_CIRCUMFERENCE = List.Join([SEGMENT_LENGTHS, CIRCUMFERENCE]);
END_LENGTHS = List.DropItems(SEGMENT_LENGTHS_WITH_CIRCUMFERENCE, 1);


2023-10-28 Arcs + Remainder by ArcLength, Overlap and Remainder.dyn (24.1 KB)

4 Likes

Thanks @Daan for your reply

Your idea is one of several options to solve this issue, and it can be effective.

You forgot to include the overlap between the first and last arcs in your graph (as the arcs should overlap at both of their ends), but I believe you can rectify that.

As I mentioned to Nick earlier, I would rather utilize a Python script instead of a graph, but nonetheless, I appreciate your suggestion.

Thanks.

Yeah, instead of adding the total length of the curve for the last endpoint you can then just add the overlap value instead.

One question: Why?

1 Like

It’s just an organizational question. This code is a part of the main script, which is longer. I’m trying to build all the rebars of my model using the API, and I don’t want to see several nodes in my script that disturb me. It’s also an opportunity for me to learn more about how to use Python, both for Dynamo DesignScript and for the Revit API.

Thanks.

So convert the nodes to Python - this is a great way to learn.

2 Likes

@jacob.small

Of course, if I find the right solution that I’m looking for. :wink:

Doesn’t the solution which @Daan provided give you the geometry you’re after once you add the overlap value to the end of the last arc (or first if that’s what you’re after)? Seems a pretty easy addition on your own, and then you can move onto generating the Python code.

1 Like

@jacob.small

My issue is now solved by @Mike.Buttery here

here the code:

import clr
from math import pi

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")
from Revit.GeometryConversion import *

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import Arc, UnitUtils, UnitTypeId, Options, Transform, XYZ

# Helper functions
metres = lambda iu: UnitUtils.ConvertFromInternalUnits(iu, UnitTypeId.Meters)
degrees = lambda rad: UnitUtils.Convert(rad, UnitTypeId.Radians, UnitTypeId.Degrees)

# Inputs
pipe = UnwrapElement(IN[0])
rebar = UnwrapElement(IN[1])

# Get geometry (Largest circle at lowest point)
geom = pipe.get_Geometry(Options())
solids = list(geom.GetTransformed(Transform.Identity))[1]
curves = [e.AsCurve() for e in solids.Edges]
arcs = [c for c in curves if "Arc" in c.ToString()]
max_r_arc = max(arcs, key=lambda c: c.get_Radius()).get_Radius()
min_z_arc = min(
    [arc for arc in arcs if arc.get_Radius() == max_r_arc],
    key=lambda c: c.get_Center().Z,
)

# Parameters
l = 12
cover = 0.05
d = metres(rebar.BarModelDiameter)
r = metres(min_z_arc.get_Radius()) - cover
c = min_z_arc.get_Center()
c = XYZ(c.X, c.Y, c.Z + cover)

# Calculations
number_full_bars = int((2 * pi * r) // (l - 50 * d))
remainder_bar = round((2 * pi * r) - (l - 50 * d) * number_full_bars + 50 * d, 3)
bars = [12] * number_full_bars + [remainder_bar]
start_angles = [(l - 50 * d) / r * n for n in range(number_full_bars + 1)]
end_angles = map(sum, zip([bar / r for bar in bars], start_angles))

out_Arc = []
for i,j in zip(start_angles, end_angles):
    out_arc = Arc.Create(c, r, i, j, XYZ(1, 0, 0), XYZ(0, 1, 0))
    out_Arc.append(out_arc)

OUT = [i.Length for i in out_Arc]

Thanks

1 Like