/
base.py
165 lines (148 loc) · 5.61 KB
/
base.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import math
from abc import ABC, abstractmethod
from io import StringIO, TextIOWrapper
from typing import Any, Union
from geofiles.domain.geo_object_file import GeoObjectFile
class BaseWriter(ABC):
"""
Base implementation for writing geo-referenced object
"""
def write(
self,
file: Any,
data: GeoObjectFile,
write_binary: bool = False,
append_file_type: bool = True,
random_seed: Any = None,
) -> None:
"""
Allows to create write a file at the given file position
:param file: file to be written. Either a opened file or a path to the file
:param data: to be written
:param write_binary: flag if file should be written in binary style (only used if file-parameter is a path)
:param append_file_type: flag if a writer's associated file type should be appended to the given file (only if it is a path)
:param random_seed: may be used by the writer for e.g. IDs
:return: None
"""
close = False
to_write: Any = None
try:
if isinstance(file, str):
if append_file_type:
file += self.get_file_type()
if write_binary:
to_write = open(file, "wb")
else:
to_write = open(file, "w")
close = True
elif isinstance(file, TextIOWrapper):
if "w" not in file.mode.lower():
raise Exception("Given file is not in write mode")
if "b" in file.mode.lower():
write_binary = True
to_write = file
else:
raise Exception(f"Can't handle {file}")
self._write(to_write, data, write_binary, random_seed)
finally:
if close and to_write is not None:
to_write.close()
@abstractmethod
def _write(
self,
file: Union[TextIOWrapper, StringIO],
data: GeoObjectFile,
write_binary: bool,
random_seed: Any,
) -> None:
"""
Write implementation
:param file: target to be written
:param data: content to be written
:param write_binary: flag if file is a binary file
:param random_seed: may be used by the writer for e.g. IDs
:return:
"""
return
@abstractmethod
def get_file_type(self) -> str:
"""
:return: the supported file type of this writer
"""
return ""
def write_to_string(
self, data: GeoObjectFile, write_binary: bool = False, random_seed: Any = None
) -> str:
"""
Write to string implementation
:param data: content to be written
:param write_binary: flag if file should be written in binary style (only used if file-parameter is a path)
:param random_seed: may be used by the writer for e.g. IDs
:return: string representation of the given data
"""
to_write = StringIO("")
self._write(to_write, data, write_binary, random_seed)
to_write.seek(0)
return "".join(to_write.readlines())
def supports_origin_base(self) -> bool: # pylint: disable=R0201
"""
:return: true if file format supports origin based representation
"""
return False
def _write_to_file(
self,
file: Union[TextIOWrapper, StringIO],
data: Any,
write_binary: bool,
append_new_line: bool = False,
encoding: str = "ascii",
) -> None:
"""
Write to the given file
:param file: to be written to
:param data: what to be written
:param write_binary: flag if data should be written binary ascii-encoded
:param append_new_line: flag if new line character should be appended
:param encoding: how data should be encoded
:return: None
"""
file.write(self._encode(data, write_binary, encoding))
if append_new_line:
file.write(self._encode("\n", write_binary, encoding))
@staticmethod
def _encode(data: Any, write_binary: bool, encoding: str = "ascii") -> Any:
"""
Encode the given data
:param data: to be encoded
:param write_binary: flag if data should be encoded
:param encoding: how data should be encoded
:return: encoded data
"""
if write_binary:
return str(data).encode(encoding)
return f"{data}"
@staticmethod
def _contains_transformation_information(data: GeoObjectFile) -> None:
"""
Check the given data if it contains translation, rotation or scale information
:param data: to be checked
:return: None
"""
if data.translation is not None:
for t in data.translation:
if not math.isclose(float(t), 0, rel_tol=1e-6):
raise Exception(
"Given data contains translation information. Transform data, before writing to file"
)
if data.rotation is not None:
for t in data.rotation:
if not math.isclose(float(t), 0, rel_tol=1e-6):
raise Exception(
"Given data contains rotation information. Transform data, before writing to file"
)
if data.scaling is not None:
for t in data.scaling:
if not math.isclose(float(t), 1, rel_tol=1e-6):
raise Exception(
"Given data contains scale information. Transform data, before writing to file"
)