made hexagons regular hexagons with specifiable side length

This commit is contained in:
grimsace
2026-05-19 11:09:20 -05:00
parent 84312dc07e
commit 47a7a8a831
4 changed files with 63 additions and 60 deletions
+1
View File
@@ -1 +1,2 @@
/releases /releases
*.zip
Binary file not shown.
+62 -60
View File
@@ -36,24 +36,40 @@ class GridDocker(DockWidget):
layout.addLayout(thickness_layout) layout.addLayout(thickness_layout)
# Width # Width
width_layout = QHBoxLayout() self.width_container = QWidget()
width_layout = QHBoxLayout(self.width_container)
width_layout.setContentsMargins(0, 0, 0, 0)
width_layout.addWidget(QLabel("Width (px):")) width_layout.addWidget(QLabel("Width (px):"))
self.width_spin = QDoubleSpinBox() self.width_spin = QDoubleSpinBox()
self.width_spin.setRange(1.0, 10000.0) self.width_spin.setRange(1.0, 10000.0)
self.width_spin.setValue(100.0) self.width_spin.setValue(100.0)
self.width_spin.valueChanged.connect(self.on_width_changed) self.width_spin.valueChanged.connect(self.on_width_changed)
width_layout.addWidget(self.width_spin) width_layout.addWidget(self.width_spin)
layout.addLayout(width_layout) layout.addWidget(self.width_container)
# Height # Height
height_layout = QHBoxLayout() self.height_container = QWidget()
height_layout = QHBoxLayout(self.height_container)
height_layout.setContentsMargins(0, 0, 0, 0)
height_layout.addWidget(QLabel("Height (px):")) height_layout.addWidget(QLabel("Height (px):"))
self.height_spin = QDoubleSpinBox() self.height_spin = QDoubleSpinBox()
self.height_spin.setRange(1.0, 10000.0) self.height_spin.setRange(1.0, 10000.0)
self.height_spin.setValue(100.0) self.height_spin.setValue(100.0)
self.height_spin.valueChanged.connect(self.on_height_changed) self.height_spin.valueChanged.connect(self.on_height_changed)
height_layout.addWidget(self.height_spin) height_layout.addWidget(self.height_spin)
layout.addLayout(height_layout) layout.addWidget(self.height_container)
# Side Length (Hexagon Only)
self.side_container = QWidget()
side_layout = QHBoxLayout(self.side_container)
side_layout.setContentsMargins(0, 0, 0, 0)
side_layout.addWidget(QLabel("Side Length (px):"))
self.side_spin = QDoubleSpinBox()
self.side_spin.setRange(1.0, 10000.0)
self.side_spin.setValue(50.0)
side_layout.addWidget(self.side_spin)
layout.addWidget(self.side_container)
self.side_container.hide()
# Lock Width/Height # Lock Width/Height
self.lock_check = QCheckBox("Lock Aspect Ratio") self.lock_check = QCheckBox("Lock Aspect Ratio")
@@ -65,17 +81,10 @@ class GridDocker(DockWidget):
type_layout.addWidget(QLabel("Type:")) type_layout.addWidget(QLabel("Type:"))
self.type_combo = QComboBox() self.type_combo = QComboBox()
self.type_combo.addItems(["Square", "Hexagon"]) self.type_combo.addItems(["Square", "Hexagon"])
self.type_combo.currentTextChanged.connect(self.on_type_changed)
type_layout.addWidget(self.type_combo) type_layout.addWidget(self.type_combo)
layout.addLayout(type_layout) layout.addLayout(type_layout)
# Layer Option
layer_layout = QHBoxLayout()
layer_layout.addWidget(QLabel("On:"))
self.layer_combo = QComboBox()
self.layer_combo.addItems(["New Layer", "Current Layer"])
layer_layout.addWidget(self.layer_combo)
layout.addLayout(layer_layout)
# Color Option # Color Option
color_layout = QHBoxLayout() color_layout = QHBoxLayout()
color_layout.addWidget(QLabel("Color:")) color_layout.addWidget(QLabel("Color:"))
@@ -92,6 +101,13 @@ class GridDocker(DockWidget):
layout.addStretch() layout.addStretch()
self.setWidget(main_widget) self.setWidget(main_widget)
def on_type_changed(self, grid_type):
is_square = grid_type == "Square"
self.width_container.setVisible(is_square)
self.height_container.setVisible(is_square)
self.lock_check.setVisible(is_square)
self.side_container.setVisible(not is_square)
def on_width_changed(self, value): def on_width_changed(self, value):
if self.lock_check.isChecked(): if self.lock_check.isChecked():
self.height_spin.blockSignals(True) self.height_spin.blockSignals(True)
@@ -123,11 +139,7 @@ class GridDocker(DockWidget):
else: else:
color = view.backgroundColor() color = view.backgroundColor()
# Ensure the color is in RGBA U8 sRGB for easy extraction
# setColorSpace signature: (colorModelId, bitDepthId, profileName)
color.setColorSpace("RGBA", "U8", "sRGB built-in") color.setColorSpace("RGBA", "U8", "sRGB built-in")
# componentsOrdered returns normalized floats [R, G, B, A]
comps = color.componentsOrdered() comps = color.componentsOrdered()
r = int(max(0, min(1, comps[0])) * 255) r = int(max(0, min(1, comps[0])) * 255)
@@ -143,46 +155,32 @@ class GridDocker(DockWidget):
return return
thickness = self.thickness_spin.value() thickness = self.thickness_spin.value()
width = self.width_spin.value()
height = self.height_spin.value()
grid_type = self.type_combo.currentText() grid_type = self.type_combo.currentText()
layer_option = self.layer_combo.currentText()
color_hex = self.get_color_hex() color_hex = self.get_color_hex()
# Determine target layer # Always create a new vector layer for the grid
target_node = None target_node = doc.createVectorLayer("grid")
if layer_option == "New Layer": doc.rootNode().addChildNode(target_node, None)
target_node = doc.createVectorLayer("grid")
doc.rootNode().addChildNode(target_node, None)
else:
target_node = doc.activeNode()
if target_node and target_node.type() != "vectorlayer":
parent = target_node.parentNode()
new_vector = doc.createVectorLayer("grid")
parent.addChildNode(new_vector, target_node)
target_node = new_vector
if not target_node:
target_node = doc.createVectorLayer("grid")
doc.rootNode().addChildNode(target_node, None)
if hasattr(target_node, "addShapesFromSvg"): if hasattr(target_node, "addShapesFromSvg"):
self.draw_grid( if grid_type == "Square":
target_node, doc, thickness, width, height, grid_type, color_hex width = self.width_spin.value()
) height = self.height_spin.value()
self.draw_square_grid(
target_node, doc, thickness, width, height, color_hex
)
else:
side_length = self.side_spin.value()
self.draw_hexagon_grid(
target_node, doc, thickness, side_length, color_hex
)
else: else:
print( print(
"Error: Target node does not support SVG shapes. Please ensure you are using Krita 5.0+ and a Vector Layer." "Error: Target node does not support SVG shapes. Please ensure you are using Krita 5.0+."
) )
doc.refreshProjection() doc.refreshProjection()
def draw_grid(self, node, doc, thickness, width, height, grid_type, color_hex):
if grid_type == "Square":
self.draw_square_grid(node, doc, thickness, width, height, color_hex)
else:
self.draw_hexagon_grid(node, doc, thickness, width, height, color_hex)
def draw_square_grid(self, node, doc, thickness, width, height, color_hex): def draw_square_grid(self, node, doc, thickness, width, height, color_hex):
svg = f'<svg><g fill="none" stroke="{color_hex}" stroke-width="{thickness}">' svg = f'<svg><g fill="none" stroke="{color_hex}" stroke-width="{thickness}">'
x = 0 x = 0
@@ -196,32 +194,36 @@ class GridDocker(DockWidget):
svg += "</g></svg>" svg += "</g></svg>"
node.addShapesFromSvg(svg) node.addShapesFromSvg(svg)
def draw_hexagon_grid(self, node, doc, thickness, width, height, color_hex): def draw_hexagon_grid(self, node, doc, thickness, side_length, color_hex):
h_width = math.sqrt(3) * side_length
v_spacing = 1.5 * side_length
svg = f'<svg><g fill="none" stroke="{color_hex}" stroke-width="{thickness}">' svg = f'<svg><g fill="none" stroke="{color_hex}" stroke-width="{thickness}">'
v_spacing = height * 0.75
h_spacing = width
rows = int(doc.height() / v_spacing) + 2 rows = int(doc.height() / v_spacing) + 2
cols = int(doc.width() / h_spacing) + 2 cols = int(doc.width() / h_width) + 2
for r in range(rows): for r in range(rows):
offset_x = (width / 2) if (r % 2 == 1) else 0 offset_x = (h_width / 2) if (r % 2 == 1) else 0
for c in range(cols): for c in range(cols):
cx = c * h_spacing + offset_x cx = c * h_width + offset_x
cy = r * v_spacing cy = r * v_spacing
v = [
(cx, cy - height / 2), v = []
(cx + width / 2, cy - height / 4), for i in range(6):
(cx + width / 2, cy + height / 4), angle_deg = 60 * i - 90
(cx, cy + height / 2), angle_rad = math.pi / 180 * angle_deg
(cx - width / 2, cy + height / 4), px = cx + side_length * math.cos(angle_rad)
(cx - width / 2, cy - height / 4), py = cy + side_length * math.sin(angle_rad)
] v.append((px, py))
points = " ".join([f"{px},{py}" for px, py in v]) points = " ".join([f"{px},{py}" for px, py in v])
svg += f'<polygon points="{points}" />' svg += f'<polygon points="{points}" />'
svg += "</g></svg>" svg += "</g></svg>"
node.addShapesFromSvg(svg) node.addShapesFromSvg(svg)
# Register the docker
Krita.instance().addDockWidgetFactory( Krita.instance().addDockWidgetFactory(
DockWidgetFactory(DOCKER_ID, DockWidgetFactoryBase.DockRight, GridDocker) DockWidgetFactory(DOCKER_ID, DockWidgetFactoryBase.DockRight, GridDocker)
) )