Spaces:
Sleeping
Sleeping
| # -*- coding: utf-8 -*- | |
| """Deploying 3.3 | |
| Automatically generated by Colab. | |
| Original file is located at | |
| https://colab.research.google.com/drive/1HEw0DdXhDcxtJN1pjs7bCnlhr-wXX3-m | |
| """ | |
| # pip install pymupdf | |
| # pip install ezdxf | |
| def normalize_vertices(vertices): | |
| """Sort vertices to ensure consistent order.""" | |
| return tuple(sorted(tuple(v) for v in vertices)) | |
| def areas_are_similar(area1, area2, tolerance=0.2): | |
| """Check if two areas are within a given tolerance.""" | |
| return abs(area1 - area2) <= tolerance | |
| from ctypes import sizeof | |
| # -*- coding: utf-8 -*-wj | |
| """Version to be deployed of 3.2 Calculating area/perimeter | |
| Automatically generated by Colab. | |
| Original file is located at | |
| https://colab.research.google.com/drive/1XPeCoTBgWSNBYZ3aMKBteP4YG3w4bORs | |
| """ | |
| # pip install ezdxf[draw] | |
| # pip install --upgrade ezdxf | |
| # pip install pymupdf #==1.22.5 | |
| # pip install PyPDF2 | |
| # pip install ezdxf scipy | |
| """## Imports""" | |
| import xml.etree.ElementTree as ET | |
| from PyPDF2 import PdfReader, PdfWriter | |
| from PyPDF2.generic import TextStringObject, NameObject, ArrayObject, FloatObject | |
| from PyPDF2.generic import NameObject, TextStringObject, DictionaryObject, FloatObject, ArrayObject | |
| from typing import NewType | |
| from ctypes import sizeof | |
| import numpy as np | |
| import cv2 | |
| from matplotlib import pyplot as plt | |
| import math | |
| from PIL import Image , ImageDraw, ImageFont , ImageColor | |
| import fitz | |
| import ezdxf as ez | |
| import sys | |
| from ezdxf import units | |
| # from google.colab.patches import cv2_imshow | |
| from ezdxf.math import OCS, Matrix44, Vec3 | |
| import ezdxf | |
| import matplotlib.pyplot as plt | |
| from matplotlib.patches import Polygon | |
| from shapely.geometry import Point, Polygon as ShapelyPolygon | |
| from ezdxf.math import Vec2 | |
| import random | |
| import pandas as pd | |
| # import google_sheet_Legend | |
| import tsadropboxretrieval | |
| from ezdxf import bbox | |
| from math import sin, cos, radians | |
| import google_sheet_Legend | |
| from PyPDF2 import PdfReader | |
| from io import BytesIO | |
| """## Notes""" | |
| #new approach to get width and height of dxf plan | |
| ''' | |
| This portion is used to convert vertices read from dxf to pixels in order to accurately locate shapes in the image and pdf | |
| ratio : | |
| MeasuredMetric* PixelValue/ DxfMetric = MeasuredPixel | |
| PixelValue: get from pixel conversion code , second number in the bracker represents the perimeter | |
| DxfMetric: measured perimeter from foxit | |
| divide pixelvalue by dxfmetric, will give u a ratio , this is ur dxfratio | |
| ''' | |
| """PDF to image""" | |
| def pdftoimg(datadoc): | |
| doc = fitz.open('pdf',datadoc) | |
| page=doc[0] | |
| pix = page.get_pixmap() # render page to an image | |
| pl=Image.frombytes('RGB', [pix.width,pix.height],pix.samples) | |
| img=np.array(pl) | |
| img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) | |
| return img | |
| # Standard ISO paper sizes in inches | |
| ISO_SIZES_INCHES = { | |
| "A0": (33.11, 46.81), | |
| "A1": (23.39, 33.11), | |
| "A2": (16.54, 23.39), | |
| "A3": (11.69, 16.54), | |
| "A4": (8.27, 11.69), | |
| "A5": (5.83, 8.27), | |
| "A6": (4.13, 5.83), | |
| "A7": (2.91, 4.13), | |
| "A8": (2.05, 2.91), | |
| "A9": (1.46, 2.05), | |
| "A10": (1.02, 1.46) | |
| } | |
| def get_paper_size_in_inches(width, height): | |
| """Find the closest matching paper size in inches.""" | |
| for size, (w, h) in ISO_SIZES_INCHES.items(): | |
| if (abs(w - width) < 0.1 and abs(h - height) < 0.1) or (abs(w - height) < 0.1 and abs(h - width) < 0.1): | |
| return size | |
| return "Unknown Size" | |
| def analyze_pdf(datadoc): | |
| # Open the PDF file | |
| pdf_document = fitz.open('pdf',datadoc) | |
| # Iterate through pages and print their sizes | |
| for page_number in range(len(pdf_document)): | |
| page = pdf_document[page_number] | |
| rect = page.rect | |
| width_points, height_points = rect.width, rect.height | |
| # Convert points to inches | |
| width_inches, height_inches = width_points / 72, height_points / 72 | |
| paper_size = get_paper_size_in_inches(width_inches, height_inches) | |
| print(f"Page {page_number + 1}: {width_inches:.2f} x {height_inches:.2f} inches ({paper_size})") | |
| pdf_document.close() | |
| return width_inches , height_inches , paper_size | |
| def get_dxfSize(dxfpath): | |
| doc = ezdxf.readfile(dxfpath) | |
| msp = doc.modelspace() | |
| # Create a cache for bounding box calculations | |
| # Get the overall bounding box for all entities in the modelspace | |
| cache = bbox.Cache() | |
| overall_bbox = bbox.extents(msp, cache=cache) | |
| print("Overall Bounding Box:", overall_bbox) | |
| print(overall_bbox.extmin[0]+overall_bbox.extmax[0], overall_bbox.extmin[1]+overall_bbox.extmax[1]) | |
| return overall_bbox.extmin[0]+overall_bbox.extmax[0], overall_bbox.extmin[1]+overall_bbox.extmax[1] | |
| def switch_case(argument): | |
| switcher = { | |
| "A0": 1.27, | |
| "A1": 2.54, | |
| "A2": 5.08, | |
| "A3": 10.16, | |
| "A4": 20.32, | |
| "A5": 40.64, | |
| "A6": 81.28, | |
| "A7": 162.56, | |
| "A8": 325.12, | |
| "A9": 650.24, | |
| "A10": 1300.48 | |
| } | |
| # Get the value from the dictionary; if not found, return a default value | |
| print("Final Ratio=",switcher.get(argument, 1)) | |
| return switcher.get(argument, 1) | |
| def RetriveRatio(datadoc,dxfpath): | |
| width,height,paper_size = analyze_pdf (datadoc) | |
| if(width > height ): | |
| bigger=width | |
| else: | |
| bigger=height | |
| width_dxf,height_dxf = get_dxfSize(dxfpath) | |
| if(width_dxf > height_dxf ): | |
| bigger_dxf=width_dxf | |
| else: | |
| bigger_dxf=height_dxf | |
| if(0.2 < bigger_dxf/bigger < 1.2): | |
| print("bigger_dxf/bigger",bigger/bigger_dxf) | |
| argument = paper_size | |
| FinalRatio=switch_case(argument) | |
| else: | |
| FinalRatio=1 | |
| return FinalRatio | |
| """Flips image | |
| DXF origin is at the bottom left while img origin is top left | |
| """ | |
| def flip(img): | |
| height, width = img.shape[:2] | |
| # Define the rotation angle (clockwise) | |
| angle = 180 | |
| # Calculate the rotation matrix | |
| rotation_matrix = cv2.getRotationMatrix2D((width/2, height/2), angle, 1) | |
| # Rotate the image | |
| rotated_image = cv2.warpAffine(img, rotation_matrix, (width, height)) | |
| flipped_horizontal = cv2.flip(rotated_image, 1) | |
| return flipped_horizontal | |
| def aci_to_rgb(aci): | |
| aci_rgb_map = { | |
| 0: (0, 0, 0), | |
| 1: (255, 0, 0), | |
| 2: (255, 255, 0), | |
| 3: (0, 255, 0), | |
| 4: (0, 255, 255), | |
| 5: (0, 0, 255), | |
| 6: (255, 0, 255), | |
| 7: (255, 255, 255), | |
| 8: (65, 65, 65), | |
| 9: (128, 128, 128), | |
| 10: (255, 0, 0), | |
| 11: (255, 170, 170), | |
| 12: (189, 0, 0), | |
| 13: (189, 126, 126), | |
| 14: (129, 0, 0), | |
| 15: (129, 86, 86), | |
| 16: (104, 0, 0), | |
| 17: (104, 69, 69), | |
| 18: (79, 0, 0), | |
| 19: (79, 53, 53), | |
| 20: (255, 63, 0), | |
| 21: (255, 191, 170), | |
| 22: (189, 46, 0), | |
| 23: (189, 141, 126), | |
| 24: (129, 31, 0), | |
| 25: (129, 96, 86), | |
| 26: (104, 25, 0), | |
| 27: (104, 78, 69), | |
| 28: (79, 19, 0), | |
| 29: (79, 59, 53), | |
| 30: (255, 127, 0), | |
| 31: (255, 212, 170), | |
| 32: (189, 94, 0), | |
| 33: (189, 157, 126), | |
| 34: (129, 64, 0), | |
| 35: (129, 107, 86), | |
| 36: (104, 52, 0), | |
| 37: (104, 86, 69), | |
| 38: (79, 39, 0), | |
| 39: (79, 66, 53), | |
| 40: (255, 191, 0), | |
| 41: (255, 234, 170), | |
| 42: (189, 141, 0), | |
| 43: (189, 173, 126), | |
| 44: (129, 96, 0), | |
| 45: (129, 118, 86), | |
| 46: (104, 78, 0), | |
| 47: (104, 95, 69), | |
| 48: (79, 59, 0), | |
| 49: (79, 73, 53), | |
| 50: (255, 255, 0), | |
| 51: (255, 255, 170), | |
| 52: (189, 189, 0), | |
| 53: (189, 189, 126), | |
| 54: (129, 129, 0), | |
| 55: (129, 129, 86), | |
| 56: (104, 104, 0), | |
| 57: (104, 104, 69), | |
| 58: (79, 79, 0), | |
| 59: (79, 79, 53), | |
| 60: (191, 255, 0), | |
| 61: (234, 255, 170), | |
| 62: (141, 189, 0), | |
| 63: (173, 189, 126), | |
| 64: (96, 129, 0), | |
| 65: (118, 129, 86), | |
| 66: (78, 104, 0), | |
| 67: (95, 104, 69), | |
| 68: (59, 79, 0), | |
| 69: (73, 79, 53), | |
| 70: (127, 255, 0), | |
| 71: (212, 255, 170), | |
| 72: (94, 189, 0), | |
| 73: (157, 189, 126), | |
| 74: (64, 129, 0), | |
| 75: (107, 129, 86), | |
| 76: (52, 104, 0), | |
| 77: (86, 104, 69), | |
| 78: (39, 79, 0), | |
| 79: (66, 79, 53), | |
| 80: (63, 255, 0), | |
| 81: (191, 255, 170), | |
| 82: (46, 189, 0), | |
| 83: (141, 189, 126), | |
| 84: (31, 129, 0), | |
| 85: (96, 129, 86), | |
| 86: (25, 104, 0), | |
| 87: (78, 104, 69), | |
| 88: (19, 79, 0), | |
| 89: (59, 79, 53), | |
| 90: (0, 255, 0), | |
| 91: (170, 255, 170), | |
| 92: (0, 189, 0), | |
| 93: (126, 189, 126), | |
| 94: (0, 129, 0), | |
| 95: (86, 129, 86), | |
| 96: (0, 104, 0), | |
| 97: (69, 104, 69), | |
| 98: (0, 79, 0), | |
| 99: (53, 79, 53), | |
| 100: (0, 255, 63), | |
| 101: (170, 255, 191), | |
| 102: (0, 189, 46), | |
| 103: (126, 189, 141), | |
| 104: (0, 129, 31), | |
| 105: (86, 129, 96), | |
| 106: (0, 104, 25), | |
| 107: (69, 104, 78), | |
| 108: (0, 79, 19), | |
| 109: (53, 79, 59), | |
| 110: (0, 255, 127), | |
| 111: (170, 255, 212), | |
| 112: (0, 189, 94), | |
| 113: (126, 189, 157), | |
| 114: (0, 129, 64), | |
| 115: (86, 129, 107), | |
| 116: (0, 104, 52), | |
| 117: (69, 104, 86), | |
| 118: (0, 79, 39), | |
| 119: (53, 79, 66), | |
| 120: (0, 255, 191), | |
| 121: (170, 255, 234), | |
| 122: (0, 189, 141), | |
| 123: (126, 189, 173), | |
| 124: (0, 129, 96), | |
| 125: (86, 129, 118), | |
| 126: (0, 104, 78), | |
| 127: (69, 104, 95), | |
| 128: (0, 79, 59), | |
| 129: (53, 79, 73), | |
| 130: (0, 255, 255), | |
| 131: (170, 255, 255), | |
| 132: (0, 189, 189), | |
| 133: (126, 189, 189), | |
| 134: (0, 129, 129), | |
| 135: (86, 129, 129), | |
| 136: (0, 104, 104), | |
| 137: (69, 104, 104), | |
| 138: (0, 79, 79), | |
| 139: (53, 79, 79), | |
| 140: (0, 191, 255), | |
| 141: (170, 234, 255), | |
| 142: (0, 141, 189), | |
| 143: (126, 173, 189), | |
| 144: (0, 96, 129), | |
| 145: (86, 118, 129), | |
| 146: (0, 78, 104), | |
| 147: (69, 95, 104), | |
| 148: (0, 59, 79), | |
| 149: (53, 73, 79), | |
| 150: (0, 127, 255), | |
| 151: (170, 212, 255), | |
| 152: (0, 94, 189), | |
| 153: (126, 157, 189), | |
| 154: (0, 64, 129), | |
| 155: (86, 107, 129), | |
| 156: (0, 52, 104), | |
| 157: (69, 86, 104), | |
| 158: (0, 39, 79), | |
| 159: (53, 66, 79), | |
| 160: (0, 63, 255), | |
| 161: (170, 191, 255), | |
| 162: (0, 46, 189), | |
| 163: (126, 141, 189), | |
| 164: (0, 31, 129), | |
| 165: (86, 96, 129), | |
| 166: (0, 25, 104), | |
| 167: (69, 78, 104), | |
| 168: (0, 19, 79), | |
| 169: (53, 59, 79), | |
| 170: (0, 0, 255), | |
| 171: (170, 170, 255), | |
| 172: (0, 0, 189), | |
| 173: (126, 126, 189), | |
| 174: (0, 0, 129), | |
| 175: (86, 86, 129), | |
| 176: (0, 0, 104), | |
| 177: (69, 69, 104), | |
| 178: (0, 0, 79), | |
| 179: (53, 53, 79), | |
| 180: (63, 0, 255), | |
| 181: (191, 170, 255), | |
| 182: (46, 0, 189), | |
| 183: (141, 126, 189), | |
| 184: (31, 0, 129), | |
| 185: (96, 86, 129), | |
| 186: (25, 0, 104), | |
| 187: (78, 69, 104), | |
| 188: (19, 0, 79), | |
| 189: (59, 53, 79), | |
| 190: (127, 0, 255), | |
| 191: (212, 170, 255), | |
| 192: (94, 0, 189), | |
| 193: (157, 126, 189), | |
| 194: (64, 0, 129), | |
| 195: (107, 86, 129), | |
| 196: (52, 0, 104), | |
| 197: (86, 69, 104), | |
| 198: (39, 0, 79), | |
| 199: (66, 53, 79), | |
| 200: (191, 0, 255), | |
| 201: (234, 170, 255), | |
| 202: (141, 0, 189), | |
| 203: (173, 126, 189), | |
| 204: (96, 0, 129), | |
| 205: (118, 86, 129), | |
| 206: (78, 0, 104), | |
| 207: (95, 69, 104), | |
| 208: (59, 0, 79), | |
| 209: (73, 53, 79), | |
| 210: (255, 0, 255), | |
| 211: (255, 170, 255), | |
| 212: (189, 0, 189), | |
| 213: (189, 126, 189), | |
| 214: (129, 0, 129), | |
| 215: (129, 86, 129), | |
| 216: (104, 0, 104), | |
| 217: (104, 69, 104), | |
| 218: (79, 0, 79), | |
| 219: (79, 53, 79), | |
| 220: (255, 0, 191), | |
| 221: (255, 170, 234), | |
| 222: (189, 0, 141), | |
| 223: (189, 126, 173), | |
| 224: (129, 0, 96), | |
| 225: (129, 86, 118), | |
| 226: (104, 0, 78), | |
| 227: (104, 69, 95), | |
| 228: (79, 0, 59), | |
| 229: (79, 53, 73), | |
| 230: (255, 0, 127), | |
| 231: (255, 170, 212), | |
| 232: (189, 0, 94), | |
| 233: (189, 126, 157), | |
| 234: (129, 0, 64), | |
| 235: (129, 86, 107), | |
| 236: (104, 0, 52), | |
| 237: (104, 69, 86), | |
| 238: (79, 0, 39), | |
| 239: (79, 53, 66), | |
| 240: (255, 0, 63), | |
| 241: (255, 170, 191), | |
| 242: (189, 0, 46), | |
| 243: (189, 126, 141), | |
| 244: (129, 0, 31), | |
| 245: (129, 86, 96), | |
| 246: (104, 0, 25), | |
| 247: (104, 69, 78), | |
| 248: (79, 0, 19), | |
| 249: (79, 53, 59), | |
| 250: (51, 51, 51), | |
| 251: (80, 80, 80), | |
| 252: (105, 105, 105), | |
| 253: (130, 130, 130), | |
| 254: (190, 190, 190), | |
| 255: (255, 255, 255) | |
| } | |
| # Default to white if index is invalid or not found | |
| return aci_rgb_map.get(aci, (255, 255, 255)) | |
| def int_to_rgb(color_int): | |
| """Convert an integer to an (R, G, B) tuple.""" | |
| r = (color_int >> 16) & 255 | |
| g = (color_int >> 8) & 255 | |
| b = color_int & 255 | |
| return (r, g, b) | |
| def get_hatch_color(entity): | |
| # Check if the entity has a "true color" set | |
| if entity.dxf.hasattr('true_color'): | |
| true_color = entity.dxf.true_color | |
| rgb_color = int_to_rgb(true_color) # Convert integer to (R, G, B) | |
| print(f"True color detected (RGB): {rgb_color}") | |
| return rgb_color | |
| color_index = entity.dxf.color | |
| print("color_index = ", color_index) | |
| # Check if the color is set to ByLayer or ByBlock | |
| if color_index == 0: # ByLayer color | |
| print("Color is ByLayer, checking layer color...") | |
| layer_name = entity.dxf.layer | |
| layer = entity.doc.layers.get(layer_name) | |
| if layer: # Ensure layer exists | |
| layer_color_index = layer.dxf.color | |
| print(f"Layer '{layer_name}' Color Index = {layer_color_index}") | |
| return aci_to_rgb(layer_color_index) # Use custom aci_to_rgb function | |
| else: | |
| print(f"Layer '{layer_name}' not found, defaulting to white.") | |
| return (255, 255, 255) # Default to white if layer not found | |
| elif color_index == 256: # ByBlock color | |
| print("Color is ByBlock, checking block color or defaulting to white.") | |
| block_color = (255, 255, 255) # White as default | |
| # Check if the entity is inside a block reference and inherit its color | |
| if hasattr(entity, 'block'): # Check if the entity belongs to a block | |
| block_ref = entity.block | |
| if block_ref.dxf.hasattr('color'): | |
| block_color = aci_to_rgb(block_ref.dxf.color) | |
| print(f"Block reference color found: {block_color}") | |
| else: | |
| print("Block has no color attribute, using default (white).") | |
| return block_color | |
| # Otherwise, convert the ACI color to RGB | |
| print(f"Entity Color Index = {color_index}") | |
| if 1 <= color_index <= 255: | |
| rgb_color = aci_to_rgb(color_index) # Use custom aci_to_rgb function | |
| print(f"Converted RGB = {rgb_color}") | |
| return rgb_color | |
| # Default to white if color index is out of bounds or invalid | |
| print("Invalid or unhandled color index, defaulting to white.") | |
| return (255, 255, 255) | |
| """### Hatched areas""" | |
| def get_hatched_areas(datadoc,filename,FinalRatio,rotationangle): | |
| text_with_positions = [] | |
| text_color_mapping = {} | |
| color_palette = [ | |
| (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) | |
| ] | |
| doc = ezdxf.readfile(filename) | |
| doc.header['$MEASUREMENT'] = 1 | |
| msp = doc.modelspace() | |
| trial=0 | |
| hatched_areas = [] | |
| threshold=0.01 | |
| unique_shapes = [] | |
| for entity in doc.modelspace().query('TEXT MTEXT'): | |
| if hasattr(entity, 'text'): # Ensure the entity has text content | |
| text = entity.text | |
| if text.startswith('C') and (len(text) > 1 and (text[1].isdigit() or text[1].upper() == 'T' or text[1].upper() == 'L')): | |
| parts = text.split(' ') # Split into two parts: before and after the first newline | |
| # print("Parts = ",parts[0]) | |
| main_text = parts[0] # Text before the first newline | |
| # Check if the main text starts with 'C' followed by a number or 'T' | |
| # if pattern.match(main_text): | |
| position = entity.dxf.insert | |
| # Check if the text already has a color assigned | |
| if main_text not in text_color_mapping: | |
| # Assign a new color from the palette | |
| color_index = len(text_color_mapping) % len(color_palette) | |
| text_color_mapping[main_text] = color_palette[color_index] | |
| # Get the assigned color | |
| color = text_color_mapping[main_text] | |
| # Set the entity's true color | |
| # entity.dxf.true_color = rgb_to_true_color(color) | |
| # Append text, position, and color to the array | |
| text_with_positions.append([main_text, position, color]) | |
| for entity in msp: | |
| if entity.dxftype() == 'HATCH': | |
| # print(f"Processing HATCH entity: {entity}") | |
| for path in entity.paths: | |
| vertices = [] # Reset vertices for each path | |
| if str(path.type) == 'BoundaryPathType.POLYLINE': | |
| # Handle POLYLINE type HATCH | |
| vertices = [(vertex[0] * FinalRatio, vertex[1] * FinalRatio) for vertex in path.vertices] | |
| if len(vertices) > 3: | |
| poly = ShapelyPolygon(vertices) | |
| minx, miny, maxx, maxy = poly.bounds | |
| width = maxx - minx | |
| height = maxy - miny | |
| if (poly.area > 0.9 and (height > 0.7 and width > 0.7)): | |
| area1 = round(poly.area, 3) | |
| perimeter = round(poly.length, 3) | |
| normalized_vertices = normalize_vertices(vertices) | |
| rgb_color = get_hatch_color(entity) | |
| if(rgb_color == (255, 255, 255)): | |
| if(len(text_with_positions)>0): | |
| for text, position, color in text_with_positions: | |
| text_position = Point(position[0], position[1]) | |
| if poly.contains(text_position): | |
| rgb_color = color | |
| break | |
| duplicate_found = False | |
| for existing_vertices, existing_area in unique_shapes: | |
| if normalized_vertices == existing_vertices and areas_are_similar(area1, existing_area): | |
| duplicate_found = True | |
| break | |
| if not duplicate_found: | |
| # rgb_color = get_hatch_color(entity) # Assuming this function exists | |
| unique_shapes.append((normalized_vertices, area1)) | |
| hatched_areas.append([vertices, area1, perimeter, rgb_color]) | |
| elif str(path.type) == 'BoundaryPathType.EDGE': | |
| # Handle EDGE type HATCH | |
| vert = [] | |
| for edge in path.edges: | |
| x, y = edge.start | |
| x1, y1 = edge.end | |
| vert.append((x * FinalRatio, y * FinalRatio)) | |
| vert.append((x1 * FinalRatio, y1 * FinalRatio)) | |
| poly = ShapelyPolygon(vert) | |
| minx, miny, maxx, maxy = poly.bounds | |
| width = maxx - minx | |
| height = maxy - miny | |
| if (poly.area > 0.9 and (height > 0.7 and width > 0.7)): | |
| area1 = round(poly.area, 3) | |
| perimeter = round(poly.length, 3) | |
| normalized_vertices = normalize_vertices(vert) | |
| rgb_color = get_hatch_color(entity) | |
| if(rgb_color == (255, 255, 255)): | |
| if(len(text_with_positions)>0): | |
| for text, position, color in text_with_positions: | |
| text_position = Point(position[0], position[1]) | |
| if poly.contains(text_position): | |
| rgb_color = color | |
| break | |
| duplicate_found = False | |
| for existing_vertices, existing_area in unique_shapes: | |
| if normalized_vertices == existing_vertices and areas_are_similar(area1, existing_area): | |
| duplicate_found = True | |
| break | |
| if not duplicate_found: | |
| # rgb_color = get_hatch_color(entity) # Assuming this function exists | |
| unique_shapes.append((normalized_vertices, area1)) | |
| hatched_areas.append([vert, area1, perimeter, rgb_color]) | |
| else: | |
| print(f"Unhandled path type: {path.type}") | |
| elif entity.dxftype() == 'SOLID': | |
| vertices = [entity.dxf.vtx0 * (FinalRatio), entity.dxf.vtx1* (FinalRatio), entity.dxf.vtx2* (FinalRatio), entity.dxf.vtx3* (FinalRatio)] | |
| poly = ShapelyPolygon(vertices) | |
| minx, miny, maxx, maxy = poly.bounds | |
| # Calculate the width and height of the bounding box | |
| width = maxx - minx | |
| height = maxy - miny | |
| if (poly.area > 0.9 and (height > 0.7 and width > 0.7)): | |
| area1 = round(poly.area, 3) | |
| perimeter = round(poly.length, 3) | |
| normalized_vertices = normalize_vertices(vertices) | |
| duplicate_found = False | |
| for existing_vertices, existing_area in unique_shapes: | |
| if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area): | |
| duplicate_found = True | |
| break | |
| if not duplicate_found: | |
| rgb_color = get_hatch_color(entity) # Assuming this function exists | |
| unique_shapes.append((normalized_vertices, area1)) | |
| hatched_areas.append([vertices, area1, perimeter, rgb_color]) | |
| elif entity.dxftype() == 'LWPOLYLINE': | |
| vertices = [] | |
| lwpolyline = entity | |
| points = lwpolyline.get_points() | |
| flag = 0 | |
| # Collect vertices and apply the FinalRatio | |
| for i in range(len(points)): | |
| vertices.append([points[i][0] * FinalRatio, points[i][1] * FinalRatio]) | |
| # # Ensure there are more than 3 vertices | |
| if len(vertices) > 3: | |
| # Check if the polyline is closed | |
| if vertices[0][0] == vertices[-1][0] or vertices[0][1] == vertices[-1][1]: | |
| poly = ShapelyPolygon(vertices) | |
| minx, miny, maxx, maxy = poly.bounds | |
| # Calculate width and height of the bounding box | |
| width = maxx - minx | |
| height = maxy - miny | |
| # Check area and size constraints | |
| if (poly.area > 0.9 and (height > 0.7 and width > 0.7)): | |
| area1 = round(poly.area, 3) | |
| perimeter = round(poly.length, 3) | |
| normalized_vertices = normalize_vertices(vertices) | |
| duplicate_found = False | |
| for existing_vertices, existing_area in unique_shapes: | |
| if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area): | |
| duplicate_found = True | |
| break | |
| if not duplicate_found: | |
| rgb_color = get_hatch_color(entity) # Assuming this function exists | |
| unique_shapes.append((normalized_vertices, area1)) | |
| hatched_areas.append([vertices, area1, perimeter, rgb_color]) | |
| elif entity.dxftype() == 'POLYLINE': | |
| # print("In POLYLINE") | |
| flag=0 | |
| vertices = [(v.dxf.location.x * (FinalRatio), v.dxf.location.y * (FinalRatio)) for v in entity.vertices] | |
| # print('Vertices:', vertices) | |
| if(len(vertices)>3): | |
| if(vertices[0][0] == vertices[len(vertices)-1][0] or vertices[0][1] == vertices[len(vertices)-1][1]): | |
| poly=ShapelyPolygon(vertices) | |
| minx, miny, maxx, maxy = poly.bounds | |
| # Calculate the width and height of the bounding box | |
| width = maxx - minx | |
| height = maxy - miny | |
| if (poly.area > 0.9 and (height > 0.7 and width > 0.7)): | |
| area1 = round(poly.area,3) | |
| perimeter = round (poly.length,3) | |
| normalized_vertices = normalize_vertices(vertices) | |
| duplicate_found = False | |
| for existing_vertices, existing_area in unique_shapes: | |
| if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area): | |
| duplicate_found = True | |
| break | |
| if not duplicate_found: | |
| rgb_color = get_hatch_color(entity) # Assuming this function exists | |
| unique_shapes.append((normalized_vertices, area1)) | |
| hatched_areas.append([vertices, area1, perimeter, rgb_color]) | |
| elif entity.dxftype() == 'SPLINE': | |
| spline_entity = entity | |
| vertices = [] | |
| control_points = spline_entity.control_points | |
| if(len(control_points)>3): | |
| for i in range(len(control_points)): | |
| vertices.append([control_points[i][0]* (FinalRatio),control_points[i][1]* (FinalRatio)]) | |
| poly=ShapelyPolygon(vertices) | |
| minx, miny, maxx, maxy = poly.bounds | |
| # Calculate the width and height of the bounding box | |
| width = maxx - minx | |
| height = maxy - miny | |
| if (poly.area > 0.9 and (height > 0.7 and width > 0.7)): | |
| area1 = round(poly.area,3) | |
| perimeter = round (poly.length,3) | |
| normalized_vertices = normalize_vertices(vertices) | |
| duplicate_found = False | |
| for existing_vertices, existing_area in unique_shapes: | |
| if normalized_vertices == existing_vertices or areas_are_similar(area1, existing_area): | |
| duplicate_found = True | |
| break | |
| if not duplicate_found: | |
| rgb_color = get_hatch_color(entity) # Assuming this function exists | |
| unique_shapes.append((normalized_vertices, area1)) | |
| hatched_areas.append([vertices, area1, perimeter, rgb_color]) | |
| sorted_data = sorted(hatched_areas, key=lambda x: x[1]) | |
| return sorted_data | |
| """### Rotate polygon""" | |
| def rotate_point(point, angle,pdfrotation,width,height, center_point=(0, 0)): | |
| """Rotates a point around center_point(origin by default) | |
| Angle is in degrees. | |
| Rotation is counter-clockwise | |
| """ | |
| angle_rad = radians(angle % 360) | |
| # Shift the point so that center_point becomes the origin | |
| new_point = (point[0] - center_point[0], point[1] - center_point[1]) | |
| new_point = (new_point[0] * cos(angle_rad) - new_point[1] * sin(angle_rad), | |
| new_point[0] * sin(angle_rad) + new_point[1] * cos(angle_rad)) | |
| # Reverse the shifting we have done | |
| if pdfrotation!=0: | |
| new_point = (new_point[0]+width + center_point[0], new_point[1] + center_point[1]) #pdfsize[2] is the same as +width | |
| else: | |
| new_point = (new_point[0] + center_point[0], new_point[1]+ height + center_point[1]) # pdfsize[3] is the same as +height | |
| # new_point = (new_point[0] + center_point[0], new_point[1] + center_point[1]) | |
| return new_point | |
| def rotate_polygon(polygon, angle, pdfrotation,width,height,center_point=(0, 0)): | |
| """Rotates the given polygon which consists of corners represented as (x,y) | |
| around center_point (origin by default) | |
| Rotation is counter-clockwise | |
| Angle is in degrees | |
| """ | |
| rotated_polygon = [] | |
| for corner in polygon: | |
| rotated_corner = rotate_point(corner, angle,pdfrotation,width,height, center_point) | |
| rotated_polygon.append(rotated_corner) | |
| return rotated_polygon | |
| #create a dataframe containing color , count(how many times is this object found in the plan), area of 1 of these shapes, total area | |
| #perimeter, totat perimeter, length, total length | |
| #import pandas as pd | |
| #SimilarAreaDictionary= pd.DataFrame(columns=['Guess','Color','Occurences','Area','Total Area','Perimeter','Total Perimeter','Length','Total Length','R','G','B']) | |
| #loop 3la hatched areas and count the occurences of each shape w create a table bl hagat di | |
| def Create_DF(dxfpath,datadoc,hatched_areas): | |
| FinalRatio= RetriveRatio(datadoc,dxfpath) | |
| # hatched_areas = get_hatched_areas(dxfpath,FinalRatio) | |
| # print('hatched_areas',hatched_areas) | |
| # hatched_areas=remove_duplicate_shapes(new_hatched_areas) | |
| # SimilarAreaDictionary= pd.DataFrame(columns=['Area', 'Total Area', 'Perimeter', 'Total Perimeter', 'Occurences', 'Color']) | |
| SimilarAreaDictionary= pd.DataFrame(columns=['Guess','Color','Occurences','Area','Total Area','Perimeter','Total Perimeter','Length','Total Length','Texts','Comments']) | |
| # colorRanges2=generate_color_array(30000) | |
| # 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]] | |
| # colorUsed=[] | |
| TotalArea=0 | |
| TotalPerimeter=0 | |
| for shape in hatched_areas: | |
| area = shape[1] # area | |
| perimeter = shape[2] # perimeter | |
| # if(i < len(colorRanges)): | |
| # color = colorRanges[i] | |
| # colorUsed.append(color) | |
| # else: | |
| # color = colorRanges2[i] | |
| # colorUsed.append(color) | |
| TotalArea = area | |
| TotalPerimeter = perimeter | |
| tol=0 | |
| condition1 = (SimilarAreaDictionary['Area'] >= area - tol) & (SimilarAreaDictionary['Area'] <= area +tol) | |
| condition2 = (SimilarAreaDictionary['Perimeter'] >= perimeter -tol) & (SimilarAreaDictionary['Perimeter'] <= perimeter +tol) | |
| combined_condition = condition1 & condition2 | |
| if any(combined_condition): | |
| index = np.where(combined_condition)[0][0] | |
| SimilarAreaDictionary.at[index, 'Occurences'] += 1 | |
| SimilarAreaDictionary.at[index, 'Total Area'] = SimilarAreaDictionary.at[index, 'Total Area'] + area | |
| SimilarAreaDictionary.at[index, 'Total Perimeter'] = SimilarAreaDictionary.at[index, 'Total Perimeter'] + perimeter | |
| else: | |
| TotalArea=area | |
| TotalPerimeter=perimeter | |
| 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 | |
| SimilarAreaDictionary = pd.concat([SimilarAreaDictionary, pd.DataFrame([new_data])], ignore_index=True) | |
| # print(SimilarAreaDictionary) | |
| return SimilarAreaDictionary | |
| """### Draw on Image and PDF""" | |
| def adjustannotations(OutputPdfStage1): | |
| input_pdf_path = OutputPdfStage1 | |
| output_pdf_path = "AnnotationAdjusted.pdf" | |
| # Load the input PDF | |
| pdf_bytes_io = BytesIO(OutputPdfStage1) | |
| reader = PdfReader(pdf_bytes_io) | |
| writer = PdfWriter() | |
| # Append all pages to the writer | |
| writer.append_pages_from_reader(reader) | |
| # Add metadata (optional) | |
| metadata = reader.metadata | |
| writer.add_metadata(metadata) | |
| # Iterate over pages | |
| for page_index, page in enumerate(writer.pages): | |
| # page.update({ | |
| # NameObject("/UserUnit"): FloatObject(1.0), # 1 unit = 1 real-world unit (e.g., 1 meter) | |
| # NameObject("/VP"): ArrayObject([ | |
| # DictionaryObject({ | |
| # NameObject("/Type"): NameObject("/Viewport"), | |
| # NameObject("/BBox"): ArrayObject([ | |
| # FloatObject(0), FloatObject(0), FloatObject(1000), FloatObject(1000) | |
| # ]), # Bounding box for the viewport | |
| # NameObject("/Measure"): DictionaryObject({ | |
| # NameObject("/Type"): NameObject("/Measure"), | |
| # NameObject("/Subtype"): NameObject("/RL"), | |
| # NameObject("/X"): FloatObject(1), | |
| # NameObject("/Y"): FloatObject(1), | |
| # NameObject("/U"): TextStringObject("m"), # Units (meters) | |
| # }), | |
| # }) | |
| # ]) | |
| # }) | |
| if "/Annots" in page: | |
| annotations = page["/Annots"] | |
| for annot_index, annot in enumerate(annotations): | |
| obj = annot.get_object() | |
| print("obj", obj) | |
| # print(obj.get("/IT")) | |
| if obj.get("/Subtype") == "/Polygon": | |
| print("AWL ANNOT IF") | |
| # Check the /IT value to differentiate annotations | |
| if "/Contents" in obj and "sq m" in obj["/Contents"]: | |
| print("Tany IF") | |
| obj.update({ | |
| NameObject("/Measure"): DictionaryObject({ | |
| NameObject("/Type"): NameObject("/Measure"), | |
| NameObject("/Area"): DictionaryObject({ | |
| NameObject("/G"): FloatObject(1), | |
| NameObject("/U"): TextStringObject("sq m"), # Unit of measurement for area | |
| }), | |
| NameObject("/X"): FloatObject(1), # Horizontal scale (e.g., 1 unit = 1 meter) | |
| NameObject("/Y"): FloatObject(1), # Vertical scale | |
| }), | |
| NameObject("/IT"): NameObject("/Area_Annotation"), # Use more distinctive name | |
| NameObject("/Subj"): TextStringObject("Area Measurement"), # Intent explicitly for Area | |
| }) | |
| print("After Update:", obj) | |
| # # Save the modified PDF | |
| output_pdf_io = BytesIO() | |
| writer.write(output_pdf_io) | |
| output_pdf_io.seek(0) | |
| return output_pdf_io.read() | |
| # writer.write(new_bytes_object) # This writes the modified PDF data to new_bytes_object | |
| # new_bytes_object.seek(0) | |
| # return new_bytes_object.read() | |
| # def adjustannotations(OutputPdfStage1): | |
| # """ | |
| # Adjusts annotations in the PDF to include measurement and scale information. | |
| # Parameters: | |
| # OutputPdfStage1 (str): Path to the input PDF file. | |
| # Returns: | |
| # bytes: The adjusted PDF data as bytes. | |
| # """ | |
| # with open(OutputPdfStage1, "rb") as pdf_file: | |
| # reader = PdfReader(pdf_file) | |
| # writer = PdfWriter() | |
| # # Append all pages from reader to writer | |
| # writer.append_pages_from_reader(reader) | |
| # # Iterate over pages and add measurement details | |
| # for page_index, page in enumerate(writer.pages): | |
| # # Add scale settings at the page level | |
| # # page.update({ | |
| # # NameObject("/UserUnit"): FloatObject(1.0), # 1 unit = 1 real-world unit | |
| # # NameObject("/VP"): ArrayObject([ | |
| # # DictionaryObject({ | |
| # # NameObject("/Type"): NameObject("/Viewport"), | |
| # # NameObject("/BBox"): ArrayObject([ | |
| # # FloatObject(0), FloatObject(0), FloatObject(100), FloatObject(100) | |
| # # ]), # Bounding box for the viewport | |
| # # NameObject("/Measure"): DictionaryObject({ | |
| # # NameObject("/Type"): NameObject("/Measure"), | |
| # # NameObject("/Subtype"): NameObject("/RL"), | |
| # # NameObject("/X"): FloatObject(1), # Horizontal scale | |
| # # NameObject("/Y"): FloatObject(1), # Vertical scale | |
| # # NameObject("/U"): TextStringObject("m"), # Units (meters) | |
| # # }), | |
| # # }) | |
| # # ]) | |
| # # }) | |
| # # Process annotations | |
| # if "/Annots" in page: | |
| # annotations = page["/Annots"] | |
| # for annot in annotations: | |
| # obj = annot.get_object() | |
| # # Adjust polygon annotations with area measurements | |
| # if obj.get("/Subtype") == "/Polygon" and "/Contents" in obj and "sq m" in obj["/Contents"]: | |
| # obj.update({ | |
| # NameObject("/Measure"): DictionaryObject({ | |
| # NameObject("/Type"): NameObject("/Measure"), | |
| # NameObject("/Area"): DictionaryObject({ | |
| # NameObject("/G"): FloatObject(1), | |
| # NameObject("/U"): TextStringObject("sq m"), # Area unit | |
| # }), | |
| # NameObject("/X"): FloatObject(1), # Horizontal scale | |
| # NameObject("/Y"): FloatObject(1), # Vertical scale | |
| # NameObject("/U"): TextStringObject("m"), # Units (meters) | |
| # }), | |
| # NameObject("/IT"): NameObject("/Area_Annotation"), | |
| # NameObject("/Subj"): TextStringObject("Area Measurement"), | |
| # }) | |
| # print(obj) | |
| # output_pdf_io = BytesIO() | |
| # writer.write(output_pdf_io) | |
| # output_pdf_io.seek(0) # Ensure buffer is at the start | |
| # return output_pdf_io | |
| def mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio,pdfpath=0,pdfname=0): | |
| OutputPdfStage1='BB Trial.pdf' | |
| FinalRatio= RetriveRatio(datadoc,dxfpath) | |
| # hatched_areas = get_hatched_areas(dxfpath,FinalRatio) | |
| # hatched_areas=remove_duplicate_shapes(new_hatched_areas) | |
| img=pdftoimg(datadoc) | |
| flipped_horizontal=flip(img) | |
| allcnts = [] | |
| imgg = flipped_horizontal | |
| # imgtransparent1=imgg.copy() | |
| doc = fitz.open('pdf',datadoc) | |
| page2 = doc[0] | |
| rotationOld=page2.rotation | |
| derotationMatrix=page2.derotation_matrix | |
| pix=page2.get_pixmap() | |
| width=abs(page2.mediabox[2])+abs(page2.mediabox[0]) | |
| height=abs(page2.mediabox[3])+abs(page2.mediabox[1]) | |
| print('mediabox', width , height) | |
| if page2.rotation!=0: | |
| rotationangle = page2.rotation | |
| page2.set_rotation(0) | |
| ratio = pix.width/ img.shape[0] | |
| else: | |
| ratio = pix.width/ img.shape[1] | |
| rotationangle = 270 | |
| hatched_areas = get_hatched_areas(datadoc,dxfpath,FinalRatio,rotationangle) | |
| allshapes=[] | |
| # Iterate through each polygon in metric units | |
| NewColors = [] | |
| SimilarAreaDictionary=Create_DF(dxfpath,datadoc,hatched_areas) | |
| i=0 | |
| flagcolor = 0 | |
| ColorCheck=[] | |
| for polygon in hatched_areas: | |
| cntPoints = [] | |
| cntPoints1 = [] | |
| shapeePerimeter = [] | |
| shapeeArea = [] | |
| blackImgShapes = np.zeros(imgg.shape[:2], dtype="uint8") | |
| blackImgShapes= cv2.cvtColor(blackImgShapes, cv2.COLOR_GRAY2BGR) | |
| # Convert each vertex from metric to pixel coordinates | |
| for vertex in polygon[0]: | |
| x = (vertex[0]) *dxfratio | |
| y = (vertex[1]) *dxfratio | |
| if rotationangle==0: | |
| if y<0: | |
| y=y*-1 | |
| cntPoints.append([int(x), int(y)]) | |
| cntPoints1.append([x, y]) | |
| cv2.drawContours(blackImgShapes, [np.array(cntPoints)], -1, ([255,255,255]), thickness=-1) | |
| x, y, w, h = cv2.boundingRect(np.array(cntPoints)) | |
| firstpoint = 0 | |
| for poi in np.array(cntPoints1): | |
| if firstpoint == 0: | |
| x2, y2 = poi | |
| p2 = fitz.Point(x2,y2) | |
| # p1 = fitz.Point(x1,y1) | |
| p2=p2*derotationMatrix | |
| shapeePerimeter.append([p2[0],p2[1]]) | |
| firstpoint = 1 | |
| else: | |
| x1, y1 = poi | |
| p1 = fitz.Point(x1,y1) | |
| # p1 = fitz.Point(x1,y1) | |
| p1=p1*derotationMatrix | |
| print("P1 = ",p1) | |
| shapeePerimeter.append([p1[0],p1[1]]) | |
| shapeePerimeter.append([p2[0],p2[1]]) | |
| shapeePerimeter=np.flip(shapeePerimeter,1) | |
| shapeePerimeter=rotate_polygon(shapeePerimeter,rotationangle,rotationOld,width,height) | |
| for poi in np.array(cntPoints1): | |
| x1, y1 = poi | |
| p1 = fitz.Point(x1,y1) | |
| # p1 = fitz.Point(x1,y1) | |
| p1=p1*derotationMatrix | |
| print("P1 = ",p1) | |
| shapeeArea.append([p1[0],p1[1]]) | |
| shapeeArea.append([p2[0],p2[1]]) | |
| shapeeArea=np.flip(shapeeArea,1) | |
| shapeeArea=rotate_polygon(shapeeArea,rotationangle,rotationOld,width,height) | |
| tol=0 | |
| condition1 = (SimilarAreaDictionary['Area'] >= polygon[1] - tol) & (SimilarAreaDictionary['Area'] <= polygon[1] +tol) | |
| condition2 = (SimilarAreaDictionary['Perimeter'] >= polygon[2] -tol) & (SimilarAreaDictionary['Perimeter'] <= polygon[2] +tol) | |
| combined_condition = condition1 & condition2 | |
| if any(combined_condition): | |
| flagcolor = 1 | |
| index = np.where(combined_condition)[0][0] | |
| # print(SimilarAreaDictionary.at[index, 'Color']) | |
| NewColors=SimilarAreaDictionary.at[index, 'Color'] | |
| else: | |
| flagcolor = 2 | |
| NewColors=SimilarAreaDictionary.at[i, 'Color'] | |
| if(int(NewColors[0])==255 and int(NewColors[1])==255 and int(NewColors[2])==255): | |
| WhiteImgFinal = cv2.bitwise_and(blackImgShapes,imgg) | |
| flipped=flip(WhiteImgFinal) | |
| imgslice = WhiteImgFinal[y:y+h, x:x+w] | |
| if(imgslice.shape[0] != 0 and imgslice.shape[1] != 0): | |
| flippedSlice=flip(imgslice) | |
| # Convert flippedSlice to PIL for color extraction | |
| flippedSlice_pil = Image.fromarray(flippedSlice) | |
| # Define patch size for color sampling (e.g., 10x10 pixels) | |
| patch_size = 100 | |
| patch_colors = [] | |
| # Loop through patches in the image | |
| for i in range(0, flippedSlice_pil.width, patch_size): | |
| for j in range(0, flippedSlice_pil.height, patch_size): | |
| # Crop a patch from the original image | |
| patch = flippedSlice_pil.crop((i, j, i + patch_size, j + patch_size)) | |
| patch_colors += patch.getcolors(patch_size * patch_size) | |
| # Calculate the dominant color from all patches | |
| max_count = 0 | |
| dominant_color = None | |
| tolerance = 5 | |
| black_threshold = 30 # Max RGB value for a color to be considered "black" | |
| white_threshold = 225 # Min RGB value for a color to be considered "white" | |
| for count, color in patch_colors: | |
| # Exclude colors within the black and white ranges | |
| if not (all(c <= black_threshold for c in color) or all(c >= white_threshold for c in color)): | |
| # Update if the current color has a higher count than previous max | |
| if count > max_count: | |
| max_count = count | |
| dominant_color = color | |
| # Append dominant color to ColorCheck and update NewColors | |
| if dominant_color is not None: | |
| ColorCheck.append(dominant_color) | |
| NewColors = None | |
| for color in ColorCheck: | |
| # Check if the current color is within the tolerance | |
| print("color = ",color) | |
| print("dominant_color = ",dominant_color) | |
| if (abs(color[0] - dominant_color[0]) < 20 and | |
| abs(color[1] - dominant_color[1]) < 20 and | |
| abs(color[2] - dominant_color[2]) < 20): | |
| NewColors = (color[2], color[1], color[0]) # Set the new color | |
| break | |
| else: | |
| # If no color in ColorCheck meets the tolerance, use the dominant color | |
| NewColors = (dominant_color[2], dominant_color[1], dominant_color[0]) | |
| if NewColors not in ColorCheck: | |
| ColorCheck.append(NewColors) | |
| if flagcolor == 1: | |
| SimilarAreaDictionary.at[index, 'Color'] = NewColors | |
| # print(f"Updated Color at index {index} with {NewColors}.") | |
| elif flagcolor == 2: | |
| SimilarAreaDictionary.at[i, 'Color'] = NewColors | |
| cv2.drawContours(imgg, [np.array(cntPoints)], -1, ([NewColors[2],NewColors[1],NewColors[0]]), thickness=-1) | |
| annot11 = page2.add_polygon_annot( points=shapeeArea) # 'Polygon' | |
| annot11.set_border(width=0.2) | |
| 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) ) | |
| annot11.set_info(content=str(polygon[1])+' sq m',subject='Area Measurement', title="ADR Team") | |
| annot11.set_opacity(0.8) | |
| # annot.set_line_ends(fitz.PDF_ANNOT_LE_DIAMOND, fitz.PDF_ANNOT_LE_CIRCLE) | |
| annot11.update() | |
| annot12 = page2.add_polyline_annot( points=shapeePerimeter ) # 'Polygon' | |
| annot12.set_border(width=0.8) | |
| annot12.set_colors(stroke=(int(NewColors[0])/255,int(NewColors[1])/255,int(NewColors[2])/255)) | |
| annot12.set_info(content=str(polygon[2])+' m',subject='Perimeter Measurement', title="ADR Team") | |
| annot12.set_opacity(0.8) | |
| # annot.set_line_ends(fitz.PDF_ANNOT_LE_DIAMOND, fitz.PDF_ANNOT_LE_CIRCLE) | |
| annot12.update() | |
| i += 1 | |
| alpha = 0.8 # Transparency factor. | |
| page2.set_rotation(rotationOld) | |
| Correct_img=flip(imgg) | |
| image_new1 = cv2.addWeighted(Correct_img, alpha, img, 1 - alpha, 0) | |
| SimilarAreaDictionary = SimilarAreaDictionary.fillna(' ') | |
| # Define white color to filter out | |
| white_color = (255, 255, 255) | |
| # Delete rows where 'Guess' equals white_color | |
| SimilarAreaDictionary = SimilarAreaDictionary[SimilarAreaDictionary['Color'] != white_color] | |
| # Reset the index to update row numbering | |
| SimilarAreaDictionary.reset_index(drop=True, inplace=True) | |
| grouped_df = SimilarAreaDictionary.groupby('Color').agg({ | |
| 'Guess':'first', | |
| 'Occurences': 'sum', # Sum of occurrences for each color | |
| 'Area':'first', | |
| 'Total Area': 'sum', # Sum of areas for each color | |
| 'Perimeter':'first', | |
| 'Total Perimeter': 'sum', # Sum of perimeters for each color | |
| 'Length':'first', | |
| 'Total Length':'first', | |
| 'Texts':'first', | |
| 'Comments':'first' | |
| }).reset_index() | |
| SimilarAreaDictionary = grouped_df | |
| # doc.save(OutputPdfStage1) | |
| modified_pdf_data = doc.tobytes() | |
| OutputPdfStage2=adjustannotations(modified_pdf_data) | |
| # with open("Adjusted_PDF.pdf", "wb") as f: | |
| # f.write(OutputPdfStage2) | |
| # doc2 = fitz.open(stream=OutputPdfStage2, filetype="pdf") | |
| # doc2 = fitz.open(stream=OutputPdfStage2, filetype="pdf") | |
| doc2 =fitz.open('pdf',OutputPdfStage2) | |
| gc,spreadsheet_service,spreadsheetId, spreadsheet_url , namepathArr=google_sheet_Legend.legendGoogleSheets(SimilarAreaDictionary , pdfname,pdfpath) | |
| # dbxTeam=tsadropboxretrieval.ADR_Access_DropboxTeam('user') | |
| # md, res =dbxTeam.files_download(path= pdfpath+pdfname) | |
| # data = res.content | |
| # doc=fitz.open("pdf", data) | |
| # list1=pd.DataFrame(columns=['content', 'creationDate', 'id', 'modDate', 'name', 'subject', 'title']) | |
| list1=pd.DataFrame(columns=['content', 'id', 'subject','color']) | |
| # for page in doc: | |
| for page in doc2: | |
| # Iterate through annotations on the page | |
| for annot in page.annots(): | |
| # Get the color of the annotation | |
| annot_color = annot.colors | |
| if annot_color is not None: | |
| # annot_color is a dictionary with 'stroke' and 'fill' keys | |
| stroke_color = annot_color.get('stroke') # Border color | |
| fill_color = annot_color.get('fill') # Fill color | |
| if fill_color: | |
| v='fill' | |
| # print('fill') | |
| if stroke_color: | |
| v='stroke' | |
| x,y,z=int(annot_color.get(v)[0]*255),int(annot_color.get(v)[1]*255),int(annot_color.get(v)[2]*255) | |
| list1.loc[len(list1)] =[annot.info['content'],annot.info['id'],annot.info['subject'],[x,y,z]] | |
| print('LISTTT',list1) | |
| return doc2,image_new1, SimilarAreaDictionary ,spreadsheetId, spreadsheet_url , namepathArr , list1,hatched_areas | |
| # doc.save('Testing(2.7).pdf') | |
| # return doc,image_new1#, SimilarAreaDictionary ,spreadsheetId, spreadsheet_url , namepathArr , list1,hatched_areas | |
| # datadoc='/content/3.3 - Ceiling finishes - Example 1 - Sheet 1.pdf' #pdf path here | |
| # dxfpath='/content/3.3 - Ceiling finishes - Example 1 - Sheet 1.dxf'#dxfpath here | |
| # dxfratio=28.3464527867108 | |
| # doc,image_new1=mainFunctionDrawImgPdf(datadoc,dxfpath, dxfratio) | |
| # cv2_imshow(image_new1) | |