def print_track(track, aSession): """ @param track: @param aSession: @return: """ limb_id = "{}{}".format("l" if track.left else "r", "p" if track.pes else "m") print(track.echoForVerification()) print( " size: (%s, %s) | field (%s, %s)" % (track.width, track.length, track.widthMeasured, track.lengthMeasured) ) aTrack = track.getAnalysisPair(aSession) print( " curve[#%s -> %s]: %s (%s)" % ( aTrack.curveIndex, aTrack.curveSegment, NumericUtils.roundToSigFigs(aTrack.segmentPosition, 4), NumericUtils.roundToSigFigs(aTrack.curvePosition, 4), ) ) print(" snapshot: {}\n".format(DictUtils.prettyPrint(track.snapshotData))) return dict(limb_id=limb_id, track=track, aTrack=aTrack)
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
def rawLabel(self): if self._asciiLabels: return self.asciiRawLabel return '%s %s %s' % ( NumericUtils.roundToSigFigs(self.raw, 6), StringUtils.unichr(0x00B1), self.uncertainty)
def getDebugReport(self): out = ['\nTRACKWAY[%s]:' % self.trackway.name] for segment in self.segments: out.append( ' TRACK: %s' % (segment.track.fingerprint if segment.track else 'NONE')) for item in segment.pairs: out.append( ' * %s (%s)' % ( item['track'].fingerprint, NumericUtils.roundToSigFigs(item['distance'], 5) )) for debugItem in item['debug']: out.append(' - %s' % DictUtils.prettyPrint(debugItem['print'])) return '\n'.join(out)
def asciiRawLabel(self): return '%s +/- %s' % (NumericUtils.roundToSigFigs(self.raw, 6), self.uncertainty)
def rawLabel(self): if self._asciiLabels: return self.asciiRawLabel return '%s %s %s' % (NumericUtils.roundToSigFigs( self.raw, 6), StringUtils.unichr(0x00B1), self.uncertainty)
def uncertainty(self): return NumericUtils.roundToSigFigs(abs(self._rawUncertainty), 1)
def _process(self): """_processDeviations doc...""" errors = [] for entry in self.entries: if 'fractional' in entry: errors.append(entry['fractional']) res = NumericUtils.getMeanAndDeviation(errors) self.logger.write('Fractional Stride Error %s' % res.label) label = 'Fractional Stride Errors' self._paths.append(self._makePlot( label=label, data=errors, histRange=(-1.0, 1.0) )) self._paths.append(self._makePlot( label=label, data=errors, isLog=True, histRange=(-1.0, 1.0) )) # noinspection PyUnresolvedReferences d = np.absolute(np.array(errors)) self._paths.append(self._makePlot( label='Absolute %s' % label, data=d, histRange=(0.0, 1.0) )) self._paths.append(self._makePlot( label='Absolute %s' % label, data=d, isLog=True, histRange=(0.0, 1.0) )) highDeviationCount = 0 for entry in self.entries: if 'measured' not in entry: # Skip tracks that have no measured stride value for comparison continue if entry['deviation'] > 2.0: highDeviationCount += 1 track = entry['track'] delta = NumericUtils.roundToSigFigs(100.0*abs(entry['delta']), 3) self._csv.addRow({ 'fingerprint':track.fingerprint, 'uid':track.uid, 'measured':entry['measured'].label, 'entered':entry['entered'].label, 'dev':entry['deviation'], 'delta':delta}) if not self._csv.save(): self.logger.write( '[ERROR]: Failed to save CSV file %s' % self._csv.path) percentage = NumericUtils.roundToOrder( 100.0*float(highDeviationCount)/float(len(self.entries)), -2) self.logger.write( '%s significant %s (%s%%)' % ( highDeviationCount, label.lower(), percentage)) if percentage > (100.0 - 95.45): self.logger.write( '[WARNING]: Large deviation count exceeds normal ' + 'distribution expectations.')
def _process(self): """_processDeviations doc...""" errors = [] for entry in self.entries: if 'fractional' in entry: errors.append(entry['fractional']) res = NumericUtils.getMeanAndDeviation(errors) self.logger.write('Fractional Pace Error %s' % res.label) label = 'Fractional Pace Errors' d = errors self._paths.append(self._makePlot( label=label, data=d, histRange=(-1.0, 1.0))) self._paths.append(self._makePlot( label=label, data=d, isLog=True, histRange=(-1.0, 1.0))) # noinspection PyUnresolvedReferences d = np.absolute(np.array(d)) self._paths.append(self._makePlot( label='Absolute %s' % label, data=d, histRange=(0.0, 1.0) )) self._paths.append(self._makePlot( label='Absolute %s' % label, data=d, isLog=True, histRange=(0.0, 1.0) )) highDeviationCount = 0 for entry in self.entries: if 'measured' not in entry: # entry['drawFunc']('purple') continue if entry['deviation'] > 2.0: entry['drawFunc']('red') highDeviationCount += 1 else: entry['drawFunc']( 'black' if abs(entry['deviation']) < 2.0 else '#FFAAAA') track = entry['track'] delta = NumericUtils.roundToSigFigs(100.0*abs(entry['delta']), 3) pairTrack = entry.get('pairTrack') if pairTrack: pairedFingerprint = pairTrack.fingerprint pairedUid = pairTrack.uid else: pairedFingerprint = '' pairedUid = '' self._csv.addRow({ 'fingerprint':track.fingerprint, 'uid':track.uid, 'measured':entry['measured'].label, 'entered':entry['entered'].label, 'dev':entry['deviation'], 'delta':delta, 'pairedUid':pairedUid, 'pairedFingerprint':pairedFingerprint}) for sitemap in self.owner.getSitemaps(): # Remove drawing from the sitemap cache and save the drawing file try: sitemap.cache.extract('drawing').save() except Exception: self.logger.write('[WARNING]: No sitemap saved for %s-%s' % ( sitemap.name, sitemap.level)) if not self._csv.save(): self.logger.write( '[ERROR]: Failed to save CSV file %s' % self._csv.path) if not self._errorCsv.save(): self.logger.write( '[ERROR]: Failed to save CSV file %s' % self._errorCsv.path) percentage = NumericUtils.roundToOrder( 100.0*float(highDeviationCount)/float(len(self.entries)), -2) self.logger.write('%s significant %s (%s%%)' % ( highDeviationCount, label.lower(), percentage)) if percentage > (100.0 - 95.45): self.logger.write( '[WARNING]: Large deviation count exceeds normal ' + 'distribution expectations.')
if not_found: missing.append(uid_entry) tracks = ordered if missing: print('MISSING UIDS:') for not_found_uid in missing: print(' * {}'.format(not_found_uid)) print('\n\n') #_______________________________________________________________________________ # TRACK ITERATOR for track in tracks: print(track.echoForVerification()) print(' size: (%s, %s) | field (%s, %s)' % ( track.width, track.length, track.widthMeasured, track.lengthMeasured)) print(' hidden: %s | custom: %s' % ( 'Y' if track.hidden else 'N', 'Y' if track.custom else 'N')) aTrack = track.getAnalysisPair(aSession) print(' curve[%s]: %s (%s)' % ( aTrack.curveSegment, NumericUtils.roundToSigFigs(aTrack.segmentPosition, 4), NumericUtils.roundToSigFigs(aTrack.curvePosition, 4))) print(' snapshot: %s' % DictUtils.prettyPrint(track.snapshotData)) print(' imports: %s' % track.echoImportFlags()) print(' analysis: %s\n' % track.echoAnalysisFlags()) session.close() aSession.close()
def _analyzeTrackSeries(self, series, trackway, sitemap): if len(series.tracks) < 2: # At least two tracks are required to make the comparison return for track in series.tracks: fieldAngle = Angle( degrees=track.rotationMeasured \ if track.rotationMeasured \ else 0.0) dataAngle = Angle(degrees=track.rotation) strideLine = StrideLine(track=track, series=series) if track.hidden or strideLine.pairTrack.hidden: continue try: strideLine.vector.normalize() except ZeroDivisionError: pair = strideLine.pairTrack self.logger.write([ '[ERROR]: Stride line was a zero length vector', 'TRACK: %s (%s, %s) [%s]' % ( track.fingerprint, NumericUtils.roundToSigFigs(track.x, 3), NumericUtils.roundToSigFigs(track.z, 3), track.uid), 'PAIRING: %s (%s, %s) [%s]' % ( pair.fingerprint, NumericUtils.roundToSigFigs(pair.x, 3), NumericUtils.roundToSigFigs(pair.z, 3), pair.uid) ]) continue axisAngle = strideLine.angle if track.left: fieldAngle.radians += axisAngle.radians else: fieldAngle.radians = axisAngle.radians - fieldAngle.radians # Adjust field angle into range [-180, 180] fieldAngle.constrainToRevolution() if fieldAngle.degrees > 180.0: fieldAngle.degrees -= 360.0 fieldAngleUnc = Angle(degrees=5.0) fieldAngleUnc.radians += \ 0.03/math.sqrt(1.0 - math.pow(strideLine.vector.x, 2)) fieldDeg = NumericUtils.toValueUncertainty( value=fieldAngle.degrees, uncertainty=fieldAngleUnc.degrees) # Adjust data angle into range [-180, 180] dataAngle.constrainToRevolution() if dataAngle.degrees > 180.0: dataAngle.degrees -= 360.0 dataAngleUnc = Angle(degrees=track.rotationUncertainty) dataDeg = NumericUtils.toValueUncertainty( value=dataAngle.degrees, uncertainty=dataAngleUnc.degrees) angle1 = Angle(degrees=dataDeg.value) angle2 = Angle(degrees=fieldDeg.value) # fill color for the disks to be added to the map are based on # diffDeg diffDeg = NumericUtils.toValueUncertainty( value=angle1.differenceBetween(angle2).degrees, uncertainty=min(90.0, math.sqrt( math.pow(dataAngleUnc.degrees, 2) + math.pow(fieldAngleUnc.degrees, 2))) ) self._diffs.append(diffDeg.value) deviation = diffDeg.value/diffDeg.uncertainty self.deviations[track.uid] = diffDeg # for now, convert +/- 180 headings to 0-360, using e and m # comment the next four lines toggle comments for entered and # measured below to revert e = dataDeg.value m = fieldDeg.value if e < 0.0: e += 360.0 if m < 0.0: m += 360.0 data = dict( uid=track.uid, fingerprint=track.fingerprint, entered=str(e), measured=str(m), delta=abs(diffDeg.value), deviation=deviation, relative=NumericUtils.roundToOrder(track.rotationMeasured, -2), axis=NumericUtils.roundToOrder(axisAngle.degrees, -2), axisPairing='NEXT' if strideLine.isNext else 'PREV') self._csv.createRow(**data) data['track'] = track self._data.append(data) # draw the stride line pointer for reference in green self._currentDrawing.use( 'pointer', (track.x, track.z), scene=True, rotation=axisAngle.degrees, stroke_width=1, scale=0.5, stroke='green') # indicate in blue the map-derived estimate of track rotation self._currentDrawing.use( 'pointer', (track.x, track.z), scene=True, rotation=dataDeg.value, stroke_width=1, stroke='blue') # add the measured (spreadsheet) estimate of rotation self._currentDrawing.use( 'pointer', (track.x, track.z), scene=True, rotation=fieldDeg.value, stroke_width=1, stroke='red') # place a translucent disk of radius proportional to the difference # in degrees radius = 100.0*diffDeg.value/180.0 self._currentDrawing.circle( (track.x, track.z), radius, scene=True, fill='red', stroke_width=0.5, stroke='red', fill_opacity='0.5')
def asciiRawLabel(self): return '%s +/- %s' % ( NumericUtils.roundToSigFigs(self.raw, 6), self.uncertainty)
def prettyPrint(self): return StringUtils.toText(NumericUtils.roundToSigFigs(self.degrees, 3))
def __str__(self): return '<%s %s>' % (self.__class__.__name__, NumericUtils.roundToSigFigs(self.degrees, 3))