示例#1
0
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