Skip to content

Commit

Permalink
Generate EDA² logo.
Browse files Browse the repository at this point in the history
  • Loading branch information
Paebbels committed Dec 28, 2024
1 parent 8159295 commit 689f7fc
Show file tree
Hide file tree
Showing 7 changed files with 350 additions and 1 deletion.
30 changes: 30 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
root = true

[*]
charset = utf-8
# end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab
indent_size = 2
tab_width = 2


[*.py]
indent_style = tab
indent_size = 2

[*.{yml,yaml}]
indent_style = space
indent_size = 2

[*.{json,ini}]
indent_style = tab
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[*.rst]
indent_style = space
indent_size = 3
41 changes: 41 additions & 0 deletions .github/workflows/Pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Generate EDA² logos

on:
push:
paths:
- '.github/workflows/Pipeline.yml'
- '*.py'
pull_request:
paths:
- '.github/workflows/Pipeline.yml'
- '*.py'
schedule:
- cron: '0 0 * * 5'
workflow_dispatch:

jobs:
Logos:
runs-on: ubuntu-latest
name: Generate logos

steps:
- name: ⏬ Repository Checkout
uses: actions/checkout@v4

- name: 🐍 Setup Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install dependencies
run: |
python -m pip install --disable-pip-version-check -U ./requirements.txt
- name: Generate EDA² logos
id: generate
run: |
python main.py
- name: Investigate
run: |
tree .
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Python cache and object files
__pycache__/
*.py[cod]

# PyCharm project files
/.idea/workspace.xml

# Git files
!.git*
154 changes: 154 additions & 0 deletions Datatypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
from typing import TypeVar, Union, Generic, Any, Self, Tuple

from pyTooling.Decorators import export

Coordinate = TypeVar("Coordinate", bound=Union[int, float])


@export
class Point(Generic[Coordinate]):
x: Coordinate
y: Coordinate

def __init__(self, x: Coordinate, y: Coordinate) -> None:
if not isinstance(x, (int, float)):
raise TypeError()
if not isinstance(y, (int, float)):
raise TypeError()

self.x = x
self.y = y

def ToTuple(self) -> Tuple[Coordinate, Coordinate]:
return self.x, self.y

def __add__(self, other: Any) -> "Point[Coordinate]":
if isinstance(other, Offset):
return Point(
self.x + other.xOffset,
self.y + other.yOffset
)
else:
raise TypeError()

def __iadd__(self, other: Any) -> Self:
if isinstance(other, Offset):
self.x += other.xOffset
self.y += other.yOffset
else:
raise TypeError()

return self

def __sub__(self, other: Any) -> Union["Offset[Coordinate]", "Point[Coordinate]"]:
if isinstance(other, Point):
return Offset(
self.x - other.x,
self.y - other.y
)
elif isinstance(other, Offset):
return Point(
self.x - other.xOffset,
self.y - other.yOffset
)
else:
raise TypeError()

def __isub__(self, other: Any) -> Self:
if isinstance(other, Offset):
self.x -= other.xOffset
self.y -= other.yOffset
else:
raise TypeError()

return self

def __repr__(self) -> str:
return f"Point({self.x}, {self.y})"

def __str__(self) -> str:
return f"({self.x}, {self.y})"


@export
class Offset(Generic[Coordinate]):
xOffset: Coordinate
yOffset: Coordinate

def __init__(self, xOffset: Coordinate, yOffset: Coordinate) -> None:
if not isinstance(xOffset, (int, float)):
raise TypeError()
if not isinstance(yOffset, (int, float)):
raise TypeError()

self.xOffset = xOffset
self.yOffset = yOffset

def ToTuple(self) -> Tuple[Coordinate, Coordinate]:
return self.xOffset, self.yOffset

def __add__(self, other: Any) -> "Offset[Coordinate]":
if isinstance(other, Offset):
return Offset(
self.xOffset + other.xOffset,
self.yOffset + other.yOffset
)
else:
raise TypeError()

def __iadd__(self, other: Any) -> Self:
if isinstance(other, Offset):
self.xOffset += other.xOffset
self.yOffset += other.yOffset
else:
raise TypeError()

return self

def __sub__(self, other: Any) -> "Offset[Coordinate]":
if isinstance(other, Offset):
return Offset(
self.xOffset - other.xOffset,
self.yOffset - other.yOffset
)
else:
raise TypeError()

def __isub__(self, other: Any) -> Self:
if isinstance(other, Offset):
self.xOffset -= other.xOffset
self.yOffset -= other.yOffset
else:
raise TypeError()

return self

def __repr__(self) -> str:
return f"Offset({self.xOffset}, {self.yOffset})"

def __str__(self) -> str:
return f"({self.xOffset}, {self.yOffset})"


@export
class Size:
width: Coordinate
height: Coordinate

def __init__(self, width: Coordinate, height: Coordinate) -> None:
if not isinstance(width, (int, float)):
raise TypeError()
if not isinstance(height, (int, float)):
raise TypeError()

self.width = width
self.height = height

def ToTuple(self) -> Tuple[Coordinate, Coordinate]:
return self.width, self.height

def __repr__(self) -> str:
return f"Size({self.width}, {self.height})"

def __str__(self) -> str:
return f"({self.width}, {self.height})"
101 changes: 101 additions & 0 deletions Logo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from enum import Enum
from pathlib import Path
from typing import Optional as Nullable, Tuple, Dict

from pyTooling.Decorators import export
from pyTooling.MetaClasses import abstractmethod
from svgwrite import Drawing

from Datatypes import Offset, Size


@export
class ColorMode(Enum):
LightMode = 0
DarkMode = 1


@export
class ColorTuple:
dark: str
light: str

def __init__(self, dark: str, light: str) -> None:
self.dark = dark
self.light = light


@export
class Logo:
@abstractmethod
def GenerateSVG(self, file: Path, colorMode: ColorMode) -> None:
pass



@export
class PyEDAALayers(Logo):
colors: Dict[ColorMode, Tuple[ColorTuple, ...]]

def __init__(self):
self.colors = {
ColorMode.LightMode: (# dark, light on light
ColorTuple("#c62828", "#ef5350"), # Red
ColorTuple("#8e24aa", "#ba68c8"), # Purple
ColorTuple("#0277bd", "#29b6f6"), # Light Blue
ColorTuple("#558b2f", "#9ccc65"), # Light Green
ColorTuple("#ff8f00", "#ffca28"), # Amber
ColorTuple("#37474f", "#78909c") # Blue Grey
),
ColorMode.DarkMode: (# dark, light on light
ColorTuple("#c62828", "#ef5350"),
ColorTuple("#8e24aa", "#ba68c8"),
ColorTuple("#0277bd", "#29b6f6"),
ColorTuple("#558b2f", "#9ccc65"),
ColorTuple("#ff8f00", "#ffca28"),
ColorTuple("#78909c", "#b0bec5")
)
}

def _drawRectangles(self, dwg, shades: Tuple[ColorTuple, ...], offset: Nullable[Offset] = None, unit: int = 50):
"""
Draw the default multi-coloured EDA² logo without strokes.
:param dwg:
:param colors: Tuple of 6 colors. One per layer.
:param shades: Tuple of 2 shades.
:param offset:
:param unit:
:return:
"""
if offset is None:
offset = Offset(0, 0)

rectSize = Size(2 * unit, unit)

for levelIndex, colors in enumerate(shades):
firstRectOffset = offset + Offset(2 * unit, levelIndex * unit)
secondRectOffset = offset + Offset(4 * unit * (levelIndex % 2), levelIndex * unit)

dwg.add(
dwg.rect(
insert=firstRectOffset.ToTuple(),
size=rectSize.ToTuple(),
fill=colors.dark,
)
)
dwg.add(
dwg.rect(
insert=secondRectOffset.ToTuple(),
size=rectSize.ToTuple(),
fill=colors.light,
)
)

def GenerateSVG(self, file: Path, colorMode: ColorMode) -> None:
"""
Generate and save the default logo to file 'edaa.svg'
"""
dwg = Drawing(str(file), (300, 300), debug=True)
self._drawRectangles(dwg, self.colors[colorMode])
dwg.save(pretty=True)
13 changes: 13 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from pathlib import Path
from typing import Dict, NoReturn

from Logo import PyEDAALayers, ColorMode


def main() -> NoReturn:
pyEDAALayersLogo = PyEDAALayers()
pyEDAALayersLogo.GenerateSVG(Path("edaa-light.svg"), ColorMode.LightMode)
pyEDAALayersLogo.GenerateSVG(Path("edaa-dark.svg"), ColorMode.DarkMode)

if __name__ == '__main__':
main()
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
svgwrite
pyTooling ~= 8.0
svgwrite ~= 1.4

0 comments on commit 689f7fc

Please sign in to comment.