Marthee commited on
Commit
4d219e8
·
verified ·
1 Parent(s): 13d4a21

Update dxf__omar3_2.py

Browse files
Files changed (1) hide show
  1. dxf__omar3_2.py +1124 -215
dxf__omar3_2.py CHANGED
@@ -1,3 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  # -*- coding: utf-8 -*-wj
2
  """Version to be deployed of 3.2 Calculating area/perimeter
3
 
@@ -18,6 +41,13 @@ Original file is located at
18
  # pip install ezdxf scipy
19
 
20
  """## Imports"""
 
 
 
 
 
 
 
21
 
22
  import numpy as np
23
  import cv2
@@ -28,17 +58,22 @@ import fitz
28
  import ezdxf as ez
29
  import sys
30
  from ezdxf import units
 
31
  from ezdxf.math import OCS, Matrix44, Vec3
32
  import ezdxf
33
  import matplotlib.pyplot as plt
34
  from matplotlib.patches import Polygon
35
- from shapely.geometry import Polygon as ShapelyPolygon
36
  from ezdxf.math import Vec2
37
  import random
38
  import pandas as pd
39
- import google_sheet_Legend
40
  import tsadropboxretrieval
41
  from ezdxf import bbox
 
 
 
 
42
 
43
  """## Notes"""
44
 
@@ -58,8 +93,11 @@ This portion is used to convert vertices read from dxf to pixels in order to acc
58
 
59
  """PDF to image"""
60
 
61
- def pdftoimg(datadoc):
62
- doc = fitz.open('pdf',datadoc)
 
 
 
63
  page=doc[0]
64
  pix = page.get_pixmap() # render page to an image
65
  pl=Image.frombytes('RGB', [pix.width,pix.height],pix.samples)
@@ -90,9 +128,12 @@ def get_paper_size_in_inches(width, height):
90
  return size
91
  return "Unknown Size"
92
 
93
- def analyze_pdf(datadoc):
94
  # Open the PDF file
95
- pdf_document = fitz.open('pdf',datadoc)
 
 
 
96
 
97
  # Iterate through pages and print their sizes
98
  for page_number in range(len(pdf_document)):
@@ -147,9 +188,12 @@ def switch_case(argument):
147
 
148
 
149
 
150
- def RetriveRatio(datadoc,dxfpath):
151
-
152
- width,height,paper_size = analyze_pdf (datadoc)
 
 
 
153
 
154
  if(width > height ):
155
  bigger=width
@@ -190,79 +234,667 @@ def flip(img):
190
  flipped_horizontal = cv2.flip(rotated_image, 1)
191
  return flipped_horizontal
192
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  """### Hatched areas"""
 
194
 
195
- def get_hatched_areas(filename,FinalRatio):
196
  doc = ezdxf.readfile(filename)
197
  doc.header['$MEASUREMENT'] = 1
198
  msp = doc.modelspace()
199
  trial=0
200
  hatched_areas = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
 
202
- for entity in msp:
203
 
204
- if entity.dxftype() == 'HATCH':
205
- flag=0
206
- trial=0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
- print(entity.dxftype())
 
209
 
 
 
 
 
 
 
 
 
 
210
  for path in entity.paths:
211
- if str(path.type)=='BoundaryPathType.POLYLINE':
212
- print('First type of Hatch')
213
- vertices = [(vertex[0]* (FinalRatio), vertex[1]* (FinalRatio))for vertex in path.vertices]
214
- if(len(vertices)>3):
215
- poly = ShapelyPolygon(vertices)
216
-
217
- minx, miny, maxx, maxy = poly.bounds
218
-
219
- # Calculate the width and height of the bounding box
220
- width = maxx - minx
221
- height = maxy - miny
222
-
223
-
224
-
225
- if (poly.area > 1.5 and (height > 0.7 and width > 0.7)):
226
- area1 = round(poly.area,3)
227
- perimeter = round (poly.length,3)
228
- if trial==0:
229
- hatched_areas.append([vertices,area1,perimeter])
230
- trial=1
231
- else:
232
- for i in range(len(hatched_areas)):
233
- if(area1 == hatched_areas[i][1]):
234
- flag=1
235
- elif str(path.type) == 'BoundaryPathType.EDGE':
236
- print('Second type of Hatch')
237
-
238
- vert=[]
239
- flag=0
240
- flag2=0
241
- for edge in path.edges:
242
- x,y=edge.start
243
- x1,y1=edge.end
244
- if(flag==0):
245
- vert=[(x* (FinalRatio),y* (FinalRatio)),(x1* (FinalRatio),y1* (FinalRatio))]
246
- else:
247
- vert.append([x1* (FinalRatio),y1* (FinalRatio)])
248
- flag=1
249
- poly = ShapelyPolygon(vert)
250
- minx, miny, maxx, maxy = poly.bounds
251
-
252
- # Calculate the width and height of the bounding box
253
- width = maxx - minx
254
- height = maxy - miny
255
-
256
- if (poly.area > 1.5 and (height > 0.7 and width > 0.7)):
257
- area1= round(poly.area,3)
258
- perimeter = round (poly.length,3)
259
- for i in range(len(hatched_areas)):
260
- if(area1 == hatched_areas[i][1]):
261
- flag2=1
262
- if(flag2==0):
263
- hatched_areas.append([vert,area1,perimeter])
264
- else:
265
- print(path.type)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
 
267
  elif entity.dxftype() == 'SOLID':
268
  vertices = [entity.dxf.vtx0 * (FinalRatio), entity.dxf.vtx1* (FinalRatio), entity.dxf.vtx2* (FinalRatio), entity.dxf.vtx3* (FinalRatio)]
@@ -273,44 +905,73 @@ def get_hatched_areas(filename,FinalRatio):
273
  width = maxx - minx
274
  height = maxy - miny
275
 
276
- if (poly.area > 1.5 and (height > 0.7 and width > 0.7)):
277
- hatched_areas.append([vertices,poly.area,poly.length])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
 
279
  elif entity.dxftype() == 'LWPOLYLINE':
 
 
 
 
280
 
281
- vertices=[]
282
- lwpolyline = entity
283
- points = lwpolyline.get_points()
284
- flag=0
285
 
286
- for i in range(len(points)):
287
- vertices.append([points[i][0]* (FinalRatio),points[i][1]* (FinalRatio)])
288
- if(len(vertices)>3):
 
 
 
289
 
290
- if(vertices[0][0] == vertices[len(vertices)-1][0] or vertices[0][1] == vertices[len(vertices)-1][1]):
 
 
291
 
292
- poly=ShapelyPolygon(vertices)
293
- minx, miny, maxx, maxy = poly.bounds
 
 
294
 
295
- # Calculate the width and height of the bounding box
296
- width = maxx - minx
297
- height = maxy - miny
 
 
 
 
 
 
 
 
 
298
 
299
- if (poly.area > 1.5 and (height > 0.7 and width > 0.7)):
300
- area1 = round(poly.area,3)
301
- perimeter = round (poly.length,3)
302
- for i in range(len(hatched_areas)):
303
- if(area1 == hatched_areas[i][1]):
304
- flag=1
305
- if(flag==0):
306
- hatched_areas.append([vertices,area1,perimeter])
307
 
308
 
309
  elif entity.dxftype() == 'POLYLINE':
310
 
 
 
311
  flag=0
312
  vertices = [(v.dxf.location.x * (FinalRatio), v.dxf.location.y * (FinalRatio)) for v in entity.vertices]
313
- print('Vertices:', vertices)
314
 
315
  if(len(vertices)>3):
316
 
@@ -323,14 +984,22 @@ def get_hatched_areas(filename,FinalRatio):
323
  width = maxx - minx
324
  height = maxy - miny
325
 
326
- if (poly.area > 1.5 and (height > 0.7 and width > 0.7)):
327
  area1 = round(poly.area,3)
328
  perimeter = round (poly.length,3)
329
- for i in range(len(hatched_areas)):
330
- if(area1 == hatched_areas[i][1]):
331
- flag=1
332
- if(flag==0):
333
- hatched_areas.append([vertices,area1,perimeter])
 
 
 
 
 
 
 
 
334
 
335
  elif entity.dxftype() == 'SPLINE':
336
  spline_entity = entity
@@ -348,17 +1017,28 @@ def get_hatched_areas(filename,FinalRatio):
348
  height = maxy - miny
349
 
350
 
351
- if (poly.area > 1.5 and (height > 0.7 and width > 0.7)):
352
  area1 = round(poly.area,3)
353
  perimeter = round (poly.length,3)
354
- hatched_areas.append([vertices,area1,perimeter])
 
 
 
 
 
 
 
 
 
 
 
355
 
356
  sorted_data = sorted(hatched_areas, key=lambda x: x[1])
357
- return sorted_data
358
 
359
  """### Rotate polygon"""
360
 
361
- from math import sin, cos, radians
362
 
363
  def rotate_point(point, angle,pdfrotation,width,height, center_point=(0, 0)):
364
  """Rotates a point around center_point(origin by default)
@@ -399,43 +1079,39 @@ def rotate_polygon(polygon, angle, pdfrotation,width,height,center_point=(0, 0))
399
  #SimilarAreaDictionary= pd.DataFrame(columns=['Guess','Color','Occurences','Area','Total Area','Perimeter','Total Perimeter','Length','Total Length','R','G','B'])
400
  #loop 3la hatched areas and count the occurences of each shape w create a table bl hagat di
401
 
402
- def generate_color_array(length):
403
- colorRanges = []
404
- while len(colorRanges) < length:
405
- # Generate random RGB values
406
- r = random.randint(0, 255)
407
- g = random.randint(0, 255)
408
- b = random.randint(0, 255)
409
- # Ensure no duplicate colors
410
- if (r, g, b) not in colorRanges:
411
- colorRanges.append((r, g, b))
412
- return colorRanges
413
-
414
- def Create_DF(dxfpath,datadoc):
415
-
416
- FinalRatio= RetriveRatio(datadoc,dxfpath)
417
 
418
- hatched_areas = get_hatched_areas(dxfpath,FinalRatio)
 
 
 
 
 
 
 
 
419
  # SimilarAreaDictionary= pd.DataFrame(columns=['Area', 'Total Area', 'Perimeter', 'Total Perimeter', 'Occurences', 'Color'])
420
  SimilarAreaDictionary= pd.DataFrame(columns=['Guess','Color','Occurences','Area','Total Area','Perimeter','Total Perimeter','Length','Total Length','Texts','Comments'])
 
 
 
 
421
 
422
- colorRanges2=generate_color_array(300)
423
- colorRanges = [[255, 0, 0], [0, 0, 255], [0, 255, 255], [0, 64, 0], [255, 204, 0], [255, 128, 64], [255, 0, 128], [255, 128, 192], [128, 128, 255], [128, 64, 0],[0, 255, 0],[0, 200, 0],[255, 128, 255], [128, 0, 255], [0, 128, 192], [128, 0, 128],[128, 0, 0], [0, 128, 255], [149, 1, 70], [255, 182, 128], [222, 48, 71], [240, 0, 112], [255, 0, 255], [192, 46, 65], [0, 0, 128],[0, 128, 64],[255, 255, 0], [128, 0, 80], [255, 255, 128], [90, 255, 140],[255, 200, 20],[91, 16, 51], [90, 105, 138], [114, 10, 138], [36, 82, 78], [225, 105, 190], [108, 150, 170], [11, 35, 75], [42, 176, 170], [255, 176, 170], [209, 151, 15],[81, 27, 85], [226, 106, 122], [67, 119, 149], [159, 179, 140], [159, 179, 30],[255, 85, 198], [255, 27, 85], [188, 158, 8],[140, 188, 120], [59, 61, 52], [65, 81, 21], [212, 255, 174], [15, 164, 90],[41, 217, 245], [213, 23, 182], [11, 85, 169], [78, 153, 239], [0, 66, 141],[64, 98, 232], [140, 112, 255], [57, 33, 154], [194, 117, 252], [116, 92, 135], [74, 43, 98], [188, 13, 123], [129, 58, 91], [255, 128, 100], [171, 122, 145], [255, 98, 98], [222, 48, 77]]
424
- colorUsed=[]
425
  TotalArea=0
426
  TotalPerimeter=0
427
- for i in range(len(hatched_areas)):
428
- area = hatched_areas[i][1] # area
429
- perimeter = hatched_areas[i][2] # perimeter
430
- if(i < len(colorRanges)):
431
- color = colorRanges[i]
432
- colorUsed.append(color)
433
- else:
434
- color = colorRanges2[i]
435
- colorUsed.append(color)
436
  TotalArea = area
437
  TotalPerimeter = perimeter
438
- tol=2
439
  condition1 = (SimilarAreaDictionary['Area'] >= area - tol) & (SimilarAreaDictionary['Area'] <= area +tol)
440
  condition2 = (SimilarAreaDictionary['Perimeter'] >= perimeter -tol) & (SimilarAreaDictionary['Perimeter'] <= perimeter +tol)
441
  combined_condition = condition1 & condition2
@@ -448,22 +1124,143 @@ def Create_DF(dxfpath,datadoc):
448
  else:
449
  TotalArea=area
450
  TotalPerimeter=perimeter
451
- new_data = {'Area': area, 'Total Area': TotalArea ,'Perimeter': perimeter, 'Total Perimeter': TotalPerimeter, 'Occurences': 1, 'Color':color,'Comments':''} #add color here and read color to insert in
452
  SimilarAreaDictionary = pd.concat([SimilarAreaDictionary, pd.DataFrame([new_data])], ignore_index=True)
453
 
454
  # print(SimilarAreaDictionary)
455
  return SimilarAreaDictionary
456
  """### Draw on Image and PDF"""
457
 
458
- def mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio,pdfpath,pdfname):
459
- FinalRatio= RetriveRatio(datadoc,dxfpath)
460
- hatched_areas = get_hatched_areas(dxfpath,FinalRatio)
461
- img=pdftoimg(datadoc)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  flipped_horizontal=flip(img)
463
  allcnts = []
464
  imgg = flipped_horizontal
465
  # imgtransparent1=imgg.copy()
466
- doc = fitz.open('pdf',datadoc)
 
 
 
467
  page2 = doc[0]
468
  rotationOld=page2.rotation
469
  derotationMatrix=page2.derotation_matrix
@@ -480,17 +1277,30 @@ def mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio,pdfpath,pdfname):
480
  ratio = pix.width/ img.shape[1]
481
  rotationangle = 270
482
 
 
 
483
  allshapes=[]
484
  # Iterate through each polygon in metric units
485
  NewColors = []
486
- SimilarAreaDictionary=Create_DF(dxfpath,datadoc)
 
 
 
487
  i=0
 
 
488
 
489
 
490
  for polygon in hatched_areas:
491
  cntPoints = []
492
  cntPoints1 = []
493
- shapee = []
 
 
 
 
 
 
494
  # Convert each vertex from metric to pixel coordinates
495
  for vertex in polygon[0]:
496
  x = (vertex[0]) *dxfratio
@@ -501,56 +1311,196 @@ def mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio,pdfpath,pdfname):
501
  cntPoints.append([int(x), int(y)])
502
  cntPoints1.append([x, y])
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  for poi in np.array(cntPoints1):
505
- x1, y1 = poi
506
- p1 = fitz.Point(x1,y1)
507
- # p1 = fitz.Point(x1,y1)
508
- p1=p1*derotationMatrix
509
- shapee.append([p1[0],p1[1]])
510
-
511
- shapee=np.flip(shapee,1)
512
- shapee=rotate_polygon(shapee,rotationangle,rotationOld,width,height)
513
- tol=2
 
 
 
 
514
  condition1 = (SimilarAreaDictionary['Area'] >= polygon[1] - tol) & (SimilarAreaDictionary['Area'] <= polygon[1] +tol)
515
  condition2 = (SimilarAreaDictionary['Perimeter'] >= polygon[2] -tol) & (SimilarAreaDictionary['Perimeter'] <= polygon[2] +tol)
516
  combined_condition = condition1 & condition2
517
 
518
  if any(combined_condition):
519
-
520
  index = np.where(combined_condition)[0][0]
521
  # print(SimilarAreaDictionary.at[index, 'Color'])
522
  NewColors=SimilarAreaDictionary.at[index, 'Color']
523
  else:
 
524
  NewColors=SimilarAreaDictionary.at[i, 'Color']
525
-
526
- # cv2.drawContours(imgg, [np.array(cntPoints)], -1, (NewColors), thickness=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  cv2.drawContours(imgg, [np.array(cntPoints)], -1, ([NewColors[2],NewColors[1],NewColors[0]]), thickness=-1)
528
- annot11 = page2.add_polygon_annot( points=shapee) # 'Polygon'
 
529
  annot11.set_border(width=0.2)
530
  annot11.set_colors(stroke=(int(NewColors[0])/255,int(NewColors[1])/255,int(NewColors[2])/255), fill= (int(NewColors[0])/255,int(NewColors[1])/255,int(NewColors[2])/255) )
531
- annot11.set_info(content='Area='+str(polygon[1])+' m^2',subject='ADR Team')
532
- annot11.set_opacity(0.9)
533
  # annot.set_line_ends(fitz.PDF_ANNOT_LE_DIAMOND, fitz.PDF_ANNOT_LE_CIRCLE)
534
  annot11.update()
535
 
536
 
537
 
538
- annot12 = page2.add_polygon_annot( points=shapee) # 'Polygon'
539
- annot12.set_border(width=0.2)
540
  annot12.set_colors(stroke=(int(NewColors[0])/255,int(NewColors[1])/255,int(NewColors[2])/255))
541
- annot12.set_info(content='Perimeter='+str(polygon[2])+' m',subject='ADR Team')
542
  annot12.set_opacity(0.8)
543
  # annot.set_line_ends(fitz.PDF_ANNOT_LE_DIAMOND, fitz.PDF_ANNOT_LE_CIRCLE)
544
  annot12.update()
545
  i += 1
546
  alpha = 0.8 # Transparency factor.
547
-
548
  page2.set_rotation(rotationOld)
549
  Correct_img=flip(imgg)
550
 
551
  image_new1 = cv2.addWeighted(Correct_img, alpha, img, 1 - alpha, 0)
552
  SimilarAreaDictionary = SimilarAreaDictionary.fillna(' ')
553
- gc,spreadsheet_service,spreadsheetId, spreadsheet_url , namepathArr=google_sheet_Legend.legendGoogleSheets(SimilarAreaDictionary , pdfname,pdfpath)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
554
  # dbxTeam=tsadropboxretrieval.ADR_Access_DropboxTeam('user')
555
  # md, res =dbxTeam.files_download(path= pdfpath+pdfname)
556
  # data = res.content
@@ -558,7 +1508,8 @@ def mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio,pdfpath,pdfname):
558
  # list1=pd.DataFrame(columns=['content', 'creationDate', 'id', 'modDate', 'name', 'subject', 'title'])
559
  list1=pd.DataFrame(columns=['content', 'id', 'subject','color'])
560
 
561
- for page in doc:
 
562
  # Iterate through annotations on the page
563
  for annot in page.annots():
564
  # Get the color of the annotation
@@ -569,63 +1520,21 @@ def mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio,pdfpath,pdfname):
569
  fill_color = annot_color.get('fill') # Fill color
570
  if fill_color:
571
  v='fill'
572
- print('fill')
573
  if stroke_color:
574
  v='stroke'
575
  x,y,z=int(annot_color.get(v)[0]*255),int(annot_color.get(v)[1]*255),int(annot_color.get(v)[2]*255)
576
  list1.loc[len(list1)] =[annot.info['content'],annot.info['id'],annot.info['subject'],[x,y,z]]
577
- return doc,image_new1, SimilarAreaDictionary ,spreadsheetId, spreadsheet_url , namepathArr , list1,hatched_areas
578
-
579
 
580
- def deletemarkupsDXF(list1, dbPath, path):
581
- '''list1 : original markup pdf
582
- list2 : deleted markup pdf
583
- deletedrows : deleted markups - difference between both dfs
584
- '''
585
 
586
- myDict1 = eval(list1)
587
- list1 = pd.DataFrame(myDict1)
 
 
 
588
 
589
- dbxTeam = tsadropboxretrieval.ADR_Access_DropboxTeam('user')
590
- md, res = dbxTeam.files_download(path=dbPath + path)
591
- data = res.content
592
- doc = fitz.open("pdf", data)
593
-
594
- # Prepare a DataFrame for the annotations in the new PDF
595
- list2 = pd.DataFrame(columns=['content', 'id', 'subject', 'color'])
596
-
597
- for page in doc:
598
- # Iterate through annotations on the page
599
- for annot in page.annots():
600
- # Get the color of the annotation
601
- annot_color = annot.colors
602
- if annot_color is not None:
603
- # Check for fill or stroke color
604
- stroke_color = annot_color.get('stroke')
605
- fill_color = annot_color.get('fill')
606
-
607
- v = 'stroke' if stroke_color else 'fill'
608
- color = annot_color.get(v)
609
- if color:
610
- # Convert color to tuple and multiply by 255 to get RGB values
611
- color_tuple = (int(color[0] * 255), int(color[1] * 255), int(color[2] * 255))
612
- # Append annotation data to list2
613
- list2.loc[len(list2)] = [annot.info['content'], annot.info['id'], annot.info['subject'], color_tuple]
614
-
615
- # Ensure that colors are stored as tuples (which are hashable)
616
- list1['color'] = list1['color'].apply(lambda x: tuple(x) if isinstance(x, list) else x)
617
-
618
- # Find the deleted rows by checking the difference between original and current annotations
619
- deletedrows = pd.concat([list1, list2]).drop_duplicates(keep=False)
620
-
621
- print(deletedrows, len(deletedrows))
622
- flag = 0
623
- if len(deletedrows) != 0:
624
- flag = 1
625
- deletedrows = deletedrows[['content', 'id', 'subject', 'color']]
626
- # Drop rows where 'content' starts with 'Scale'
627
- deletedrows = deletedrows.drop(deletedrows.index[deletedrows['content'].str.startswith('Scale')])
628
- else:
629
- flag = 0
630
-
631
- return deletedrows
 
1
+ # -*- coding: utf-8 -*-
2
+ """Deploying 3.2
3
+
4
+ Automatically generated by Colab.
5
+
6
+ Original file is located at
7
+ https://colab.research.google.com/drive/1HEw0DdXhDcxtJN1pjs7bCnlhr-wXX3-m
8
+ """
9
+
10
+ # pip install pymupdf
11
+
12
+ # pip install ezdxf
13
+
14
+ def normalize_vertices(vertices):
15
+ """Sort vertices to ensure consistent order."""
16
+ return tuple(sorted(tuple(v) for v in vertices))
17
+
18
+ def areas_are_similar(area1, area2, tolerance=0.2):
19
+ """Check if two areas are within a given tolerance."""
20
+ return abs(area1 - area2) <= tolerance
21
+
22
+
23
+ from ctypes import sizeof
24
  # -*- coding: utf-8 -*-wj
25
  """Version to be deployed of 3.2 Calculating area/perimeter
26
 
 
41
  # pip install ezdxf scipy
42
 
43
  """## Imports"""
44
+ import xml.etree.ElementTree as ET
45
+ from PyPDF2 import PdfReader, PdfWriter
46
+ from PyPDF2.generic import TextStringObject, NameObject, ArrayObject, FloatObject
47
+ from PyPDF2.generic import NameObject, TextStringObject, DictionaryObject, FloatObject, ArrayObject
48
+
49
+ from typing import NewType
50
+ from ctypes import sizeof
51
 
52
  import numpy as np
53
  import cv2
 
58
  import ezdxf as ez
59
  import sys
60
  from ezdxf import units
61
+ # from google.colab.patches import cv2_imshow
62
  from ezdxf.math import OCS, Matrix44, Vec3
63
  import ezdxf
64
  import matplotlib.pyplot as plt
65
  from matplotlib.patches import Polygon
66
+ from shapely.geometry import Point, Polygon as ShapelyPolygon
67
  from ezdxf.math import Vec2
68
  import random
69
  import pandas as pd
70
+ # import google_sheet_Legend
71
  import tsadropboxretrieval
72
  from ezdxf import bbox
73
+ from math import sin, cos, radians
74
+ import google_sheet_Legend
75
+ from PyPDF2 import PdfReader
76
+ from io import BytesIO
77
 
78
  """## Notes"""
79
 
 
93
 
94
  """PDF to image"""
95
 
96
+ def pdftoimg(datadoc,pdf_content=0):
97
+ if pdf_content:
98
+ doc = fitz.open(stream=pdf_content, filetype="pdf")
99
+ else:
100
+ doc = fitz.open('pdf',datadoc)
101
  page=doc[0]
102
  pix = page.get_pixmap() # render page to an image
103
  pl=Image.frombytes('RGB', [pix.width,pix.height],pix.samples)
 
128
  return size
129
  return "Unknown Size"
130
 
131
+ def analyze_pdf(datadoc,pdf_content=0):
132
  # Open the PDF file
133
+ if pdf_content:
134
+ pdf_document = fitz.open(stream=pdf_content, filetype="pdf")
135
+ else:
136
+ pdf_document = fitz.open('pdf',datadoc)
137
 
138
  # Iterate through pages and print their sizes
139
  for page_number in range(len(pdf_document)):
 
188
 
189
 
190
 
191
+ def RetriveRatio(datadoc,dxfpath,pdf_content=0):
192
+ if pdf_content:
193
+ width,height,paper_size = analyze_pdf (datadoc,pdf_content)
194
+ else:
195
+ width,height,paper_size = analyze_pdf (datadoc)
196
+
197
 
198
  if(width > height ):
199
  bigger=width
 
234
  flipped_horizontal = cv2.flip(rotated_image, 1)
235
  return flipped_horizontal
236
 
237
+
238
+
239
+ def aci_to_rgb(aci):
240
+ aci_rgb_map = {
241
+ 0: (0, 0, 0),
242
+ 1: (255, 0, 0),
243
+ 2: (255, 255, 0),
244
+ 3: (0, 255, 0),
245
+ 4: (0, 255, 255),
246
+ 5: (0, 0, 255),
247
+ 6: (255, 0, 255),
248
+ 7: (255, 255, 255),
249
+ 8: (65, 65, 65),
250
+ 9: (128, 128, 128),
251
+ 10: (255, 0, 0),
252
+ 11: (255, 170, 170),
253
+ 12: (189, 0, 0),
254
+ 13: (189, 126, 126),
255
+ 14: (129, 0, 0),
256
+ 15: (129, 86, 86),
257
+ 16: (104, 0, 0),
258
+ 17: (104, 69, 69),
259
+ 18: (79, 0, 0),
260
+ 19: (79, 53, 53),
261
+ 20: (255, 63, 0),
262
+ 21: (255, 191, 170),
263
+ 22: (189, 46, 0),
264
+ 23: (189, 141, 126),
265
+ 24: (129, 31, 0),
266
+ 25: (129, 96, 86),
267
+ 26: (104, 25, 0),
268
+ 27: (104, 78, 69),
269
+ 28: (79, 19, 0),
270
+ 29: (79, 59, 53),
271
+ 30: (255, 127, 0),
272
+ 31: (255, 212, 170),
273
+ 32: (189, 94, 0),
274
+ 33: (189, 157, 126),
275
+ 34: (129, 64, 0),
276
+ 35: (129, 107, 86),
277
+ 36: (104, 52, 0),
278
+ 37: (104, 86, 69),
279
+ 38: (79, 39, 0),
280
+ 39: (79, 66, 53),
281
+ 40: (255, 191, 0),
282
+ 41: (255, 234, 170),
283
+ 42: (189, 141, 0),
284
+ 43: (189, 173, 126),
285
+ 44: (129, 96, 0),
286
+ 45: (129, 118, 86),
287
+ 46: (104, 78, 0),
288
+ 47: (104, 95, 69),
289
+ 48: (79, 59, 0),
290
+ 49: (79, 73, 53),
291
+ 50: (255, 255, 0),
292
+ 51: (255, 255, 170),
293
+ 52: (189, 189, 0),
294
+ 53: (189, 189, 126),
295
+ 54: (129, 129, 0),
296
+ 55: (129, 129, 86),
297
+ 56: (104, 104, 0),
298
+ 57: (104, 104, 69),
299
+ 58: (79, 79, 0),
300
+ 59: (79, 79, 53),
301
+ 60: (191, 255, 0),
302
+ 61: (234, 255, 170),
303
+ 62: (141, 189, 0),
304
+ 63: (173, 189, 126),
305
+ 64: (96, 129, 0),
306
+ 65: (118, 129, 86),
307
+ 66: (78, 104, 0),
308
+ 67: (95, 104, 69),
309
+ 68: (59, 79, 0),
310
+ 69: (73, 79, 53),
311
+ 70: (127, 255, 0),
312
+ 71: (212, 255, 170),
313
+ 72: (94, 189, 0),
314
+ 73: (157, 189, 126),
315
+ 74: (64, 129, 0),
316
+ 75: (107, 129, 86),
317
+ 76: (52, 104, 0),
318
+ 77: (86, 104, 69),
319
+ 78: (39, 79, 0),
320
+ 79: (66, 79, 53),
321
+ 80: (63, 255, 0),
322
+ 81: (191, 255, 170),
323
+ 82: (46, 189, 0),
324
+ 83: (141, 189, 126),
325
+ 84: (31, 129, 0),
326
+ 85: (96, 129, 86),
327
+ 86: (25, 104, 0),
328
+ 87: (78, 104, 69),
329
+ 88: (19, 79, 0),
330
+ 89: (59, 79, 53),
331
+ 90: (0, 255, 0),
332
+ 91: (170, 255, 170),
333
+ 92: (0, 189, 0),
334
+ 93: (126, 189, 126),
335
+ 94: (0, 129, 0),
336
+ 95: (86, 129, 86),
337
+ 96: (0, 104, 0),
338
+ 97: (69, 104, 69),
339
+ 98: (0, 79, 0),
340
+ 99: (53, 79, 53),
341
+ 100: (0, 255, 63),
342
+ 101: (170, 255, 191),
343
+ 102: (0, 189, 46),
344
+ 103: (126, 189, 141),
345
+ 104: (0, 129, 31),
346
+ 105: (86, 129, 96),
347
+ 106: (0, 104, 25),
348
+ 107: (69, 104, 78),
349
+ 108: (0, 79, 19),
350
+ 109: (53, 79, 59),
351
+ 110: (0, 255, 127),
352
+ 111: (170, 255, 212),
353
+ 112: (0, 189, 94),
354
+ 113: (126, 189, 157),
355
+ 114: (0, 129, 64),
356
+ 115: (86, 129, 107),
357
+ 116: (0, 104, 52),
358
+ 117: (69, 104, 86),
359
+ 118: (0, 79, 39),
360
+ 119: (53, 79, 66),
361
+ 120: (0, 255, 191),
362
+ 121: (170, 255, 234),
363
+ 122: (0, 189, 141),
364
+ 123: (126, 189, 173),
365
+ 124: (0, 129, 96),
366
+ 125: (86, 129, 118),
367
+ 126: (0, 104, 78),
368
+ 127: (69, 104, 95),
369
+ 128: (0, 79, 59),
370
+ 129: (53, 79, 73),
371
+ 130: (0, 255, 255),
372
+ 131: (170, 255, 255),
373
+ 132: (0, 189, 189),
374
+ 133: (126, 189, 189),
375
+ 134: (0, 129, 129),
376
+ 135: (86, 129, 129),
377
+ 136: (0, 104, 104),
378
+ 137: (69, 104, 104),
379
+ 138: (0, 79, 79),
380
+ 139: (53, 79, 79),
381
+ 140: (0, 191, 255),
382
+ 141: (170, 234, 255),
383
+ 142: (0, 141, 189),
384
+ 143: (126, 173, 189),
385
+ 144: (0, 96, 129),
386
+ 145: (86, 118, 129),
387
+ 146: (0, 78, 104),
388
+ 147: (69, 95, 104),
389
+ 148: (0, 59, 79),
390
+ 149: (53, 73, 79),
391
+ 150: (0, 127, 255),
392
+ 151: (170, 212, 255),
393
+ 152: (0, 94, 189),
394
+ 153: (126, 157, 189),
395
+ 154: (0, 64, 129),
396
+ 155: (86, 107, 129),
397
+ 156: (0, 52, 104),
398
+ 157: (69, 86, 104),
399
+ 158: (0, 39, 79),
400
+ 159: (53, 66, 79),
401
+ 160: (0, 63, 255),
402
+ 161: (170, 191, 255),
403
+ 162: (0, 46, 189),
404
+ 163: (126, 141, 189),
405
+ 164: (0, 31, 129),
406
+ 165: (86, 96, 129),
407
+ 166: (0, 25, 104),
408
+ 167: (69, 78, 104),
409
+ 168: (0, 19, 79),
410
+ 169: (53, 59, 79),
411
+ 170: (0, 0, 255),
412
+ 171: (170, 170, 255),
413
+ 172: (0, 0, 189),
414
+ 173: (126, 126, 189),
415
+ 174: (0, 0, 129),
416
+ 175: (86, 86, 129),
417
+ 176: (0, 0, 104),
418
+ 177: (69, 69, 104),
419
+ 178: (0, 0, 79),
420
+ 179: (53, 53, 79),
421
+ 180: (63, 0, 255),
422
+ 181: (191, 170, 255),
423
+ 182: (46, 0, 189),
424
+ 183: (141, 126, 189),
425
+ 184: (31, 0, 129),
426
+ 185: (96, 86, 129),
427
+ 186: (25, 0, 104),
428
+ 187: (78, 69, 104),
429
+ 188: (19, 0, 79),
430
+ 189: (59, 53, 79),
431
+ 190: (127, 0, 255),
432
+ 191: (212, 170, 255),
433
+ 192: (94, 0, 189),
434
+ 193: (157, 126, 189),
435
+ 194: (64, 0, 129),
436
+ 195: (107, 86, 129),
437
+ 196: (52, 0, 104),
438
+ 197: (86, 69, 104),
439
+ 198: (39, 0, 79),
440
+ 199: (66, 53, 79),
441
+ 200: (191, 0, 255),
442
+ 201: (234, 170, 255),
443
+ 202: (141, 0, 189),
444
+ 203: (173, 126, 189),
445
+ 204: (96, 0, 129),
446
+ 205: (118, 86, 129),
447
+ 206: (78, 0, 104),
448
+ 207: (95, 69, 104),
449
+ 208: (59, 0, 79),
450
+ 209: (73, 53, 79),
451
+ 210: (255, 0, 255),
452
+ 211: (255, 170, 255),
453
+ 212: (189, 0, 189),
454
+ 213: (189, 126, 189),
455
+ 214: (129, 0, 129),
456
+ 215: (129, 86, 129),
457
+ 216: (104, 0, 104),
458
+ 217: (104, 69, 104),
459
+ 218: (79, 0, 79),
460
+ 219: (79, 53, 79),
461
+ 220: (255, 0, 191),
462
+ 221: (255, 170, 234),
463
+ 222: (189, 0, 141),
464
+ 223: (189, 126, 173),
465
+ 224: (129, 0, 96),
466
+ 225: (129, 86, 118),
467
+ 226: (104, 0, 78),
468
+ 227: (104, 69, 95),
469
+ 228: (79, 0, 59),
470
+ 229: (79, 53, 73),
471
+ 230: (255, 0, 127),
472
+ 231: (255, 170, 212),
473
+ 232: (189, 0, 94),
474
+ 233: (189, 126, 157),
475
+ 234: (129, 0, 64),
476
+ 235: (129, 86, 107),
477
+ 236: (104, 0, 52),
478
+ 237: (104, 69, 86),
479
+ 238: (79, 0, 39),
480
+ 239: (79, 53, 66),
481
+ 240: (255, 0, 63),
482
+ 241: (255, 170, 191),
483
+ 242: (189, 0, 46),
484
+ 243: (189, 126, 141),
485
+ 244: (129, 0, 31),
486
+ 245: (129, 86, 96),
487
+ 246: (104, 0, 25),
488
+ 247: (104, 69, 78),
489
+ 248: (79, 0, 19),
490
+ 249: (79, 53, 59),
491
+ 250: (51, 51, 51),
492
+ 251: (80, 80, 80),
493
+ 252: (105, 105, 105),
494
+ 253: (130, 130, 130),
495
+ 254: (190, 190, 190),
496
+ 255: (255, 255, 255)
497
+ }
498
+
499
+ # Default to white if index is invalid or not found
500
+ return aci_rgb_map.get(aci, (255, 255, 255))
501
+
502
+
503
+
504
+ def int_to_rgb(color_int):
505
+ """Convert an integer to an (R, G, B) tuple."""
506
+ r = (color_int >> 16) & 255
507
+ g = (color_int >> 8) & 255
508
+ b = color_int & 255
509
+ return (r, g, b)
510
+
511
+
512
+
513
+ def get_hatch_color(entity):
514
+ # Check if the entity has a "true color" set
515
+ if entity.dxf.hasattr('true_color'):
516
+ true_color = entity.dxf.true_color
517
+ rgb_color = int_to_rgb(true_color) # Convert integer to (R, G, B)
518
+ print(f"True color detected (RGB): {rgb_color}")
519
+ return rgb_color
520
+
521
+ color_index = entity.dxf.color
522
+ print("color_index = ", color_index)
523
+
524
+ # Check if the color is set to ByLayer or ByBlock
525
+ if color_index == 0: # ByLayer color
526
+ print("Color is ByLayer, checking layer color...")
527
+ layer_name = entity.dxf.layer
528
+ layer = entity.doc.layers.get(layer_name)
529
+
530
+ if layer: # Ensure layer exists
531
+ layer_color_index = layer.dxf.color
532
+ print(f"Layer '{layer_name}' Color Index = {layer_color_index}")
533
+ return aci_to_rgb(layer_color_index) # Use custom aci_to_rgb function
534
+ else:
535
+ print(f"Layer '{layer_name}' not found, defaulting to white.")
536
+ return (255, 255, 255) # Default to white if layer not found
537
+
538
+ elif color_index == 256: # ByBlock color
539
+ print("Color is ByBlock, checking block color or defaulting to white.")
540
+ block_color = (255, 255, 255) # White as default
541
+
542
+ # Check if the entity is inside a block reference and inherit its color
543
+ if hasattr(entity, 'block'): # Check if the entity belongs to a block
544
+ block_ref = entity.block
545
+ if block_ref.dxf.hasattr('color'):
546
+ block_color = aci_to_rgb(block_ref.dxf.color)
547
+ print(f"Block reference color found: {block_color}")
548
+ else:
549
+ print("Block has no color attribute, using default (white).")
550
+ return block_color
551
+
552
+ # Otherwise, convert the ACI color to RGB
553
+ print(f"Entity Color Index = {color_index}")
554
+ if 1 <= color_index <= 255:
555
+ rgb_color = aci_to_rgb(color_index) # Use custom aci_to_rgb function
556
+ print(f"Converted RGB = {rgb_color}")
557
+ return rgb_color
558
+
559
+ # Default to white if color index is out of bounds or invalid
560
+ print("Invalid or unhandled color index, defaulting to white.")
561
+ return (255, 255, 255)
562
+
563
+ def calculate_distance(p1, p2):
564
+ return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
565
+
566
+ def normalize_color(color):
567
+ """Convert PDF color (range 0-1) to RGB (range 0-255)."""
568
+ return tuple(min(max(round(c * 255), 0), 255) for c in color)
569
+
570
+ def color_close_enough(c1, c2, threshold=10):
571
+ return all(abs(a - b) <= threshold for a, b in zip(c1, c2))
572
+
573
+
574
  """### Hatched areas"""
575
+ def get_hatched_areas(datadoc,filename,FinalRatio,rotationangle,SearchArray):
576
 
 
577
  doc = ezdxf.readfile(filename)
578
  doc.header['$MEASUREMENT'] = 1
579
  msp = doc.modelspace()
580
  trial=0
581
  hatched_areas = []
582
+ threshold=0.001
583
+ TextFound = 0
584
+ j=0
585
+ unique_shapes = []
586
+
587
+ text_with_positions = []
588
+ text_color_mapping = {}
589
+ color_palette = [
590
+ (255, 0, 0), (0, 0, 255), (0, 255, 255), (0, 64, 0), (255, 204, 0),
591
+ (255, 128, 64), (255, 0, 128), (255, 128, 192), (128, 128, 255),
592
+ (128, 64, 0), (0, 255, 0), (0, 200, 0), (255, 128, 255), (128, 0, 255),
593
+ (0, 128, 192), (128, 0, 128), (128, 0, 0), (0, 128, 255), (149, 1, 70),
594
+ (255, 182, 128), (222, 48, 71), (240, 0, 112), (255, 0, 255),
595
+ (192, 46, 65), (0, 0, 128), (0, 128, 64), (255, 255, 0), (128, 0, 80),
596
+ (255, 255, 128), (90, 255, 140), (255, 200, 20), (91, 16, 51),
597
+ (90, 105, 138), (114, 10, 138), (36, 82, 78), (225, 105, 190),
598
+ (108, 150, 170), (11, 35, 75), (42, 176, 170), (255, 176, 170),
599
+ (209, 151, 15), (81, 27, 85), (226, 106, 122), (67, 119, 149),
600
+ (159, 179, 140), (159, 179, 30), (255, 85, 198), (255, 27, 85),
601
+ (188, 158, 8), (140, 188, 120), (59, 61, 52), (65, 81, 21),
602
+ (212, 255, 174), (15, 164, 90), (41, 217, 245), (213, 23, 182),
603
+ (11, 85, 169), (78, 153, 239), (0, 66, 141), (64, 98, 232),
604
+ (140, 112, 255), (57, 33, 154), (194, 117, 252), (116, 92, 135),
605
+ (74, 43, 98), (188, 13, 123), (129, 58, 91), (255, 128, 100),
606
+ (171, 122, 145), (255, 98, 98), (222, 48, 77)
607
+ ]
608
+
609
+ import re
610
+
611
+ Legendarray = []
612
+
613
+ if(SearchArray):
614
+ for i in range(len(SearchArray)):
615
+
616
+ if (SearchArray[i][0] and SearchArray[i][1] and SearchArray[i][2]):
617
+ for text_entity in doc.modelspace().query('TEXT MTEXT'):
618
+ text = text_entity.text.strip() if hasattr(text_entity, 'text') else ""
619
+ # if (text.startswith("P") and len(text) == 3) or (text.startswith("I") and len(text) == 3): # Filter for "Wall"
620
+ if(text.startswith(SearchArray[i][0]) and len(text)==int(SearchArray[i][2])):
621
+ position = text_entity.dxf.insert # Extract text position
622
+ x, y = position.x, position.y
623
+
624
+ for text_entity in doc.modelspace().query('TEXT MTEXT'):
625
+ NBS = text_entity.text.strip() if hasattr(text_entity, 'text') else ""
626
+ if (NBS.startswith(SearchArray[i][1])):
627
+ positionNBS = text_entity.dxf.insert # Extract text position
628
+ xNBS, yNBS = positionNBS.x, positionNBS.y
629
+
630
+ if(x == xNBS or y == yNBS):
631
+ textNBS=NBS
632
+ break
633
+
634
+ else:
635
+ textNBS = None
636
+
637
+
638
+
639
+ nearest_hatch = None
640
+ min_distance = float('inf') # Initialize with a very large value
641
+ detected_color = (255, 255, 255) # Default to white
642
+
643
+ # Search for the nearest hatch
644
+ for hatch in doc.modelspace().query('HATCH'): # Query only hatches
645
+ if hatch.paths:
646
+ for path in hatch.paths:
647
+ if path.type == 1: # PolylinePath
648
+ vertices = [v[:2] for v in path.vertices]
649
+ # Calculate the centroid of the hatch
650
+ centroid_x = sum(v[0] for v in vertices) / len(vertices)
651
+ centroid_y = sum(v[1] for v in vertices) / len(vertices)
652
+ centroid = (centroid_x, centroid_y)
653
+
654
+ # Calculate the distance between the text and the hatch centroid
655
+ distance = calculate_distance((x, y), centroid)
656
+
657
+ # Update the nearest hatch if a closer one is found
658
+ if distance < min_distance:
659
+ min_distance = distance
660
+ nearest_hatch = hatch
661
+
662
+ # Get the color of this hatch
663
+ current_color = get_hatch_color(hatch)
664
+ if current_color != (255, 255, 255): # Valid color found
665
+ detected_color = current_color
666
+ break # Stop checking further paths for this hatch
667
+
668
+
669
+ # Append the detected result only once
670
+ Legendarray.append([text, textNBS, (x, y), detected_color])
671
+ print("text_with_positions=",text_with_positions)
672
+
673
+ elif (SearchArray[i][0] and SearchArray[i][2]):
674
+ for text_entity in doc.modelspace().query('TEXT MTEXT'):
675
+ text = text_entity.text.strip() if hasattr(text_entity, 'text') else ""
676
+ # if (text.startswith("P") and len(text) == 3) or (text.startswith("I") and len(text) == 3): # Filter for "Wall"
677
+ if(text.startswith(SearchArray[i][0]) and len(text)==int(SearchArray[i][2])):
678
+ position = text_entity.dxf.insert # Extract text position
679
+ x, y = position.x, position.y
680
+ textNBS = None
681
+ nearest_hatch = None
682
+ min_distance = float('inf') # Initialize with a very large value
683
+ detected_color = (255, 255, 255) # Default to white
684
+
685
+ # Search for the nearest hatch
686
+ for hatch in doc.modelspace().query('HATCH'): # Query only hatches
687
+ if hatch.paths:
688
+ for path in hatch.paths:
689
+ if path.type == 1: # PolylinePath
690
+ vertices = [v[:2] for v in path.vertices]
691
+ # Calculate the centroid of the hatch
692
+ centroid_x = sum(v[0] for v in vertices) / len(vertices)
693
+ centroid_y = sum(v[1] for v in vertices) / len(vertices)
694
+ centroid = (centroid_x, centroid_y)
695
+
696
+ # Calculate the distance between the text and the hatch centroid
697
+ distance = calculate_distance((x, y), centroid)
698
+
699
+ # Update the nearest hatch if a closer one is found
700
+ if distance < min_distance:
701
+ min_distance = distance
702
+ nearest_hatch = hatch
703
+
704
+ # Get the color of this hatch
705
+ current_color = get_hatch_color(hatch)
706
+ if current_color != (255, 255, 255): # Valid color found
707
+ detected_color = current_color
708
+ break # Stop checking further paths for this hatch
709
+
710
+
711
+ # Append the detected result only once
712
+ Legendarray.append([text, textNBS, (x, y), detected_color])
713
+ print("text_with_positions=",text_with_positions)
714
+
715
+ elif(SearchArray[i][0]):
716
+ for text_entity in doc.modelspace().query('TEXT MTEXT'):
717
+ text = text_entity.text.strip() if hasattr(text_entity, 'text') else ""
718
+ # if (text.startswith("P") and len(text) == 3) or (text.startswith("I") and len(text) == 3): # Filter for "Wall"
719
+ if(text.startswith(SearchArray[i][0])):
720
+ position = text_entity.dxf.insert # Extract text position
721
+ x, y = position.x, position.y
722
+ textNBS = None
723
+ nearest_hatch = None
724
+ min_distance = float('inf') # Initialize with a very large value
725
+ detected_color = (255, 255, 255) # Default to white
726
+
727
+ # Search for the nearest hatch
728
+ for hatch in doc.modelspace().query('HATCH'): # Query only hatches
729
+ if hatch.paths:
730
+ for path in hatch.paths:
731
+ if path.type == 1: # PolylinePath
732
+ vertices = [v[:2] for v in path.vertices]
733
+ # Calculate the centroid of the hatch
734
+ centroid_x = sum(v[0] for v in vertices) / len(vertices)
735
+ centroid_y = sum(v[1] for v in vertices) / len(vertices)
736
+ centroid = (centroid_x, centroid_y)
737
+
738
+ # Calculate the distance between the text and the hatch centroid
739
+ distance = calculate_distance((x, y), centroid)
740
+
741
+ # Update the nearest hatch if a closer one is found
742
+ if distance < min_distance:
743
+ min_distance = distance
744
+ nearest_hatch = hatch
745
+
746
+ # Get the color of this hatch
747
+ current_color = get_hatch_color(hatch)
748
+ if current_color != (255, 255, 255): # Valid color found
749
+ detected_color = current_color
750
+ break # Stop checking further paths for this hatch
751
+
752
+
753
+ # Append the detected result only once
754
+ Legendarray.append([text, textNBS, (x, y), detected_color])
755
+ print("text_with_positions=",Legendarray)
756
+
757
+
758
+
759
+
760
+
761
+
762
+
763
+
764
+ grouped = {}
765
+ for entry in Legendarray:
766
+ key = entry[0]
767
+ grouped.setdefault(key, []).append(entry)
768
+
769
+ # Filter the groups: if any entry in a group has a non-None Text Nbs, keep only one of those
770
+ filtered_results = []
771
+ for key, entries in grouped.items():
772
+ # Find the first entry with a valid textNBS (non-None)
773
+ complete = next((entry for entry in entries if entry[1] is not None), None)
774
+ if complete:
775
+ filtered_results.append(complete)
776
+ else:
777
+ # If none are complete, you can choose to keep just one entry
778
+ filtered_results.append(entries[0])
779
+
780
+ Legendarray=filtered_results
781
+
782
 
 
783
 
784
+ for entity in doc.modelspace().query('TEXT MTEXT'):
785
+ if hasattr(entity, 'text'): # Ensure the entity has text content
786
+ text = entity.text
787
+ if text.startswith('C') and (len(text) > 1 and (text[1].isdigit() or text[1].upper() == 'T' or text[1].upper() == 'L')):
788
+ parts = text.split(' ') # Split into two parts: before and after the first newline
789
+ # print("Parts = ",parts[0])
790
+ main_text = parts[0] # Text before the first newline
791
+
792
+ # Check if the main text starts with 'C' followed by a number or 'T'
793
+ # if pattern.match(main_text):
794
+ position = entity.dxf.insert
795
+
796
+
797
+ # Check if the text already has a color assigned
798
+ if main_text not in text_color_mapping:
799
+ # Assign a new color from the palette
800
+ color_index = len(text_color_mapping) % len(color_palette)
801
+ text_color_mapping[main_text] = color_palette[color_index]
802
 
803
+ # Get the assigned color
804
+ color = text_color_mapping[main_text]
805
 
806
+ # Set the entity's true color
807
+ # entity.dxf.true_color = rgb_to_true_color(color)
808
+
809
+ # Append text, position, and color to the array
810
+ text_with_positions.append([main_text, position, color])
811
+
812
+ for entity in msp:
813
+ if entity.dxftype() == 'HATCH':
814
+ # print(f"Processing HATCH entity: {entity}")
815
  for path in entity.paths:
816
+ vertices = [] # Reset vertices for each path
817
+
818
+ if str(path.type) == 'BoundaryPathType.POLYLINE':
819
+ # Handle POLYLINE type HATCH
820
+ vertices = [(vertex[0] * FinalRatio, vertex[1] * FinalRatio) for vertex in path.vertices]
821
+
822
+ if len(vertices) > 3:
823
+ poly = ShapelyPolygon(vertices)
824
+ minx, miny, maxx, maxy = poly.bounds
825
+ width = maxx - minx
826
+ height = maxy - miny
827
+
828
+ if (poly.area > 0.9 and (height > 0.7 and width > 0.7)):
829
+ area1 = round(poly.area, 3)
830
+ perimeter = round(poly.length, 3)
831
+ normalized_vertices = normalize_vertices(vertices)
832
+
833
+ rgb_color = get_hatch_color(entity)
834
+ if(rgb_color == (255, 255, 255)):
835
+ if(len(text_with_positions)>0):
836
+
837
+ for text, position, color in text_with_positions:
838
+ text_position = Point(position[0], position[1])
839
+
840
+ if poly.contains(text_position):
841
+ rgb_color = color
842
+ break
843
+
844
+ duplicate_found = False
845
+ for existing_vertices, existing_area in unique_shapes:
846
+ if normalized_vertices == existing_vertices and areas_are_similar(area1, existing_area):
847
+ duplicate_found = True
848
+ break
849
+
850
+ if not duplicate_found:
851
+ # rgb_color = get_hatch_color(entity) # Assuming this function exists
852
+ unique_shapes.append((normalized_vertices, area1))
853
+ hatched_areas.append([vertices, area1, perimeter, rgb_color])
854
+
855
+ elif str(path.type) == 'BoundaryPathType.EDGE':
856
+ # Handle EDGE type HATCH
857
+ vert = []
858
+ for edge in path.edges:
859
+ x, y = edge.start
860
+ x1, y1 = edge.end
861
+ vert.append((x * FinalRatio, y * FinalRatio))
862
+ vert.append((x1 * FinalRatio, y1 * FinalRatio))
863
+
864
+ poly = ShapelyPolygon(vert)
865
+ minx, miny, maxx, maxy = poly.bounds
866
+ width = maxx - minx
867
+ height = maxy - miny
868
+
869
+ if (poly.area > 0.9 and (height > 0.7 and width > 0.7)):
870
+ area1 = round(poly.area, 3)
871
+ perimeter = round(poly.length, 3)
872
+
873
+ normalized_vertices = normalize_vertices(vert)
874
+
875
+ rgb_color = get_hatch_color(entity)
876
+ if(rgb_color == (255, 255, 255)):
877
+ if(len(text_with_positions)>0):
878
+ for text, position, color in text_with_positions:
879
+ text_position = Point(position[0], position[1])
880
+
881
+ if poly.contains(text_position):
882
+ rgb_color = color
883
+ break
884
+
885
+ duplicate_found = False
886
+ for existing_vertices, existing_area in unique_shapes:
887
+ if normalized_vertices == existing_vertices and areas_are_similar(area1, existing_area):
888
+ duplicate_found = True
889
+ break
890
+
891
+ if not duplicate_found:
892
+ # rgb_color = get_hatch_color(entity) # Assuming this function exists
893
+ unique_shapes.append((normalized_vertices, area1))
894
+ hatched_areas.append([vert, area1, perimeter, rgb_color])
895
+
896
+ else:
897
+ print(f"Unhandled path type: {path.type}")
898
 
899
  elif entity.dxftype() == 'SOLID':
900
  vertices = [entity.dxf.vtx0 * (FinalRatio), entity.dxf.vtx1* (FinalRatio), entity.dxf.vtx2* (FinalRatio), entity.dxf.vtx3* (FinalRatio)]
 
905
  width = maxx - minx
906
  height = maxy - miny
907
 
908
+ if (poly.area > 0.9 and (height > 0.7 and width > 0.7)):
909
+ area1 = round(poly.area, 3)
910
+ perimeter = round(poly.length, 3)
911
+ normalized_vertices = normalize_vertices(vertices)
912
+
913
+ duplicate_found = False
914
+ for existing_vertices, existing_area in unique_shapes:
915
+ if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area):
916
+ duplicate_found = True
917
+ break
918
+
919
+ if not duplicate_found:
920
+ rgb_color = get_hatch_color(entity) # Assuming this function exists
921
+ unique_shapes.append((normalized_vertices, area1))
922
+ hatched_areas.append([vertices, area1, perimeter, rgb_color])
923
+
924
+
925
+
926
 
927
  elif entity.dxftype() == 'LWPOLYLINE':
928
+ vertices = []
929
+ lwpolyline = entity
930
+ points = lwpolyline.get_points()
931
+ flag = 0
932
 
933
+ # Collect vertices and apply the FinalRatio
934
+ for i in range(len(points)):
935
+ vertices.append([points[i][0] * FinalRatio, points[i][1] * FinalRatio])
 
936
 
937
+ # # Ensure there are more than 3 vertices
938
+ if len(vertices) > 3:
939
+ # Check if the polyline is closed
940
+ if vertices[0][0] == vertices[-1][0] or vertices[0][1] == vertices[-1][1]:
941
+ poly = ShapelyPolygon(vertices)
942
+ minx, miny, maxx, maxy = poly.bounds
943
 
944
+ # Calculate width and height of the bounding box
945
+ width = maxx - minx
946
+ height = maxy - miny
947
 
948
+ # Check area and size constraints
949
+ if (poly.area > 0.9 and (height > 0.7 and width > 0.7)):
950
+ area1 = round(poly.area, 3)
951
+ perimeter = round(poly.length, 3)
952
 
953
+ normalized_vertices = normalize_vertices(vertices)
954
+
955
+ duplicate_found = False
956
+ for existing_vertices, existing_area in unique_shapes:
957
+ if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area):
958
+ duplicate_found = True
959
+ break
960
+
961
+ if not duplicate_found:
962
+ rgb_color = get_hatch_color(entity) # Assuming this function exists
963
+ unique_shapes.append((normalized_vertices, area1))
964
+ hatched_areas.append([vertices, area1, perimeter, rgb_color])
965
 
 
 
 
 
 
 
 
 
966
 
967
 
968
  elif entity.dxftype() == 'POLYLINE':
969
 
970
+ # print("In POLYLINE")
971
+
972
  flag=0
973
  vertices = [(v.dxf.location.x * (FinalRatio), v.dxf.location.y * (FinalRatio)) for v in entity.vertices]
974
+ # print('Vertices:', vertices)
975
 
976
  if(len(vertices)>3):
977
 
 
984
  width = maxx - minx
985
  height = maxy - miny
986
 
987
+ if (poly.area > 0.9 and (height > 0.7 and width > 0.7)):
988
  area1 = round(poly.area,3)
989
  perimeter = round (poly.length,3)
990
+ normalized_vertices = normalize_vertices(vertices)
991
+
992
+ duplicate_found = False
993
+ for existing_vertices, existing_area in unique_shapes:
994
+ if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area):
995
+ duplicate_found = True
996
+ break
997
+
998
+ if not duplicate_found:
999
+ rgb_color = get_hatch_color(entity) # Assuming this function exists
1000
+ unique_shapes.append((normalized_vertices, area1))
1001
+ hatched_areas.append([vertices, area1, perimeter, rgb_color])
1002
+
1003
 
1004
  elif entity.dxftype() == 'SPLINE':
1005
  spline_entity = entity
 
1017
  height = maxy - miny
1018
 
1019
 
1020
+ if (poly.area > 0.9 and (height > 0.7 and width > 0.7)):
1021
  area1 = round(poly.area,3)
1022
  perimeter = round (poly.length,3)
1023
+ normalized_vertices = normalize_vertices(vertices)
1024
+
1025
+ duplicate_found = False
1026
+ for existing_vertices, existing_area in unique_shapes:
1027
+ if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area):
1028
+ duplicate_found = True
1029
+ break
1030
+
1031
+ if not duplicate_found:
1032
+ rgb_color = get_hatch_color(entity) # Assuming this function exists
1033
+ unique_shapes.append((normalized_vertices, area1))
1034
+ hatched_areas.append([vertices, area1, perimeter, rgb_color])
1035
 
1036
  sorted_data = sorted(hatched_areas, key=lambda x: x[1])
1037
+ return sorted_data,Legendarray
1038
 
1039
  """### Rotate polygon"""
1040
 
1041
+
1042
 
1043
  def rotate_point(point, angle,pdfrotation,width,height, center_point=(0, 0)):
1044
  """Rotates a point around center_point(origin by default)
 
1079
  #SimilarAreaDictionary= pd.DataFrame(columns=['Guess','Color','Occurences','Area','Total Area','Perimeter','Total Perimeter','Length','Total Length','R','G','B'])
1080
  #loop 3la hatched areas and count the occurences of each shape w create a table bl hagat di
1081
 
1082
+
1083
+ def Create_DF(dxfpath,datadoc,hatched_areas,pdf_content=0):
 
 
 
 
 
 
 
 
 
 
 
 
 
1084
 
1085
+ if pdf_content:
1086
+ FinalRatio= RetriveRatio(datadoc,dxfpath,pdf_content)
1087
+ else:
1088
+ FinalRatio= RetriveRatio(datadoc,dxfpath)
1089
+
1090
+ # hatched_areas = get_hatched_areas(dxfpath,FinalRatio)
1091
+ # print('hatched_areas',hatched_areas)
1092
+ # hatched_areas=remove_duplicate_shapes(new_hatched_areas)
1093
+
1094
  # SimilarAreaDictionary= pd.DataFrame(columns=['Area', 'Total Area', 'Perimeter', 'Total Perimeter', 'Occurences', 'Color'])
1095
  SimilarAreaDictionary= pd.DataFrame(columns=['Guess','Color','Occurences','Area','Total Area','Perimeter','Total Perimeter','Length','Total Length','Texts','Comments'])
1096
+
1097
+ # colorRanges2=generate_color_array(30000)
1098
+ # colorRanges = [[255, 0, 0], [0, 0, 255], [0, 255, 255], [0, 64, 0], [255, 204, 0], [255, 128, 64], [255, 0, 128], [255, 128, 192], [128, 128, 255], [128, 64, 0],[0, 255, 0],[0, 200, 0],[255, 128, 255], [128, 0, 255], [0, 128, 192], [128, 0, 128],[128, 0, 0], [0, 128, 255], [149, 1, 70], [255, 182, 128], [222, 48, 71], [240, 0, 112], [255, 0, 255], [192, 46, 65], [0, 0, 128],[0, 128, 64],[255, 255, 0], [128, 0, 80], [255, 255, 128], [90, 255, 140],[255, 200, 20],[91, 16, 51], [90, 105, 138], [114, 10, 138], [36, 82, 78], [225, 105, 190], [108, 150, 170], [11, 35, 75], [42, 176, 170], [255, 176, 170], [209, 151, 15],[81, 27, 85], [226, 106, 122], [67, 119, 149], [159, 179, 140], [159, 179, 30],[255, 85, 198], [255, 27, 85], [188, 158, 8],[140, 188, 120], [59, 61, 52], [65, 81, 21], [212, 255, 174], [15, 164, 90],[41, 217, 245], [213, 23, 182], [11, 85, 169], [78, 153, 239], [0, 66, 141],[64, 98, 232], [140, 112, 255], [57, 33, 154], [194, 117, 252], [116, 92, 135], [74, 43, 98], [188, 13, 123], [129, 58, 91], [255, 128, 100], [171, 122, 145], [255, 98, 98], [222, 48, 77]]
1099
+ # colorUsed=[]
1100
 
 
 
 
1101
  TotalArea=0
1102
  TotalPerimeter=0
1103
+ for shape in hatched_areas:
1104
+ area = shape[1] # area
1105
+ perimeter = shape[2] # perimeter
1106
+ # if(i < len(colorRanges)):
1107
+ # color = colorRanges[i]
1108
+ # colorUsed.append(color)
1109
+ # else:
1110
+ # color = colorRanges2[i]
1111
+ # colorUsed.append(color)
1112
  TotalArea = area
1113
  TotalPerimeter = perimeter
1114
+ tol=0
1115
  condition1 = (SimilarAreaDictionary['Area'] >= area - tol) & (SimilarAreaDictionary['Area'] <= area +tol)
1116
  condition2 = (SimilarAreaDictionary['Perimeter'] >= perimeter -tol) & (SimilarAreaDictionary['Perimeter'] <= perimeter +tol)
1117
  combined_condition = condition1 & condition2
 
1124
  else:
1125
  TotalArea=area
1126
  TotalPerimeter=perimeter
1127
+ new_data = {'Area': area, 'Total Area': TotalArea ,'Perimeter': perimeter, 'Total Perimeter': TotalPerimeter, 'Occurences': 1, 'Color':shape[3],'Comments':''} #add color here and read color to insert in
1128
  SimilarAreaDictionary = pd.concat([SimilarAreaDictionary, pd.DataFrame([new_data])], ignore_index=True)
1129
 
1130
  # print(SimilarAreaDictionary)
1131
  return SimilarAreaDictionary
1132
  """### Draw on Image and PDF"""
1133
 
1134
+ def adjustannotations(OutputPdfStage1,text_with_positions):
1135
+ input_pdf_path = OutputPdfStage1
1136
+ output_pdf_path = "Final-WallsAdjusted.pdf"
1137
+
1138
+ # Load the input PDF
1139
+ pdf_bytes_io = BytesIO(OutputPdfStage1)
1140
+
1141
+ reader = PdfReader(pdf_bytes_io)
1142
+ writer = PdfWriter()
1143
+
1144
+ # Append all pages to the writer
1145
+ writer.append_pages_from_reader(reader)
1146
+
1147
+ # Add metadata (optional)
1148
+ metadata = reader.metadata
1149
+ writer.add_metadata(metadata)
1150
+
1151
+ for page_index, page in enumerate(writer.pages):
1152
+ if "/Annots" in page:
1153
+ annotations = page["/Annots"]
1154
+ for annot_index, annot in enumerate(annotations):
1155
+ obj = annot.get_object()
1156
+
1157
+ # print("obj", obj)
1158
+ # print(obj.get("/IT"))
1159
+
1160
+ if obj.get("/Subtype") == "/Line":
1161
+ # print("AWL ANNOT IF")
1162
+ # Check the /IT value to differentiate annotations
1163
+ # if "/Contents" in obj and "m" in obj["/Contents"]:
1164
+ if "/Subj" in obj and "Perimeter Measurement" in obj["/Subj"]:
1165
+ # print("Tany IF")
1166
+ obj.update({
1167
+ NameObject("/Measure"): DictionaryObject({
1168
+ NameObject("/Type"): NameObject("/Measure"),
1169
+ NameObject("/L"): DictionaryObject({
1170
+ NameObject("/G"): FloatObject(1),
1171
+ NameObject("/U"): TextStringObject("m"), # Unit of measurement for area
1172
+ }),
1173
+
1174
+ }),
1175
+ NameObject("/IT"): NameObject("/LineDimension"), # Use more distinctive name
1176
+ NameObject("/Subj"): TextStringObject("Length Measurement"), # Intent explicitly for Area
1177
+ })
1178
+ # print(obj)
1179
+
1180
+ if obj.get("/Subtype") in ["/Line", "/PolyLine"] and "/C" in obj:
1181
+ # Normalize and match the color
1182
+ annot_color = normalize_color(obj["/C"])
1183
+ matched_entry = next(
1184
+ ((text, NBS) for text,NBS, _, color in text_with_positions if color_close_enough(annot_color, color)),
1185
+ (None, None)
1186
+ )
1187
+ # print("matched_entry = ",matched_entry)
1188
+ matched_text, matched_nbs = matched_entry
1189
+
1190
+ combined_text = ""
1191
+ if matched_text and matched_nbs:
1192
+ combined_text = f"{matched_text} - {matched_nbs}"
1193
+ elif matched_text:
1194
+ combined_text = matched_text
1195
+ elif matched_nbs:
1196
+ combined_text = matched_nbs
1197
+
1198
+ obj.update({
1199
+ NameObject("/T"): TextStringObject(combined_text), # Custom text for "Comment" column
1200
+ })
1201
+
1202
+ elif (obj.get("/Subtype") == "/Polygon" and "/C" in obj):
1203
+ # Normalize and match the color
1204
+ annot_color = normalize_color(obj["/C"])
1205
+ # print("annot_color = ",annot_color)
1206
+ # print("LASTarray = ",text_with_positions)
1207
+ # matched_entry = next(
1208
+ # ((text, NBS) for text,NBS, _, color in text_with_positions if annot_color == color),
1209
+ # (None, None)
1210
+ # )
1211
+ matched_entry = next(
1212
+ ((text, NBS) for text,NBS, _, color in text_with_positions if color_close_enough(annot_color, color)),
1213
+ (None, None)
1214
+ )
1215
+ # print("matched_entry = ",matched_entry)
1216
+ matched_text, matched_nbs = matched_entry
1217
+
1218
+ combined_text = ""
1219
+ if matched_text and matched_nbs:
1220
+ combined_text = f"{matched_text} - {matched_nbs}"
1221
+ elif matched_text:
1222
+ combined_text = matched_text
1223
+ elif matched_nbs:
1224
+ combined_text = matched_nbs
1225
+
1226
+ obj.update({
1227
+ NameObject("/T"): TextStringObject(combined_text), # Custom text for "Comment" column
1228
+ })
1229
+
1230
+
1231
+
1232
+ output_pdf_io = BytesIO()
1233
+ writer.write(output_pdf_io)
1234
+ output_pdf_io.seek(0)
1235
+
1236
+ print(f"Annotations updated and saved to {output_pdf_path}")
1237
+ return output_pdf_io.read()
1238
+
1239
+
1240
+
1241
+
1242
+ def mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio,SearchArray,pdfpath=0,pdfname=0,pdf_content=0):
1243
+ OutputPdfStage1='BB Trial.pdf'
1244
+ if pdf_content:
1245
+ FinalRatio= RetriveRatio(datadoc,dxfpath,pdf_content)
1246
+ else:
1247
+ FinalRatio= RetriveRatio(datadoc,dxfpath)
1248
+
1249
+
1250
+ # hatched_areas = get_hatched_areas(dxfpath,FinalRatio)
1251
+ # hatched_areas=remove_duplicate_shapes(new_hatched_areas)
1252
+ if pdf_content:
1253
+ img=pdftoimg(datadoc,pdf_content)
1254
+ else:
1255
+ img=pdftoimg(datadoc)
1256
  flipped_horizontal=flip(img)
1257
  allcnts = []
1258
  imgg = flipped_horizontal
1259
  # imgtransparent1=imgg.copy()
1260
+ if pdf_content:
1261
+ doc = fitz.open(stream=pdf_content, filetype="pdf")
1262
+ else:
1263
+ doc = fitz.open('pdf',datadoc)
1264
  page2 = doc[0]
1265
  rotationOld=page2.rotation
1266
  derotationMatrix=page2.derotation_matrix
 
1277
  ratio = pix.width/ img.shape[1]
1278
  rotationangle = 270
1279
 
1280
+
1281
+ hatched_areas,Legendarray = get_hatched_areas(datadoc,dxfpath,FinalRatio,rotationangle,SearchArray)
1282
  allshapes=[]
1283
  # Iterate through each polygon in metric units
1284
  NewColors = []
1285
+ if pdf_content:
1286
+ SimilarAreaDictionary=Create_DF(dxfpath,datadoc,hatched_areas,pdf_content)
1287
+ else:
1288
+ SimilarAreaDictionary=Create_DF(dxfpath,datadoc,hatched_areas)
1289
  i=0
1290
+ flagcolor = 0
1291
+ ColorCheck=[]
1292
 
1293
 
1294
  for polygon in hatched_areas:
1295
  cntPoints = []
1296
  cntPoints1 = []
1297
+ shapeePerimeter = []
1298
+ shapeeArea = []
1299
+
1300
+ blackImgShapes = np.zeros(imgg.shape[:2], dtype="uint8")
1301
+ blackImgShapes= cv2.cvtColor(blackImgShapes, cv2.COLOR_GRAY2BGR)
1302
+
1303
+
1304
  # Convert each vertex from metric to pixel coordinates
1305
  for vertex in polygon[0]:
1306
  x = (vertex[0]) *dxfratio
 
1311
  cntPoints.append([int(x), int(y)])
1312
  cntPoints1.append([x, y])
1313
 
1314
+ cv2.drawContours(blackImgShapes, [np.array(cntPoints)], -1, ([255,255,255]), thickness=-1)
1315
+ x, y, w, h = cv2.boundingRect(np.array(cntPoints))
1316
+ firstpoint = 0
1317
+ for poi in np.array(cntPoints1):
1318
+ if firstpoint == 0:
1319
+ x2, y2 = poi
1320
+ p2 = fitz.Point(x2,y2)
1321
+ # p1 = fitz.Point(x1,y1)
1322
+ p2=p2*derotationMatrix
1323
+ shapeePerimeter.append([p2[0],p2[1]])
1324
+ firstpoint = 1
1325
+ else:
1326
+ x1, y1 = poi
1327
+ p1 = fitz.Point(x1,y1)
1328
+ # p1 = fitz.Point(x1,y1)
1329
+ p1=p1*derotationMatrix
1330
+ print("P1 = ",p1)
1331
+ shapeePerimeter.append([p1[0],p1[1]])
1332
+
1333
+ shapeePerimeter.append([p2[0],p2[1]])
1334
+ shapeePerimeter=np.flip(shapeePerimeter,1)
1335
+ shapeePerimeter=rotate_polygon(shapeePerimeter,rotationangle,rotationOld,width,height)
1336
+
1337
  for poi in np.array(cntPoints1):
1338
+ x1, y1 = poi
1339
+ p1 = fitz.Point(x1,y1)
1340
+ # p1 = fitz.Point(x1,y1)
1341
+ p1=p1*derotationMatrix
1342
+ print("P1 = ",p1)
1343
+ shapeeArea.append([p1[0],p1[1]])
1344
+
1345
+ shapeeArea.append([p2[0],p2[1]])
1346
+ shapeeArea=np.flip(shapeeArea,1)
1347
+ shapeeArea=rotate_polygon(shapeeArea,rotationangle,rotationOld,width,height)
1348
+
1349
+
1350
+ tol=0
1351
  condition1 = (SimilarAreaDictionary['Area'] >= polygon[1] - tol) & (SimilarAreaDictionary['Area'] <= polygon[1] +tol)
1352
  condition2 = (SimilarAreaDictionary['Perimeter'] >= polygon[2] -tol) & (SimilarAreaDictionary['Perimeter'] <= polygon[2] +tol)
1353
  combined_condition = condition1 & condition2
1354
 
1355
  if any(combined_condition):
1356
+ flagcolor = 1
1357
  index = np.where(combined_condition)[0][0]
1358
  # print(SimilarAreaDictionary.at[index, 'Color'])
1359
  NewColors=SimilarAreaDictionary.at[index, 'Color']
1360
  else:
1361
+ flagcolor = 2
1362
  NewColors=SimilarAreaDictionary.at[i, 'Color']
1363
+
1364
+ if(int(NewColors[0])==255 and int(NewColors[1])==255 and int(NewColors[2])==255):
1365
+ WhiteImgFinal = cv2.bitwise_and(blackImgShapes,imgg)
1366
+ flipped=flip(WhiteImgFinal)
1367
+
1368
+
1369
+ imgslice = WhiteImgFinal[y:y+h, x:x+w]
1370
+ if(imgslice.shape[0] != 0 and imgslice.shape[1] != 0):
1371
+ flippedSlice=flip(imgslice)
1372
+
1373
+
1374
+ # Convert flippedSlice to PIL for color extraction
1375
+ flippedSlice_pil = Image.fromarray(flippedSlice)
1376
+
1377
+ # Define patch size for color sampling (e.g., 10x10 pixels)
1378
+ patch_size = 100
1379
+ patch_colors = []
1380
+
1381
+ # Loop through patches in the image
1382
+ for i in range(0, flippedSlice_pil.width, patch_size):
1383
+ for j in range(0, flippedSlice_pil.height, patch_size):
1384
+ # Crop a patch from the original image
1385
+ patch = flippedSlice_pil.crop((i, j, i + patch_size, j + patch_size))
1386
+ patch_colors += patch.getcolors(patch_size * patch_size)
1387
+
1388
+ # Calculate the dominant color from all patches
1389
+ max_count = 0
1390
+ dominant_color = None
1391
+ tolerance = 5
1392
+ black_threshold = 30 # Max RGB value for a color to be considered "black"
1393
+ white_threshold = 225 # Min RGB value for a color to be considered "white"
1394
+
1395
+ for count, color in patch_colors:
1396
+ # Exclude colors within the black and white ranges
1397
+ if not (all(c <= black_threshold for c in color) or all(c >= white_threshold for c in color)):
1398
+ # Update if the current color has a higher count than previous max
1399
+ if count > max_count:
1400
+ max_count = count
1401
+ dominant_color = color
1402
+
1403
+
1404
+
1405
+ # Append dominant color to ColorCheck and update NewColors
1406
+ if dominant_color is not None:
1407
+ ColorCheck.append(dominant_color)
1408
+
1409
+ NewColors = None
1410
+
1411
+ for color in ColorCheck:
1412
+ # Check if the current color is within the tolerance
1413
+ print("color = ",color)
1414
+ print("dominant_color = ",dominant_color)
1415
+ if (abs(color[0] - dominant_color[0]) < 20 and
1416
+ abs(color[1] - dominant_color[1]) < 20 and
1417
+ abs(color[2] - dominant_color[2]) < 20):
1418
+ NewColors = (color[2], color[1], color[0]) # Set the new color
1419
+ break
1420
+ else:
1421
+ # If no color in ColorCheck meets the tolerance, use the dominant color
1422
+ NewColors = (dominant_color[2], dominant_color[1], dominant_color[0])
1423
+
1424
+ if NewColors not in ColorCheck:
1425
+ ColorCheck.append(NewColors)
1426
+
1427
+
1428
+ if flagcolor == 1:
1429
+ SimilarAreaDictionary.at[index, 'Color'] = NewColors
1430
+ # print(f"Updated Color at index {index} with {NewColors}.")
1431
+ elif flagcolor == 2:
1432
+ SimilarAreaDictionary.at[i, 'Color'] = NewColors
1433
+
1434
+
1435
  cv2.drawContours(imgg, [np.array(cntPoints)], -1, ([NewColors[2],NewColors[1],NewColors[0]]), thickness=-1)
1436
+
1437
+ annot11 = page2.add_polygon_annot( points=shapeeArea) # 'Polygon'
1438
  annot11.set_border(width=0.2)
1439
  annot11.set_colors(stroke=(int(NewColors[0])/255,int(NewColors[1])/255,int(NewColors[2])/255), fill= (int(NewColors[0])/255,int(NewColors[1])/255,int(NewColors[2])/255) )
1440
+ annot11.set_info(content=str(polygon[1])+' sq m',subject='Area Measurement', title="ADR Team")
1441
+ annot11.set_opacity(0.8)
1442
  # annot.set_line_ends(fitz.PDF_ANNOT_LE_DIAMOND, fitz.PDF_ANNOT_LE_CIRCLE)
1443
  annot11.update()
1444
 
1445
 
1446
 
1447
+ annot12 = page2.add_polyline_annot( points=shapeePerimeter ) # 'Polygon'
1448
+ annot12.set_border(width=0.8)
1449
  annot12.set_colors(stroke=(int(NewColors[0])/255,int(NewColors[1])/255,int(NewColors[2])/255))
1450
+ annot12.set_info(content=str(polygon[2])+' m',subject='Perimeter Measurement', title="ADR Team")
1451
  annot12.set_opacity(0.8)
1452
  # annot.set_line_ends(fitz.PDF_ANNOT_LE_DIAMOND, fitz.PDF_ANNOT_LE_CIRCLE)
1453
  annot12.update()
1454
  i += 1
1455
  alpha = 0.8 # Transparency factor.
1456
+
1457
  page2.set_rotation(rotationOld)
1458
  Correct_img=flip(imgg)
1459
 
1460
  image_new1 = cv2.addWeighted(Correct_img, alpha, img, 1 - alpha, 0)
1461
  SimilarAreaDictionary = SimilarAreaDictionary.fillna(' ')
1462
+
1463
+ # Define white color to filter out
1464
+ white_color = (255, 255, 255)
1465
+
1466
+ # Delete rows where 'Guess' equals white_color
1467
+ SimilarAreaDictionary = SimilarAreaDictionary[SimilarAreaDictionary['Color'] != white_color]
1468
+
1469
+ # Reset the index to update row numbering
1470
+ SimilarAreaDictionary.reset_index(drop=True, inplace=True)
1471
+
1472
+ grouped_df = SimilarAreaDictionary.groupby('Color').agg({
1473
+ 'Guess':'first',
1474
+ 'Occurences': 'sum', # Sum of occurrences for each color
1475
+ 'Area':'first',
1476
+ 'Total Area': 'sum', # Sum of areas for each color
1477
+ 'Perimeter':'first',
1478
+ 'Total Perimeter': 'sum', # Sum of perimeters for each color
1479
+ 'Length':'first',
1480
+ 'Total Length':'first',
1481
+ 'Texts':'first',
1482
+ 'Comments':'first'
1483
+
1484
+ }).reset_index()
1485
+
1486
+ SimilarAreaDictionary = grouped_df
1487
+ # doc.save(OutputPdfStage1)
1488
+ modified_pdf_data = doc.tobytes()
1489
+ # OutputPdfStage2=adjustannotations(modified_pdf_data)
1490
+ OutputPdfStage2=adjustannotations(modified_pdf_data,Legendarray)
1491
+
1492
+
1493
+ # with open("Adjusted_PDF.pdf", "wb") as f:
1494
+ # f.write(OutputPdfStage2)
1495
+
1496
+ # doc2 = fitz.open(stream=OutputPdfStage2, filetype="pdf")
1497
+ # doc2 = fitz.open(stream=OutputPdfStage2, filetype="pdf")
1498
+
1499
+ doc2 =fitz.open('pdf',OutputPdfStage2)
1500
+ if pdf_content:
1501
+ gc,spreadsheet_service,spreadsheetId, spreadsheet_url , namepathArr=google_sheet_Legend.legendGoogleSheets(SimilarAreaDictionary , pdfname,pdfpath,pdf_content)
1502
+ else:
1503
+ gc,spreadsheet_service,spreadsheetId, spreadsheet_url , namepathArr=google_sheet_Legend.legendGoogleSheets(SimilarAreaDictionary , pdfname,pdfpath)
1504
  # dbxTeam=tsadropboxretrieval.ADR_Access_DropboxTeam('user')
1505
  # md, res =dbxTeam.files_download(path= pdfpath+pdfname)
1506
  # data = res.content
 
1508
  # list1=pd.DataFrame(columns=['content', 'creationDate', 'id', 'modDate', 'name', 'subject', 'title'])
1509
  list1=pd.DataFrame(columns=['content', 'id', 'subject','color'])
1510
 
1511
+ # for page in doc:
1512
+ for page in doc2:
1513
  # Iterate through annotations on the page
1514
  for annot in page.annots():
1515
  # Get the color of the annotation
 
1520
  fill_color = annot_color.get('fill') # Fill color
1521
  if fill_color:
1522
  v='fill'
1523
+ # print('fill')
1524
  if stroke_color:
1525
  v='stroke'
1526
  x,y,z=int(annot_color.get(v)[0]*255),int(annot_color.get(v)[1]*255),int(annot_color.get(v)[2]*255)
1527
  list1.loc[len(list1)] =[annot.info['content'],annot.info['id'],annot.info['subject'],[x,y,z]]
1528
+ print('LISTTT',list1)
1529
+ return doc2,image_new1, SimilarAreaDictionary ,spreadsheetId, spreadsheet_url , namepathArr , list1,hatched_areas
1530
 
1531
+ # doc.save('Testing(2.7).pdf')
1532
+ # return doc,image_new1#, SimilarAreaDictionary ,spreadsheetId, spreadsheet_url , namepathArr , list1,hatched_areas
 
 
 
1533
 
1534
+ # datadoc='/content/3.3 - Ceiling finishes - Example 1 - Sheet 1.pdf' #pdf path here
1535
+ # dxfpath='/content/3.3 - Ceiling finishes - Example 1 - Sheet 1.dxf'#dxfpath here
1536
+ # dxfratio=28.3464527867108
1537
+ # doc,image_new1=mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio)
1538
+ # cv2_imshow(image_new1)
1539
 
1540
+