def get_coordinate(start, bearing, distance): """ Return the x/y coordinate of the line at the specified distance along it """ _vec = TupleMath.bearing_vector(bearing) return TupleMath.add(tuple(start), TupleMath.multiply(tuple(_vec), distance))
def discretize_geometry(self, interval=None, method='Segment', delta=10.0): """ Discretizes the alignment geometry to a series of vector points interval - the starting internal station and length of curve method - method of discretization delta - discretization interval parameter """ geometry = self.data.get('geometry') points = [] last_curve = None #undefined = entire length if not interval: interval = [0.0, self.data.get('meta').get('Length')] #only one element = starting position if len(interval) == 1: interval.append(self.data.get('meta').get('Length')) #discretize each arc in the geometry list, #store each point set as a sublist in the main points list for curve in geometry: if not curve: continue _sta = curve.get('InternalStation') #skip if curve end precedes start of interval if _sta[1] < interval[0]: continue #skip if curve start exceeds end of interval if _sta[0] > interval[1]: continue _start = _sta[0] #if curve starts before interval, use start of interval if _sta[0] < interval[0]: _start = interval[0] _end = _sta[1] #if curve ends past the interval, stop at end of interval if _sta[1] > interval[1]: _end = interval[1] #calculate start position on arc and length to discretize _arc_int = [_start - _sta[0], _end - _start] #just in case, skip for zero or negative lengths if _arc_int[1] <= 0.0: continue if curve.get('Type') == 'Curve': _pts = arc.get_points(curve, size=delta, method=method, interval=_arc_int) if _pts: points.append(_pts) elif curve.get('Type') == 'Spiral': _pts = spiral.get_points(curve, size=delta, method=method) if _pts: points.append(_pts) else: _start_coord = line.get_coordinate(curve.get('Start'), curve.get('BearingIn'), _arc_int[0]) points.append([ _start_coord, line.get_coordinate(_start_coord, curve.get('BearingIn'), _arc_int[1]) ]) last_curve = curve #store the last point of the first geometry for the next iteration _prev = points[0][-1] result = points[0] if not (_prev and result): return None #iterate the point sets, adding them to the result set #and eliminating any duplicate points for item in points[1:]: _v = item #duplicate points are within a hundredth of a foot of each other if TupleMath.length( TupleMath.subtract(tuple(_prev), tuple(item[0]))) < 0.01: _v = item[1:] result.extend(_v) _prev = item[-1] #add a line segment for the last tangent if it exists last_tangent = abs( self.data.get('meta').get('Length') \ - last_curve.get('InternalStation')[1] ) if not support.within_tolerance(last_tangent): _vec = TupleMath.bearing_vector( last_curve.get('BearingOut') * last_tangent) # _vec = support.vector_from_angle(last_curve.get('BearingOut'))\ # .multiply(last_tangent) last_point = tuple(result[-1]) result.append(TupleMath.add(last_point, _vec)) #set the end point if not self.data.get('meta').get('End'): self.data.get('meta')['End'] = result[-1] return result
def validate_coordinates(self, zero_reference): """ Iterate the geometry, testing for incomplete / incorrect station / coordinate values. Fix them where possible, error otherwise """ #calculate distance between curve start and end using #internal station and coordinate vectors _datum = self.data.get('meta') _geo_data = self.data.get('geometry') _prev_geo = { 'End': _datum.get('Start'), 'InternalStation': (0.0, 0.0), 'StartStation': _datum.get('StartStation'), 'Length': 0.0 } if zero_reference: _prev_geo['End'] = Vector() for _geo in _geo_data: if not _geo: continue #get the vector between the two geometries #and the station distance _vector = TupleMath.subtract(tuple(_geo.get('Start')), tuple(_prev_geo.get('End'))) _sta_len = abs( _geo.get('InternalStation')[0] \ - _prev_geo.get('InternalStation')[1] ) #calculate the difference between the vector length #and station distance in document units _delta = \ (TupleMath.length(_vector) - _sta_len) / units.scale_factor() #if the stationing / coordinates are out of tolerance, #the error is with the coordinate vector or station if not support.within_tolerance(_delta): bearing_angle = TupleMath.bearing(_vector) #fix station if coordinate vector bearings match if support.within_tolerance(bearing_angle, _geo.get('BearingIn')): _int_sta = ( _prev_geo.get('InternalStation')[1] \ + TupleMath.length(_vector), _geo.get('InternalStation')[0] ) _start_sta = _prev_geo.get('StartStation') + \ _prev_geo.get('Length') / \ units.scale_factor() + \ TupleMath.length(_vector) / \ units.scale_factor() _geo['InternalStation'] = _int_sta _geo['StartStation'] = _start_sta #otherwise, fix the coordinate else: _bearing_vector = TupleMath.multiply( TupleMath.bearing_vector(_geo.get('BearingIn')), _sta_len) _start_pt = TupleMath.add(_prev_geo.get('End'), _bearing_vector) _geo['Start'] = _start_pt _prev_geo = _geo
def validate_datum(self): """ Ensure the datum is valid, assuming 0+00 / (0,0,0) for station and coordinate where none is suplpied and it cannot be inferred fromt the starting geometry """ _datum = self.data.get('meta') _geo = self.data.get('geometry')[0] if not _geo or not _datum: return _datum_truth = [ not _datum.get('StartStation') is None, not _datum.get('Start') is None ] _geo_truth = [ not _geo.get('StartStation') is None, not _geo.get('Start') is None ] #---------------------------- #CASE 0 #---------------------------- #both defined? nothing to do if all(_datum_truth): return #---------------------------- #Parameter Initialization #---------------------------- _geo_station = 0 _geo_start = Vector() if _geo_truth[0]: _geo_station = _geo.get('StartStation') if _geo_truth[1]: _geo_start = _geo.get('Start') #--------------------- #CASE 1 #--------------------- #no datum defined? use initial geometry or zero defaults if not any(_datum_truth): _datum['StartStation'] = _geo_station _datum['Start'] = _geo_start return #-------------------- #CASE 2 #-------------------- #station defined? #if the geometry has a station and coordinate, #project the start coordinate if _datum_truth[0]: _datum['Start'] = _geo_start #assume geometry start if no geometry station if not _geo_truth[0]: return #scale the distance to the system units delta = _geo_station - _datum['StartStation'] #cutoff if error is below tolerance if not support.within_tolerance(delta): delta *= units.scale_factor() else: delta = 0.0 #assume geometry start if station delta is zero if delta: #calculate the start based on station delta _datum['Start'] =\ TupleMath.subtract(_datum.get('Start'), TupleMath.scale( TupleMath.bearing_vector(_geo.get('BearingIn')), delta) #_geo.get('BearingIn')).multiply(delta) ) return #--------------------- #CASE 3 #--------------------- #datum start coordinate is defined #if the geometry has station and coordinate, #project the start station _datum['StartStation'] = _geo_station #assume geometry station if no geometry start if _geo_truth[1]: #scale the length to the document units delta = TupleMath.length( TupleMath.subtract( _geo_start, _datum.get('Start'))) / units.scale_factor() _datum['StartStation'] -= delta