2024-05-16 17:49:48 +02:00
|
|
|
import win32com.client
|
|
|
|
import pythoncom
|
|
|
|
from enum import Enum
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Enum to represent common colors in AutoCAD
|
2024-05-16 17:49:48 +02:00
|
|
|
class Color(Enum):
|
|
|
|
RED = 1
|
|
|
|
YELLOW = 2
|
|
|
|
GREEN = 3
|
|
|
|
CYAN = 4
|
|
|
|
BLUE = 5
|
|
|
|
MAGENTA = 6
|
|
|
|
WHITE = 7
|
|
|
|
GRAY = 8
|
|
|
|
ORANGE = 30
|
|
|
|
PURPLE = 40
|
|
|
|
BROWN = 41
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def from_name(name):
|
|
|
|
try:
|
|
|
|
return Color[name.upper()].value
|
|
|
|
except KeyError:
|
|
|
|
raise ValueError(f"Color '{name}' is not a valid color name")
|
|
|
|
|
2024-05-16 22:36:16 +02:00
|
|
|
# Enum to represent alignments in AutoCAD
|
|
|
|
class Alignment(Enum):
|
|
|
|
LEFT = 'left'
|
|
|
|
CENTER = 'center'
|
|
|
|
RIGHT = 'right'
|
|
|
|
|
|
|
|
# Enum to represent dimension types in AutoCAD
|
|
|
|
class DimensionType(Enum):
|
|
|
|
ALIGNED = 'aligned'
|
|
|
|
LINEAR = 'linear'
|
|
|
|
ANGULAR = 'angular'
|
|
|
|
RADIAL = 'radial'
|
|
|
|
DIAMETER = 'diameter'
|
|
|
|
|
|
|
|
# Enum to represent line styles in AutoCAD
|
|
|
|
class LineStyle(Enum):
|
|
|
|
CONTINUOUS = 'Continuous' # ------------
|
|
|
|
DASHED = 'Dashed' # - - - - - -
|
|
|
|
DOTTED = 'Dotted' # . . . . . .
|
|
|
|
CENTER = 'Center' # - . - . - .
|
|
|
|
HIDDEN = 'Hidden' # - - - - - -
|
|
|
|
PHANTOM = 'Phantom' # - . . - . .
|
|
|
|
BREAK = 'Break' # - -
|
|
|
|
BORDER = 'Border' # - - - . - -
|
|
|
|
DOT2 = 'Dot2' # . . . .
|
|
|
|
DOTX2 = 'DotX2' # . . .
|
|
|
|
DIVIDE = 'Divide' # - . - .
|
|
|
|
TRACKING = 'Tracking' # - . - .
|
|
|
|
DASHDOT = 'Dashdot' # - . - . -
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Class to represent a 3D point
|
2024-05-16 17:49:48 +02:00
|
|
|
class APoint:
|
|
|
|
def __init__(self, x=0, y=0, z=0):
|
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
self.z = z
|
|
|
|
|
|
|
|
def to_variant(self):
|
|
|
|
return win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, [self.x, self.y, self.z])
|
|
|
|
|
|
|
|
def to_tuple(self):
|
|
|
|
return (self.x, self.y)
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"APoint({self.x}, {self.y}, {self.z})"
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Class to represent a layer
|
2024-05-16 17:49:48 +02:00
|
|
|
class Layer:
|
|
|
|
def __init__(self, name, color=Color.WHITE, visible=True):
|
|
|
|
self.name = name
|
|
|
|
self.color = color
|
|
|
|
self.visible = visible
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"Layer(name='{self.name}', color={self.color}, visible={self.visible})"
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Class to represent a block reference
|
2024-05-16 17:49:48 +02:00
|
|
|
class BlockReference:
|
|
|
|
def __init__(self, name, insertion_point, scale=1.0, rotation=0.0):
|
|
|
|
self.name = name
|
|
|
|
self.insertion_point = insertion_point
|
|
|
|
self.scale = scale
|
|
|
|
self.rotation = rotation
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"BlockReference(name='{self.name}', insertion_point={self.insertion_point}, scale={self.scale}, rotation={self.rotation})"
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Class to represent a text object
|
2024-05-16 17:49:48 +02:00
|
|
|
class Text:
|
2024-05-16 22:36:16 +02:00
|
|
|
def __init__(self, content, insertion_point, height, alignment=Alignment.LEFT):
|
2024-05-16 17:49:48 +02:00
|
|
|
self.content = content
|
|
|
|
self.insertion_point = insertion_point
|
|
|
|
self.height = height
|
|
|
|
self.alignment = alignment
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"Text(content='{self.content}', insertion_point={self.insertion_point}, height={self.height}, alignment='{self.alignment}')"
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Class to represent a dimension
|
2024-05-16 17:49:48 +02:00
|
|
|
class Dimension:
|
2024-05-16 22:36:16 +02:00
|
|
|
def __init__(self, start_point, end_point, text_point, dimension_type=DimensionType.ALIGNED):
|
2024-05-16 17:49:48 +02:00
|
|
|
self.start_point = start_point
|
|
|
|
self.end_point = end_point
|
|
|
|
self.text_point = text_point
|
|
|
|
self.dimension_type = dimension_type
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"Dimension(start_point={self.start_point}, end_point={self.end_point}, text_point={self.text_point}, dimension_type='{self.dimension_type}')"
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Custom class for handling AutoCAD errors
|
2024-05-16 17:49:48 +02:00
|
|
|
class AutoCADError(Exception):
|
|
|
|
def __init__(self, message):
|
|
|
|
super().__init__(message)
|
2024-05-16 18:08:04 +02:00
|
|
|
# Additional error handling logic can be added here, such as logging to a file
|
2024-05-16 17:49:48 +02:00
|
|
|
print(f"AutoCADError: {message}")
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Main class for interacting with AutoCAD
|
2024-05-16 17:49:48 +02:00
|
|
|
class AutoCAD:
|
|
|
|
def __init__(self):
|
|
|
|
try:
|
|
|
|
self.acad = win32com.client.Dispatch("AutoCAD.Application")
|
|
|
|
self.acad.Visible = True
|
|
|
|
self.doc = self.acad.ActiveDocument
|
|
|
|
self.modelspace = self.doc.ModelSpace
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error initializing AutoCAD: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Iterate over objects in the model space, optionally filtering by object type
|
2024-05-16 17:49:48 +02:00
|
|
|
def iter_objects(self, object_type=None):
|
|
|
|
for obj in self.modelspace:
|
|
|
|
if object_type is None or obj.EntityName == object_type:
|
|
|
|
yield obj
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Add a circle to the model space
|
2024-05-16 17:49:48 +02:00
|
|
|
def add_circle(self, center, radius):
|
|
|
|
try:
|
|
|
|
circle = self.modelspace.AddCircle(center.to_variant(), radius)
|
|
|
|
return circle
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error adding circle: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Add a line to the model space
|
2024-05-16 17:49:48 +02:00
|
|
|
def add_line(self, start_point, end_point):
|
|
|
|
try:
|
|
|
|
line = self.modelspace.AddLine(start_point.to_variant(), end_point.to_variant())
|
|
|
|
return line
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error adding line: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Add a rectangle to the model space
|
2024-05-16 17:49:48 +02:00
|
|
|
def add_rectangle(self, lower_left, upper_right):
|
|
|
|
try:
|
|
|
|
x1, y1 = lower_left.to_tuple()
|
|
|
|
x2, y2 = upper_right.to_tuple()
|
|
|
|
points = [
|
|
|
|
x1, y1,
|
|
|
|
x2, y1,
|
|
|
|
x2, y2,
|
|
|
|
x1, y2,
|
|
|
|
x1, y1
|
|
|
|
]
|
|
|
|
points_variant = win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, points)
|
|
|
|
polyline = self.modelspace.AddLightweightPolyline(points_variant)
|
|
|
|
return polyline
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error adding rectangle: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Add an ellipse to the model space
|
2024-05-16 17:49:48 +02:00
|
|
|
def add_ellipse(self, center, major_axis, ratio):
|
|
|
|
try:
|
|
|
|
ellipse = self.modelspace.AddEllipse(center.to_variant(), major_axis.to_variant(), ratio)
|
|
|
|
return ellipse
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error adding ellipse: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Add a text object to the model space
|
2024-05-16 17:49:48 +02:00
|
|
|
def add_text(self, text):
|
|
|
|
try:
|
|
|
|
text_obj = self.modelspace.AddText(text.content, text.insertion_point.to_variant(), text.height)
|
|
|
|
return text_obj
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error adding text: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Add a dimension to the model space
|
2024-05-16 17:49:48 +02:00
|
|
|
def add_dimension(self, dimension):
|
|
|
|
try:
|
|
|
|
dimension_obj = None
|
2024-05-16 22:36:16 +02:00
|
|
|
if dimension.dimension_type == DimensionType.ALIGNED:
|
2024-05-16 17:49:48 +02:00
|
|
|
dimension_obj = self.modelspace.AddDimAligned(dimension.start_point.to_variant(), dimension.end_point.to_variant(), dimension.text_point.to_variant())
|
2024-05-16 22:36:16 +02:00
|
|
|
elif dimension.dimension_type == DimensionType.LINEAR:
|
|
|
|
dimension_obj = self.modelspace.AddDimLinear(dimension.start_point.to_variant(), dimension.end_point.to_variant(), dimension.text_point.to_variant())
|
|
|
|
elif dimension.dimension_type == DimensionType.ANGULAR:
|
|
|
|
dimension_obj = self.modelspace.AddDimAngular(dimension.start_point.to_variant(), dimension.end_point.to_variant(), dimension.text_point.to_variant())
|
|
|
|
elif dimension.dimension_type == DimensionType.RADIAL:
|
|
|
|
dimension_obj = self.modelspace.AddDimRadial(dimension.start_point.to_variant(), dimension.end_point.to_variant(), dimension.text_point.to_variant())
|
|
|
|
elif dimension.dimension_type == DimensionType.DIAMETER:
|
|
|
|
dimension_obj = self.modelspace.AddDimDiameter(dimension.start_point.to_variant(), dimension.end_point.to_variant(), dimension.text_point.to_variant())
|
2024-05-16 17:49:48 +02:00
|
|
|
return dimension_obj
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error adding dimension: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 22:36:16 +02:00
|
|
|
# Add a point to the model space
|
|
|
|
def add_point(self, point):
|
|
|
|
try:
|
|
|
|
point_obj = self.modelspace.AddPoint(point.to_variant())
|
|
|
|
return point_obj
|
|
|
|
except Exception as e:
|
|
|
|
raise AutoCADError(f"Error adding point: {e}")
|
|
|
|
|
|
|
|
# Add a polyline to the model space
|
|
|
|
def add_polyline(self, points):
|
|
|
|
try:
|
|
|
|
points_variant = win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, [coord for point in points for coord in point.to_tuple()])
|
|
|
|
polyline = self.modelspace.AddLightweightPolyline(points_variant)
|
|
|
|
return polyline
|
|
|
|
except Exception as e:
|
|
|
|
raise AutoCADError(f"Error adding polyline: {e}")
|
|
|
|
|
|
|
|
# Add a spline to the model space
|
|
|
|
def add_spline(self, points):
|
|
|
|
try:
|
|
|
|
points_variant = win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, [coord for point in points for coord in point.to_variant()])
|
|
|
|
spline = self.modelspace.AddSpline(points_variant)
|
|
|
|
return spline
|
|
|
|
except Exception as e:
|
|
|
|
raise AutoCADError(f"Error adding spline: {e}")
|
|
|
|
|
|
|
|
# Add an arc to the model space
|
|
|
|
def add_arc(self, center, radius, start_angle, end_angle):
|
|
|
|
try:
|
|
|
|
arc = self.modelspace.AddArc(center.to_variant(), radius, start_angle, end_angle)
|
|
|
|
return arc
|
|
|
|
except Exception as e:
|
|
|
|
raise AutoCADError(f"Error adding arc: {e}")
|
|
|
|
|
|
|
|
# Explode an object or a set of joined objects
|
|
|
|
def explode_object(self, obj):
|
|
|
|
try:
|
|
|
|
exploded_items = obj.Explode()
|
|
|
|
return exploded_items
|
|
|
|
except Exception as e:
|
|
|
|
raise AutoCADError(f"Error exploding object: {e}")
|
|
|
|
|
|
|
|
# Get maximum extents of a block
|
|
|
|
def get_block_extents(self, block_name):
|
|
|
|
try:
|
|
|
|
for entity in self.iter_objects("AcDbBlockReference"):
|
|
|
|
if entity.Name == block_name:
|
|
|
|
min_point = APoint(*entity.GeometricExtents.MinPoint)
|
|
|
|
max_point = APoint(*entity.GeometricExtents.MaxPoint)
|
|
|
|
return min_point, max_point
|
|
|
|
except Exception as e:
|
|
|
|
raise AutoCADError(f"Error getting extents of block '{block_name}': {e}")
|
|
|
|
|
|
|
|
# Add overall dimensions to an object or block
|
|
|
|
def add_overall_dimensions(self, entity):
|
|
|
|
try:
|
|
|
|
min_point, max_point = APoint(*entity.GeometricExtents.MinPoint), APoint(*entity.GeometricExtents.MaxPoint)
|
|
|
|
# Horizontal dimension
|
|
|
|
self.add_dimension(Dimension(min_point, APoint(max_point.x, min_point.y, min_point.z), APoint(min_point.x, min_point.y - 5, min_point.z), DimensionType.ALIGNED))
|
|
|
|
# Vertical dimension
|
|
|
|
self.add_dimension(Dimension(min_point, APoint(min_point.x, max_point.y, min_point.z), APoint(min_point.x - 5, min_point.y, min_point.z), DimensionType.ALIGNED))
|
|
|
|
except Exception as e:
|
|
|
|
raise AutoCADError(f"Error adding overall dimensions: {e}")
|
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Get user-defined blocks in the document
|
2024-05-16 17:49:48 +02:00
|
|
|
def get_user_defined_blocks(self):
|
|
|
|
try:
|
|
|
|
blocks = self.doc.Blocks
|
|
|
|
user_defined_blocks = [block.Name for block in blocks
|
|
|
|
if not block.IsLayout and not block.Name.startswith('*') and block.Name != 'GENAXEH']
|
|
|
|
return user_defined_blocks
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error getting user-defined blocks: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Create a new layer
|
2024-05-16 17:49:48 +02:00
|
|
|
def create_layer(self, layer):
|
|
|
|
try:
|
|
|
|
layers = self.doc.Layers
|
|
|
|
new_layer = layers.Add(layer.name)
|
|
|
|
new_layer.Color = layer.color.value
|
|
|
|
return new_layer
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error creating layer '{layer.name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Set the active layer
|
2024-05-16 17:49:48 +02:00
|
|
|
def set_active_layer(self, layer_name):
|
|
|
|
try:
|
|
|
|
self.doc.ActiveLayer = self.doc.Layers.Item(layer_name)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error setting active layer '{layer_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Insert a block into the model space
|
2024-05-16 17:49:48 +02:00
|
|
|
def insert_block(self, block):
|
|
|
|
try:
|
|
|
|
block_ref = self.modelspace.InsertBlock(block.insertion_point.to_variant(), block.name, block.scale, block.scale, block.scale, block.rotation)
|
|
|
|
return block_ref
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error inserting block '{block.name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Save the document with a new name
|
2024-05-16 17:49:48 +02:00
|
|
|
def save_as(self, file_path):
|
|
|
|
try:
|
|
|
|
self.doc.SaveAs(file_path)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error saving document as '{file_path}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Open an existing file
|
2024-05-16 17:49:48 +02:00
|
|
|
def open_file(self, file_path):
|
|
|
|
try:
|
|
|
|
self.acad.Documents.Open(file_path)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error opening file '{file_path}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Get the insertion coordinates of a specific block
|
2024-05-16 17:49:48 +02:00
|
|
|
def get_block_coordinates(self, block_name):
|
|
|
|
try:
|
|
|
|
block_references = []
|
|
|
|
for entity in self.iter_objects("AcDbBlockReference"):
|
|
|
|
if entity.Name == block_name:
|
|
|
|
insertion_point = entity.InsertionPoint
|
|
|
|
block_references.append(APoint(insertion_point[0], insertion_point[1], insertion_point[2]))
|
|
|
|
return block_references
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error getting coordinates of block '{block_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Delete an object
|
2024-05-16 17:49:48 +02:00
|
|
|
def delete_object(self, obj):
|
|
|
|
try:
|
|
|
|
obj.Delete()
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error deleting object: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Clone an object
|
2024-05-16 17:49:48 +02:00
|
|
|
def clone_object(self, obj, new_insertion_point):
|
|
|
|
try:
|
|
|
|
cloned_obj = obj.Copy(new_insertion_point.to_variant())
|
|
|
|
return cloned_obj
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error cloning object: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Modify a property of an object
|
2024-05-16 17:49:48 +02:00
|
|
|
def modify_object_property(self, obj, property_name, new_value):
|
|
|
|
try:
|
|
|
|
setattr(obj, property_name, new_value)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error modifying property '{property_name}' of object: {e}")
|
|
|
|
|
|
|
|
# Repeat a block horizontally until a specified length is reached
|
2024-05-16 17:49:48 +02:00
|
|
|
def repeat_block_horizontally(self, block_name, total_length, block_length, insertion_point):
|
|
|
|
try:
|
|
|
|
x, y, z = insertion_point.x, insertion_point.y, insertion_point.z
|
|
|
|
num_blocks = total_length // block_length
|
|
|
|
|
|
|
|
for i in range(int(num_blocks)):
|
|
|
|
new_insertion_point = APoint(x + i * block_length, y, z)
|
|
|
|
self.insert_block(BlockReference(block_name, new_insertion_point))
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error repeating block '{block_name}' horizontally: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Set the visibility of a layer
|
2024-05-16 17:49:48 +02:00
|
|
|
def set_layer_visibility(self, layer_name, visible=True):
|
|
|
|
try:
|
|
|
|
layer = self.doc.Layers.Item(layer_name)
|
|
|
|
layer.LayerOn = visible
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error setting visibility of layer '{layer_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Lock or unlock a layer
|
2024-05-16 17:49:48 +02:00
|
|
|
def lock_layer(self, layer_name, lock=True):
|
|
|
|
try:
|
|
|
|
layer = self.doc.Layers.Item(layer_name)
|
|
|
|
layer.Lock = lock
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error locking/unlocking layer '{layer_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Delete a layer
|
2024-05-16 17:49:48 +02:00
|
|
|
def delete_layer(self, layer_name):
|
|
|
|
try:
|
|
|
|
layer = self.doc.Layers.Item(layer_name)
|
|
|
|
layer.Delete()
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error deleting layer '{layer_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Change the color of a layer
|
2024-05-16 17:49:48 +02:00
|
|
|
def change_layer_color(self, layer_name, color):
|
|
|
|
try:
|
|
|
|
layer = self.doc.Layers.Item(layer_name)
|
|
|
|
layer.color = color.value
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error changing color of layer '{layer_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Set the linetype of a layer
|
2024-05-16 17:49:48 +02:00
|
|
|
def set_layer_linetype(self, layer_name, linetype_name):
|
|
|
|
try:
|
|
|
|
layer = self.doc.Layers.Item(layer_name)
|
|
|
|
linetypes = self.doc.Linetypes
|
|
|
|
if linetype_name not in linetypes:
|
|
|
|
self.doc.Linetypes.Load(linetype_name, linetype_name)
|
|
|
|
layer.Linetype = linetype_name
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error setting linetype of layer '{layer_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Move an object
|
2024-05-16 17:49:48 +02:00
|
|
|
def move_object(self, obj, new_insertion_point):
|
|
|
|
try:
|
|
|
|
obj.Move(obj.InsertionPoint, new_insertion_point.to_variant())
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error moving object: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Scale an object
|
2024-05-16 17:49:48 +02:00
|
|
|
def scale_object(self, obj, base_point, scale_factor):
|
|
|
|
try:
|
|
|
|
obj.ScaleEntity(base_point.to_variant(), scale_factor)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error scaling object: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Rotate an object
|
2024-05-16 17:49:48 +02:00
|
|
|
def rotate_object(self, obj, base_point, rotation_angle):
|
|
|
|
try:
|
|
|
|
obj.Rotate(base_point.to_variant(), rotation_angle)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error rotating object: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Align objects
|
2024-05-16 22:36:16 +02:00
|
|
|
def align_objects(self, objects, alignment=Alignment.LEFT):
|
2024-05-16 17:49:48 +02:00
|
|
|
try:
|
|
|
|
if not objects:
|
|
|
|
return
|
2024-05-16 22:36:16 +02:00
|
|
|
if alignment == Alignment.LEFT:
|
2024-05-16 17:49:48 +02:00
|
|
|
min_x = min(obj.InsertionPoint[0] for obj in objects)
|
|
|
|
for obj in objects:
|
|
|
|
self.move_object(obj, APoint(min_x, obj.InsertionPoint[1], obj.InsertionPoint[2]))
|
2024-05-16 22:36:16 +02:00
|
|
|
elif alignment == Alignment.RIGHT:
|
2024-05-16 17:49:48 +02:00
|
|
|
max_x = max(obj.InsertionPoint[0] for obj in objects)
|
|
|
|
for obj in objects:
|
|
|
|
self.move_object(obj, APoint(max_x, obj.InsertionPoint[1], obj.InsertionPoint[2]))
|
2024-05-16 22:36:16 +02:00
|
|
|
elif alignment == Alignment.CENTER:
|
|
|
|
center_x = (min(obj.InsertionPoint[0] for obj in objects) + max(obj.InsertionPoint[0] for obj in objects)) / 2
|
|
|
|
for obj in objects:
|
|
|
|
self.move_object(obj, APoint(center_x, obj.InsertionPoint[1], obj.InsertionPoint[2]))
|
2024-05-16 17:49:48 +02:00
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error aligning objects: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Distribute objects with specified spacing
|
2024-05-16 17:49:48 +02:00
|
|
|
def distribute_objects(self, objects, spacing):
|
|
|
|
try:
|
|
|
|
if not objects:
|
|
|
|
return
|
|
|
|
objects.sort(key=lambda obj: obj.InsertionPoint[0])
|
|
|
|
for i in range(1, len(objects)):
|
|
|
|
new_x = objects[i-1].InsertionPoint[0] + spacing
|
|
|
|
self.move_object(objects[i], APoint(new_x, objects[i].InsertionPoint[1], objects[i].InsertionPoint[2]))
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error distributing objects: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Insert a block from a file
|
2024-05-16 17:49:48 +02:00
|
|
|
def insert_block_from_file(self, file_path, insertion_point, scale=1.0, rotation=0.0):
|
|
|
|
try:
|
|
|
|
block_name = self.doc.Blocks.Import(file_path, file_path)
|
|
|
|
block_ref = self.modelspace.InsertBlock(insertion_point.to_variant(), block_name, scale, scale, scale, rotation)
|
|
|
|
return block_ref
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error inserting block from file '{file_path}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Export a block to a file
|
2024-05-16 17:49:48 +02:00
|
|
|
def export_block_to_file(self, block_name, file_path):
|
|
|
|
try:
|
|
|
|
block = self.doc.Blocks.Item(block_name)
|
|
|
|
block.Export(file_path)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error exporting block '{block_name}' to '{file_path}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Modify a block attribute
|
2024-05-16 17:49:48 +02:00
|
|
|
def modify_block_attribute(self, block_ref, tag, new_value):
|
|
|
|
try:
|
|
|
|
for attribute in block_ref.GetAttributes():
|
|
|
|
if attribute.TagString == tag:
|
|
|
|
attribute.TextString = new_value
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error modifying block attribute '{tag}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Delete a block attribute
|
2024-05-16 17:49:48 +02:00
|
|
|
def delete_block_attribute(self, block_ref, tag):
|
|
|
|
try:
|
|
|
|
for attribute in block_ref.GetAttributes():
|
|
|
|
if attribute.TagString == tag:
|
|
|
|
attribute.Delete()
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error deleting block attribute '{tag}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Request point input from the user
|
|
|
|
def get_user_input_point(self, prompt="Select a point"):
|
2024-05-16 17:49:48 +02:00
|
|
|
try:
|
|
|
|
point = self.doc.Utility.GetPoint(None, prompt)
|
|
|
|
return APoint(point[0], point[1], point[2])
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error getting point input from user: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Request string input from the user
|
|
|
|
def get_user_input_string(self, prompt="Enter a string"):
|
2024-05-16 17:49:48 +02:00
|
|
|
try:
|
|
|
|
return self.doc.Utility.GetString(False, prompt)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error getting string input from user: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Request integer input from the user
|
|
|
|
def get_user_input_integer(self, prompt="Enter an integer"):
|
2024-05-16 17:49:48 +02:00
|
|
|
try:
|
|
|
|
return self.doc.Utility.GetInteger(prompt)
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error getting integer input from user: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Display a message to the user
|
2024-05-16 17:49:48 +02:00
|
|
|
def show_message(self, message):
|
|
|
|
try:
|
|
|
|
self.doc.Utility.Prompt(message + "\n")
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error displaying message: {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Create a group of objects
|
2024-05-16 17:49:48 +02:00
|
|
|
def create_group(self, group_name, objects):
|
|
|
|
try:
|
|
|
|
group = self.doc.Groups.Add(group_name)
|
2025-06-03 19:34:48 +02:00
|
|
|
|
|
|
|
# Ensure objects is a list or tuple
|
|
|
|
if not isinstance(objects, (list, tuple)):
|
|
|
|
objects = [objects]
|
|
|
|
|
|
|
|
# Create SAFEARRAY of IDispatch pointers
|
|
|
|
variant_array = win32com.client.VARIANT(
|
|
|
|
pythoncom.VT_ARRAY | pythoncom.VT_DISPATCH,
|
|
|
|
objects
|
|
|
|
)
|
|
|
|
group.AppendItems(variant_array)
|
2024-05-16 17:49:48 +02:00
|
|
|
return group
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error creating group '{group_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Add objects to a group
|
2024-05-16 17:49:48 +02:00
|
|
|
def add_to_group(self, group_name, objects):
|
|
|
|
try:
|
|
|
|
group = self.doc.Groups.Item(group_name)
|
|
|
|
for obj in objects:
|
|
|
|
group.AppendItems([obj])
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error adding objects to group '{group_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Remove objects from a group
|
2024-05-16 17:49:48 +02:00
|
|
|
def remove_from_group(self, group_name, objects):
|
|
|
|
try:
|
|
|
|
group = self.doc.Groups.Item(group_name)
|
|
|
|
for obj in objects:
|
|
|
|
group.RemoveItems([obj])
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error removing objects from group '{group_name}': {e}")
|
2024-05-16 17:49:48 +02:00
|
|
|
|
2024-05-16 18:08:04 +02:00
|
|
|
# Select a group of objects
|
2024-05-16 17:49:48 +02:00
|
|
|
def select_group(self, group_name):
|
|
|
|
try:
|
|
|
|
group = self.doc.Groups.Item(group_name)
|
|
|
|
return [item for item in group.GetItems()]
|
|
|
|
except Exception as e:
|
2024-05-16 18:08:04 +02:00
|
|
|
raise AutoCADError(f"Error selecting group '{group_name}': {e}")
|