def get_intersection(self, segment): """ Calculate the intersection of two line segments """ _lhs = TupleMath.subtract(self.end, self.start)[0:2] _lhs = TupleMath.multiply(_lhs, (1.0, -1.0)) _lhs += (sum(TupleMath.multiply(_lhs, self.start)),) _rhs = TupleMath.subtract(segment.end, segment.start)[0:2] _rhs = TupleMath.multiply(_lhs, (1.0, -1.0)) _rhs += (sum(TupleMath.multiply(_rhs, segment.start)),) _determinant = TupleMath.cross(_lhs, _rhs, (0, 0, 1))[2] if not _determinant: return (math.nan, math.nan) _intersection = ( TupleMath.cross(_lhs, _rhs, (1, 0, 0))[0], TupleMath.cross(_lhs, _rhs, (0, 1, 0))[1] ) return TupleMath.scale(_intersection, 1.0 / _determinant)
def get_ortho_vector(line, distance, side=''): """ Return the orthogonal vector pointing toward the indicated side at the provided position. Defaults to left-hand side """ _dir = 1.0 _side = side.lower() if _side in ['r', 'rt', 'right']: _dir = -1.0 start = tuple(line.get('Start')) end = tuple(line.get('End')) bearing = line.get('BearingIn') if (start is None) or (end is None): return None, None _delta = TupleMath.subtract(end, start) _delta = TupleMath.normalize(_delta) _left = tuple(-_delta.y, _delta.x, 0.0) _coord = get_coordinate(start, bearing, distance) return _coord, TupleMath.multiply(_left, _dir)
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 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