def step_2():
    # Step 3: Reproject both shapefiles to EPSG3395 WGS '84 Transverse Mercator (for distance calculations in meters)
    in_a = os.path.join(utility.getPath_outputs()['step_1'],
                        os.path.basename(utility.getPath_centerlines()))
    in_b = os.path.join(utility.getPath_outputs()['step_1'],
                        os.path.basename(utility.getPath_glaciers()))
    print in_a
    print in_b

    out_a = os.path.join(utility.getPath_outputs()['step_2'],
                         'reproject_' + os.path.basename(in_a))
    out_b = os.path.join(utility.getPath_outputs()['step_2'],
                         'reproject_' + os.path.basename(in_b))

    centerline = QgsVectorLayer(in_a, os.path.basename(in_a), "ogr")
    glacier = QgsVectorLayer(in_b, os.path.basename(in_b), "ogr")

    crs = QgsCoordinateReferenceSystem(3395,
                                       QgsCoordinateReferenceSystem.EpsgCrsId)
    print "Coordinate Reference System (CRS) %s %s will be used." % (
        crs.authid(), crs.description())

    print "--> %s's CRS is: %s" % (centerline.name(),
                                   centerline.crs().authid())
    print "		Reprojecting %s to %s %s" % (centerline.name(), crs.authid(),
                                          crs.description())
    processing.runalg('qgis:reprojectlayer', centerline, crs.authid(), out_a)
    print "--> %s's CRS is: %s" % (glacier.name(), glacier.crs().authid())
    print "		Reprojecting %s to %s %s" % (glacier.name(), crs.authid(),
                                          crs.description())
    processing.runalg('qgis:reprojectlayer', glacier, crs.authid(), out_b)
def step_1():
    in_a = os.path.join(utility.getPath_inputs()['step_1'],
                        os.path.basename(utility.getPath_centerlines()))
    in_b = os.path.join(utility.getPath_inputs()['step_1'],
                        os.path.basename(utility.getPath_glaciers()))

    out_a = utility.getPath_outputs()['step_1']
    out_b = utility.getPath_outputs()['step_1']

    utility.copyShapefile(in_a, out_a)
    utility.copyShapefile(in_b, out_b)

    out_a = os.path.join(utility.getPath_outputs()['step_1'],
                         os.path.basename(utility.getPath_centerlines()))
    out_b = os.path.join(utility.getPath_outputs()['step_1'],
                         os.path.basename(utility.getPath_glaciers()))

    centerline = QgsVectorLayer(out_a, os.path.basename(out_a), "ogr")
    glacier = QgsVectorLayer(out_b, os.path.basename(out_b), "ogr")

    # Check that input files are valid.
    if not centerline.isValid():
        print "%s failed to load!" % centerline.name()
    if not centerline.crs().isValid():
        print "%s does not have a valid CRS." % centerline.name()
    if not glacier.isValid():
        print "%s failed to load!" % glacier.name()
    if not glacier.crs().isValid():
        print "%s does not have a valid CRS." % glacier.name()

    # Delete all unecessary fields.
    print "Cleaning attribute table... (%s)" % glacier.name()
    glacierFieldsToKeep = ['RGIId', 'GLIMSId']
    glacierFields = [field.name() for field in glacier.pendingFields()]
    fieldsDeleted = 0
    for f in glacierFields:
        if f not in glacierFieldsToKeep:
            fieldID = glacier.fieldNameIndex(f)
            print "  delete field... (%s)" % f
            glacier.dataProvider().deleteAttributes([fieldID])
            glacier.updateFields()
            fieldsDeleted += 1
    print "%d fields deleted from %s" % (fieldsDeleted, glacier.name())

    print "Cleaning attribute table... (%s)" % centerline.name()
    centerlineFieldsToKeep = ['GLIMSID', 'OBJECTID', 'LENGTH_CL']
    centerlineFields = [field.name() for field in centerline.pendingFields()]
    fieldsDeleted = 0
    for f in centerlineFields:
        if f not in centerlineFieldsToKeep:
            fieldID = centerline.fieldNameIndex(f)
            print "  deleting field... (%s)" % f
            centerline.dataProvider().deleteAttributes([fieldID])
            centerline.updateFields()
            fieldsDeleted += 1
    print "%d fields deleted from %s" % (fieldsDeleted, centerline.name())
def configure_folders():
	main_path = utility.getPath_main()
	if not os.path.isdir(main_path):
		print "Invalid main_path parameter in settings.py"
		sys.exit(1)

	shapefile_folder = utility.getPath_all_shapefiles()
	input_folder = utility.getPath_orig_shapefiles()
	if not os.path.isdir(shapefile_folder):
		os.mkdir(shapefile_folder)
	if not os.path.isdir(input_folder):
		os.mkdir(input_folder)
	inputs = utility.getPath_inputs()
	outputs = utility.getPath_outputs()
	for key in inputs:
		step_path = os.path.dirname(inputs[key])
		if not os.path.isdir(step_path):
			os.mkdir(step_path)
		if not os.path.isdir(inputs[key]):
			os.mkdir(inputs[key])
	for key in outputs:
		if not os.path.isdir(outputs[key]):
			os.mkdir(outputs[key])
	if not os.path.isfile(utility.getPath_centerlines()):
		return "Not a valid input centerline filepath"
		sys.exit(1)
	if not os.path.isfile(utility.getPath_glaciers()):
		return "Not a valid input glacier filepath"
		sys.exit(1)
	utility.copyShapefile(utility.getPath_centerlines(),input_folder)
	utility.copyShapefile(utility.getPath_glaciers(),input_folder)

	utility.copyShapefile(utility.getPath_centerlines(),inputs['step_1'])
	utility.copyShapefile(utility.getPath_glaciers(),inputs['step_1'])
def step_4b(glimsId):
    # Step 4b: Sort the centerlines in descending order of field "LENGTH_M"

    in_a = os.path.join(
        os.path.join(utility.getPath_outputs()['step_4'], glimsId),
        'ALL_lines_' + glimsId + '.shp')
    centerline = QgsVectorLayer(in_a, os.path.basename(in_a), "ogr")

    out_a = os.path.join(
        os.path.join(utility.getPath_outputs()['step_4'], glimsId),
        "ALL_sorted_" + glimsId + ".shp")

    writer = QgsVectorFileWriter(out_a, "CP1250", centerline.fields(),
                                 centerline.wkbType(), centerline.crs(),
                                 "ESRI Shapefile")
    if writer.hasError() != QgsVectorFileWriter.NoError:
        print("Error when creating shapefile: ", writer.errorMessage())
    sortindex = centerline.fieldNameIndex("LENGTH_M")
    direction = "descending"
    table = []
    for index, feature in enumerate(centerline.getFeatures()):
        record = feature.id(), feature.attributes()[sortindex]
        table.append(record)
    if (direction.lower() == "descending"):
        table.sort(key=operator.itemgetter(1), reverse=True)
    else:
        table.sort(key=operator.itemgetter(1))
    # Add features to new shapefile in same order as sorted table
    writecount = 0
    provider = centerline.dataProvider()
    objectIdIndex = centerline.fieldNameIndex("OBJECTID")
    print("  Glacier has " + str(len(table)) +
          " centerlines. Sorting centerlines by length.\n" +
          "  Sorted file will be written to: \n" + "    " + out_a)
    for index, record in enumerate(table):
        iterator = centerline.getFeatures(QgsFeatureRequest(record[0]))
        feature = QgsFeature()
        if iterator.nextFeature(feature):
            feature.setAttribute("LINE_ID",
                                 feature.attributes()[objectIdIndex])
            writer.addFeature(feature)
            writecount += 1
        if writecount == len(table):
            print "  " + str(writecount) + " of " + str(
                len(table)) + " features sorted successfully."
    # Delete the writer to flush features to disk
    del writer
def step_4c(glimsId):
    # Step 4c: Reproject sorted layer
    in_a = os.path.join(
        os.path.join(utility.getPath_outputs()['step_4'], glimsId),
        "ALL_sorted_" + glimsId + ".shp")
    out_a = os.path.join(
        os.path.join(utility.getPath_outputs()['step_4'], glimsId),
        "rpj_sorted_" + glimsId + ".shp")

    all_sorted = QgsVectorLayer(in_a, os.path.basename(in_a), "ogr")

    crs = QgsCoordinateReferenceSystem(3395,
                                       QgsCoordinateReferenceSystem.EpsgCrsId)
    print "Coordinate Reference System (CRS) %s %s will be used." % (
        crs.authid(), crs.description())

    print "--> %s's CRS is: %s" % (all_sorted.name(),
                                   all_sorted.crs().authid())
    print "		Reprojecting %s to %s %s" % (all_sorted.name(), crs.authid(),
                                          crs.description())
    processing.runalg('qgis:reprojectlayer', all_sorted, crs.authid(), out_a)
def step_3():
    # Step 3: Add length field to Centerline Shapefile
    in_a = os.path.join(
        utility.getPath_outputs()['step_2'],
        'reproject_' + os.path.basename(utility.getPath_centerlines()))
    utility.copyShapefile(in_a, utility.getPath_outputs()['step_3'])
    out_a = os.path.join(
        utility.getPath_outputs()['step_3'],
        'reproject_' + os.path.basename(utility.getPath_centerlines()))

    centerline = QgsVectorLayer(out_a, os.path.basename(out_a), "ogr")
    # lineLayer.dataProvider().AddAttributes([QgsField("LENGTH_M", QVariant.Double)])
    # lineLayer.updateFields()
    centerline.startEditing()
    centerline.addAttribute(QgsField('LENGTH_M', QVariant.Double))
    idx = centerline.fieldNameIndex('LENGTH_M')
    e = QgsExpression('$LENGTH')
    e.prepare(centerline.pendingFields())
    for f in centerline.getFeatures():
        f[idx] = e.evaluate(f)
        centerline.updateFeature(f)
    centerline.commitChanges()
def step_4a():
    # Step 4a: Extract one glacier polygon and all corresponding centerlines by GLIMS Id
    # REPEAT this step for every unique GLIMSID
    glimsId = 'G220886E60666N'
    print "Processing glacier: " + glimsId

    in_a = os.path.join(
        utility.getPath_outputs()['step_3'],
        'reproject_' + os.path.basename(utility.getPath_centerlines()))
    out_a = os.path.join(utility.getPath_outputs()['step_4'], glimsId)
    if not os.path.isdir(out_a):
        os.mkdir(out_a)
    out_a = os.path.join(out_a, 'ALL_lines_' + glimsId + '.shp')
    processing.runalg("qgis:extractbyattribute", in_a, "GLIMSID", 0, glimsId,
                      out_a)

    centerlines = QgsVectorLayer(out_a, os.path.basename(out_a), "ogr")
    res = centerlines.dataProvider().addAttributes(
        [QgsField("LINE_ID", QVariant.Int)])
    centerlines.updateFields()

    in_b = os.path.join(
        utility.getPath_outputs()['step_2'],
        'reproject_' + os.path.basename(utility.getPath_glaciers()))
    out_b = os.path.join(os.path.dirname(out_a),
                         "boundary_" + glimsId + "_poly.shp")
    processing.runalg("qgis:extractbyattribute", in_b, "GLIMSId", 0, glimsId,
                      out_b)

    in_c = out_b
    out_c = os.path.join(os.path.dirname(out_a),
                         "boundary_" + glimsId + "_line.shp")
    processing.runalg("qgis:polygonstolines", in_c, out_c)

    in_d = out_c
    out_d = os.path.join(os.path.dirname(out_a),
                         "diss_bound_" + glimsId + "_line.shp")
    processing.runalg("qgis:dissolve", in_d, False, "GLIMSId;RGIId", out_d)
def step_5(glimsId):
    '''
	Step 5: Extract centerlines 1 by 1 and put into individual folders
	 	      (they are now ordered in the db longest to shortest)
	'''
    bufferDistance = 250  #meters
    count = 0
    print(
        "  --> Extracting " + str(252) + " individual centerlines.\n" +
        "  --> A " + str(bufferDistance) +
        " meter buffer will be made for each centerline.\n" +
        "  --> Each buffer will be converted to a linetype geometry shapefile.\n"
        "  --> Each line-buffer will be intersected with all centerlines from the glacier."
    )
    '''
		Extent of glacier boundary layer  is needed to use the tool "grass7:v.distance"
		in a later step. Calling layer.extent() returns a QgsRectangle() object, but 
		"grass7:v.distance" requires a string type, so we extract the x-min, x-max, y-min, 
		y-max from the rectangle object and store it as string to be used as a valid 
		parameter for the tool. We calculate this here so that it is not needlessly 
		repeated for every centerline within the glacier.
	'''

    in_a = os.path.join(
        os.path.join(utility.getPath_outputs()['step_4'], glimsId),
        "diss_bound_" + glimsId + "_line.shp")
    glacier = QgsVectorLayer(in_a, os.path.basename(in_a), "ogr")
    extent = glacier.extent()
    xmin = extent.xMinimum()
    xmax = extent.xMaximum()
    ymin = extent.yMinimum()
    ymax = extent.yMaximum()
    stringExtent = "%f,%f,%f,%f" % (xmin, xmax, ymin, ymax
                                    )  # creates the string we need
    '''
		Iterate over the sorted centerlines for the current glacier and calculate the
		intersections for each individual centerline.
	'''
    counter = 0

    in_b = os.path.join(
        os.path.join(utility.getPath_outputs()['step_4'], glimsId),
        "rpj_sorted_" + glimsId + ".shp")
    rpj_sorted = QgsVectorLayer(in_b, os.path.basename(in_b), "ogr")

    iter = rpj_sorted.getFeatures()
    for feature in iter:
        # if counter == 0 :
        line_ID = feature['LINE_ID']

        print "line_ID = " + str(line_ID)

        # Create a folder for each centerline which will contain all sub-processes
        singleLinePath = os.path.join(
            os.path.join(utility.getPath_outputs()['step_4'], glimsId),
            "id_" + str(line_ID))
        if not os.path.isdir(singleLinePath):
            os.mkdir(singleLinePath)


# USE THIS CODE TO DELETE INTERMEDIATE STEPS (USE TEMP FILES IN MEMORY AND DELETE ON EXIT)
        out_a = os.path.join(singleLinePath, 'single_line.shp')
        print "singleLine"
        # Extract one line
        processing.runalg("qgis:extractbyattribute", rpj_sorted, "LINE_ID", 0,
                          line_ID, out_a)

        print "singleLinePoints"
        out_b = os.path.join(singleLinePath, 'single_line_points.shp')
        # Convert lines to points
        processing.runalg("grass7:v.to.points", out_a, "50", 1, True,
                          stringExtent, -1, 0.0001, 0, out_b)

        print "adding DST_TO_EGE field"
        # Add distance field for v.distance to tool
        linePts = QgsVectorLayer(out_b, "dist_to_boundary.shp", "ogr")
        provider = linePts.dataProvider()
        linePts.startEditing()
        provider.addAttributes(
            [QgsField("DST_TO_EGE", QVariant.Double, 'double', 10, 2)])
        linePts.commitChanges()

        print "v.distance"
        # Find the minimum distance from every centerline point to the glacier boundary
        out_c = os.path.join(singleLinePath, "vdistPoints.shp")
        out_d = os.path.join(singleLinePath, "vdistLines.shp")
        processing.runalg("grass7:v.distance", linePts.source(), "point",
                          glacier.source(), "point,line", -1, -1, "dist",
                          "DST_TO_EGE", None, stringExtent, -1, 0.0001, out_c,
                          out_d)

        print "varBuff"
        # Create variable distance buffer along centerline points
        out_e = os.path.join(singleLinePath, "var_buff.shp")
        processing.runalg("qgis:variabledistancebuffer", out_c, "DST_TO_EGE",
                          10, True, out_e)

        print "lineVarBuff"
        # Convert buffer to line
        out_f = os.path.join(singleLinePath, "line_var_buff.shp")
        processing.runalg("qgis:polygonstolines", out_e, out_f)

        print "angleVertices"
        # Intersect line buffer with all the glaciers centerlines
        out_g = os.path.join(singleLinePath, "angle_vertices.shp")
        processing.runalg("qgis:lineintersections", out_f, rpj_sorted.source(),
                          "LINE_ID", "OBJECTID", out_g)

        print "circles"
        # Buffer intersection points to create 50m circles around them
        out_h = os.path.join(singleLinePath, "circles.shp")
        processing.runalg("qgis:fixeddistancebuffer", out_g, 50, 10, False,
                          out_h)

        print "lineCircles"
        # Convert buffered circles to lines
        out_i = os.path.join(singleLinePath, "line_circles.shp")
        processing.runalg("qgis:polygonstolines", out_h, out_i)

        print "intersectBuffer"
        # Intersect line circles with centerline buffer
        out_j = os.path.join(singleLinePath, "intersectBuffer.shp")
        processing.runalg("qgis:lineintersections", out_f, out_i, "LINE_ID",
                          "OBJECTID", out_j)

        print "intersectCenterlines"
        # Intersect line circles with centerlines
        out_k = os.path.join(singleLinePath, "intersectCenterlines.shp")
        processing.runalg("qgis:lineintersections", out_i, rpj_sorted.source(),
                          "LINE_ID", "OBJECTID", out_k)

        print "clippedIntersectCenterlines"
        # Clip/delete the intersection point inside the glacier boundary
        out_l = os.path.join(singleLinePath, "clippedIntersectCenterlines.shp")
        processing.runalg("qgis:difference", out_k, out_e, True, out_l)
        # Delete the features since they are clipped but still exist with NULL geometry
        clippedIntLayer = QgsVectorLayer(out_l, "clippedICL", "ogr")
        with edit(clippedIntLayer):
            icl_feats = clippedIntLayer.getFeatures()
            for icl_feat in icl_feats:
                if not icl_feat.geometry():
                    clippedIntLayer.deleteFeature(icl_feat.id())
            # print clippedIntersectCenterlines
        # Convert the geometry of the file from type 'Multi-Point' to 'Point'
        out_m = os.path.join(singleLinePath, "clippedSinglePart.shp")
        processing.runalg("qgis:multiparttosingleparts", out_l, out_m)

        intersectFields = QgsFields()
        intersectFields.append(QgsField("CENTERLINE", QVariant.Double, '', 10))
        intersectFields.append(QgsField("INTSCT_ID", QVariant.Double, '', 10))
        intersectFields.append(QgsField("INTSCT_VTX", QVariant.Int, '', 1))
        intersectFields.append(QgsField("INTSCT_LNE", QVariant.Int, '', 1))
        intersectFields.append(QgsField("FROM_BUFF", QVariant.Int, '', 1))
        intersectFields.append(QgsField("UP_POINT", QVariant.Int, '', 1))
        intersectFields.append(QgsField("DOWN_POINT", QVariant.Int, '', 1))

        intersectId = -1
        intersectFileFieldValues = [('intersect_angleVertices.shp', out_g,
                                     [line_ID, intersectId, 1, 0, 0, 0, 0]),
                                    ('intersect_fromBuffVertices.shp', out_j,
                                     [line_ID, intersectId, 0, 0, 1, 0, 0]),
                                    ('intersect_CLineVertices.shp', out_m,
                                     [line_ID, intersectId, 0, 1, 0, 0, 0])]
        num = 0
        for f in intersectFileFieldValues:
            fileSrc = os.path.join(singleLinePath, f[0])
            layer = QgsVectorLayer(f[1], f[0], "ogr")
            writer = QgsVectorFileWriter(fileSrc, "CP1250", intersectFields,
                                         layer.wkbType(), layer.crs(),
                                         "ESRI Shapefile")
            if writer.hasError() != QgsVectorFileWriter.NoError:
                print("Error when creating shapefile: ", writer.errorMessage())
            inFeats = layer.getFeatures()
            for inFeat in inFeats:
                outFeat = QgsFeature()
                outFeat.setGeometry(inFeat.geometry())
                f[2][1] = inFeat["OBJECTID"]
                outFeat.setAttributes(f[2])
                writer.addFeature(outFeat)
            del writer
            del layer
    # For every intersection, there are two intersection points generated from intersecting the glacier centerline buffer
    # with the intersection point circles.  We need to know which one is 'higher-up' the glacier so that it can be used to
    # calculate a consistent and relevent glacier angle (ie. the upslope intersection angle).  We do NOT want to include a
    # Digital Elevation Model (DEM) to check which point is higher because it will mean aquiring a LOT more input data and
    # also drastically decrease the algorithm performance. To solve this, I do the following for each pair of points:
    # 	- split the centerline buffer line at the vertice nearest to the first point
    # 	- calculate the distance of the 2 lines resulting from spliting the line
    # 	- repeat this for the second point
    # 	- compare and find the minimum distances of all 4 resulting line segments
    # 	- whichever point this line segment 'belongs to' is the higher point, because the centerline buffer line begins
    # 	  and ends at the centerline head (highest point) for any given glacier or sub-glacier
        buffLayer = QgsVectorLayer(out_f, "line_buffer", "ogr")
        ptLayer = QgsVectorLayer(
            os.path.join(singleLinePath, intersectFileFieldValues[1][0]),
            intersectFileFieldValues[1][0], "ogr")
        ptIds = ptLayer.uniqueValues(ptLayer.fieldNameIndex('INTSCT_ID'))
        buff_feats = [feat for feat in buffLayer.getFeatures()]
        point_Dict = {
            'pt_1 ID': None,
            'pt_1 minDist': None,
            'pt_2 ID': None,
            'pt_2 minDist': None
        }
        highPoints = []
        lowPoints = []
        for ptId in ptIds:
            expr = QgsExpression("\"INTSCT_ID\"=" + str(ptId))
            it = ptLayer.getFeatures(QgsFeatureRequest(expr))
            ids = [i.id() for i in it]
            ptLayer.setSelectedFeatures(ids)
            selection = ptLayer.selectedFeatures()
            if len(selection) != 2:
                if len(selection) > 2:
                    print "ptId: " + str(ptId) + " has " + str(
                        len(selection)
                    ) + " points. Perhaps multiple intersections in ablation zone?"
                continue
            count = 0
            for pt in selection:
                tup = buff_feats[0].geometry().closestSegmentWithContext(
                    pt.geometry().asPoint())
                polyLine = [
                    feat.geometry().asPolyline() for feat in buff_feats
                ]
                first_segment = []
                second_segment = [tup[1]]
                for line in polyLine:
                    for i, point in enumerate(line):
                        if i < tup[2]:
                            first_segment.append(point)
                        else:
                            second_segment.append(point)
                first_segment.append(tup[1])
                geom_1 = QgsGeometry.fromPolyline(first_segment)
                length_1 = geom_1.length()
                geom_2 = QgsGeometry.fromPolyline(second_segment)
                length_2 = geom_2.length()
                if count == 0:
                    point_Dict['pt_1 ID'] = pt.id()
                    point_Dict['pt_1 minDist'] = min(length_1, length_2)
                elif count == 1:
                    point_Dict['pt_2 ID'] = pt.id()
                    point_Dict['pt_2 minDist'] = min(length_1, length_2)
                count += 1
            # Compare the lengths of the resulting split line segments from splitting at each point
            if point_Dict['pt_1 minDist'] < point_Dict['pt_2 minDist']:
                highPoints.append(point_Dict['pt_1 ID'])
                lowPoints.append(point_Dict['pt_2 ID'])
            elif point_Dict['pt_2 minDist'] <= point_Dict['pt_1 minDist']:
                highPoints.append(point_Dict['pt_2 ID'])
                lowPoints.append(point_Dict['pt_1 ID'])
            # Clear selection for next iteration with an empty list
            ptLayer.setSelectedFeatures([])

        # Update attribute to indicate which buffer point is at higher elevation
        ptLayer.startEditing()
        ptLayer.updateFields()
        idx = ptLayer.fieldNameIndex('UP_POINT')
        for i in highPoints:
            ptLayer.changeAttributeValue(i, idx, 1)
        # idx = ptLayer.fieldNameIndex('DOWN_POINT')
        # for i in lowPoints:
        # 	ptLayer.changeAttributeValue(i,idx,1)
        ptLayer.commitChanges()
        ptLayer.startEditing()
        for i in lowPoints:
            ptLayer.deleteFeature(i)
        ptLayer.commitChanges()

        for f in intersectFileFieldValues:
            fileSrc = os.path.join(singleLinePath, f[0])
            layer = QgsVectorLayer(f[1], f[0], "ogr")
        # Merge all of the intersection points needed for angle calculations into one point file
        mergeSrc = os.path.join(singleLinePath, "merged_intersect_pts.shp")
        processing.runalg(
            "qgis:mergevectorlayers",
            os.path.join(singleLinePath, intersectFileFieldValues[0][0]) +
            ";" +
            os.path.join(singleLinePath, intersectFileFieldValues[1][0]) +
            ";" + os.path.join(singleLinePath, intersectFileFieldValues[2][0]),
            mergeSrc)
        # Calculate angles from merged point file
        intLayer = QgsVectorLayer(mergeSrc, os.path.basename(mergeSrc), "ogr")
        print intLayer.isValid()
        for intId in ptIds:
            expr = QgsExpression("\"INTSCT_ID\"=" + str(intId))
            print "\"INTSCT_ID\"=" + str(intId)
            print intId
            it = intLayer.getFeatures(QgsFeatureRequest(expr))
            ids = [i.id() for i in it]
            print ids
            intLayer.setSelectedFeatures(ids)
            selection = intLayer.selectedFeatures()
            print selection
            pt_A = QgsFeature()  # Upslope point on current centerline
            pt_B = QgsFeature()  # Angle/intersection vertex
            pt_C = QgsFeature()  # Upslope point on intersecting centerline
            if len(selection) == 3:
                for s in selection:
                    if s['UP_POINT'] == 1:
                        pt_A = s
                    elif s['INTSCT_VTX'] == 1:
                        pt_B = s
                    elif s['INTSCT_LNE'] == 1:
                        pt_C = s
                gLine = QgsGeometry.fromPolyline([
                    pt_A.geometry().asPoint(),
                    pt_B.geometry().asPoint(),
                    pt_C.geometry().asPoint()
                ])
                angle1 = gLine.angleAtVertex(0)
                angle2 = gLine.angleAtVertex(1)
                angle3 = gLine.angleAtVertex(2)
                print angle1
                print angle2
                print angle3
            else:
                print "ERROR: Need exactly 3 points to calculate angle."
            intLayer.setSelectedFeatures([])