Skip to content

Commit

Permalink
Make building colors configurable.
Browse files Browse the repository at this point in the history
It is now possible to draw building colors with `--building-colors`
option.  Map Machine will use roof colors in flat building mode and
roof and wall colors in isometric building mode.
  • Loading branch information
enzet committed May 28, 2023
1 parent 55a6698 commit d3c18a3
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 47 deletions.
121 changes: 80 additions & 41 deletions map_machine/feature/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,26 @@ def __init__(
)
self.has_walls: bool = tags.get("building") != "roof"

self.default_fill: Color
self.default_stroke: Color
if self.is_construction:
self.fill: Color = scheme.get_color("building_construction_color")
self.stroke: Color = scheme.get_color(
self.default_fill = scheme.get_color("building_construction_color")
self.default_stroke = scheme.get_color(
"building_construction_border_color"
)
else:
if color := tags.get("roof:colour"):
self.fill = scheme.get_color(color)
self.stroke: Color = Color(self.fill)
self.stroke.set_luminance(self.fill.get_luminance() * 0.85)
else:
self.fill: Color = scheme.get_color("building_color")
self.stroke: Color = scheme.get_color("building_border_color")
self.default_fill = scheme.get_color("building_color")
self.default_stroke = scheme.get_color("building_border_color")

self.fill: Color
self.stroke: Color
if color := tags.get("roof:colour"):
self.fill = scheme.get_color(color)
self.stroke = Color(self.fill)
self.stroke.set_luminance(self.fill.get_luminance() * 0.85)
else:
self.fill = scheme.get_color("building_color")
self.stroke = scheme.get_color("building_border_color")

self.parts: list[Segment] = []

Expand All @@ -65,31 +72,23 @@ def __init__(
self.height: float = BUILDING_MINIMAL_HEIGHT
self.min_height: float = 0.0

self.wall_color: Color
self.wall_default_color: Color
if self.is_construction:
self.wall_color = scheme.get_color("wall_construction_color")
self.wall_default_color = scheme.get_color(
"wall_construction_color"
)
else:
self.wall_color = scheme.get_color("wall_color")
self.wall_default_color = scheme.get_color("wall_color")

self.wall_color: Color = self.wall_default_color
if material := tags.get("building:material"):
if material in scheme.material_colors:
self.wall_color = Color(scheme.material_colors[material])

if color := tags.get("building:colour"):
self.wall_color = scheme.get_color(color)

if color := tags.get("colour"):
self.wall_color = scheme.get_color(color)

self.wall_bottom_color_1: Color = Color(self.wall_color)
self.wall_bottom_color_1.set_luminance(
self.wall_color.get_luminance() * 0.70
)
self.wall_bottom_color_2: Color = Color(self.wall_color)
self.wall_bottom_color_2.set_luminance(
self.wall_color.get_luminance() * 0.85
)

if levels := self.get_float("building:levels"):
self.height = BUILDING_MINIMAL_HEIGHT + levels * LEVEL_HEIGHT

Expand All @@ -102,18 +101,24 @@ def __init__(
if height := self.get_length("min_height"):
self.min_height = BUILDING_MINIMAL_HEIGHT + height

def draw(self, svg: Drawing, flinger: Flinger) -> None:
def draw(
self, svg: Drawing, flinger: Flinger, use_building_colors: bool
) -> None:
"""Draw simple building shape."""
path: Path = Path(
d=self.get_path(flinger),
stroke=self.stroke.hex,
fill=self.fill.hex,
stroke=self.stroke.hex
if use_building_colors
else self.default_stroke.hex,
fill=self.fill.hex
if use_building_colors
else self.default_fill.hex,
stroke_linejoin="round",
)
svg.add(path)

def draw_shade(self, building_shade: Group, flinger: Flinger) -> None:
"""Draw shade casted by the building."""
"""Draw shade cast by the building."""
scale: float = flinger.get_scale() * SHADE_SCALE
shift_1: np.ndarray = np.array((scale * self.min_height, 0.0))
shift_2: np.ndarray = np.array((scale * self.height, 0.0))
Expand Down Expand Up @@ -141,7 +146,12 @@ def draw_shade(self, building_shade: Group, flinger: Flinger) -> None:
building_shade.add(path)

def draw_walls(
self, svg: Drawing, height: float, previous_height: float, scale: float
self,
svg: Drawing,
height: float,
previous_height: float,
scale: float,
use_building_colors: bool,
) -> None:
"""Draw building walls."""
if not self.has_walls:
Expand All @@ -153,16 +163,36 @@ def draw_walls(
shift_2: np.ndarray = np.array((0.0, -height * scale * BUILDING_SCALE))

for segment in self.parts:
draw_walls(svg, self, segment, height, shift_1, shift_2)
draw_walls(
svg,
self,
segment,
height,
shift_1,
shift_2,
use_building_colors,
)

def draw_roof(self, svg: Drawing, flinger: Flinger, scale: float) -> None:
def draw_roof(
self,
svg: Drawing,
flinger: Flinger,
scale: float,
use_building_colors: bool,
) -> None:
"""Draw building roof."""

fill: Color = self.fill if use_building_colors else self.default_fill
stroke: Color = (
self.stroke if use_building_colors else self.default_stroke
)

path: Path = Path(
d=self.get_path(
flinger, np.array([0.0, -self.height * scale * BUILDING_SCALE])
),
stroke=self.stroke,
fill="none" if self.is_construction else self.fill.hex,
stroke=stroke,
fill="none" if self.is_construction else fill.hex,
stroke_linejoin="round",
)
svg.add(path)
Expand All @@ -175,33 +205,42 @@ def draw_walls(
height: float,
shift_1: np.ndarray,
shift_2: np.ndarray,
):
use_building_colors: bool,
) -> None:
"""
Draw walls for buildings as a quadrangle.
Color of the wall is based on illumination.
"""
color: Color = (
building.wall_color
if use_building_colors
else building.wall_default_color
)

color: Color
if building.is_construction:
color_part: float = segment.angle * 0.2
color = Color(
rgb=(
building.wall_color.get_red() + color_part,
building.wall_color.get_green() + color_part,
building.wall_color.get_blue() + color_part,
color.get_red() + color_part,
color.get_green() + color_part,
color.get_blue() + color_part,
)
)
elif height <= 0.25 / BUILDING_SCALE:
color = building.wall_bottom_color_1
color = Color(color)
color.set_luminance(color.get_luminance() * 0.70)
elif height <= 0.5 / BUILDING_SCALE:
color = building.wall_bottom_color_2
color = Color(color)
color.set_luminance(color.get_luminance() * 0.85)
else:
color_part: float = segment.angle * 0.2 - 0.1
color = Color(
rgb=(
max(min(building.wall_color.get_red() + color_part, 1), 0),
max(min(building.wall_color.get_green() + color_part, 1), 0),
max(min(building.wall_color.get_blue() + color_part, 1), 0),
max(min(color.get_red() + color_part, 1), 0),
max(min(color.get_green() + color_part, 1), 0),
max(min(color.get_blue() + color_part, 1), 0),
)
)

Expand Down
24 changes: 18 additions & 6 deletions map_machine/mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def draw(self, constructor: Constructor) -> None:
for crater in constructor.craters:
crater.draw(self.svg, self.flinger)

self.draw_buildings(constructor)
self.draw_buildings(constructor, self.configuration.use_building_colors)

for direction_sector in constructor.direction_sectors:
direction_sector.draw(self.svg, self.scheme)
Expand Down Expand Up @@ -133,16 +133,18 @@ def draw(self, constructor: Constructor) -> None:
if self.configuration.show_credit:
self.draw_credits(constructor.flinger.size)

def draw_buildings(self, constructor: Constructor) -> None:
def draw_buildings(
self, constructor: Constructor, use_building_colors: bool
) -> None:
"""Draw buildings: shade, walls, and roof."""
if self.configuration.building_mode == BuildingMode.NO:
return
if self.configuration.building_mode == BuildingMode.FLAT:
for building in constructor.buildings:
building.draw(self.svg, self.flinger)
building.draw(self.svg, self.flinger, use_building_colors)
return

logging.info("Drawing buildings...")
logging.info("Drawing isometric buildings...")

scale: float = self.flinger.get_scale()
building_shade: Group = Group(opacity=0.1)
Expand Down Expand Up @@ -171,12 +173,22 @@ def draw_buildings(self, constructor: Constructor) -> None:
if building.height < height or building.min_height >= height:
continue

draw_walls(self.svg, building, wall, height, shift_1, shift_2)
draw_walls(
self.svg,
building,
wall,
height,
shift_1,
shift_2,
use_building_colors,
)

if self.configuration.draw_roofs:
for building in constructor.buildings:
if building.height == height:
building.draw_roof(self.svg, self.flinger, scale)
building.draw_roof(
self.svg, self.flinger, scale, use_building_colors
)

previous_height = height

Expand Down

0 comments on commit d3c18a3

Please sign in to comment.