Marthee commited on
Commit
a672b4c
·
verified ·
1 Parent(s): 9e12634

Update Doors_Schedule

Browse files
Files changed (1) hide show
  1. Doors_Schedule +190 -0
Doors_Schedule CHANGED
@@ -227,3 +227,193 @@ def get_st_op_pattern(clm_idx, clmn_name, starting_row_index):
227
  kelma = df.iloc[starting_row_index[position], structural_opening_value]
228
  return kelma
229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  kelma = df.iloc[starting_row_index[position], structural_opening_value]
228
  return kelma
229
 
230
+ def get_similar_colors(selected_columns_new):
231
+ def generate_rgb():
232
+ return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) # RGB tuple
233
+
234
+ unique_keys = selected_columns_new['door_type'].unique()
235
+ key_colors = {key: generate_rgb() for key in unique_keys} # Assign a unique RGB color to each key
236
+
237
+ # Create dictionary storing values, colors, and widths
238
+ col_dict = defaultdict(lambda: {'values': [], 'color': None, 'widths': []})
239
+
240
+ for _, row in selected_columns_new.iterrows():
241
+ key = row['door_type']
242
+ col_dict[key]['values'].append(row['door_id'])
243
+ col_dict[key]['widths'].append(row['structural opening']) # Add structural opening
244
+ col_dict[key]['color'] = key_colors[key] # Assign the unique RGB color
245
+
246
+ # Convert defaultdict to a normal dictionary
247
+ col_dict = dict(col_dict)
248
+ return col_dict
249
+
250
+ def get_flattened_tuples_list(col_dict):
251
+ tuples_list = []
252
+ for key in col_dict.keys():
253
+ tuples_list.append([(value, width, col_dict[key]["color"]) for value, width in zip(col_dict[key]['values'], col_dict[key]['widths'])])
254
+ flattened_list = [item for sublist in tuples_list for item in sublist]
255
+ return flattened_list
256
+
257
+ def find_text_in_plan(label, x):
258
+ substring_coordinates = []
259
+ words = []
260
+ point_list = []
261
+ #None, None, None
262
+ for tpl in x:
263
+ if tpl[4] == label:
264
+ substring_coordinates.append(calculate_midpoint(tpl[0],tpl[1],tpl[2],tpl[3]))# for pdf
265
+ point_list.append(calculate_midpoint(tpl[1],tpl[0],tpl[3],tpl[2]))# for rotated
266
+ words.append(tpl[4])
267
+ return substring_coordinates, words, point_list
268
+
269
+ def get_word_locations_plan(flattened_list):
270
+ locations = []
271
+ not_found = []
272
+ for lbl, w, clr in flattened_list:
273
+ location,worz, txt_pt = find_text_in_plan(lbl, plan_texts)
274
+ if len(location) ==0:
275
+ not_found.append(lbl)
276
+ locations.append((location, lbl, clr, w))
277
+ return locations, not_found
278
+
279
+ def get_repeated_labels(locations):
280
+ seen_labels = set()
281
+ repeated_labels = set()
282
+
283
+ for item in locations:
284
+ label = item[1]
285
+ if label in seen_labels:
286
+ repeated_labels.add(label)
287
+ else:
288
+ seen_labels.add(label)
289
+ return repeated_labels
290
+
291
+ def get_cleaned_data(locations):
292
+ processed = defaultdict(int)
293
+
294
+ new_data = []
295
+ for coords, label, color, w in locations:
296
+ if len(coords)>1:
297
+ index = processed[label] % len(coords) # Round-robin indexing
298
+ new_coord = [coords[index]] # Pick the correct coordinate
299
+ new_data.append((new_coord, label, color, w))
300
+ processed[label] += 1 # Move to the next coordinate for this label
301
+ if len(coords)==1:
302
+ new_data.append((coords, label, color, w))
303
+ return new_data
304
+
305
+ def get_width_info_tobeprinted(new_data):
306
+ width_info_tobeprinted = []
307
+ for _,_,_, w in new_data:
308
+ width_info_tobeprinted.append(w)
309
+ return width_info_tobeprinted
310
+
311
+ def clean_dimensions(text):
312
+ # Remove commas and "mm"
313
+ text = re.sub(r'[,\s]*mm', '', text) # Remove "mm" with optional spaces or commas before it
314
+ text = text.replace(",", "") # Remove remaining commas if any
315
+ return text
316
+
317
+ def get_cleaned_width(width_info_tobeprinted):
318
+ cleaned_width = []
319
+ for w in width_info_tobeprinted:
320
+ cleaned_width.append(clean_dimensions(w))
321
+ return cleaned_width
322
+
323
+ def get_widths_bb_format(cleaned_width):
324
+ pattern = r"\bW(?:idth)?\s*[×x]\s*H(?:eight)?\b"
325
+ match = re.search(pattern, kelma)
326
+ widths = []
327
+ for widthaa in cleaned_width:
328
+ index = max(widthaa.find("x"), widthaa.find("×"), widthaa.find("x"), widthaa.find("X"), widthaa.find("x"))
329
+ width_name = widthaa[:index]
330
+ height_name = widthaa[index+1:]
331
+ if match:
332
+ full_text = f"{width_name}mm wide x {height_name}mm high"
333
+ else:
334
+ full_text = f"{height_name}mm wide x {width_name}mm high"
335
+ widths.append(full_text)
336
+ return widths
337
+
338
+ import fitz # PyMuPDF
339
+ import PyPDF2
340
+ import io
341
+ from PyPDF2.generic import TextStringObject # ✅ Required for setting string values
342
+
343
+ def add_bluebeam_count_annotations(pdf_bytes, locations):
344
+ pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
345
+ pdf_document = fitz.open("pdf", pdf_stream.read()) # Open PDF in memory
346
+
347
+ page = pdf_document[0] # First page
348
+ for loc in locations:
349
+ coor, lbl, clr,w = loc
350
+ clr = (clr[0] / 255, clr[1] / 255, clr[2] / 255)
351
+ for cor in coor:
352
+ #Create a Circle annotation (Count Markup)
353
+ annot = page.add_circle_annot(
354
+ fitz.Rect(cor[0] - 10, cor[1] - 10, cor[0] + 10, cor[1] + 10) # Small circle
355
+ )
356
+
357
+ #Assign required Bluebeam metadata
358
+ annot.set_colors(stroke=clr, fill=(1, 1, 1)) # Set stroke color and fill white
359
+ annot.set_border(width=2) # Border thickness
360
+ annot.set_opacity(1) # Fully visible
361
+
362
+ #Set annotation properties for Bluebeam Count detection
363
+ annot.set_info("name", lbl) # Unique name for each count
364
+ annot.set_info("subject", "Count") #Bluebeam uses "Count" for Count markups
365
+ annot.set_info("title", lbl) # Optional
366
+ annot.update() # Apply changes
367
+
368
+ #Save modified PDF to a variable instead of a file
369
+ output_stream = io.BytesIO()
370
+ pdf_document.save(output_stream)
371
+ pdf_document.close()
372
+
373
+ return output_stream.getvalue() # Return the modified PDF as bytes
374
+
375
+ def modify_author_in_pypdf2(pdf_bytes, new_authors):
376
+ pdf_stream = io.BytesIO(pdf_bytes) # Load PDF from bytes
377
+ reader = PyPDF2.PdfReader(pdf_stream)
378
+ writer = PyPDF2.PdfWriter()
379
+
380
+ author_index = 0 # Track author assignment
381
+
382
+ for page in reader.pages:
383
+ if "/Annots" in page: #Check if annotations exist
384
+ for annot in page["/Annots"]:
385
+ annot_obj = annot.get_object()
386
+
387
+ # Assign each annotation a unique author
388
+ if author_index < len(new_authors):
389
+ annot_obj.update({"/T": TextStringObject(new_authors[author_index])})#Convert to PdfString
390
+ author_index += 1 # Move to next author
391
+
392
+ # If authors list is exhausted, keep the last one
393
+ else:
394
+ annot_obj.update({"/T": TextStringObject(new_authors[-1])})
395
+
396
+ writer.add_page(page)
397
+
398
+ #Save the modified PDF to a variable
399
+ output_stream = io.BytesIO()
400
+ writer.write(output_stream)
401
+
402
+ return output_stream.getvalue() # Return modified PDF as bytes
403
+
404
+ def process_pdf(input_pdf_path, output_pdf_path, locations, new_authors):
405
+ #Load original PDF
406
+ with open(input_pdf_path, "rb") as file:
407
+ original_pdf_bytes = file.read()
408
+
409
+ #Add Bluebeam-compatible count annotations
410
+ annotated_pdf_bytes = add_bluebeam_count_annotations(original_pdf_bytes, locations)
411
+
412
+ #Modify author field using PyPDF2
413
+ final_pdf_bytes = modify_author_in_pypdf2(annotated_pdf_bytes, new_authors)
414
+
415
+ #Save the final modified PDF to disk
416
+ with open(output_pdf_path, "wb") as file:
417
+ file.write(final_pdf_bytes)
418
+
419
+ process_pdf(plan, "final_output_width.pdf", new_data, widths)