def _write_alignment_data(self, data, parent):
        '''
        Write individual alignment to XML
        '''

        _align_node = LandXml.add_child(parent, 'Alignment')

        #write the alignment attributes
        self._write_tree_data(data['meta'], _align_node, maps.XML_ATTRIBS['Alignment'])

        _coord_geo_node = LandXml.add_child(_align_node, 'CoordGeom')

        #write the geo coordinate attributes
        self._write_tree_data(data['meta'], _coord_geo_node, maps.XML_ATTRIBS['CoordGeom'])

        #write the station equation data
        self.write_station_data(data['station'], _align_node)

        #write the alignment geometry data
        for _geo in data['geometry']:

            _node = None

            if _geo['Type'] == 'line':

                _node = LandXml.add_child(_coord_geo_node, 'Line')
                self._write_tree_data(_geo, _node, maps.XML_ATTRIBS['Line'])

            elif _geo['Type'] == 'arc':

                _node = LandXml.add_child(_coord_geo_node, 'Curve')
                self._write_tree_data(_geo, _node, maps.XML_ATTRIBS['Curve'])

            if _node is not None:
                self._write_coordinates(_geo, _node)
Ejemplo n.º 2
0
    def _parse_data(self, align_name, tags, attrib):
        '''
        Build a dictionary keyed to the internal attribute names from the XML
        '''
        result = {}

        #test to ensure all required tags are in the imrpoted XML data
        missing_tags = set(tags[0]).difference(set(list(attrib.keys())))

        #report error and skip the alignment if required tags are missing
        if missing_tags:
            self.errors.append(
                'The required XML tags were not found in alignment %s:\n%s' %
                (align_name, missing_tags))
            return None

        #merge the required / optional tag dictionaries and iterate the items
        for _tag in tags[0] + tags[1]:

            attr_val = LandXml.convert_token(_tag, attrib.get(_tag))

            if attr_val is None:

                if _tag in tags[0]:
                    self.errors.append(
                        'Missing or invalid %s attribute in alignment %s' %
                        (_tag, align_name))

            #test for angles and convert to radians
            elif _tag in maps.XML_TAGS['angle']:
                attr_val = Utils.to_float(attrib.get(_tag))

                if attr_val:
                    attr_val = math.radians(attr_val)

            #test for lengths to convert to mm
            elif _tag in maps.XML_TAGS['length']:
                attr_val = Utils.to_float(attrib.get(_tag))

                if attr_val:
                    attr_val = attr_val * Units.scale_factor()

            #convert rotation from string to number
            elif _tag == 'rot':

                attr_val = 0.0

                if attrib.get(_tag) == 'cw':
                    attr_val = 1.0

                elif attrib.get(_tag) == 'ccw':
                    attr_val = -1.0

            if not attr_val:
                attr_val = LandXml.get_tag_default(_tag)

            result[maps.XML_MAP[_tag]] = attr_val

        return result
    def write_meta_data(self, data, node):
        '''
        Write the project and application data to the file
        '''

        self._write_tree_data(data, LandXml.get_child(node, 'Project'), maps.XML_ATTRIBS['Project'])

        node = LandXml.get_child(node, 'Application')

        node.set('version', ''.join(App.Version()[0:3]))
        node.set('timeStamp', datetime.datetime.utcnow().isoformat())
Ejemplo n.º 4
0
    def _parse_coord_geo_data(self, align_name, alignment):
        '''
        Parse the alignment coorinate geometry data to get curve information and
        return as a dictionary
        '''

        coord_geo = LandXml.get_child(alignment, 'CoordGeom')

        if not coord_geo:
            print('Missing coordinate geometry for ', align_name)
            return None

        result = []

        for geo_node in coord_geo:

            node_tag = geo_node.tag.split('}')[1]

            if not node_tag in ['Curve', 'Spiral', 'Line']:
                continue

            points = []

            for _tag in ['Start', 'End', 'Center', 'PI']:

                _pt = LandXml.get_child_as_vector(geo_node, _tag)

                points.append(None)

                if _pt:
                    points[-1] = (_pt.multiply(Units.scale_factor()))
                    continue

                if not (node_tag == 'Line' and _tag in ['Center', 'PI']):
                    self.errors.append(
                        'Missing %s %s coordinate in alignment %s' %
                        (node_tag, _tag, align_name))

            coords = {
                'Type': node_tag,
                'Start': points[0],
                'End': points[1],
                'Center': points[2],
                'PI': points[3]
            }

            result.append({
                **coords,
                **self._parse_data(align_name, maps.XML_ATTRIBS[node_tag], geo_node.attrib)
            })

        print('\n<---- Import result ---->\n', result)
        return result
    def write(self, data, source_path, target_path):
        '''
        Write the alignment data to a land xml file in the target location
        '''

        root = etree.parse(source_path).getroot()

        _parent = LandXml.add_child(root, 'Alignments')

        for _align in data:
            self._write_alignment_data(_align, _parent)

        LandXml.write_to_file(root, target_path)
Ejemplo n.º 6
0
    def import_file(self, filepath):
        '''
        Import a LandXML and build the Python dictionary fronm the appropriate elements
        '''

        #get element tree and key nodes for parsing
        doc = etree.parse(filepath)
        root = doc.getroot()

        project = LandXml.get_child(root, 'Project')
        units = LandXml.get_child(root, 'Units')
        alignments = LandXml.get_child(root, 'Alignments')

        #aport if key nodes are missing
        if not units:
            self.errors.append('Missing project units')
            return None

        unit_name = self._validate_units(units)

        if not unit_name:
            self.errors.append('Invalid project units')
            return None

        #default project name if missing
        project_name = 'Unknown Project'

        if not project is None:
            project_name = project.attrib['name']

        #build final dictionary and return
        result = {}
        result['Project'] = {}
        result['Project'][maps.XML_MAP['name']] = project_name
        result['Alignments'] = {}

        for alignment in alignments:

            align_name = self._get_alignment_name(alignment,
                                                  list(result.keys()))

            result['Alignments'][align_name] = {}
            align_dict = result['Alignments'][align_name]

            align_dict['meta'] = self._parse_meta_data(align_name, alignment)
            align_dict['station'] = self._parse_station_data(
                align_name, alignment)
            align_dict['geometry'] = self._parse_coord_geo_data(
                align_name, alignment)

        return result
    def _write_coordinates(self, data, parent):
        '''
        Write coordinate children to parent geometry
        '''

        _sf = 1.0 / Units.scale_factor()

        for _key in maps.XML_TAGS['coordinate']:

            if not _key in data:
                continue

            #scale the coordinates to the document units
            _vec = App.Vector(data[_key])
            _vec.multiply(_sf)

            _child = LandXml.add_child(parent, _key)

            _vec_string = LandXml.get_vector_string(_vec)

            LandXml.set_text(_child, _vec_string)
Ejemplo n.º 8
0
    def _parse_meta_data(self, align_name, alignment):
        '''
        Parse the alignment elements and strip out meta data for each alignment,
        returning it as a dictionary keyed to the alignment name
        '''

        result = self._parse_data(align_name, maps.XML_ATTRIBS['Alignment'],
                                  alignment.attrib)

        _start = LandXml.get_child_as_vector(alignment, 'Start')

        if _start:
            _start.multiply()

        result['Start'] = _start

        return result
    def _write_tree_data(self, data, node, attribs):
        '''
        Write data to the tree using the passed parameters
        '''

        for _tag in attribs[0] + attribs[1]:

            #find the xml tag for the current dictionary key
            _key = maps.XML_MAP.get(_tag)

            _value = None

            if _key:
                value = data.get(_key)

            #assign default if no value in the dictionary
            if value is None:
                value = LandXml.get_tag_default(_tag)

            if _tag in maps.XML_TAGS['angle']:
                value = math.degrees(value)

            elif _tag in maps.XML_TAGS['length']:
                value /= Units.scale_factor()

            elif _tag == 'rot':

                if value < 0.0:
                    value = 'ccw'

                elif value > 0.0:
                    value = 'cw'

                else:
                    value = ''

            result = str(value)

            if isinstance(value, float):
                result = '{:.8f}'.format(value)

            node.set(_tag, result)
Ejemplo n.º 10
0
    def _parse_geo_data(self, align_name, geometry, curve_type):
        '''
        Parse curve data and return as a dictionary
        '''

        result = []

        for curve in geometry:

            #add the curve / line start / center / end coordinates, skipping if any are missing
            _points = []

            for _tag in ['Start', 'End', 'Center', 'PI']:

                _pt = LandXml.get_child_as_vector(curve, _tag)

                if _pt:
                    _pt.multiply(Units.scale_factor())
                else:

                    #report missing coordinates
                    if not (curve_type == 'line' and _tag in ['Center', 'PI']):
                        self.errors.append(
                            'Missing %s %s coordinate in alignment %s' %
                            (curve_type, _tag, align_name))

                _points.append(_pt)

            coords = {
                'Type': curve_type,
                'Start': _points[0],
                'End': _points[1],
                'Center': _points[2],
                'PI': _points[3]
            }

            result.append({
                **coords,
                **self._parse_data(align_name, maps.XML_ATTRIBS[curve_type], curve.attrib)
            })

        return result
Ejemplo n.º 11
0
    def _parse_station_data(self, align_name, alignment):
        '''
        Parse the alignment data to get station equations and return a list of equation dictionaries
        '''

        equations = LandXml.get_children(alignment, 'StaEquation')

        print(equations)
        result = []

        for equation in equations:

            print(equation.attrib)

            _dict = self._parse_data(align_name,
                                     maps.XML_ATTRIBS['StaEquation'],
                                     equation.attrib)
            _dict['Alignment'] = align_name

            print('\n<--- dict --->\n', _dict)
            result.append(_dict)

        return result