def __init__(self,
                 inputFC,
                 outputFC=None,
                 caseField=None,
                 orientationOnly=False):

        #### Create SSDataObject ####
        ssdo = SSDO.SSDataObject(inputFC,
                                 templateFC=outputFC,
                                 useChordal=False)
        cnt = UTILS.getCount(inputFC)
        ERROR.errorNumberOfObs(cnt, minNumObs=1)
        fieldList = [ssdo.oidName, "SHAPE@"]
        caseIsString = False
        if caseField:
            fieldList.append(caseField)
            caseType = ssdo.allFields[caseField].type.upper()
            caseIsString = caseType == "STRING"

        #### Initialize Accounting Structures ####
        xyLenVals = {}
        sinCosVals = {}

        #### Open Search Cursor ####
        try:
            rows = DA.SearchCursor(inputFC, fieldList, "",
                                   ssdo.spatialRefString)
        except:
            ARCPY.AddIDMessage("ERROR", 204)
            raise SystemExit()

        #### Keep track of Invalid Fields ####
        badIDs = []
        badLengths = []
        badRecord = False
        negativeWeights = False

        #### Create Progressor ####
        ARCPY.SetProgressor("step", ARCPY.GetIDMessage(84001), 0, cnt, 1)

        for row in rows:
            OID = row[0]
            shapeInfo = row[1]
            badRow = row.count(None)
            try:
                centroidInfo = shapeInfo.trueCentroid
                xVal = centroidInfo.X
                yVal = centroidInfo.Y
                length = float(shapeInfo.length)
                firstPoint = shapeInfo.firstPoint
                lastPoint = shapeInfo.lastPoint
                if firstPoint == lastPoint:
                    badLengths.append(OID)
                    badRow = True
                else:
                    firstX = float(firstPoint.X)
                    firstY = float(firstPoint.Y)
                    lastX = float(lastPoint.X)
                    lastY = float(lastPoint.Y)
            except:
                badRow = True

            #### Process Good Records ####
            if not badRow:
                #### Case Field ####
                caseVal = "ALL"
                if caseField:
                    caseVal = UTILS.caseValue2Print(row[2], caseIsString)

                #### Get Angle ####
                numer = lastX - firstX
                denom = lastY - firstY
                angle = UTILS.getAngle(numer, denom)

                #### Adjust for Orientation Only ####
                if orientationOnly:
                    angle2Degree = UTILS.convert2Degree(angle)
                    if angle2Degree < 180:
                        numer = firstX - lastX
                        denom = firstY - lastY
                        angle = UTILS.getAngle(numer, denom)

                sinVal = NUM.sin(angle)
                cosVal = NUM.cos(angle)

                xyLenVal = (xVal, yVal, length)
                sinCosVal = (sinVal, cosVal)

                try:
                    xyLenVals[caseVal].append(xyLenVal)
                    sinCosVals[caseVal].append(sinCosVal)
                except:
                    xyLenVals[caseVal] = [xyLenVal]
                    sinCosVals[caseVal] = [sinCosVal]

            else:
                #### Bad Record ####
                badRecord = True
                badIDs.append(OID)

            ARCPY.SetProgressorPosition()

        del rows

        #### Get Set of Bad IDs ####
        badIDs = list(set(badIDs))
        badIDs.sort()
        badIDs = [str(i) for i in badIDs]

        #### Process any bad records encountered ####
        bn = len(badIDs)
        if badRecord:
            err = ERROR.reportBadRecords(cnt, bn, badIDs, label=ssdo.oidName)

        #### Error For Not Enough Observations ####
        goodRecs = cnt - bn
        ERROR.errorNumberOfObs(goodRecs, minNumObs=1)

        #### Report Features With No Length ####
        badLengths = list(set(badLengths))
        badLengths.sort()
        badLengths = [str(i) for i in badLengths]
        numBadLengths = len(badLengths)
        if numBadLengths > 0:
            ERROR.reportBadLengths(cnt,
                                   numBadLengths,
                                   badLengths,
                                   label=ssdo.oidName)

        #### Set up for Bad Cases ####
        badCases = []
        cases = xyLenVals.keys()
        meanCenter = {}
        dm = {}

        #### Calculate Mean Center and Standard Distance ####
        for case in cases:
            xyLens = xyLenVals[case]
            numFeatures = len(xyLens)
            if numFeatures > 0:
                #### Mean Centers and Lengths ####
                xyLens = NUM.array(xyLens)
                meanX, meanY, meanL = NUM.mean(xyLens, 0)

                #### Sum Sin and Cos ####
                scVals = NUM.array(sinCosVals[case])
                sumSin, sumCos = NUM.sum(scVals, 0)

                #### Calculate Angle ####
                radianAngle = UTILS.getAngle(sumSin, sumCos)
                degreeAngle = UTILS.convert2Degree(radianAngle)

                #### Get Start and End Points ####
                halfMeanLen = meanL / 2.0
                endX = (halfMeanLen * NUM.sin(radianAngle)) + meanX
                startX = (2.0 * meanX) - endX
                endY = (halfMeanLen * NUM.cos(radianAngle)) + meanY
                startY = (2.0 * meanY) - endY
                unstandardized = NUM.sqrt(sumSin**2.0 + sumCos**2.0)
                circVar = 1.0 - (unstandardized / (numFeatures * 1.0))

                #### Re-adjust Angle Back towards North ####
                if orientationOnly:
                    degreeAngle = degreeAngle - 180.0
                    radianAngle = UTILS.convert2Radians(degreeAngle)

                #### Populate Results Structure ####
                meanCenter[case] = (meanX, meanY)
                dm[case] = [(startX, startY), (endX, endY), meanL, radianAngle,
                            degreeAngle, circVar]

        #### Sorted Case List ####
        caseKeys = dm.keys()
        caseKeys.sort()
        self.caseKeys = caseKeys

        #### Set Attributes ####
        self.ssdo = ssdo
        self.meanCenter = meanCenter
        self.dm = dm
        self.badCases = badCases
        self.inputFC = inputFC
        self.outputFC = outputFC
        self.caseField = caseField
        self.orientationOnly = orientationOnly
        self.caseIsString = caseIsString