snapmark 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snapmark/__init__.py +165 -0
- snapmark/checking/__init__.py +0 -0
- snapmark/checking/checking.py +183 -0
- snapmark/core.py +154 -0
- snapmark/entities/__init__.py +0 -0
- snapmark/entities/add_entities.py +120 -0
- snapmark/mark_algorithm/__init__.py +0 -0
- snapmark/mark_algorithm/mark_algorithm.py +668 -0
- snapmark/operations/__init__.py +0 -0
- snapmark/operations/aligner.py +303 -0
- snapmark/operations/basic_operations.py +361 -0
- snapmark/operations/counter.py +172 -0
- snapmark/sequence/__init__.py +0 -0
- snapmark/sequence/sequence_legacy.py +141 -0
- snapmark/sequence/sequence_system.py +337 -0
- snapmark/shortcuts.py +183 -0
- snapmark/utils/__init__.py +0 -0
- snapmark/utils/backup_manager.py +161 -0
- snapmark/utils/helpers.py +64 -0
- snapmark/utils/segments_dict.py +44 -0
- snapmark-2.0.0.dist-info/METADATA +95 -0
- snapmark-2.0.0.dist-info/RECORD +25 -0
- snapmark-2.0.0.dist-info/WHEEL +5 -0
- snapmark-2.0.0.dist-info/licenses/LICENSE +21 -0
- snapmark-2.0.0.dist-info/top_level.txt +1 -0
snapmark/__init__.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SnapMark - Library for marking and manipulating DXF files.
|
|
3
|
+
|
|
4
|
+
Basic Usage:
|
|
5
|
+
import snapmark as sm
|
|
6
|
+
|
|
7
|
+
# Quick mark by file name
|
|
8
|
+
sm.mark_by_name("Examples/Input")
|
|
9
|
+
|
|
10
|
+
# Mark folder
|
|
11
|
+
sm.Operation.process_folder("folder", mark)
|
|
12
|
+
|
|
13
|
+
# Multiple pipeline example
|
|
14
|
+
manager = sm.IterationManager("folder")
|
|
15
|
+
manager.add_operation(
|
|
16
|
+
sm.Aligner(),
|
|
17
|
+
sm.AddMark(sequence),
|
|
18
|
+
sm.CountHoles(sm.find_circle_by_radius(5, 10))
|
|
19
|
+
)
|
|
20
|
+
manager.execute()
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# ========== CORE: Main operations ==========
|
|
24
|
+
from .operations.basic_operations import (
|
|
25
|
+
Operation,
|
|
26
|
+
AddMark,
|
|
27
|
+
SubstituteCircle,
|
|
28
|
+
AddX,
|
|
29
|
+
RemoveCircle,
|
|
30
|
+
RemoveLayer,
|
|
31
|
+
PrintLayers,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
from .operations.counter import (
|
|
35
|
+
Counter,
|
|
36
|
+
CountFiles,
|
|
37
|
+
CountHoles,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
from .operations.aligner import Aligner
|
|
41
|
+
|
|
42
|
+
# ========== SEQUENCE (NEW SYSTEM) ==========
|
|
43
|
+
from .sequence.sequence_system import (
|
|
44
|
+
SequenceBuilder,
|
|
45
|
+
from_file_name,
|
|
46
|
+
from_splitted_text
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# ========== SEQUENCE (OLD - DEPRECATED) ==========
|
|
50
|
+
from .sequence.sequence_legacy import (
|
|
51
|
+
Conc,
|
|
52
|
+
FixSeq,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# ========== SHORTCUTS ==========
|
|
56
|
+
from .shortcuts import (
|
|
57
|
+
mark_by_name,
|
|
58
|
+
mark_by_splitted_text,
|
|
59
|
+
mark_with_sequence,
|
|
60
|
+
quick_count_holes,
|
|
61
|
+
single_file_pipeline,
|
|
62
|
+
restore_backup
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ========== ITERATION MANAGER ==========
|
|
67
|
+
from .core import IterationManager, iteration_manager # iteration_manager = alias legacy
|
|
68
|
+
|
|
69
|
+
# ========== UTILITIES ==========
|
|
70
|
+
from .utils.backup_manager import BackupManager
|
|
71
|
+
from .utils.helpers import (
|
|
72
|
+
count_holes,
|
|
73
|
+
find_all_circles,
|
|
74
|
+
find_circle_by_radius,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# ========== CHECKING/SEARCH ==========
|
|
78
|
+
from .checking.checking import (
|
|
79
|
+
find_spec_holes,
|
|
80
|
+
find_circle_centers,
|
|
81
|
+
find_longer_entity,
|
|
82
|
+
print_layers as print_document_layers,
|
|
83
|
+
print_entities,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# ========== METADATA ==========
|
|
88
|
+
__version__ = "2.0.0"
|
|
89
|
+
__author__ = "serg_you_lin"
|
|
90
|
+
__all__ = [
|
|
91
|
+
# Shortcuts (main API)
|
|
92
|
+
'mark_by_name',
|
|
93
|
+
'mark_by_splitted_text',
|
|
94
|
+
'mark_with_sequence',
|
|
95
|
+
'quick_count_holes',
|
|
96
|
+
'single_file_pipeline',
|
|
97
|
+
'restore_backup',
|
|
98
|
+
|
|
99
|
+
# Sequence Builder
|
|
100
|
+
'SequenceBuilder',
|
|
101
|
+
'from_file_name',
|
|
102
|
+
'from_file_part',
|
|
103
|
+
|
|
104
|
+
# Operations
|
|
105
|
+
'Operation',
|
|
106
|
+
'AddMark',
|
|
107
|
+
'AddCircle',
|
|
108
|
+
'SubstituteCircle',
|
|
109
|
+
'AddX',
|
|
110
|
+
'RemoveCircle',
|
|
111
|
+
'RemoveLayer',
|
|
112
|
+
'PrintLayers',
|
|
113
|
+
'Counter',
|
|
114
|
+
'CountFiles',
|
|
115
|
+
'CountHoles',
|
|
116
|
+
'Aligner',
|
|
117
|
+
|
|
118
|
+
# Manager
|
|
119
|
+
'IterationManager',
|
|
120
|
+
'iteration_manager', # Alias legacy
|
|
121
|
+
|
|
122
|
+
# Utils
|
|
123
|
+
'BackupManager',
|
|
124
|
+
'count_holes',
|
|
125
|
+
'mult_campana',
|
|
126
|
+
'find_all_circles',
|
|
127
|
+
'find_circle_by_radius',
|
|
128
|
+
|
|
129
|
+
# Checking
|
|
130
|
+
'find_spec_holes',
|
|
131
|
+
'find_circle_centers',
|
|
132
|
+
'find_longer_entity',
|
|
133
|
+
'print_document_layers',
|
|
134
|
+
'print_entities',
|
|
135
|
+
|
|
136
|
+
# DEPRECATED (manteinence to backward compatibility)
|
|
137
|
+
'Conc',
|
|
138
|
+
'FixSeq',
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# ========== DEPRECATION WARNINGS ==========
|
|
144
|
+
|
|
145
|
+
def __getattr__(name):
|
|
146
|
+
"""
|
|
147
|
+
Manages import of deprecated functions with warning.
|
|
148
|
+
"""
|
|
149
|
+
import warnings
|
|
150
|
+
|
|
151
|
+
deprecated = {
|
|
152
|
+
'select_files': 'Use file_pattern in process_folder() instead',
|
|
153
|
+
'iter_on_a_folder': 'Use Operation.process_folder() or IterationManager',
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if name in deprecated:
|
|
157
|
+
warnings.warn(
|
|
158
|
+
f"{name} is deprecated. {deprecated[name]}",
|
|
159
|
+
DeprecationWarning,
|
|
160
|
+
stacklevel=2
|
|
161
|
+
)
|
|
162
|
+
# Per ora solleva errore (funzioni rimosse)
|
|
163
|
+
raise AttributeError(f"Deprecated removed function: {name}")
|
|
164
|
+
|
|
165
|
+
raise AttributeError(f"module 'snapmark' has no attribute '{name}'")
|
|
File without changes
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import ezdxf
|
|
4
|
+
from snapmark.mark_algorithm.mark_algorithm import *
|
|
5
|
+
from snapmark.entities.add_entities import *
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Print the names of the layers
|
|
9
|
+
def print_layers(doc):
|
|
10
|
+
# print("Layers:")
|
|
11
|
+
for layer in doc.layers:
|
|
12
|
+
print(layer.dxf.name)
|
|
13
|
+
return print(layer.dxf.name)
|
|
14
|
+
|
|
15
|
+
def find_spec_holes(doc, diametro_minimo=0, diametro_massimo=float('inf')):
|
|
16
|
+
"""
|
|
17
|
+
Searches for specific holes in a document based on diameter range.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
doc: The document containing the entities to search.
|
|
21
|
+
diametro_minimo: Minimum diameter of the holes to find (default: 0).
|
|
22
|
+
diametro_massimo: Maximum diameter of the holes to find (default: infinity).
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
A list of circular entities that match the specified diameter range.
|
|
26
|
+
"""
|
|
27
|
+
holes = [] # List to store circular entities
|
|
28
|
+
|
|
29
|
+
msp = doc.modelspace() # Access the model space of the drawing
|
|
30
|
+
|
|
31
|
+
# Iterate through all entities in the model space
|
|
32
|
+
for entity in msp.query('CIRCLE'): # Filter only entities of type circle
|
|
33
|
+
diameter = entity.dxf.radius * 2 # Calculate the diameter of the circle
|
|
34
|
+
if diametro_minimo <= diameter <= diametro_massimo:
|
|
35
|
+
holes.append(entity)
|
|
36
|
+
# Add the circular entity to the list if it falls within the diameter range
|
|
37
|
+
|
|
38
|
+
return holes
|
|
39
|
+
|
|
40
|
+
# # Cerca fori specifici
|
|
41
|
+
# def find_spec_holes(doc, diametro_minimo=0, diametro_massimo=float('inf')):
|
|
42
|
+
# holes = [] # Lista per memorizzare le entità circolari
|
|
43
|
+
|
|
44
|
+
# msp = doc.modelspace() # Accedi al modello spaziale del disegno
|
|
45
|
+
|
|
46
|
+
# # Itera attraverso tutte le entità nel modello spaziale
|
|
47
|
+
# for entity in msp.query('CIRCLE'): # Filtra solo le entità di tipo cerchio
|
|
48
|
+
# diametro = entity.dxf.radius * 2 # Calcola il diametro del cerchio
|
|
49
|
+
# if diametro_minimo <= diametro <= diametro_massimo:
|
|
50
|
+
# holes.append(entity)
|
|
51
|
+
# # print(entity)# Aggiungi l'entità circolare alla lista se rientra nel range di diametri
|
|
52
|
+
|
|
53
|
+
# return holes
|
|
54
|
+
|
|
55
|
+
def find_entities(file_path, entity_type):
|
|
56
|
+
"""Return a list of DXF entities of the given type from the specified file."""
|
|
57
|
+
# Load DXF file using ezdxf
|
|
58
|
+
doc = ezdxf.readfile(file_path)
|
|
59
|
+
|
|
60
|
+
# extract entities from model
|
|
61
|
+
msp = doc.modelspace()
|
|
62
|
+
|
|
63
|
+
entities = []
|
|
64
|
+
|
|
65
|
+
# Iterate through all entities of the specified type
|
|
66
|
+
for entity in msp.query(entity_type):
|
|
67
|
+
entities.append(entity)
|
|
68
|
+
|
|
69
|
+
return entities
|
|
70
|
+
|
|
71
|
+
def print_entities(msp):
|
|
72
|
+
for e in msp.query():
|
|
73
|
+
print(e)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# def find_longer_entity(entities):
|
|
78
|
+
|
|
79
|
+
# lato_piu_lungo = None
|
|
80
|
+
# lunghezza_lato_piu_lungo = 0
|
|
81
|
+
# lato_piu_lungo_is_sotto = True
|
|
82
|
+
# minimum_point = float('inf')
|
|
83
|
+
# # Itera tutte le linee nel modello
|
|
84
|
+
# for entity in entities:
|
|
85
|
+
# minimum_point = min(entity.dxf.start.y, entity.dxf.end.y, minimum_point)
|
|
86
|
+
# # Calcola la lunghezza della linea utilizzando il teorema di Pitagora
|
|
87
|
+
# lunghezza = ((entity.dxf.start.x - entity.dxf.end.x) ** 2 + (entity.dxf.start.y - entity.dxf.end.y) ** 2) ** 0.5
|
|
88
|
+
# # Se la lunghezza della linea è maggiore della lunghezza massima finora trovata, aggiornala
|
|
89
|
+
# if lunghezza > lunghezza_lato_piu_lungo:
|
|
90
|
+
# lunghezza_lato_piu_lungo = lunghezza
|
|
91
|
+
# lato_piu_lungo = entity
|
|
92
|
+
|
|
93
|
+
# # Controllare che il lato più lungo sia una linea perimetrale
|
|
94
|
+
# if min(lato_piu_lungo.dxf.start.y, lato_piu_lungo.dxf.end.y) > minimum_point:
|
|
95
|
+
# lato_piu_lungo_is_sotto = False
|
|
96
|
+
|
|
97
|
+
# return lato_piu_lungo, lato_piu_lungo_is_sotto
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def find_longer_entity(entities):
|
|
101
|
+
"""
|
|
102
|
+
Finds the longest entity among the given entities and checks if it is below a certain minimum point.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
entities: A list of entities to evaluate.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
A tuple containing the longest entity and a boolean indicating if it is below the minimum point.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
longest_side = None
|
|
112
|
+
longest_side_length = 0
|
|
113
|
+
longest_side_is_below = True
|
|
114
|
+
minimum_point = float('inf')
|
|
115
|
+
|
|
116
|
+
# Iterate through all the lines in the model
|
|
117
|
+
for entity in entities:
|
|
118
|
+
minimum_point = min(entity.dxf.start.y, entity.dxf.end.y, minimum_point)
|
|
119
|
+
# Calculate the length of the line using the Pythagorean theorem
|
|
120
|
+
length = ((entity.dxf.start.x - entity.dxf.end.x) ** 2 + (entity.dxf.start.y - entity.dxf.end.y) ** 2) ** 0.5
|
|
121
|
+
# If the length of the line is greater than the maximum length found so far, update it
|
|
122
|
+
if length > longest_side_length:
|
|
123
|
+
longest_side_length = length
|
|
124
|
+
longest_side = entity
|
|
125
|
+
|
|
126
|
+
# Check if the longest side is a perimeter line
|
|
127
|
+
if min(longest_side.dxf.start.y, longest_side.dxf.end.y) > minimum_point:
|
|
128
|
+
longest_side_is_below = False
|
|
129
|
+
|
|
130
|
+
return longest_side, longest_side_is_below
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def find_circle_centers(holes_list):
|
|
135
|
+
"""
|
|
136
|
+
Finds the centers of circles from a list of holes.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
holes_list: A list of circular entities representing holes.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
A list of tuples containing the (x, y) coordinates of the circle centers.
|
|
143
|
+
"""
|
|
144
|
+
centers = [] # List to store the centers of the circles
|
|
145
|
+
|
|
146
|
+
# Iterate through the circular entities in the holes_list
|
|
147
|
+
for circle in holes_list: # Use the list passed as an argument
|
|
148
|
+
center_x = circle.dxf.center.x # Extract the x coordinate of the circle's center
|
|
149
|
+
center_y = circle.dxf.center.y # Extract the y coordinate of the circle's center
|
|
150
|
+
centers.append((center_x, center_y)) # Add the x and y coordinates of the center to the list
|
|
151
|
+
|
|
152
|
+
return centers
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def find_circle_centers_2(doc):
|
|
156
|
+
"""
|
|
157
|
+
Searches for circles in a document and detects their centers.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
doc: The document containing the entities to search.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
A list of tuples containing the (x, y) coordinates of the circle centers.
|
|
164
|
+
"""
|
|
165
|
+
centers = [] # List to store the centers of the circles
|
|
166
|
+
|
|
167
|
+
msp = doc.modelspace() # Access the model space of the drawing
|
|
168
|
+
|
|
169
|
+
# Iterate through all entities in the model space
|
|
170
|
+
for circle in msp.query('CIRCLE'): # Filter only entities of type circle
|
|
171
|
+
center_x = circle.dxf.center.x # Extract the x coordinate of the circle's center
|
|
172
|
+
center_y = circle.dxf.center.y # Extract the y coordinate of the circle's center
|
|
173
|
+
centers.append((center_x, center_y)) # Add the x and y coordinates of the center to the list
|
|
174
|
+
|
|
175
|
+
return centers
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def change_layer(entities, new_layer):
|
|
179
|
+
for entity in entities:
|
|
180
|
+
entity.set_dxf_attrib('layer', new_layer)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
snapmark/core.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""
|
|
2
|
+
core.py - Core components of SnapMark.
|
|
3
|
+
|
|
4
|
+
Contains IterationManager for multiple batch operations.
|
|
5
|
+
"""
|
|
6
|
+
import os
|
|
7
|
+
import ezdxf
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from snapmark.utils.helpers import find_dxf_files
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from .utils.backup_manager import BackupManager
|
|
13
|
+
BACKUP_AVAILABLE = True
|
|
14
|
+
except ImportError:
|
|
15
|
+
BACKUP_AVAILABLE = False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class IterationManager:
|
|
19
|
+
"""
|
|
20
|
+
Manages applying multiple operations in sequence on DXF files.
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
>>> manager = IterationManager("folder_path")
|
|
24
|
+
>>> manager.add_operation(AddMark(...), CountHoles(...))
|
|
25
|
+
>>> manager.execute()
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, folder_path, use_backup_system=True):
|
|
29
|
+
"""
|
|
30
|
+
Initializes the IterationManager with the specified folder path and backup option.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
folder_path (str): The path of the folder containing the DXF files.
|
|
34
|
+
use_backup_system (bool): If True, uses .bak for backups (recommended).
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
self.folder_path = folder_path
|
|
38
|
+
self.operation_list = []
|
|
39
|
+
self.use_backup_system = use_backup_system and BACKUP_AVAILABLE
|
|
40
|
+
|
|
41
|
+
if use_backup_system and not BACKUP_AVAILABLE:
|
|
42
|
+
print("⚠ BackupManager not available")
|
|
43
|
+
|
|
44
|
+
def add_operation(self, *operations):
|
|
45
|
+
"""Adds operations to the pipeline."""
|
|
46
|
+
for op in operations:
|
|
47
|
+
self.operation_list.append(op)
|
|
48
|
+
|
|
49
|
+
def execute(self, file_pattern="*.dxf", recursive=False):
|
|
50
|
+
"""
|
|
51
|
+
Executes all operations on the files in the specified folder.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
file_pattern (str): Pattern to filter files (e.g., "F*.dxf").
|
|
55
|
+
recursive (bool): If True, includes subfolders.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
dict: Statistics containing {'processed': int, 'modified': int, 'errors': list}.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
if not self.operation_list:
|
|
62
|
+
print("⚠ No operations added")
|
|
63
|
+
return {'processed': 0, 'modified': 0, 'errors': []}
|
|
64
|
+
|
|
65
|
+
dxf_files = find_dxf_files(self.folder_path, recursive)
|
|
66
|
+
|
|
67
|
+
if self.use_backup_system:
|
|
68
|
+
print("🔧 Backup mode active")
|
|
69
|
+
|
|
70
|
+
# Processa file
|
|
71
|
+
stats = {'processed': 0, 'modified': 0, 'errors': []}
|
|
72
|
+
|
|
73
|
+
for file_path in dxf_files:
|
|
74
|
+
try:
|
|
75
|
+
modified = self._process_single_file(str(file_path))
|
|
76
|
+
stats['processed'] += 1
|
|
77
|
+
if modified:
|
|
78
|
+
stats['modified'] += 1
|
|
79
|
+
except Exception as e:
|
|
80
|
+
error_msg = f"Error on {file_path.name}: {str(e)}"
|
|
81
|
+
stats['errors'].append(error_msg)
|
|
82
|
+
print(f"❌ {error_msg}")
|
|
83
|
+
|
|
84
|
+
# Final messages
|
|
85
|
+
self._final_messages()
|
|
86
|
+
|
|
87
|
+
# Report
|
|
88
|
+
print(f"\n✓ Processed: {stats['processed']}")
|
|
89
|
+
print(f"✓ Modified: {stats['modified']}")
|
|
90
|
+
if stats['errors']:
|
|
91
|
+
print(f"❌ Errors: {len(stats['errors'])}")
|
|
92
|
+
|
|
93
|
+
return stats
|
|
94
|
+
|
|
95
|
+
def _process_single_file(self, file_path: str) -> bool:
|
|
96
|
+
"""Applies operations to a single file."""
|
|
97
|
+
|
|
98
|
+
# Backup
|
|
99
|
+
if self.use_backup_system:
|
|
100
|
+
BackupManager.ensure_original(file_path)
|
|
101
|
+
|
|
102
|
+
# Extract folder and filename
|
|
103
|
+
folder = os.path.dirname(file_path)
|
|
104
|
+
file_name = os.path.basename(file_path)
|
|
105
|
+
|
|
106
|
+
# Open file
|
|
107
|
+
doc = ezdxf.readfile(file_path)
|
|
108
|
+
|
|
109
|
+
# Apply operations
|
|
110
|
+
should_save = False
|
|
111
|
+
for operation in self.operation_list:
|
|
112
|
+
temp_should_save = operation.execute(doc, folder, file_name)
|
|
113
|
+
should_save = should_save or temp_should_save
|
|
114
|
+
operation.message(file_name)
|
|
115
|
+
|
|
116
|
+
# Save if necessary
|
|
117
|
+
if should_save:
|
|
118
|
+
doc.saveas(file_path)
|
|
119
|
+
return True
|
|
120
|
+
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
def _final_messages(self):
|
|
124
|
+
"""Prints final messages (e.g., from Counter)."""
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
from .operations.counter import Counter
|
|
128
|
+
for operation in self.operation_list:
|
|
129
|
+
if isinstance(operation, Counter):
|
|
130
|
+
operation.count_message()
|
|
131
|
+
except ImportError:
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
def file_selection_logic(self, filter_files=None):
|
|
135
|
+
"""DEPRECATED: Use execute() instead."""
|
|
136
|
+
import warnings
|
|
137
|
+
warnings.warn(
|
|
138
|
+
"file_selection_logic() is deprecated. Use execute().",
|
|
139
|
+
DeprecationWarning,
|
|
140
|
+
stacklevel=2
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
pattern = "*.dxf"
|
|
144
|
+
if filter_files:
|
|
145
|
+
if isinstance(filter_files, str):
|
|
146
|
+
pattern = filter_files
|
|
147
|
+
elif isinstance(filter_files, list) and filter_files:
|
|
148
|
+
pattern = filter_files[0]
|
|
149
|
+
|
|
150
|
+
return self.execute(file_pattern=pattern, recursive=False)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# Alias for backward compatibility with old scripts
|
|
154
|
+
iteration_manager = IterationManager
|
|
File without changes
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
def add_circle(doc, hole_list, radius, layer='0'):
|
|
4
|
+
"""Adds circles at specified positions in the document."""
|
|
5
|
+
msp = doc.modelspace() # Access the model space of the drawing
|
|
6
|
+
for center_x, center_y in hole_list:
|
|
7
|
+
center = (center_x, center_y)
|
|
8
|
+
# print(center_x, center_y)
|
|
9
|
+
msp.add_circle(center=center, radius=radius, dxfattribs={'layer': layer})
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def add_circle_with_handle(doc, center_x, center_y, radius=10, layer='0', handle=68):
|
|
13
|
+
"""Adds a circle at a specified position with a specific handle."""
|
|
14
|
+
msp = doc.modelspace() # Access the model space of the drawing
|
|
15
|
+
center = center_x, center_y
|
|
16
|
+
|
|
17
|
+
# Create a new circle with the specified handle
|
|
18
|
+
circle = msp.add_circle(center=center, radius=radius, dxfattribs={'layer': layer})
|
|
19
|
+
circle.dxf.handle = handle # Set the specified handle
|
|
20
|
+
|
|
21
|
+
return circle
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def add_x(doc, hole_list, x_size=8, layer='0'):
|
|
25
|
+
"""Adds an 'X' shape at specified positions in the document."""
|
|
26
|
+
msp = doc.modelspace()
|
|
27
|
+
for center_x, center_y in hole_list:
|
|
28
|
+
# Calculate the coordinates for the 'x'
|
|
29
|
+
x1 = center_x - (x_size / 1.4141) /2
|
|
30
|
+
y1 = center_y - (x_size / 1.4141) /2
|
|
31
|
+
x2 = center_x + (x_size / 1.4141) /2
|
|
32
|
+
y2 = center_y + (x_size / 1.4141) /2
|
|
33
|
+
|
|
34
|
+
# Add diagonal lines to form an 'x'
|
|
35
|
+
msp.add_line(start=(x1, y1), end=(x2, y2), dxfattribs={'layer': layer})
|
|
36
|
+
msp.add_line(start=(x1, y2), end=(x2, y1), dxfattribs={'layer': layer})
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def add_numbers_to_layer(doc, sequence, layer = '0'):
|
|
41
|
+
"""Adds a sequence of lines to a specified layer in the document."""
|
|
42
|
+
msp = doc.modelspace()
|
|
43
|
+
|
|
44
|
+
for scaled_segments, position in sequence.sequence:
|
|
45
|
+
|
|
46
|
+
# Add lines based on the segments at the scaled position
|
|
47
|
+
scaled_position = position # The position has already been scaled
|
|
48
|
+
for i in range(len(scaled_segments) - 1):
|
|
49
|
+
start_point = (
|
|
50
|
+
scaled_segments[i][0] + scaled_position[0],
|
|
51
|
+
scaled_segments[i][1] + scaled_position[1]
|
|
52
|
+
)
|
|
53
|
+
end_point = (
|
|
54
|
+
scaled_segments[i + 1][0] + scaled_position[0],
|
|
55
|
+
scaled_segments[i + 1][1] + scaled_position[1]
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
msp.add_line(start=start_point, end=end_point, dxfattribs={'layer': layer})
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def delete_circle(doc, hole_list):
|
|
63
|
+
"""Deletes circles from the model based on the provided list."""
|
|
64
|
+
msp = doc.modelspace()
|
|
65
|
+
|
|
66
|
+
for hole in hole_list:
|
|
67
|
+
msp.delete_entity(hole)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def delete_layer(doc, layer_name):
|
|
71
|
+
"""Deletes a specific layer and all entities associated with."""
|
|
72
|
+
msp = doc.modelspace()
|
|
73
|
+
|
|
74
|
+
# Find all entities belonging to the specified layer
|
|
75
|
+
entities_to_remove = [entity for entity in msp.query('*[layer=="{}"]'.format(layer_name))]
|
|
76
|
+
|
|
77
|
+
# Delete all entities associated with the layer
|
|
78
|
+
for entity in entities_to_remove:
|
|
79
|
+
msp.delete_entity(entity)
|
|
80
|
+
|
|
81
|
+
# Delete the layer
|
|
82
|
+
doc.layers.remove(layer_name)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def copy_entities_but_2(source_msp, dest_msp, holes_to_exclude=[]):
|
|
87
|
+
"""Copies entities from source model space to target, excluding specified entities."""
|
|
88
|
+
|
|
89
|
+
for entity in source_msp.query('*'):
|
|
90
|
+
if entity not in holes_to_exclude:
|
|
91
|
+
dest_msp.add_entity(entity)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def copy_entities_but(source_msp, target_msp, entities_to_exclude=[]):
|
|
96
|
+
"""Copies entities from source model space to target, excluding specified entities."""
|
|
97
|
+
for entity in source_msp.query('*'):
|
|
98
|
+
exclude = False
|
|
99
|
+
for exclude_entity in entities_to_exclude:
|
|
100
|
+
if entity.dxf.handle == exclude_entity.dxf.handle:
|
|
101
|
+
exclude = True
|
|
102
|
+
break
|
|
103
|
+
if not exclude:
|
|
104
|
+
target_msp.add_entity(entity.clone())
|
|
105
|
+
|
|
106
|
+
def remove_entities(msp, entities_to_remove):
|
|
107
|
+
"""Removes specified entities from the model space."""
|
|
108
|
+
# Create a new list of entities excluding those to remove
|
|
109
|
+
new_entities = [entity for entity in msp.query('*') if entity not in entities_to_remove]
|
|
110
|
+
|
|
111
|
+
# Delete all entities from the model space
|
|
112
|
+
msp.delete_all_entities()
|
|
113
|
+
|
|
114
|
+
# Add the new entities to the model space
|
|
115
|
+
for entity in new_entities:
|
|
116
|
+
msp.add_entity(entity.clone())
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
File without changes
|