Пример #1
0
    def _adjustPositionForward(self, pair, maxOffset =1.0e8):
        """_adjustPositionForward doc..."""

        delta = 0.001
        segment = pair['segment']
        offset = segment.offset + pair['distance']

        while maxOffset <= (offset + delta) or NumericUtils.equivalent(maxOffset, offset + delta):
            delta *= 0.5

        point = pair['line'].start.clone()
        segment.line.adjustPointAlongLine(point, delta, inPlace=True)
        dist = segment.line.start.distanceTo(point).raw

        if not NumericUtils.equivalent(pair['distance'] + delta, dist, machineEpsilonFactor=1000.0):
            self.stage.logger.write([
                '[ERROR]: Forward adjust failure in CurveSeries.adjustPositionForward',
                'TRACK: %s [%s]' % (pair['track'].fingerprint, pair['track'].uid),
                'EXPECTED: %s' % (pair['distance'] + delta),
                'ACTUAL: %s' % dist,
                'DELTA: %s' % delta])

        pair['line'].start.copyFrom(point)

        track = pair['track']
        pair['distance'] = dist

        if not self.saveToAnalysisTracks:
            return

        at = track.getAnalysisPair(self.stage.analysisSession)
        at.curvePosition = segment.offset + dist
        at.segmentPosition = dist
Пример #2
0
    def _resolveSpatialCoincidences(self, pair):
        """ Correct for cases where projected prints reside at the same spatial location on the
            curve series by adjusting one of the tracks projection position slightly. """

        segment = pair['segment']

        try:
            nextSegment = self.segments[self.segments.index(segment) + 1]
            nextOffset = nextSegment.offset
        except Exception:
            nextOffset = 1.0e8

        # Adjust a pair print if it resides at the same position as its curve series track
        if NumericUtils.equivalent(pair['distance'], 0.0):
            self._adjustPositionForward(pair, nextOffset)

        try:
            # Retrieve the next pair track in the segment if one exists
            nextPair = segment.pairs[segment.pairs.index(pair) + 1]
        except Exception:
            return

        pDist = pair['distance']
        npDist = nextPair['distance']

        # Adjust pair tracks that reside at the same spatial position
        if npDist <= pDist or NumericUtils.equivalent(pDist, npDist):
            self._adjustPositionForward(nextPair, nextOffset)
Пример #3
0
    def _drawMeasuredWidth(self, track, drawing):
        if NumericUtils.equivalent(track.widthMeasured, 0.0):
            return

        if track.uid in self.trackDeviations:
            data = self.trackDeviations[track.uid]
            if data['wSigma'] > 2.0:
                strokeWidth = 3.0
                color = 'red'
            else:
                strokeWidth = 1.0
                color = 'green'
        else:
            strokeWidth = 1.0
            color = 'green'

        w   = 100*track.widthMeasured
        rot = math.radians(track.rotation)
        x1  = w/2.0
        x2  = -w/2.0

        drawing.line(
             (track.x + x1*math.cos(rot), track.z - x1*math.sin(rot)),
             (track.x + x2*math.cos(rot), track.z - x2*math.sin(rot)),
             scene=True,
             stroke=color,
             stroke_width=strokeWidth)
Пример #4
0
    def _drawMeasuredLength(self, track, drawing):
        if NumericUtils.equivalent(track.lengthMeasured, 0.0):
            return

        if track.uid in self.trackDeviations:
            data = self.trackDeviations[track.uid]
            if data['lSigma'] > 2.0:
                  strokeWidth = 3.0
                  color = 'red'
            else:
                strokeWidth = 1.0
                color = 'green'
        else:
            strokeWidth = 1.0
            color = 'green'

        l   = 100*track.lengthMeasured
        rot = math.radians(track.rotation)
        z1  = track.lengthRatio*l
        z2  = z1 - l

        drawing.line(
             (track.x + z1*math.sin(rot), track.z + z1*math.cos(rot)),
             (track.x + z2*math.sin(rot), track.z + z2*math.cos(rot)),
             scene=True,
             stroke=color,
             stroke_width=strokeWidth)
Пример #5
0
    def _plot(self):
        """_plot doc..."""

        x = []
        y = []
        yUnc = []

        for value in self.data:
            entry = self._dataItemToValue(value)
            y.append(entry['y'])
            x.append(entry.get('x', len(x)))
            yUnc.append(entry.get('yUnc', 0.0))

        if NumericUtils.equivalent(max(yUnc), 0.0):
            yUnc = None

        pl = self.pl
        pl.bar(x, y, yerr=yUnc, facecolor=self.color, edgecolor=self.strokeColor, log=self.isLog)
        pl.title(self.title)
        pl.xlabel(self.xLabel)
        pl.ylabel(self.yLabel)
        if self.xLimits:
            pl.xlim(*self.xLimits)
        if self.yLimits:
            pl.ylim(*self.yLimits)
        pl.grid(True)
Пример #6
0
    def _extrapolateByLength(self, lengthAdjust, pre =False):
        """_extrapolateByLength doc..."""

        length = self.length
        targetLengthSqr = (length.raw + lengthAdjust)**2

        s = self.start
        e = self.end
        deltaX = e.x - s.x
        deltaY = e.y - s.y

        delta = lengthAdjust
        if NumericUtils.equivalent(deltaX, 0.0):
            # Vertical lines should invert delta if start is above the end
            delta *= -1.0 if deltaY < 0.0 else 1.0
        elif deltaX < 0.0:
            # Other lines should invert delta if start is right of the end
            delta *= -1.0

        if pre:
            delta *= -1.0
            startY = s.y
            prevX = s.x
            point = self.end
        else:
            startY = e.y
            prevX = e.x
            point = self.start

        if NumericUtils.equivalent(deltaX, 0.0):
            return s.x, startY + delta

        i = 0
        while i < 100000:
            x = prevX + delta
            y = s.y + deltaY*(x - s.x)/deltaX
            testLengthSqr = math.pow(x - point.x, 2) + math.pow(y - point.y, 2)

            if NumericUtils.equivalent(testLengthSqr/targetLengthSqr, 1.0, 0.000001):
                return x, y
            elif testLengthSqr > targetLengthSqr:
                delta *= 0.5
            else:
                prevX = x
            i += 1

        raise ValueError('Unable to extrapolate line segment to specified length')
Пример #7
0
    def project(self, track, data =None):
        """ Tests the specified segment and modifies the data dictionary with the results of the
            test if it was successful. """

        data = self._initializeData(data, track)

        position = track.positionValue
        debugItem = {'TRACK':self.track.fingerprint if self.track else 'NONE'}
        debugData = {}
        data['debug'].append({'print':debugItem, 'data':debugData})

        # Make sure the track resides in a generally forward direction relative to
        # the direction of the segment. The prevents tracks from matching from behind.
        angle = self.line.angleBetweenPoint(position)
        if abs(angle.degrees) > 100.0:
            debugItem['CAUSE'] = 'Segment position angle [%s]' % angle.prettyPrint
            return

        # Calculate the closest point on the line segment. If the point and line are not
        # properly coincident, the testPoint will be None and the attempt should be aborted.
        testPoint = self.line.closestPointOnLine(position, contained=True)
        if not testPoint:
            debugItem['CAUSE'] = 'Not aligned to segment'
            return

        testLine = LineSegment2D(testPoint, position.clone())

        # Make sure the test line intersects the segment line at 90 degrees, or the
        # value is invalid.
        angle = testLine.angleBetweenPoint(self.line.end)
        if not NumericUtils.equivalent(angle.degrees, 90.0, 2.0):
            debugItem['CAUSE'] = 'Projection angle [%s]' % angle.prettyPrint
            debugData['testLine'] = testLine
            debugData['testPoint'] = testPoint
            return

        # Skip if the test line length is greater than the existing test line
        length = data.get('projectionLength', 1.0e10)
        if testLine.length.raw > length:
            debugItem['CAUSE'] = 'Greater length [%s > %s]' % (
                NumericUtils.roundToSigFigs(length, 5),
                NumericUtils.roundToSigFigs(testLine.length.raw, 5) )
            debugData['testLine'] = testLine
            debugData['testPoint'] = testPoint
            return

        # Populate the projection values if the projection was successful
        p  = testPoint.clone()
        # p.xUnc = position.xUnc
        # p.yUnc = position.yUnc
        data['segment'] = self
        data['projectionLength'] = position.distanceTo(p).raw
        data['line'] = LineSegment2D(p, position)

        data['distance'] = self.line.start.distanceTo(p).raw
        debugData['distance'] = data['distance']

        return data
Пример #8
0
    def angleBetween(self, position):
        """angleBetween doc..."""

        myLength = self.length
        posLength = position.length
        denom = myLength.raw*posLength.raw
        denomUnc = math.sqrt(
            myLength.rawUncertainty*myLength.rawUncertainty +
            posLength.rawUncertainty*posLength.rawUncertainty)

        if denom == 0.0:
            return Angle(radians=0.0, uncertainty=0.5*math.pi)

        nom = self.x*position.x + self.y*position.y
        nomUnc = (abs(position.x)*self.xUnc +
            abs(self.x)*position.xUnc +
            abs(position.y)*self.yUnc +
            abs(self.y)*position.yUnc)/denom

        b = nom/denom
        bUnc = abs(1.0/denom)*nomUnc + \
            abs(nom/math.pow(denom, 2))*denomUnc

        if NumericUtils.equivalent(b, 1.0):
            return Angle()

        try:
            if NumericUtils.equivalent(b, -1.0):
                a = math.pi
            else:
                a = math.acos(b)
        except Exception:
            print('[ERROR]: Unable to calculate angle between', b)
            return Angle()

        if NumericUtils.equivalent(a, math.pi):
            return Angle(radians=a, uncertainty=180.0)

        try:
            aUnc = abs(1.0/math.sqrt(1.0 - b*b))*bUnc
        except Exception:
            print('[ERROR]: Unable to calculate angle between uncertainty', b, a)
            return Angle()

        return Angle(radians=a, uncertainty=aUnc)
Пример #9
0
    def angleBetween(self, position):
        """angleBetween doc..."""

        myLength = self.length
        posLength = position.length
        denom = myLength.raw * posLength.raw
        denomUnc = math.sqrt(
            myLength.rawUncertainty * myLength.rawUncertainty +
            posLength.rawUncertainty * posLength.rawUncertainty)

        if denom == 0.0:
            return Angle(radians=0.0, uncertainty=0.5 * math.pi)

        nom = self.x * position.x + self.y * position.y
        nomUnc = (abs(position.x) * self.xUnc + abs(self.x) * position.xUnc +
                  abs(position.y) * self.yUnc +
                  abs(self.y) * position.yUnc) / denom

        b = nom / denom
        bUnc = abs(1.0/denom)*nomUnc + \
            abs(nom/math.pow(denom, 2))*denomUnc

        if NumericUtils.equivalent(b, 1.0):
            return Angle()

        try:
            if NumericUtils.equivalent(b, -1.0):
                a = math.pi
            else:
                a = math.acos(b)
        except Exception:
            print('[ERROR]: Unable to calculate angle between', b)
            return Angle()

        if NumericUtils.equivalent(a, math.pi):
            return Angle(radians=a, uncertainty=180.0)

        try:
            aUnc = abs(1.0 / math.sqrt(1.0 - b * b)) * bUnc
        except Exception:
            print('[ERROR]: Unable to calculate angle between uncertainty', b,
                  a)
            return Angle()

        return Angle(radians=a, uncertainty=aUnc)
Пример #10
0
    def _analyzeTrack(self, track, series, trackway, sitemap):
        trackId = '%s (%s)' % (track.fingerprint, track.uid)

        if NumericUtils.equivalent(track.width, 0.0):
            self.logger.write('[ERROR]: Zero track width %s' % trackId)
        if NumericUtils.equivalent(track.widthUncertainty, 0.0):
            self.logger.write('[ERROR]: Zero track width uncertainty %s' % trackId)

        if NumericUtils.equivalent(track.length, 0.0):
            self.logger.write('[ERROR]: Zero track length %s' % trackId)
        if NumericUtils.equivalent(track.lengthUncertainty, 0.0):
            self.logger.write('[ERROR]: Zero track length uncertainty %s' % trackId)

        self._tracks.append(track)
        x = track.xValue
        self._uncs.append(x.uncertainty)
        z = track.zValue
        self._uncs.append(z.uncertainty)
Пример #11
0
def getNormalityColor(normality, goodChannel, badChannel):
    if NumericUtils.equivalent(normality, -1.0, 0.01):
        return ColorValue({'r':100, 'g':100, 'b':100})

    test  = min(1.0, max(0.0, normality))
    limit = NORMAL_THRESHOLD
    slope = 1.0/(1.0 - limit)
    intercept = -slope*limit
    test = min(1.0, max(0.0, slope*test + intercept))

    color = dict(r=0.0, b=0.0, g=0.0)
    color[badChannel] = max(0, 255.0*min(1.0, 1.0 - 1.0*test))
    color[goodChannel] = max(0, min(255, 255.0*test))
    return ColorValue(color)
Пример #12
0
    def _drawWidth(self, track, drawing, color ='orange', strokeWidth =0.5):
        if NumericUtils.equivalent(track.widthMeasured, 0.0):
            return

        w   = 100*track.width
        rot = math.radians(track.rotation)
        x1  = w/2.0
        x2  = -w/2.0

        drawing.line(
             (track.x + x1*math.cos(rot), track.z - x1*math.sin(rot)),
             (track.x + x2*math.cos(rot), track.z - x2*math.sin(rot)),
             scene=True,
             stroke=color,
             stroke_width=strokeWidth)
Пример #13
0
    def _drawLength(self, track, drawing, color ='orange', strokeWidth =0.5):
        if NumericUtils.equivalent(track.lengthMeasured, 0.0):
            return

        l   = 100*track.length
        rot = math.radians(track.rotation)
        z1  = track.lengthRatio*l
        z2  = z1 - l

        # draw the length line
        drawing.line(
             (track.x + z1*math.sin(rot), track.z + z1*math.cos(rot)),
             (track.x + z2*math.sin(rot), track.z + z2*math.cos(rot)),
             scene=True,
             stroke=color,
             stroke_width=strokeWidth)
Пример #14
0
    def _getNextTrack(self, track, trackway):
        """
        Iterates through all the tracks in the trackway and finds the track
        closest to the specified track. If the track argument is None the first
        track in the trackway will be returned.
        """

        bundle = self.owner.getSeriesBundle(trackway)
        trackPosition = -1.0e8
        targetPosition = 1.0e8
        nextTrack = None
        anaTrack = None

        if track:
            anaTrack = track.getAnalysisPair(self.analysisSession)
            trackPosition = anaTrack.curvePosition

        for value in bundle.asList():
            for t in value.tracks:
                if track and t == track:
                    continue

                at = t.getAnalysisPair(self.analysisSession)
                if  at.curvePosition < trackPosition:
                    continue

                sigFigsRound = NumericUtils.roundToSigFigs
                if NumericUtils.equivalent(at.curvePosition, targetPosition):
                    log = [
                        '[ERROR]: Multiple tracks at the same curve location',
                        'TARGET: %s' % sigFigsRound(targetPosition, 5),
                        'TEST: %s [%s]' % (t.fingerprint, t.uid),
                        'LOCATION[TEST]: %s (%s)' % (
                            sigFigsRound(at.curvePosition, 5),
                            sigFigsRound(at.segmentPosition, 5)
                        )
                    ]

                    if nextTrack:
                        nat = nextTrack.getAnalysisPair(self.analysisSession)
                        log.append('COMPARE: %s [%s]' % (
                            nextTrack.fingerprint,
                            nextTrack.uid
                        ))
                        log.append('LOCATION[COMP]: %s (%s)' % (
                            sigFigsRound(nat.curvePosition, 5),
                            sigFigsRound(nat.segmentPosition, 5)
                        ))

                    if track:
                        log.append('TRACK: %s [%s]' % (
                            track.fingerprint,
                            track.uid
                        ))
                        log.append('LOCATION[TRACK]: %s (%s)' % (
                            sigFigsRound(anaTrack.curvePosition, 5),
                            sigFigsRound(anaTrack.segmentPosition, 5)
                        ))

                    self.logger.write(log)
                    raise ValueError(
                        'Found multiple tracks at the same curve location'
                    )

                if at.curvePosition < targetPosition:
                    nextTrack = t
                    targetPosition = at.curvePosition
                else:
                    break

        return nextTrack
Пример #15
0
    def _addQuartileEntry(self, label, trackway, data):
        if not data or len(data) < 4:
            return

        if label not in self._quartileStats:
            csv = CsvWriter()
            csv.path = self.getPath(
                '%s-Quartiles.csv' % label.replace(' ', '-'),
                isFile=True)
            csv.autoIndexFieldName = 'Index'
            csv.addFields(
                ('name', 'Name'),

                ('normality', 'Normality'),
                ('unweightedNormality', 'Unweighted Normality'),

                ('unweightedLowerBound', 'Unweighted Lower Bound'),
                ('unweightedLowerQuart', 'Unweighted Lower Quartile'),
                ('unweightedMedian',     'Unweighted Median'),
                ('unweightedUpperQuart', 'Unweighted Upper Quartile'),
                ('unweightedUpperBound', 'Unweighted Upper Bound'),

                ('lowerBound', 'Lower Bound'),
                ('lowerQuart', 'Lower Quartile'),
                ('median',     'Median'),
                ('upperQuart', 'Upper Quartile'),
                ('upperBound', 'Upper Bound'),

                ('diffLowerBound', 'Diff Lower Bound'),
                ('diffLowerQuart', 'Diff Lower Quartile'),
                ('diffMedian',     'Diff Median'),
                ('diffUpperQuart', 'Diff Upper Quartile'),
                ('diffUpperBound', 'Diff Upper Bound') )
            self._quartileStats[label] = csv

        csv = self._quartileStats[label]
        dd = mstats.density.Distribution(data)
        unweighted = mstats.density.boundaries.unweighted_two(dd)
        weighted = mstats.density.boundaries.weighted_two(dd)

        #-----------------------------------------------------------------------
        # PLOT DENSITY
        #   Create a density plot for each value
        p = MultiScatterPlot(
            title='%s %s Density Distribution' % (trackway.name, label),
            xLabel=label,
            yLabel='Probability (AU)')

        x_values = mstats.density.ops.adaptive_range(dd, 10.0)
        y_values = dd.probabilities_at(x_values=x_values)

        p.addPlotSeries(
            line=True,
            markers=False,
            label='Weighted',
            color='blue',
            data=zip(x_values, y_values)
        )

        temp = mstats.density.create_distribution(
            dd.naked_measurement_values(raw=True)
        )
        x_values = mstats.density.ops.adaptive_range(dd, 10.0)
        y_values = dd.probabilities_at(x_values=x_values)

        p.addPlotSeries(
            line=True,
            markers=False,
            label='Unweighted',
            color='red',
            data=zip(x_values, y_values)
        )

        if label not in self._densityPlots:
            self._densityPlots[label] = []
        self._densityPlots[label].append(
            p.save(self.getTempFilePath(extension='pdf')))

        #-----------------------------------------------------------------------
        # NORMALITY
        #       Calculate the normality of the weighted and unweighted
        #       distributions as a test against how well they conform to
        #       the Normal distribution calculated from the unweighted data.
        #
        #       The unweighted Normality test uses a basic bandwidth detection
        #       algorithm to create a uniform Gaussian kernel to populate the
        #       DensityDistribution. It is effectively a density kernel
        #       estimation, but is aggressive in selecting the bandwidth to
        #       prevent over-smoothing multi-modal distributions.
        if len(data) < 8:
            normality = -1.0
            unweightedNormality = -1.0
        else:
            result = NumericUtils.getMeanAndDeviation(data)
            mean = result.raw
            std = result.rawUncertainty
            normality = mstats.density.ops.overlap(
                dd,
                mstats.density.create_distribution([mean], [std])
            )

            rawValues = []
            for value in data:
                rawValues.append(value.value)
            ddRaw = mstats.density.create_distribution(rawValues)
            unweightedNormality = mstats.density.ops.overlap(
                ddRaw,
                mstats.density.create_distribution([mean], [std])
            )

        # Prevent divide by zero
        unweighted = [
            0.00001 if NumericUtils.equivalent(x, 0) else x
            for x in unweighted
        ]

        csv.addRow({
            'index':trackway.index,
            'name':trackway.name,

            'normality':normality,
            'unweightedNormality':unweightedNormality,

            'unweightedLowerBound':unweighted[0],
            'unweightedLowerQuart':unweighted[1],
            'unweightedMedian'    :unweighted[2],
            'unweightedUpperQuart':unweighted[3],
            'unweightedUpperBound':unweighted[4],

            'lowerBound':weighted[0],
            'lowerQuart':weighted[1],
            'median'    :weighted[2],
            'upperQuart':weighted[3],
            'upperBound':weighted[4],

            'diffLowerBound':abs(unweighted[0] - weighted[0])/unweighted[0],
            'diffLowerQuart':abs(unweighted[1] - weighted[1])/unweighted[1],
            'diffMedian'    :abs(unweighted[2] - weighted[2])/unweighted[2],
            'diffUpperQuart':abs(unweighted[3] - weighted[3])/unweighted[3],
            'diffUpperBound':abs(unweighted[4] - weighted[4])/unweighted[4]
        })
Пример #16
0
 def test_equivalent(self):
     """test_equivalent doc..."""
     self.assertTrue(NumericUtils.equivalent(1.0, 1.001, 0.01))
     self.assertFalse(NumericUtils.equivalent(1.0, 1.011, 0.01))
Пример #17
0
 def _analyzeTrack(self, track, series, trackway, sitemap):
     if NumericUtils.equivalent(track.x, 0.0) and NumericUtils.equivalent(track.z, 0.0):
         self._tracks.append(track)
         self._csv.addRow({'uid':track.uid, 'fingerprint':track.fingerprint})
Пример #18
0
 def test_equivalent(self):
     """test_equivalent doc..."""
     self.assertTrue(NumericUtils.equivalent(1.0, 1.001, 0.01))
     self.assertFalse(NumericUtils.equivalent(1.0, 1.011, 0.01))