Hi Tim,Take a look at the python script below. I hope this script makes the job.You can test it after modify inputs parameters.I'm going to optimize it for adding it in cgeoprocessing script tool gallery.
# -*- coding: cp1252 -*-
"""
ConeLineBuffer.py
Author : fpr
Many thank to rba for algorythm
Date: 01/25/2011
Description : Create cone from line buffer with min buffer value at the start line
and with max buffer value at the end line.
Warning:
you must have :
1. min value <> max value
2. start point of line always have the min value
3. end point of line always have the max value
Parameters list :
Parameters properties
Name Data type Type Direction Multiple value Default Filter Obtain from
argv[1] Input SHP Feature class Required Input No
argv[2] Input min radius long Required Input No
argv[3] Input max radius long Required Input No
----------------------------------------------------------------------
"""
# Import system modules
import arcpy, os
def getScratchWorkspace(outDataset):
# Set the scratchWorkspace environment to local file geodatabase
outPath = os.path.dirname(outDataset)
arcpy.CreateFileGDB_management(outPath, "scratch.gdb", "CURRENT")
scratchWorkspace = os.path.join(outPath, "scratch.gdb")
arcpy.env.scratchWorkspace = scratchWorkspace
return scratchWorkspace
def getStartPointOfLine(line):
"""
Return first point of line
"""
pointStart = arcpy.Point()
pointStart = line.firstPoint
return pointStart
def getEndPointOfLine(line):
"""
Return end point of line
"""
pointEnd = arcpy.Point()
pointEnd = line.lastPoint
return pointEnd
def bufferPoint(point, dis, scratchWorkspace, outName):
# Process : buffer first point of line
pointGeometry = arcpy.PointGeometry(point)
outBufferPoint = scratchWorkspace + "\\" + outName
if arcpy.Exists(outBufferPoint):
outBufferPoint = outBufferPoint + "1"
arcpy.Buffer_analysis(pointGeometry, outBufferPoint, dis, "FULL", "ROUND", "NONE", "")
return outBufferPoint
def creerPolyligneSelonPoint(PointDebut, arcTan, longueurLigne):
import math
"""Retourne un objet ligne à partir du point de début, un angle et une longueur.
INPUTS:
point de début, l'angle de la ligne, une longueur
OUTPUT:
objet ligne
"""
#Créer une polyligne
array = arcpy.Array()
array.add(PointDebut)
# Détermine le point de fin selo
PointFin = arcpy.Point()
PointFin.X = PointDebut.X - math.sin(arcTan)* longueurLigne
PointFin.Y = PointDebut.Y - math.cos(arcTan)* longueurLigne
array.add(PointFin)
polyline = arcpy.Polyline(array)
array.removeAll()
return polyline
def arcTanEntreDeuxPoints(PointDebut, PointFin):
import math
"""Retourne l'arc tan entre deux points.
INPUTS:
point de début et point de fin
OUTPUT:
arcTan
"""
arcTan = math.atan2((PointDebut.X - PointFin.X),(PointDebut.Y - PointFin.Y))
return arcTan
def distanceRelative(Distance, Pourcentage):
"""Retourne la distance issue du pourcentage souhaitée.
INPUTS:
distance
OUTPUT:
50 pourcent de la distance par exemple
"""
distanceRel = (float((Distance)) * float(Pourcentage))/100
return distanceRel
def distanceEntreDeuxPoints(PointDebut, PointFin):
import math
"""Retourne la distance entre deux points.
INPUTS:
point de début et point de fin
OUTPUT:
distance
"""
distance = math.sqrt((PointDebut.X - PointFin.X)**2 + (PointDebut.Y - PointFin.Y)**2)
return distance
def getTangentIntersect(radiusCircleMin, radiusCircleMax, dist2points):
""" Return intersection point of circle tangent a with the line
"""
GetTangentIntersect = (radiusCircleMin * dist2points)/ (radiusCircleMax - radiusCircleMin)
return GetTangentIntersect
def deleteFcStoreScratchWorkspace(pathFGDB, wild_card):
arcpy.env.workspace = pathFGDB
fcs = arcpy.ListFeatureClasses(wild_card)
for fc in fcs:
arcpy.Delete_management(fc)
return
def run_ConeLineBuffer():
inFC = r"D:\fpr10_PYDEV\fprPYDEV_v10\ConeLineBuffer\data\lines.shp" # CHANGE
inRadiusBufferMin = 50 # CHANGE
inRadiusBufferMax = 300 # CHANGE
return create_ConeLineBuffer(inFC, inRadiusBufferMin, inRadiusBufferMax)
def create_ConeLineBuffer(inFC, inRadiusBufferMin, inRadiusBufferMax):
arcpy.AddMessage("*"*10)
arcpy.AddMessage("Process : Create cone line buffer ...\nrunning ...")
arcpy.OverWriteOutput = True
# Process: Define the scratch workspace
sw = getScratchWorkspace(inFC)
arcpy.env.workspace = sw
# Process: get path of input ...
outPath = os.path.dirname(inFC)
# Process: prepare SQL query SHP or GDB
OID = arcpy.Describe(inFC).OIDFieldName
delimitedField = arcpy.AddFieldDelimiters(inFC, OID)
# Iterate through the lines in the cursor
sRows = arcpy.SearchCursor(inFC)
for sRow in sRows:
index = sRow.getValue(OID)
shapeLine = sRow.Shape
# Process : Get start and end point of line
startPoint = getStartPointOfLine(shapeLine)
endPoint = getEndPointOfLine(shapeLine)
# Process : Create buffer for start/end line
bufferMin = bufferPoint(startPoint, str(inRadiusBufferMin) + " Meters", sw, "_bufferMin")
bufferMax = bufferPoint(endPoint, str(inRadiusBufferMax) + " Meters", sw, "_bufferMax")
## Process : Search point a
dist2points = distanceEntreDeuxPoints(startPoint, endPoint)
a = getTangentIntersect(inRadiusBufferMin, inRadiusBufferMax, dist2points)
radiusCircleMax = (dist2points + a)/2
## Process : Create circle c1 (Max)
# Process: Get arctan of line
valeurArcTan = arcTanEntreDeuxPoints(endPoint, startPoint)
# Process: create line
lineCircleMax = creerPolyligneSelonPoint(endPoint, valeurArcTan, radiusCircleMax)
# Process :
endPtCircleMax = getEndPointOfLine(lineCircleMax)
# Process :
circleMax = bufferPoint(endPtCircleMax, radiusCircleMax, sw, "_circleMax")
# Process : Intersect BufferMaw with CircleMax to get
# Process: Intersect
intersectMax = sw + "\\_intersectMax"
arcpy.Intersect_analysis(bufferMax + ";" + circleMax, intersectMax, "ALL", "", "POINT")
## Process : Create circle c2 (Min)
radiusCircleMin = a/2
# Process: create line
lineCircleMin = creerPolyligneSelonPoint(startPoint, valeurArcTan, radiusCircleMin)
# Process :
endPtCircleMin = getEndPointOfLine(lineCircleMin)
# Process :
circleMin = bufferPoint(endPtCircleMin, radiusCircleMin, sw, "_circleMin")
# Process :
# Process : Intersect BufferMaw with CircleMax to get
# Process: Intersect
intersectMin = sw + "\\_intersectMin"
arcpy.Intersect_analysis(bufferMin + ";" + circleMin, intersectMin, "ALL", "", "POINT")
# Process :
arcpy.env.workspace =sw
arcpy.Merge_management([intersectMin, intersectMax], "_intersectMerge")
# Process: Minimum Bounding Geometry
arcpy.MinimumBoundingGeometry_management("_intersectMerge", "_Bounding", "CONVEX_HULL", "ALL", "", "NO_MBG_FIELDS")
# Process: Merge
Bounding = sw + "\\_Bounding"
arcpy.Merge_management([bufferMin, bufferMax, Bounding], "_Bounding_Merge")
# Process: Dissolve
Bounding_Merge = sw + "\\_Bounding_Merge"
arcpy.Dissolve_management(Bounding_Merge, "result" + str(index), "", "", "MULTI_PART", "DISSOLVE_LINES")
# Process : delete intermediate fc begin by "_"
deleteFcStoreScratchWorkspace(sw, "_*")
# Process: Merge all result feature classes
## Create a value table to hold names of input feature classes for Merge tool.
vt = arcpy.ValueTable()
fcs = arcpy.ListFeatureClasses("r*")
for fc in fcs:
vt.addRow(fc)
outFC = os.path.join(outPath,"ConeLineBuffer.shp")
arcpy.Merge_management(vt, outFC)
# Process: Delete scratch workspace
arcpy.Delete_management(sw)
arcpy.AddMessage("Process: End")
arcpy.AddMessage("*"*10)
if __name__ == '__main__':
run_ConeLineBuffer()