Add fanchart option with overhang

A fanchart consisting of half a circle fills paper with aspect ratio
1:2. Common paper and screens have larger aspect ratios (e.g. 16:9 or
1:1.41). By adding an overhang to the fanchart, more space can be used.
This commit is contained in:
Tammo Jan Dijkema 2020-10-03 14:18:42 +02:00 committed by Nick Hall
parent 2b033dfaff
commit 2aaeea8784

View File

@ -30,7 +30,7 @@
# python modules # python modules
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from math import pi, cos, sin, log10, acos from math import pi, cos, sin, log10, acos, asin, degrees, radians
def log2(val): def log2(val):
""" """
@ -69,6 +69,7 @@ from gramps.gen.display.name import displayer as _nd
FULL_CIRCLE = 0 FULL_CIRCLE = 0
HALF_CIRCLE = 1 HALF_CIRCLE = 1
QUAR_CIRCLE = 2 QUAR_CIRCLE = 2
OVERHANG = 3
BACKGROUND_WHITE = 0 BACKGROUND_WHITE = 0
BACKGROUND_GEN = 1 BACKGROUND_GEN = 1
@ -96,10 +97,9 @@ def draw_wedge(doc, style, centerx, centery, radius, start_angle,
path = [] path = []
degreestoradians = pi / 180.0 radiansdelta = radians(0.5)
radiansdelta = degreestoradians / 2 sangle = radians(start_angle)
sangle = start_angle * degreestoradians eangle = radians(end_angle)
eangle = end_angle * degreestoradians
while eangle < sangle: while eangle < sangle:
eangle = eangle + 2 * pi eangle = eangle + 2 * pi
angle = sangle angle = sangle
@ -162,7 +162,8 @@ class FanChart(Report):
that come in the options class. that come in the options class.
maxgen - Maximum number of generations to include. maxgen - Maximum number of generations to include.
circle - Draw a full circle, half circle, or quarter circle. circle - Draw a full circle, half circle, half circle with
overhang or quarter circle.
background - Background color is generation dependent or white. background - Background color is generation dependent or white.
radial - Print radial texts roundabout or as upright as possible. radial - Print radial texts roundabout or as upright as possible.
draw_empty - draw background when there is no information draw_empty - draw background when there is no information
@ -244,6 +245,23 @@ class FanChart(Report):
_y_ = self.doc.get_usable_height() _y_ = self.doc.get_usable_height()
min_xy = min(_x_, _y_) min_xy = min(_x_, _y_)
elif self.circle == OVERHANG:
if self.doc.get_usable_height() < self.doc.get_usable_width() and \
self.doc.get_usable_height() > self.doc.get_usable_width() / 2:
# Determine overhang angle to fill the paper
radius = self.doc.get_usable_width() / 2
_overhang_height_ = self.doc.get_usable_height() - radius
overhang_angle = degrees(asin(_overhang_height_ / radius))
else:
overhang_angle = 25.0
max_angle = 180 + 2 * overhang_angle
start_angle = 180 - overhang_angle
max_circular = 3
_x_ = (self.doc.get_usable_width()/2.0)
_overhang_height_ = sin(radians(overhang_angle)) * _x_
_y_ = self.doc.get_usable_height() - _overhang_height_
min_xy = min(_x_, _y_)
else: # quarter circle else: # quarter circle
max_angle = 90.0 max_angle = 90.0
start_angle = 270 start_angle = 270
@ -308,8 +326,13 @@ class FanChart(Report):
# title # title
mark = IndexMark(title, INDEX_TYPE_TOC, 1) mark = IndexMark(title, INDEX_TYPE_TOC, 1)
self.doc.center_text('FC-Graphic-title', title, titlex = self.doc.get_usable_width() / 2
self.doc.get_usable_width() / 2, 0, mark) if self.circle == OVERHANG:
titley = self.doc.get_usable_height() - _overhang_height_ / 2
else:
titley = 0
self.doc.center_text('FC-Graphic-title', title, titlex, titley, mark)
# wheel # wheel
for generation in range(0, min(max_circular, self.max_generations)): for generation in range(0, min(max_circular, self.max_generations)):
self.draw_circular(_x_, _y_, self.draw_circular(_x_, _y_,
@ -373,7 +396,7 @@ class FanChart(Report):
if self.circle == FULL_CIRCLE: if self.circle == FULL_CIRCLE:
return [name, val] return [name, val]
elif self.circle == HALF_CIRCLE: elif self.circle in (HALF_CIRCLE, OVERHANG):
return [name, val] return [name, val]
else: else:
if (name != "") and (val != ""): if (name != "") and (val != ""):
@ -384,7 +407,7 @@ class FanChart(Report):
elif generation == 6: elif generation == 6:
if self.circle == FULL_CIRCLE: if self.circle == FULL_CIRCLE:
return [p_pn.get_first_name(), p_pn.get_surname(), val] return [p_pn.get_first_name(), p_pn.get_surname(), val]
elif self.circle == HALF_CIRCLE: elif self.circle in (HALF_CIRCLE, OVERHANG):
return [p_pn.get_first_name(), p_pn.get_surname(), val] return [p_pn.get_first_name(), p_pn.get_surname(), val]
else: else:
if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""): if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""):
@ -620,7 +643,7 @@ class FanChart(Report):
if circle == FULL_CIRCLE: if circle == FULL_CIRCLE:
rad1 = size * ((generation * 2) - 5) rad1 = size * ((generation * 2) - 5)
rad2 = size * ((generation * 2) - 3) rad2 = size * ((generation * 2) - 3)
elif circle == HALF_CIRCLE: elif circle in (HALF_CIRCLE, OVERHANG):
rad1 = size * ((generation * 2) - 3) rad1 = size * ((generation * 2) - 3)
rad2 = size * ((generation * 2) - 1) rad2 = size * ((generation * 2) - 1)
else: # quarter circle else: # quarter circle
@ -698,9 +721,10 @@ class FanChartOptions(MenuReportOptions):
circle = EnumeratedListOption(_('Type of graph'), HALF_CIRCLE) circle = EnumeratedListOption(_('Type of graph'), HALF_CIRCLE)
circle.add_item(FULL_CIRCLE, _('full circle')) circle.add_item(FULL_CIRCLE, _('full circle'))
circle.add_item(HALF_CIRCLE, _('half circle')) circle.add_item(HALF_CIRCLE, _('half circle'))
circle.add_item(OVERHANG, _('overhang'))
circle.add_item(QUAR_CIRCLE, _('quarter circle')) circle.add_item(QUAR_CIRCLE, _('quarter circle'))
circle.set_help(_("The form of the graph: full circle, half circle," circle.set_help(_("The form of the graph: full circle, half circle,"
" or quarter circle.")) " half circle with overhang or quarter circle."))
menu.add_option(category_name, "circle", circle) menu.add_option(category_name, "circle", circle)
background = EnumeratedListOption(_('Background color'), BACKGROUND_GEN) background = EnumeratedListOption(_('Background color'), BACKGROUND_GEN)