Add background stroke width to mobjects

This commit is contained in:
Grant Sanderson 2018-08-08 11:15:45 -07:00
parent 7119f0cc6e
commit 3dc5b10e8b
3 changed files with 75 additions and 23 deletions

View file

@ -316,8 +316,18 @@ class Camera(object):
pen, fill = self.get_pen_and_fill(vmobject) pen, fill = self.get_pen_and_fill(vmobject)
pathstring = self.get_pathstring(vmobject) pathstring = self.get_pathstring(vmobject)
symbol = aggdraw.Symbol(pathstring) symbol = aggdraw.Symbol(pathstring)
self.draw_background_stroke(canvas, vmobject, symbol)
canvas.symbol((0, 0), symbol, pen, fill) canvas.symbol((0, 0), symbol, pen, fill)
def draw_background_stroke(self, canvas, vmobject, symbol):
bs_width = vmobject.get_background_stroke_width()
if bs_width == 0:
return
bs_rgb = vmobject.get_background_stroke_rgb()
bs_hex = rgb_to_hex(bs_rgb)
pen = aggdraw.Pen(bs_hex, bs_width)
canvas.symbol((0, 0), symbol, pen, None)
def get_pen_and_fill(self, vmobject): def get_pen_and_fill(self, vmobject):
stroke_width = max(vmobject.get_stroke_width(), 0) stroke_width = max(vmobject.get_stroke_width(), 0)
if stroke_width == 0: if stroke_width == 0:

View file

@ -39,6 +39,8 @@ class SingleStringTexMobject(SVGMobject):
"template_tex_file": TEMPLATE_TEX_FILE, "template_tex_file": TEMPLATE_TEX_FILE,
"stroke_width": 0, "stroke_width": 0,
"fill_opacity": 1.0, "fill_opacity": 1.0,
"background_stroke_width": 5,
"background_stroke_color": BLACK,
"should_center": True, "should_center": True,
"height": None, "height": None,
"organize_left_to_right": False, "organize_left_to_right": False,

View file

@ -19,6 +19,10 @@ class VMobject(Mobject):
"fill_opacity": 0.0, "fill_opacity": 0.0,
"stroke_color": None, "stroke_color": None,
"stroke_width": DEFAULT_POINT_THICKNESS, "stroke_width": DEFAULT_POINT_THICKNESS,
# The purpose of background stroke is to have
# something that won't overlap the fill
"background_stroke_color": BLACK,
"background_stroke_width": 0,
# Indicates that it will not be displayed, but # Indicates that it will not be displayed, but
# that it should count in parent mobject's path # that it should count in parent mobject's path
"is_subpath": False, "is_subpath": False,
@ -36,10 +40,12 @@ class VMobject(Mobject):
# Colors # Colors
def init_colors(self): def init_colors(self):
self.set_style_data( self.set_style_data(
stroke_color=self.stroke_color or self.color,
stroke_width=self.stroke_width,
fill_color=self.fill_color or self.color, fill_color=self.fill_color or self.color,
fill_opacity=self.fill_opacity, fill_opacity=self.fill_opacity,
stroke_color=self.stroke_color or self.color,
stroke_width=self.stroke_width,
background_stroke_color=self.background_stroke_color,
background_stroke_width=self.background_stroke_width,
family=self.propagate_style_to_family family=self.propagate_style_to_family
) )
return self return self
@ -49,29 +55,37 @@ class VMobject(Mobject):
setattr(mob, attr, value) setattr(mob, attr, value)
def set_style_data(self, def set_style_data(self,
stroke_color=None,
stroke_width=None,
fill_color=None, fill_color=None,
fill_opacity=None, fill_opacity=None,
stroke_color=None,
stroke_width=None,
background_stroke_color=None,
background_stroke_width=None,
family=True family=True
): ):
if stroke_color is not None: kwargs = {
self.stroke_rgb = color_to_rgb(stroke_color) "fill_color": fill_color,
if fill_color is not None: "fill_opacity": fill_opacity,
self.fill_rgb = color_to_rgb(fill_color) "stroke_color": stroke_color,
if stroke_width is not None: "stroke_width": stroke_width,
self.stroke_width = stroke_width "background_stroke_color": background_stroke_color,
if fill_opacity is not None: "background_stroke_width": background_stroke_width,
self.fill_opacity = fill_opacity "family": family,
}
for key in "fill_color", "stroke_color", "background_stroke_color":
# Instead of setting a self.fill_color attr,
# set a numerical self.fill_rgb to make
# interpolation easier
key_with_rgb = key.replace("color", "rgb")
color = kwargs[key]
if color is not None:
setattr(self, key_with_rgb, color_to_rgb(color))
for key in "fill_opacity", "stroke_width", "background_stroke_width":
if kwargs[key] is not None:
setattr(self, key, kwargs[key])
if family: if family:
for mob in self.submobjects: for mob in self.submobjects:
mob.set_style_data( mob.set_style_data(**kwargs)
stroke_color=stroke_color,
stroke_width=stroke_width,
fill_color=fill_color,
fill_opacity=fill_opacity,
family=family
)
return self return self
def set_fill(self, color=None, opacity=None, family=True): def set_fill(self, color=None, opacity=None, family=True):
@ -88,6 +102,13 @@ class VMobject(Mobject):
family=family family=family
) )
def set_background_stroke(self, color=None, width=None, family=True):
return self.set_style_data(
background_stroke_color=color,
background_stroke_width=width,
family=family
)
def set_color(self, color, family=True): def set_color(self, color, family=True):
self.set_style_data( self.set_style_data(
stroke_color=color, stroke_color=color,
@ -99,10 +120,12 @@ class VMobject(Mobject):
def match_style(self, vmobject): def match_style(self, vmobject):
self.set_style_data( self.set_style_data(
stroke_color=vmobject.get_stroke_color(),
stroke_width=vmobject.get_stroke_width(),
fill_color=vmobject.get_fill_color(), fill_color=vmobject.get_fill_color(),
fill_opacity=vmobject.get_fill_opacity(), fill_opacity=vmobject.get_fill_opacity(),
stroke_color=vmobject.get_stroke_color(),
stroke_width=vmobject.get_stroke_width(),
background_stroke_color=vmobject.get_background_stroke_color(),
background_stroke_width=vmobject.get_background_stroke_width(),
family=False family=False
) )
@ -154,6 +177,21 @@ class VMobject(Mobject):
def get_stroke_width(self): def get_stroke_width(self):
return max(0, self.stroke_width) return max(0, self.stroke_width)
def get_background_stroke_rgb(self):
return np.clip(self.background_stroke_rgb, 0, 1)
def get_background_stroke_color(self):
try:
self.background_stroke_rgb = np.clip(
self.background_stroke_rgb, 0, 1
)
return Color(rgb=self.background_stroke_rgb)
except:
return Color(WHITE)
def get_background_stroke_width(self):
return max(0, self.background_stroke_width)
def get_color(self): def get_color(self):
if self.fill_opacity == 0: if self.fill_opacity == 0:
return self.get_stroke_color() return self.get_stroke_color()
@ -404,10 +442,12 @@ class VMobject(Mobject):
def interpolate_color(self, mobject1, mobject2, alpha): def interpolate_color(self, mobject1, mobject2, alpha):
attrs = [ attrs = [
"stroke_rgb",
"stroke_width",
"fill_rgb", "fill_rgb",
"fill_opacity", "fill_opacity",
"stroke_rgb",
"stroke_width",
"background_stroke_rgb",
"background_stroke_width",
] ]
for attr in attrs: for attr in attrs:
setattr(self, attr, interpolate( setattr(self, attr, interpolate(