Skip to content

Commit

Permalink
Create an independent renderer for draw_marker_at_points
Browse files Browse the repository at this point in the history
  • Loading branch information
jwiggins committed Mar 16, 2021
1 parent b0b8454 commit cd06311
Show file tree
Hide file tree
Showing 27 changed files with 11,860 additions and 2 deletions.
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ include docs/Makefile
include docs/kiva/agg/notes
include kiva/_cython_speedups.*
include kiva/_hit_test.*
include kiva/_marker_renderer.*
recursive-include docs *.py *.rst *.txt *.css *.png *.ico *.doc
recursive-include enable/examples *.py *.svg *.jpg *.enaml
recursive-include kiva/examples *.py *.txt *.gif *.jpg
Expand All @@ -19,4 +20,5 @@ recursive-include kiva/agg/LICENSES *
recursive-include kiva/fonttools/tests/data *.ttc *.ttf *.afm
recursive-include kiva/fonttools/LICENSES *
recursive-include kiva/gl *.h *.cpp *.i LICENSE_*
recursive-include kiva/markers *.h LICENSE_*
recursive-include kiva/quartz *.pyx *.pxi *.pxd mac_context*.*
44 changes: 44 additions & 0 deletions kiva/_marker_renderer.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
from libcpp cimport bool

cdef extern from "marker_renderer.h" namespace "agg24markers":
cdef cppclass pixfmt_abgr32:
pass
cdef cppclass pixfmt_argb32:
pass
cdef cppclass pixfmt_bgra32:
pass
cdef cppclass pixfmt_rgba32:
pass
cdef cppclass pixfmt_bgr24:
pass
cdef cppclass pixfmt_rgb24:
pass


cdef extern from "marker_renderer.h" namespace "kiva_markers":
# This is just here for the type signature/
cdef enum marker_type:
pass

# Abstract base class
cdef cppclass marker_renderer_base:
void draw_marker_at_points(double* pts, unsigned Npts,
unsigned size, marker_type marker,
double* fill, double* stroke)
void transform(double sx, double shy,
double shx, double sy,
double tx, double ty)

# Template class
cdef cppclass marker_renderer[pixfmt_T]:
marker_renderer(unsigned char* buf, unsigned width, unsigned height,
int stride, bool bottom_up)
126 changes: 126 additions & 0 deletions kiva/_marker_renderer.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
import cython
import numpy as np
from numpy cimport uint8_t

cimport _marker_renderer

ctypedef _marker_renderer.marker_renderer_base renderer_base_t
# Template specializations
ctypedef _marker_renderer.marker_renderer[_marker_renderer.pixfmt_abgr32] renderer_abgr32_t
ctypedef _marker_renderer.marker_renderer[_marker_renderer.pixfmt_argb32] renderer_argb32_t
ctypedef _marker_renderer.marker_renderer[_marker_renderer.pixfmt_bgra32] renderer_bgra32_t
ctypedef _marker_renderer.marker_renderer[_marker_renderer.pixfmt_rgba32] renderer_rgba32_t
ctypedef _marker_renderer.marker_renderer[_marker_renderer.pixfmt_bgr24] renderer_bgr24_t
ctypedef _marker_renderer.marker_renderer[_marker_renderer.pixfmt_rgb24] renderer_rgb24_t

@cython.internal
cdef class MarkerRendererBase:
cdef renderer_base_t* _this
cdef object py_array

def __dealloc__(self):
del self._this

cdef int base_init(self, image) except -1:
if image is None:
raise ValueError('image argument must not be None.')

# Retain a reference to the memory view supplied to the constructor
# so that it lives as long as this object
self.py_array = image

def draw_marker_at_points(self, points, size, marker, fill, stroke):
"""draw_marker_at_points(points, size, marker, fill, stroke)
Draw markers at a collection of points.
"""
cdef:
double[:,::1] _points = np.asarray(points, dtype=np.float64, order='c')
double[::1] _fill = np.asarray(fill, dtype=np.float64, order='c')
double[::1] _stroke = np.asarray(stroke, dtype=np.float64, order='c')
unsigned _size = <unsigned>size
_marker_renderer.marker_type _marker = <_marker_renderer.marker_type>marker

if _points.shape[1] != 2:
msg = "points argument must be an iterable of (x, y) pairs."
raise ValueError(msg)

self._this.draw_marker_at_points(
&_points[0][0],
_points.shape[0],
_size, _marker,
&_fill[0],
&_stroke[0]
)

def transform(self, sx, shy, shx, sy, tx, ty):
"""transform(sx, shy, shx, sy, tx, ty)
Set the transform to be applied to the markers.
:param sx: Scale in X
:param shy: Shear in X
:param shx: Shear in Y
:param sy: Scale in Y
:param tx: Translation in X
:param ty: Translation in Y
"""
cdef:
double _sx = <double>sx
double _shy = <double>shy
double _shx = <double>shx
double _sy = <double>sy
double _tx = <double>tx
double _ty = <double>ty

self._this.transform(_sx, _shy, _shx, _sy, _tx, _ty)


cdef class MarkerRendererABGR32(MarkerRendererBase):
def __cinit__(self, uint8_t[:,:,::1] image, bottom_up=True):
self.base_init(image)
self._this = <renderer_base_t*> new renderer_abgr32_t(
&image[0][0][0], image.shape[1], image.shape[0], image.strides[0], bottom_up
)

cdef class MarkerRendererARGB32(MarkerRendererBase):
def __cinit__(self, uint8_t[:,:,::1] image, bottom_up=True):
self.base_init(image)
self._this = <renderer_base_t*> new renderer_argb32_t(
&image[0][0][0], image.shape[1], image.shape[0], image.strides[0], bottom_up
)

cdef class MarkerRendererBGRA32(MarkerRendererBase):
def __cinit__(self, uint8_t[:,:,::1] image, bottom_up=True):
self.base_init(image)
self._this = <renderer_base_t*> new renderer_bgra32_t(
&image[0][0][0], image.shape[1], image.shape[0], image.strides[0], bottom_up
)

cdef class MarkerRendererRGBA32(MarkerRendererBase):
def __cinit__(self, uint8_t[:,:,::1] image, bottom_up=True):
self.base_init(image)
self._this = <renderer_base_t*> new renderer_rgba32_t(
&image[0][0][0], image.shape[1], image.shape[0], image.strides[0], bottom_up
)

cdef class MarkerRendererBGR24(MarkerRendererBase):
def __cinit__(self, uint8_t[:,:,::1] image, bottom_up=True):
self.base_init(image)
self._this = <renderer_base_t*> new renderer_bgr24_t(
&image[0][0][0], image.shape[1], image.shape[0], image.strides[0], bottom_up
)

cdef class MarkerRendererRGB24(MarkerRendererBase):
def __cinit__(self, uint8_t[:,:,::1] image, bottom_up=True):
self.base_init(image)
self._this = <renderer_base_t*> new renderer_rgb24_t(
&image[0][0][0], image.shape[1], image.shape[0], image.strides[0], bottom_up
)
16 changes: 16 additions & 0 deletions kiva/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@
- :attr:`~.DOT_MARKER`
- :attr:`~.PIXEL_MARKER`
Marker Renderers
================
These can be used by Kiva backends to implement
:py:meth:`draw_marker_at_points`.
- :class:`~.MarkerRendererABGR32`
- :class:`~.MarkerRendererARGB32`
- :class:`~.MarkerRendererBGR24`
- :class:`~.MarkerRendererBGRA32`
- :class:`~.MarkerRendererRGB24`
- :class:`~.MarkerRendererRGBA32`
Fonts
=====
Expand Down Expand Up @@ -148,3 +160,7 @@
)
from ._cython_speedups import points_in_polygon
from .fonttools import add_application_fonts, Font
from .marker_renderer import (
MarkerRendererABGR32, MarkerRendererARGB32, MarkerRendererBGR24,
MarkerRendererBGRA32, MarkerRendererRGB24, MarkerRendererRGBA32
)
40 changes: 38 additions & 2 deletions kiva/celiagg.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import celiagg as agg
import numpy as np

from kiva import marker_renderer
from kiva.abstract_graphics_context import AbstractGraphicsContext
import kiva.constants as constants
from kiva.fonttools import Font
Expand Down Expand Up @@ -75,6 +76,11 @@
'bgra32': agg.CanvasBGRA32,
'rgb24': agg.CanvasRGB24,
}
pix_format_marker_renderers = {
'rgba32': marker_renderer.MarkerRendererRGBA32,
'bgra32': marker_renderer.MarkerRendererBGRA32,
'rgb24': marker_renderer.MarkerRendererRGB24,
}
StateBundle = namedtuple(
'StateBundle',
['state', 'path', 'stroke', 'fill', 'transform', 'text_transform', 'font'],
Expand All @@ -89,8 +95,11 @@ def __init__(self, size, *args, **kwargs):
self.pix_format = kwargs.get('pix_format', 'rgba32')

shape = (self._height, self._width, 4)
buffer = np.zeros(shape, dtype=np.uint8)
canvas_klass = pix_format_canvases[self.pix_format]
self.gc = canvas_klass(np.zeros(shape, dtype=np.uint8), bottom_up=True)
self.gc = canvas_klass(buffer, bottom_up=True)
marker_ren_klass = pix_format_marker_renderers[self.pix_format]
self.marker_gc = marker_ren_klass(buffer, bottom_up=True)

# init the state variables
clip = agg.Rect(0, 0, self._width, self._height)
Expand Down Expand Up @@ -826,6 +835,33 @@ def draw_path_at_points(self, points, path, mode=constants.FILL_STROKE):
fill=self.fill_paint,
)

def draw_marker_at_points(self, points, size,
marker=constants.SQUARE_MARKER):
""" Draw a marker at a collection of points
"""
# Apply the current transform
ctm = self.transform
self.marker_gc.transform(
ctm.sx, ctm.shy,
ctm.shx, ctm.sy,
ctm.tx, ctm.ty,
)

# Grab the fill and stroke colors (where possible)
fill = (0.0, 0.0, 0.0, 0.0)
stroke = (0.0, 0.0, 0.0, 1.0)
if isinstance(self.fill_paint, agg.SolidPaint):
fp = self.fill_paint
fill = (fp.r, fp.g, fp.b, fp.a)
if isinstance(self.stroke_paint, agg.SolidPaint):
sp = self.stroke_paint
stroke = (sp.r, sp.g, sp.b, sp.a)

# Draw using the marker renderer
self.marker_gc.draw_marker_at_points(
points, size, marker, fill, stroke
)

def save(self, filename, file_format=None, pil_options=None):
""" Save the contents of the context to a file
"""
Expand All @@ -841,7 +877,7 @@ def save(self, filename, file_format=None, pil_options=None):
os.path.splitext(filename)[1][1:] if isinstance(filename, str)
else ''
)

# Check the output format to see if it can handle an alpha channel.
no_alpha_formats = ('jpg', 'bmp', 'eps', 'jpeg')
if ext in no_alpha_formats or file_format.lower() in no_alpha_formats:
Expand Down
18 changes: 18 additions & 0 deletions kiva/marker_renderer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# (C) Copyright 2005-2021 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
from kiva._marker_renderer import (
MarkerRendererABGR32, MarkerRendererARGB32, MarkerRendererBGR24,
MarkerRendererBGRA32, MarkerRendererRGB24, MarkerRendererRGBA32,
)

__all__ = [
"MarkerRendererABGR32", "MarkerRendererARGB32", "MarkerRendererBGR24",
"MarkerRendererBGRA32", "MarkerRendererRGB24", "MarkerRendererRGBA32",
]
65 changes: 65 additions & 0 deletions kiva/markers/LICENSES/LICENSE_Agg
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
The Anti-Grain Geometry Project
A high quality rendering engine for C++
http://antigrain.com

Anti-Grain Geometry has dual licensing model. The Modified BSD
License was first added in version v2.4 just for convenience.
It is a simple, permissive non-copyleft free software license,
compatible with the GNU GPL. It's well proven and recognizable.
See http://www.fsf.org/licensing/licenses/index_html#ModifiedBSD
for details.

Note that the Modified BSD license DOES NOT restrict your rights
if you choose the Anti-Grain Geometry Public License.




Anti-Grain Geometry Public License
====================================================

Anti-Grain Geometry - Version 2.4
Copyright (C) 2002-2005 Maxim Shemanarev (McSeem)

Permission to copy, use, modify, sell and distribute this software
is granted provided this copyright notice appears in all copies.
This software is provided "as is" without express or implied
warranty, and with no claim as to its suitability for any purpose.





Modified BSD License
====================================================
Anti-Grain Geometry - Version 2.4
Copyright (C) 2002-2005 Maxim Shemanarev (McSeem)

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.

3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior
written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

Loading

0 comments on commit cd06311

Please sign in to comment.