1 # -*- indent-tabs-mode:1 tab-width:4 mode:python minor-mode:whitespace -*-
2 import libxml2
3 import re
4 import os
5 import glob
6
7
8 '''
9 This class has all the colors to be used with colored output
10 terminal.
11 '''
12 class ESC[4;38;5;81mbcolors:
13 HEADER = '\033[95m'
14 OKBLUE = '\033[94m'
15 OKGREEN = '\033[92m'
16 WARNING = '\033[93m'
17 FAIL = '\033[91m'
18 ENDC = '\033[0m'
19
20
21 '''
22 This functions uses the script to generate xml which can be used for
23 comparison later.
24
25 @param string dwgdir The path to DWG dir
26 '''
27 def generatexml(dwgdir):
28 # This beats ‘sys.argv[0]’, which is not guaranteed to be set.
29 me = os.getenv ("PYTHON")
30 if not me:
31 me = "python"
32 srcdir = os.path.dirname(__file__)
33 current_dir = os.getcwd()
34 os.chdir(dwgdir)
35 for filename in glob.glob ("*/*.txt"):
36 # maybe add double-quotes for the script?
37 os.system (me + " " + srcdir + "/txttoxml.py " + filename + " "
38 + current_dir + "/test_output")
39 os.chdir(current_dir)
40
41 '''
42 This functions main aim is to process special types of attributes
43 which are difficult to equate to each other. Currently this only
44 handles 2D and 3D point. It converts these string in certain format
45 so that they can be equated
46
47 @param string attr the attribute to be processed
48 @return string The processed attribute
49 '''
50 def processattr(attr):
51 pattern = re.compile(r"(\d+\.\d{1,})\s{0,1}")
52 if re.search(pattern, attr):
53 #extract the numbers and adjust them
54 extract_pattern = re.compile(r"(\d+\.\d{1,})\s{0,1}");
55 result = extract_pattern.findall(attr)
56 for no in range(len(result)):
57 result[no] = float(result[no])
58
59 #if its a 3d point
60 if len(result) == 3:
61 return "(%.2f %.2f %.2f)" % (round(result[0],2), round(result[1],2),
62 round(result[2],2))
63 elif len(result) == 2:
64 return "(%.2f %.2f)" % round(round(result[0],2), round(result[1],2))
65 else:
66 return attr
67
68 '''
69 This function takes handle to both ideal file which came from AutoCAD and
70 practical file which came from LibreDWG and compares them to emit out the
71 result
72
73 @param ideal Name of the ideal file
74 @param practical Name of the practical file
75
76 return array[2]
77 [0] = The percentage of entity that matched
78 [1] = The unmatched attributes with following format
79 {attrname, original, duplicate}
80 attrname = Name of the attribute
81 original = Value came from AutoCAD
82 duplicate = Value that came from LibreDWG.
83 '''
84 def xmlprocess(ideal, practical):
85 doc = libxml2.parseFile(ideal)
86
87 root = doc.getRootElement()
88 child = root.children
89
90 # Let's first collect all the entities present in the file
91 original_entities = []
92
93 while child is not None:
94 if child.type == "element":
95 original_entities.insert(len(original_entities), child)
96 child = child.next
97
98 doc2 = libxml2.parseFile(practical)
99
100 root2 = doc2.getRootElement()
101 child2 = root2.children
102
103 duplicate_entities = []
104
105 while child2 is not None:
106 if child2.type == "element":
107 duplicate_entities.insert(len(duplicate_entities), child2)
108 child2 = child2.next
109
110 match = 0
111
112 # Now its time for comparison, For each dwg entity
113 for original, duplicate in zip(original_entities, duplicate_entities):
114 original_attributes = {}
115 duplicate_attributes = {}
116 excluded_attributes = ["Delta", "id", "Document", "Visible", "text",
117 "Application", "Hyperlinks"]
118
119 # collect original attributes. Removing the attributes here, so the
120 # total length is also set
121 try:
122 #print (ideal + " original.properties")
123 for attr in original.properties:
124 if attr.name not in excluded_attributes:
125 original_attributes[attr.name] = processattr(attr.content)
126 except (TypeError):
127 print ("Need python3 compatible libxml2 with __next__ iterator")
128
129 try:
130 for attr in duplicate.properties:
131 duplicate_attributes[attr.name] = processattr(attr.content)
132 except (TypeError):
133 pass
134
135 unmatched_attr = []
136 # collect duplicate attributes and check if it matches with
137 # original ones
138 for key,value in original_attributes.items():
139 try:
140 if value == duplicate_attributes[key]:
141 match += 1
142 else:
143 # The attributes didn't match.
144 # Report the unmatched attribute
145 unmatched_attr.append({"attrname" : key, "original" : value,
146 "duplicate" : duplicate_attributes[key]})
147
148 except Exception:
149 # This exception would occur when
150 # We can't find the given attribute
151
152 unmatched_attr.append({"attrname" : key, "original" : value,
153 "duplicate" : ""})
154 continue
155
156 # What are the total number of attributes
157 try:
158 total_attr = len(original_attributes)
159 if total_attr == 0:
160 percent_each = 0
161 else:
162 percent_each = 100 / total_attr
163 except NameError:
164 return [0,[]]
165 raise
166
167
168 res_percent = percent_each*match;
169
170 doc.freeDoc()
171 doc2.freeDoc()
172
173 return [res_percent, unmatched_attr]