It would be important to know what software you are using (and the version). Are you using desktop (Pro or ArcMap) or ArcGIS Online?
In case of Desktop, you could create a script to generate a field with the rotation based on the bisector. A few years ago I created a tool to define service areas of transmission tower applying the rotation based on the bisector (the green polygons in the image below):
The rotation determined by the tool could be written to the transmission towers and those can be used to define the rotation of the label. See the code below. The angles are determined on lines 51, 73 and 93.
import arcpy
def main():
import os
arcpy.env.overwriteOutput = True
fc = arcpy.GetParameterAsText(0)
fld_label = arcpy.GetParameterAsText(1)
fld_orden = arcpy.GetParameterAsText(2)
buf = arcpy.GetParameter(3)
fc_out = arcpy.GetParameterAsText(4)
sr = arcpy.Describe(fc).spatialReference
arcpy.AddMessage('Generar dictionarios con coordenadas, labels y orden...')
flds = (fld_orden, 'SHAPE@')
dct_crds = {r[0]: r[1] for r in arcpy.da.SearchCursor(fc, flds)}
flds = (fld_orden, fld_label)
dct_lbl = {r[0]: r[1] for r in arcpy.da.SearchCursor(fc, flds)}
arcpy.AddMessage('Ordenar torres...')
lst_ptgs = [pntg for orden, pntg in sorted(dct_crds.items())]
lst_orden = sorted(dct_crds.keys())
arcpy.AddMessage('Crear featureclass de salida...')
ws, fc_name = os.path.split(fc_out)
arcpy.CreateFeatureclass_management(ws, fc_name, "POLYGON", None, None, None, sr)
arcpy.AddField_management(fc_out, fld_label, "TEXT", None, None, 50)
flds_out = ('SHAPE@', fld_label)
lst_puntos = []
lst_lineas = []
lst_poligonos = []
arcpy.AddMessage('Recorrer torres...')
with arcpy.da.InsertCursor(fc_out, flds_out) as curs:
if len(lst_ptgs) >= 2:
pntg_1 = lst_ptgs[0]
pntg_2 = lst_ptgs[1]
angle_12 = getAngle(pntg_1, pntg_2)
cut_line = createPerpendicularCutLine(pntg_1, angle_12, buf, sr)
polygon = createServidumbre(pntg_1, cut_line, buf, sr)
lbl1 = dct_lbl[lst_orden[0]]
arcpy.AddMessage(' - procesar: {0}'.format(lbl1))
curs.insertRow((polygon, lbl1, ))
for i in range(1, len(lst_ptgs) - 1):
pntg_a = lst_ptgs[i - 1]
pntg_1 = lst_ptgs[i]
pntg_2 = lst_ptgs[i + 1]
angle_1a = getAngle(pntg_1, pntg_a)
angle_12 = getAngle(pntg_1, pntg_2)
bearing_l = (angle_1a + angle_12) / 2.0
cut_line = createCutLine(pntg_1, bearing_l, buf, sr)
polygon = createServidumbre(pntg_1, cut_line, buf, sr)
lbl1 = dct_lbl[lst_orden[i]]
arcpy.AddMessage(' - procesar: {0}'.format(lbl1))
curs.insertRow((polygon, lbl1, ))
if len(lst_ptgs) >= 2:
pntg_1 = lst_ptgs[len(lst_ptgs) - 2]
pntg_2 = lst_ptgs[len(lst_ptgs) - 1]
angle_21 = getAngle(pntg_2, pntg_1)
cut_line = createPerpendicularCutLine(pntg_2, angle_21, buf, sr)
polygon = createServidumbre(pntg_2, cut_line, buf, sr)
lbl1 = dct_lbl[lst_orden[len(lst_ptgs) - 2]]
arcpy.AddMessage(' - procesar: {0}'.format(lbl1))
curs.insertRow((polygon, lbl1, ))
arcpy.AddMessage('Listo...')
def createServidumbre(pntg, cut_line, servidumbre, sr):
'''
Create rectangle using the cutline
and the size of the servidumbre
'''
angle_cut_line = getAngleLine(cut_line)
tmp_pntg1 = pntg.pointFromAngleAndDistance(angle_cut_line, servidumbre / 2.0, 'PLANAR')
tmp_pntg2 = pntg.pointFromAngleAndDistance(angle_cut_line + 180, servidumbre / 2.0, 'PLANAR')
pntg1a = tmp_pntg1.pointFromAngleAndDistance(angle_cut_line - 90, servidumbre / 2.0, 'PLANAR')
pntg1b = tmp_pntg1.pointFromAngleAndDistance(angle_cut_line + 90, servidumbre / 2.0, 'PLANAR')
pntg2a = tmp_pntg2.pointFromAngleAndDistance(angle_cut_line + 90, servidumbre / 2.0, 'PLANAR')
pntg2b = tmp_pntg2.pointFromAngleAndDistance(angle_cut_line - 90, servidumbre / 2.0, 'PLANAR')
polygon = arcpy.Polygon(arcpy.Array([pntg1a.firstPoint, pntg1b.firstPoint,
pntg2a.firstPoint, pntg2b.firstPoint, pntg1a.firstPoint]), sr)
return polygon
def getAngleLine(line):
pntg1 = arcpy.PointGeometry(line.firstPoint, line.spatialReference)
pntg2 = arcpy.PointGeometry(line.lastPoint, line.spatialReference)
return getAngle(pntg1, pntg2)
def createPerpendicularCutLine(pntg, angle, dist, sr):
pntg_cut_1 = pntg.pointFromAngleAndDistance(angle - 90, dist * 2.0, 'PLANAR')
pntg_cut_2 = pntg.pointFromAngleAndDistance(angle + 90, dist * 2.0, 'PLANAR')
cut_line = arcpy.Polyline(arcpy.Array([pntg_cut_1.firstPoint, pntg_cut_2.firstPoint]), sr)
return cut_line
def createCutLine(pntg, bearing1, buf, sr):
bearing2 = bearing1 + 180
pntg_cut_1 = pntg.pointFromAngleAndDistance(bearing1, buf * 10.0, 'PLANAR')
pntg_cut_2 = pntg.pointFromAngleAndDistance(bearing2, buf * 10.0, 'PLANAR')
cut_line = arcpy.Polyline(arcpy.Array([pntg_cut_1.firstPoint, pntg_cut_2.firstPoint]), sr)
return cut_line
def createLine(pntg1, pntg2, sr):
return arcpy.Polyline(arcpy.Array([pntg1.firstPoint, pntg2.firstPoint]), sr)
def getAngle(pntg1, pntg2):
return pntg1.angleAndDistanceTo(pntg2, method='PLANAR')[0]
if __name__ == '__main__':
main()