pax_global_header00006660000000000000000000000064124065770530014523gustar00rootroot0000000000000052 comment=83434d6b54da91f48225bff3bf6de095ca477de3 abstract_rendering-0.5.1/000077500000000000000000000000001240657705300153665ustar00rootroot00000000000000abstract_rendering-0.5.1/.gitignore000066400000000000000000000011121240657705300173510ustar00rootroot00000000000000MANIFEST .DS_Store *.stats *.csv *.hdf *.hdf5 # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Distribution / packaging .Python env/ bin/ build/ develop-eggs/ dist/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # Rope .ropeproject # Django stuff: *.log *.pot # Sphinx documentation _build/ abstract_rendering-0.5.1/.travis.yml000066400000000000000000000014301240657705300174750ustar00rootroot00000000000000language: python python: - "2.7" - "3.3" - "3.4" install: - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then wget http://repo.continuum.io/miniconda/Miniconda-3.4.2-Linux-x86_64.sh -O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-3.4.2-Linux-x86_64.sh -O miniconda.sh; fi - bash miniconda.sh -b -p $HOME/miniconda - export PATH="$HOME/miniconda/bin:$PATH" - hash -r - conda config --set always_yes yes --set changeps1 no - conda update -q conda # Useful for debugging any issues with conda - conda info -a - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy blaze nose - source activate test-environment - python setup.py install script: - cd abstract_rendering/test - nosetests *.py abstract_rendering-0.5.1/LICENSE000066400000000000000000000036371240657705300164040ustar00rootroot00000000000000Copyright (c) 2011-2013 The Trustees of Indiana University and Indiana University Research and Technology Corporation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer listed in this license in the documentation and/or other materials provided with the distribution. - Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. The copyright holders provide no reassurances that the source code provided does not infringe any patent, copyright, or any other intellectual property rights of third parties. The copyright holders disclaim any liability to any recipient for claims brought against recipient by any third party for infringement of that parties intellectual property rights. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. abstract_rendering-0.5.1/README.md000066400000000000000000000030261240657705300166460ustar00rootroot00000000000000Abstract Rendering ====== Information visualization rests on the idea that a meaningful relationship can be drawn between pixels and data. This is most often mediated by geometric entities (such as circles, squares and text) but always involves pixels eventually to display. In most systems, the pixels are tucked away under levels of abstraction in the rendering system. Abstract Rendering takes the opposite approach: expose the pixels and gain powerful pixel-level control. This pixel-level power is a complement many existing visualization techniques. It is an elaboration on rendering, not an analytic or projection step, so it can be used as epilogue to many existing techniques. In standard rendering, geometric objects are projected to an image and represented on that image's discrete pixels. The source space is a canvas that contains logically continuous geometric primitives and the target space is an image that contains discrete colors. Abstract Rendering fits between these two states. It introduces a discretization of the data at the pixel-level, but not necessarily all the way to colors. This enables many pixel-level concerns to be efficiently and concisely captured. This repository is a Python implementation of the abstract rendering framework. For more details on the conceptual framework and examples of applications, please see the [more general repository](https://github.com/JosephCottam/AbstractRendering/). Sample images can be found in [the central wiki](https://github.com/JosephCottam/AbstractRendering/wiki). abstract_rendering-0.5.1/abstract_rendering/000077500000000000000000000000001240657705300212265ustar00rootroot00000000000000abstract_rendering-0.5.1/abstract_rendering/README.md000066400000000000000000000016031240657705300225050ustar00rootroot00000000000000Organization ------------- The tools are arranged roughly by data-type. The core system (drives and interface definitions) is in core.py. Tools for creating or working with categorical aggregates are found in categories.py. Tools for working with numerical aggregates are found in numeric.py. NOTE: We are experimenting with names...so what is know as 'transfer' in other implementations is known as 'shader' in the python implementation. Verb forms change accordingly. Build and Dependencies ========== The python distribution includes a setup file. To install (including c++ extensions) simply run 'python setup.py install'. Building of the extensions requires c++11 support. Examples Applications --------------------- GUI: python.app arDemo.py text checkerboard: python ar.py ../data/checkerboard.csv 2 0 1 3 1 text circlepoints: python ar.py ../data/circlepoints.csv 1 2 3 4 .1 abstract_rendering-0.5.1/abstract_rendering/__init__.py000066400000000000000000000007071240657705300233430ustar00rootroot00000000000000from __future__ import print_function import os __version__ = "-1.-1.-1" try: version_file = os.path.join(os.path.dirname(__file__), '', '_version.txt') with open(version_file, 'r') as version_file: __version__ = version_file.read().strip() except Exception as e: print("Error finding version info.") print(e) __version_info__ = dict(zip(["major","minor","micro"], map(int, __version__.split(".")))) abstract_rendering-0.5.1/abstract_rendering/_version.txt000066400000000000000000000000061240657705300236070ustar00rootroot000000000000000.5.1 abstract_rendering-0.5.1/abstract_rendering/categories.py000066400000000000000000000167021240657705300237330ustar00rootroot00000000000000""" Tools for working with counts from multiple categories of data at once. Categories are modeled as stakced 2D arrays. Each category is in its own slice of the stack. """ from __future__ import print_function, division, absolute_import from six.moves import reduce import numpy as np from math import log import abstract_rendering.util as util import abstract_rendering.core as core # ------------ Aggregators ------------------- class CountCategories(core.GlyphAggregator): """ Count the number of items that fall into a particular grid element. To operateo correctly, allocate must be called with infos representing all possible categories; that set of categories is used in combine to determine where to place values. It is, therefore, important that any call to combine must in some way correspond to the most recent call to allocate. TODO: This seems convoluted...is there a better way? """ out_type = np.int32 identity = np.asarray([0]) cats = None def allocate(self, glyphset, screen): """Allocates one array slice for each unique info passed. Output array shape is (#cats, height, width). """ (width, height) = screen self.cats = np.unique(glyphset.data()) return np.zeros((height, width, len(self.cats)), dtype=self.out_type) def combine(self, existing, points, shapecode, val): entry = np.zeros(len(self.cats)) idx = np.nonzero(self.cats == val)[0][0] entry[idx] = 1 update = self.glyphAggregates(points, shapecode, entry, self.identity) existing[points[1]:points[3], points[0]:points[2], :] \ += update def rollup(self, *vals): """NOTE: Assumes co-registration of categories...""" return reduce(lambda x, y: x+y, vals) # ----------- Shaders ----------------------- class ToCounts(core.CellShader): """Convert from count-by-categories to just raw counts. Then data shader functions from the count module can be used. """ @staticmethod def shade(grid, dtype=None): dtype = (grid.dtype if dtype is None else dtype) return grid.sum(axis=2, dtype=dtype) class NonZeros(core.CellShader): "How many non-zero categories are there?" def shade(self, grid): mask = grid != 0 nonzero = np.zeros_like(grid) nonzero[mask] = 1 return nonzero.sum(axis=2) class Ratio(core.CellShader): """ Compute the ratio of one category to the sum of all cateogires. Any cell with sum of zero is propogated as a 'zero' in the sum * focus: The "one cateogry" Will pick the local 'max' cateogry if set to a negative """ def __init__(self, focus=-1): self.focus = focus def shade(self, grid): if self.focus < 0: plane = grid.max(axis=2) else: plane = grid[:, :, self.focus] sum = grid.sum(axis=2) mask = (sum != 0) ratio = plane/sum ratio[~mask] = 0 return ratio class Select(core.CellShader): """Get the counts from just one category. Operates by taking a single plane of the count of categories. TODO: Consider changing shade to take a wrapper 'grid' that can carry info like a category-label-to-grid-slice mapping.... """ def __init__(self, slice): """slice -- Which slice of the aggregates grid should be returned""" self.slice = slice def shade(self, aggregates): return aggregates[:, :, self.slice] class MinPercent(core.CellShader): """If the item in the specified bin represents more than a certain percent of the total number of items, color it as "above" otherwise, "below" TODO: Change from idx to category label, lookup idx for 'cat' parameter TODO: Extend to work with more than just colors * cutoff -- percent value to split above and below coloring * cat -- integer indicating which category number to use * above -- color to paint above (default is a red) * below -- color to paint below (default is a blue) * background -- color to paint when there are no values (default is clear) """ def __init__(self, cutoff, cat=0, above=util.Color(228, 26, 28, 255), below=util.Color(55, 126, 184, 255), background=util.Color(255, 255, 255, 0)): self.cutoff = cutoff self.cat = cat self.above = np.array(above, dtype=np.uint8) self.below = np.array(below, dtype=np.uint8) self.background = np.array(background, dtype=np.uint8) def shade(self, grid): (height, width, depth) = grid.shape outgrid = np.empty((height, width, 4), dtype=np.uint8) sums = ToCounts.shade(grid, dtype=np.float32) maskbg = (sums == 0) mask = (grid[:, :, self.cat]/sums) >= self.cutoff outgrid[mask] = self.above outgrid[~mask] = self.below outgrid[maskbg] = self.background return outgrid class HDAlpha(core.CellShader): def __init__(self, colors, background=util.Color(255, 255, 255, 255), alphamin=0, log=False, logbase=10): """ colors -- a list of colors in cateogry-order. alphamin -- minimum alpha value when (default is 0) log -- Log-based interpolate? (default is false) logbase -- Base to use if log is true (default is 10) background -- Color for empty category list (default is white) If C categories and N colors are presented: * N == C: No problems * N > C: Only the first C colors are used * N < C: The last color is replicated to make N == C TODO: Change 'colors' to a dictionary of category-to-color mapping TODO: mask out zero-sum regions in alpha and opaque blend """ self.catcolors = np.array([np.array(v, dtype=np.uint8) for v in colors]) self.background = np.array(background, dtype=np.uint8) self.alphamin = alphamin self.log = log self.logbase = logbase def shade(self, grid): sums = ToCounts.shade(grid, dtype=np.float32) mask = (sums != 0) # Ensure category count and color count match cats = grid.shape[2] catcolors = self.catcolors if len(catcolors) > cats: catcolors = catcolors[:cats] elif len(catcolors) < cats: other = catcolors[-1] replicated = [other] * (cats-len(catcolors)) catcolors = np.vstack([catcolors, replicated]) colors = HDAlpha.opaqueblend(catcolors, grid, sums) colors[~mask] = self.background HDAlpha.alpha(colors, sums, mask, self.alphamin, self.log, self.logbase) return colors # ------------------- Utilities ----------------- @staticmethod def alpha(colors, sums, mask, alphamin, dolog=False, base=10): maxval = sums.max() if (dolog): base = log(base) maxval = log(maxval)/base sums[mask] = np.log10(sums[mask])/base np.putmask(colors[:, :, 3], mask, ((alphamin + ((1-alphamin) * (sums/maxval)))*255).astype(np.uint8)) @staticmethod def opaqueblend(catcolors, counts, sums): weighted = (counts/sums[:, :, np.newaxis]).astype(float) weighted = catcolors[np.newaxis, np.newaxis, :] * weighted[:, :, :, np.newaxis] colors = weighted.sum(axis=2).astype(np.uint8) return colors abstract_rendering-0.5.1/abstract_rendering/cntr.c000066400000000000000000001616171240657705300223540ustar00rootroot00000000000000/* cntr.c General purpose contour tracer for quadrilateral meshes. Handles single level contours, or region between a pair of levels. The routines that do all the work, as well as the explanatory comments, came from gcntr.c, part of the GIST package. The original mpl interface was also based on GIST. The present interface uses parts of the original, but places them in the entirely different framework of a Python type. It was written by following the Python "Extending and Embedding" tutorial. License Note: * cntr.c was part of the chaco library, licensed under 3-clause BSD. * gcntr.c was part of the yorick, licensed under 3-clause BSD. $Id: cntr.c,v 1.3 2005/06/02 22:02:32 jdh2358 Exp $ Change log: * Aug 2014 -- Joseph Cottam: * Changed name of resulting module and added license notes * */ #include #include "structmember.h" #include #include #ifdef NUMPY #include "numpy/arrayobject.h" # ifndef PyArray_SBYTE # include "numpy/oldnumeric.h" # include "numpy/old_defines.h" # endif #else # include "Numeric/arrayobject.h" # define PyArray_UBYTELTR 'b' #endif /* Note that all arrays in these routines are Fortran-style, in the sense that the "i" index varies fastest; the dimensions of the corresponding C array are z[jmax][imax] in the notation used here. We can identify i and j with the x and y dimensions, respectively. */ /* What is a contour? * * Given a quadrilateral mesh (x,y), and values of a z at the points * of that mesh, we seek a set of polylines connecting points at a * particular value of z. Each point on such a contour curve lies * on an edge of the mesh, at a point linearly interpolated to the * contour level z0 between the given values of z at the endpoints * of the edge. * * Identifying these points is easy. Figuring out how to connect them * into a curve -- or possibly a set of disjoint curves -- is difficult. * Each disjoint curve may be either a closed circuit, or it may begin * and end on a mesh boundary. * * One of the problems with a quadrilateral mesh is that when the z * values at one pair of diagonally opposite points lie below z0, and * the values at the other diagonal pair of the same zone lie above z0, * all four edges of the zone are cut, and there is an ambiguity in * how we should connect the points. I call this a saddle zone. * The problem is that two disjoint curves cut through a saddle zone * (I reject the alternative of connecting the opposite points to make * a single self-intersecting curve, since those make ugly contour plots * -- I've tried it). The real problem with saddle zones is that you * need to communicate the connectivity decision you make back to the * calling routine, since for the next contour level, we need to tell * the contour tracer to make the same decision as on the previous * level. The input/output triangulation array is the solution to this * nasty problem. * * Another complicating factor is that there may be logical holes in * the mesh -- zones which do not exist. We want our contours to stop * if they hit the edge of such a zone, just as if they'd hit the edge * of the whole mesh. The input region array addresses this issue. * * Yet another complication: We may want a list of closed polygons which * outline the region between two contour levels z0 and z1. These may * include sections of the mesh boundary (including edges of logical * holes defined by the region array), in addition to sections of the * contour curves at one or both levels. This introduces a huge * topological problem -- if one of the closed contours (possibly * including an interior logical hole in the mesh, but not any part of * the boundary of the whole mesh) encloses a region which is not * between z0 and z1, that curve must be connected by a slit (or "branch * cut") to the enclosing curve, so that the list of disjoint polygons * we return is each simply connected. * * Okay, one final stunning difficulty: For the two level case, no * individual polygon should have more than a few thousand sides, since * huge filled polygons place an inordinate load on rendering software, * which needs an amount of scratch space proportional to the number * of sides it needs to fill. So in the two level case, we want to * chunk the mesh into rectangular pieces of no more than, say, 30x30 * zones, which keeps each returned polygon to less than a few thousand * sides (the worst case is very very bad -- you can easily write down * a function and two level values which produce a polygon that cuts * every edge of the mesh twice). */ /* * Here is the numbering scheme for points, edges, and zones in * the mesh -- note that each ij corresponds to one point, one zone, * one i-edge (i=constant edge) and one j-edge (j=constant edge): * * (ij-1)-------(ij)-------(ij) * | | * | | * | | * (ij-1) (ij) (ij) * | | * | | * | | * (ij-iX-1)----(ij-iX)----(ij-iX) * * At each point, the function value is either 0, 1, or 2, depending * on whether it is below z0, between z0 and z1, or above z1. * Each zone either exists (1) or not (0). * From these three bits of data, all of the curve connectivity follows. * * The tracing algorithm is naturally edge-based: Either you are at a * point where a level cuts an edge, ready to step across a zone to * another edge, or you are drawing the edge itself, if it happens to * be a boundary with at least one section between z0 and z1. * * In either case, the edge is a directed edge -- either the zone * you are advancing into is to its left or right, or you are actually * drawing it. I always trace curves keeping the region between z0 and * z1 to the left of the curve. If I'm tracing a boundary, I'm always * moving CCW (counter clockwise) around the zone that exists. And if * I'm about to cross a zone, I'll make the direction of the edge I'm * sitting on be such that the zone I'm crossing is to its left. * * I start tracing each curve near its lower left corner (mesh oriented * as above), which is the first point I encounter scanning through the * mesh in order. When I figure the 012 z values and zonal existence, * I also mark the potential starting points: Each edge may harbor a * potential starting point corresponding to either direction, so there * are four start possibilities at each ij point. Only the following * possibilities need to be marked as potential starting edges: * * +-+-+-+ * | | | | * A-0-C-+ One or both levels cut E and have z=1 above them, and * | EZ| | 0A is cut and either 0C is cut or CD is cut. * +-B-D-+ Or, one or both levels cut E and E is a boundary edge. * | | | | (and Z exists) * +-+-+-+ * * +-+-+-+ * | | | | * +-A-0-C One or both levels cut E and have z=1 below them, and * | |ZE | 0A is cut and either 0C is cut or CD is cut. * +-+-B-D Or, one or both levels cut E and E is a boundary edge. * | | | | (and Z exists) * +-+-+-+ * * +-+-+-+ * | | | | * +-+-+-+ E is a boundary edge, Z exists, at some point on E * | |Z| | lies between the levels. * +-+E+-+ * | | | | * +-+-+-+ * * +-+-+-+ * | | | | * +-+E+-+ E is a boundary edge, Z exists, at some point on E * | |Z| | lies between the levels. * +-+-+-+ * | | | | * +-+-+-+ * * During the first tracing pass, the start mark is erased whenever * any non-starting edge is encountered, reducing the number of points * that need to be considered for the second pass. The first pass * makes the basic connectivity decisions. It figures out how many * disjoint curves there will be, and identifies slits for the two level * case or open contours for the single level case, and removes all but * the actual start markers. A second tracing pass can perform the * actual final trace. */ /* ------------------------------------------------------------------------ */ /* the data about edges, zones, and points -- boundary or not, exists * or not, z value 0, 1, or 2 -- is kept in a mesh sized data array */ typedef short Cdata; /* here is the minimum structure required to tell where we are in the * mesh sized data array */ typedef struct Csite Csite; struct Csite { long edge; /* ij of current edge */ long left; /* +-1 or +-imax as the zone is to right, left, below, * or above the edge */ long imax; /* imax for the mesh */ long jmax; /* jmax for the mesh */ long n; /* number of points marked on this curve so far */ long count; /* count of start markers visited */ double zlevel[2]; /* contour levels, zlevel[1]<=zlevel[0] * signals single level case */ short *triangle; /* triangulation array for the mesh */ char *reg; /* region array for the mesh (was int) */ Cdata *data; /* added by EF */ long edge0, left0; /* starting site on this curve for closure */ int level0; /* starting level for closure */ long edge00; /* site needing START_ROW mark */ /* making the actual marks requires a bunch of other stuff */ const double *x, *y, *z; /* mesh coordinates and function values */ double *xcp, *ycp; /* output contour points */ }; void print_Csite(Csite *Csite) { Cdata *data = Csite->data; int i, j, ij; int nd = Csite->imax * (Csite->jmax + 1) + 1; printf("zlevels: %8.2lg %8.2lg\n", Csite->zlevel[0], Csite->zlevel[1]); printf("edge %ld, left %ld, n %ld, count %ld, edge0 %ld, left0 %ld\n", Csite->edge, Csite->left, Csite->n, Csite->count, Csite->edge0, Csite->left0); printf(" level0 %d, edge00 %ld\n", Csite->level0, Csite->edge00); printf("%04x\n", data[nd-1]); for (j = Csite->jmax; j >= 0; j--) { for (i=0; i < Csite->imax; i++) { ij = i + j * Csite->imax; printf("%04x ", data[ij]); } printf("\n"); } printf("\n"); } /* triangle only takes values of -1, 0, 1, so it could be a signed char. */ /* most or all of the longs probably could be converted to ints with no loss */ /* the Cdata array consists of the following bits: * Z_VALUE (2 bits) 0, 1, or 2 function value at point * ZONE_EX 1 zone exists, 0 zone doesn't exist * I_BNDY this i-edge (i=constant edge) is a mesh boundary * J_BNDY this j-edge (i=constant edge) is a mesh boundary * I0_START this i-edge is a start point into zone to left * I1_START this i-edge is a start point into zone to right * J0_START this j-edge is a start point into zone below * J1_START this j-edge is a start point into zone above * START_ROW next start point is in current row (accelerates 2nd pass) * SLIT_UP marks this i-edge as the beginning of a slit upstroke * SLIT_DN marks this i-edge as the beginning of a slit downstroke * OPEN_END marks an i-edge start point whose other endpoint is * on a boundary for the single level case * ALL_DONE marks final start point */ #define Z_VALUE 0x0003 #define ZONE_EX 0x0004 #define I_BNDY 0x0008 #define J_BNDY 0x0010 #define I0_START 0x0020 #define I1_START 0x0040 #define J0_START 0x0080 #define J1_START 0x0100 #define START_ROW 0x0200 #define SLIT_UP 0x0400 #define SLIT_DN 0x0800 #define OPEN_END 0x1000 #define ALL_DONE 0x2000 /* some helpful macros to find points relative to a given directed * edge -- points are designated 0, 1, 2, 3 CCW around zone with 0 and * 1 the endpoints of the current edge */ #define FORWARD(left,ix) ((left)>0?((left)>1?1:-(ix)):((left)<-1?-1:(ix))) #define POINT0(edge,fwd) ((edge)-((fwd)>0?fwd:0)) #define POINT1(edge,fwd) ((edge)+((fwd)<0?fwd:0)) #define IS_JEDGE(edge,left) ((left)>0?((left)>1?1:0):((left)<-1?1:0)) #define ANY_START (I0_START|I1_START|J0_START|J1_START) #define START_MARK(left) \ ((left)>0?((left)>1?J1_START:I1_START):((left)<-1?J0_START:I0_START)) /* ------------------------------------------------------------------------ */ /* these actually mark points */ static int zone_crosser (Csite * site, int level, int pass2); static int edge_walker (Csite * site, int pass2); static int slit_cutter (Csite * site, int up, int pass2); /* this calls the first three to trace the next disjoint curve * -- return value is number of points on this curve, or * 0 if there are no more curves this pass * -(number of points) on first pass if: * this is two level case, and the curve closed on a hole * this is single level case, curve is open, and will start from * a different point on the second pass * -- in both cases, this curve will be combined with another * on the second pass */ static long curve_tracer (Csite * site, int pass2); /* this initializes the data array for curve_tracer */ static void data_init (Csite * site, int region, long nchunk); /* ------------------------------------------------------------------------ */ /* zone_crosser assumes you are sitting at a cut edge about to cross * the current zone. It always marks the initial point, crosses at * least one zone, and marks the final point. On non-boundary i-edges, * it is responsible for removing start markers on the first pass. */ static int zone_crosser (Csite * site, int level, int pass2) { Cdata * data = site->data; long edge = site->edge; long left = site->left; long n = site->n; long fwd = FORWARD (left, site->imax); long p0, p1; int jedge = IS_JEDGE (edge, left); long edge0 = site->edge0; long left0 = site->left0; int level0 = site->level0 == level; int two_levels = site->zlevel[1] > site->zlevel[0]; short *triangle = site->triangle; const double *x = pass2 ? site->x : 0; const double *y = pass2 ? site->y : 0; const double *z = pass2 ? site->z : 0; double zlevel = pass2 ? site->zlevel[level] : 0.0; double *xcp = pass2 ? site->xcp : 0; double *ycp = pass2 ? site->ycp : 0; int z0, z1, z2, z3; int keep_left = 0; /* flag to try to minimize curvature in saddles */ int done = 0; if (level) level = 2; for (;;) { /* set edge endpoints */ p0 = POINT0 (edge, fwd); p1 = POINT1 (edge, fwd); /* always mark cut on current edge */ if (pass2) { /* second pass actually computes and stores the point */ double zcp = (zlevel - z[p0]) / (z[p1] - z[p0]); xcp[n] = zcp * (x[p1] - x[p0]) + x[p0]; ycp[n] = zcp * (y[p1] - y[p0]) + y[p0]; } if (!done && !jedge) { if (n) { /* if this is not the first point on the curve, and we're * not done, and this is an i-edge, check several things */ if (!two_levels && !pass2 && (data[edge] & OPEN_END)) { /* reached an OPEN_END mark, skip the n++ */ done = 4; /* same return value 4 used below */ break; } /* check for curve closure -- if not, erase any start mark */ if (edge == edge0 && left == left0) { /* may signal closure on a downstroke */ if (level0) done = (!pass2 && two_levels && left < 0) ? 5 : 3; } else if (!pass2) { Cdata start = data[edge] & (fwd > 0 ? I0_START : I1_START); if (start) { data[edge] &= ~start; site->count--; } if (!two_levels) { start = data[edge] & (fwd > 0 ? I1_START : I0_START); if (start) { data[edge] &= ~start; site->count--; } } } } } n++; if (done) break; /* cross current zone to another cut edge */ z0 = (data[p0] & Z_VALUE) != level; /* 1 if fill toward p0 */ z1 = !z0; /* know level cuts edge */ z2 = (data[p1 + left] & Z_VALUE) != level; z3 = (data[p0 + left] & Z_VALUE) != level; if (z0 == z2) { if (z1 == z3) { /* this is a saddle zone, need triangle to decide * -- set triangle if not already decided for this zone */ long zone = edge + (left > 0 ? left : 0); if (triangle) { if (!triangle[zone]) { if (keep_left) triangle[zone] = jedge ? -1 : 1; else triangle[zone] = jedge ? 1 : -1; } if (triangle[zone] > 0 ? !jedge : jedge) goto bkwd; } else { if (keep_left) goto bkwd; } } /* bend forward (right along curve) */ keep_left = 1; jedge = !jedge; edge = p1 + (left > 0 ? left : 0); { long tmp = fwd; fwd = -left; left = tmp; } } else if (z1 == z3) { bkwd: /* bend backward (left along curve) */ keep_left = 0; jedge = !jedge; edge = p0 + (left > 0 ? left : 0); { long tmp = fwd; fwd = left; left = -tmp; } } else { /* straight across to opposite edge */ edge += left; } /* after crossing zone, edge/left/fwd is oriented CCW relative to * the next zone, assuming we will step there */ /* now that we've taken a step, check for the downstroke * of a slit on the second pass (upstroke checked above) * -- taking step first avoids a race condition */ if (pass2 && two_levels && !jedge) { if (left > 0) { if (data[edge] & SLIT_UP) done = 6; } else { if (data[edge] & SLIT_DN) done = 5; } } if (!done) { /* finally, check if we are on a boundary */ if (data[edge] & (jedge ? J_BNDY : I_BNDY)) { done = two_levels ? 2 : 4; /* flip back into the zone that exists */ left = -left; fwd = -fwd; if (!pass2 && (edge != edge0 || left != left0)) { Cdata start = data[edge] & START_MARK (left); if (start) { data[edge] &= ~start; site->count--; } } } } } site->edge = edge; site->n = n; site->left = left; return done > 4 ? slit_cutter (site, done - 5, pass2) : done; } /* edge_walker assumes that the current edge is being drawn CCW * around the current zone. Since only boundary edges are drawn * and we always walk around with the filled region to the left, * no edge is ever drawn CW. We attempt to advance to the next * edge on this boundary, but if current second endpoint is not * between the two contour levels, we exit back to zone_crosser. * Note that we may wind up marking no points. * -- edge_walker is never called for single level case */ static int edge_walker (Csite * site, int pass2) { Cdata * data = site->data; long edge = site->edge; long left = site->left; long n = site->n; long fwd = FORWARD (left, site->imax); long p0 = POINT0 (edge, fwd); long p1 = POINT1 (edge, fwd); int jedge = IS_JEDGE (edge, left); long edge0 = site->edge0; long left0 = site->left0; int level0 = site->level0 == 2; int marked; const double *x = pass2 ? site->x : 0; const double *y = pass2 ? site->y : 0; double *xcp = pass2 ? site->xcp : 0; double *ycp = pass2 ? site->ycp : 0; int z0, z1, heads_up = 0; for (;;) { /* mark endpoint 0 only if value is 1 there, and this is a * two level task */ z0 = data[p0] & Z_VALUE; z1 = data[p1] & Z_VALUE; marked = 0; if (z0 == 1) { /* mark current boundary point */ if (pass2) { xcp[n] = x[p0]; ycp[n] = y[p0]; } marked = 1; } else if (!n) { /* if this is the first point is not between the levels * must do the job of the zone_crosser and mark the first cut here, * so that it will be marked again by zone_crosser as it closes */ if (pass2) { double zcp = site->zlevel[(z0 != 0)]; zcp = (zcp - site->z[p0]) / (site->z[p1] - site->z[p0]); xcp[n] = zcp * (x[p1] - x[p0]) + x[p0]; ycp[n] = zcp * (y[p1] - y[p0]) + y[p0]; } marked = 1; } if (n) { /* check for closure */ if (level0 && edge == edge0 && left == left0) { site->edge = edge; site->left = left; site->n = n + marked; /* if the curve is closing on a hole, need to make a downslit */ if (fwd < 0 && !(data[edge] & (jedge ? J_BNDY : I_BNDY))) return slit_cutter (site, 0, pass2); return 3; } else if (pass2) { if (heads_up || (fwd < 0 && (data[edge] & SLIT_DN))) { site->edge = edge; site->left = left; site->n = n + marked; return slit_cutter (site, heads_up, pass2); } } else { /* if this is not first point, clear start mark for this edge */ Cdata start = data[edge] & START_MARK (left); if (start) { data[edge] &= ~start; site->count--; } } } if (marked) n++; /* if next endpoint not between levels, need to exit to zone_crosser */ if (z1 != 1) { site->edge = edge; site->left = left; site->n = n; return (z1 != 0); /* return level closest to p1 */ } /* step to p1 and find next edge * -- turn left if possible, else straight, else right * -- check for upward slit beginning at same time */ edge = p1 + (left > 0 ? left : 0); if (pass2 && jedge && fwd > 0 && (data[edge] & SLIT_UP)) { jedge = !jedge; heads_up = 1; } else if (data[edge] & (jedge ? I_BNDY : J_BNDY)) { long tmp = fwd; fwd = left; left = -tmp; jedge = !jedge; } else { edge = p1 + (fwd > 0 ? fwd : 0); if (pass2 && !jedge && fwd > 0 && (data[edge] & SLIT_UP)) { heads_up = 1; } else if (!(data[edge] & (jedge ? J_BNDY : I_BNDY))) { edge = p1 - (left < 0 ? left : 0); jedge = !jedge; { long tmp = fwd; fwd = -left; left = tmp; } } } p0 = p1; p1 = POINT1 (edge, fwd); } } /* -- slit_cutter is never called for single level case */ static int slit_cutter (Csite * site, int up, int pass2) { Cdata * data = site->data; long imax = site->imax; long n = site->n; const double *x = pass2 ? site->x : 0; const double *y = pass2 ? site->y : 0; double *xcp = pass2 ? site->xcp : 0; double *ycp = pass2 ? site->ycp : 0; if (up) { /* upward stroke of slit proceeds up left side of slit until * it hits a boundary or a point not between the contour levels * -- this never happens on the first pass */ long p1 = site->edge; int z1; for (;;) { z1 = data[p1] & Z_VALUE; if (z1 != 1) { site->edge = p1; site->left = -1; site->n = n; return (z1 != 0); } else if (data[p1] & J_BNDY) { /* this is very unusual case of closing on a mesh hole */ site->edge = p1; site->left = -imax; site->n = n; return 2; } xcp[n] = x[p1]; ycp[n] = y[p1]; n++; p1 += imax; } } else { /* downward stroke proceeds down right side of slit until it * hits a boundary or point not between the contour levels */ long p0 = site->edge; int z0; /* at beginning of first pass, mark first i-edge with SLIT_DN */ data[p0] |= SLIT_DN; p0 -= imax; for (;;) { z0 = data[p0] & Z_VALUE; if (!pass2) { if (z0 != 1 || (data[p0] & I_BNDY) || (data[p0 + 1] & J_BNDY)) { /* at end of first pass, mark final i-edge with SLIT_UP */ data[p0 + imax] |= SLIT_UP; /* one extra count for splicing at outer curve */ site->n = n + 1; return 4; /* return same special value as for OPEN_END */ } } else { if (z0 != 1) { site->edge = p0 + imax; site->left = 1; site->n = n; return (z0 != 0); } else if (data[p0 + 1] & J_BNDY) { site->edge = p0 + 1; site->left = imax; site->n = n; return 2; } else if (data[p0] & I_BNDY) { site->edge = p0; site->left = 1; site->n = n; return 2; } } if (pass2) { xcp[n] = x[p0]; ycp[n] = y[p0]; n++; } else { /* on first pass need to count for upstroke as well */ n += 2; } p0 -= imax; } } } /* ------------------------------------------------------------------------ */ /* curve_tracer finds the next starting point, then traces the curve, * returning the number of points on this curve * -- in a two level trace, the return value is negative on the * first pass if the curve closed on a hole * -- in a single level trace, the return value is negative on the * first pass if the curve is an incomplete open curve * -- a return value of 0 indicates no more curves */ static long curve_tracer (Csite * site, int pass2) { Cdata * data = site->data; long imax = site->imax; long edge0 = site->edge0; long left0 = site->left0; long edge00 = site->edge00; int two_levels = site->zlevel[1] > site->zlevel[0]; int level, level0, mark_row; long n; /* it is possible for a single i-edge to serve as two actual start * points, one to the right and one to the left * -- for the two level case, this happens on the first pass for * a doubly cut edge, or on a chunking boundary * -- for single level case, this is impossible, but a similar * situation involving open curves is handled below * a second two start possibility is when the edge0 zone does not * exist and both the i-edge and j-edge boundaries are cut * yet another possibility is three start points at a junction * of chunk cuts * -- sigh, several other rare possibilities, * allow for general case, just go in order i1, i0, j1, j0 */ int two_starts; /* printf("curve_tracer pass %d\n", pass2); */ /* print_Csite(site); */ if (left0 == 1) two_starts = data[edge0] & (I0_START | J1_START | J0_START); else if (left0 == -1) two_starts = data[edge0] & (J1_START | J0_START); else if (left0 == imax) two_starts = data[edge0] & J0_START; else two_starts = 0; if (pass2 || edge0 == 0) { /* zip up to row marked on first pass (or by data_init if edge0==0) * -- but not for double start case */ if (!two_starts) { /* final start point marked by ALL_DONE marker */ int first = (edge0 == 0 && !pass2); long e0 = edge0; if (data[edge0] & ALL_DONE) return 0; while (!(data[edge0] & START_ROW)) edge0 += imax; if (e0 == edge0) edge0++; /* two starts handled specially */ if (first) /* if this is the very first start point, we want to remove * the START_ROW marker placed by data_init */ data[edge0 - edge0 % imax] &= ~START_ROW; } } else { /* first pass ends when all potential start points visited */ if (site->count <= 0) { /* place ALL_DONE marker for second pass */ data[edge00] |= ALL_DONE; /* reset initial site for second pass */ site->edge0 = site->edge00 = site->left0 = 0; return 0; } if (!two_starts) edge0++; } if (two_starts) { /* trace second curve with this start immediately */ if (left0 == 1 && (data[edge0] & I0_START)) { left0 = -1; level = (data[edge0] & I_BNDY) ? 2 : 0; } else if ((left0 == 1 || left0 == -1) && (data[edge0] & J1_START)) { left0 = imax; level = 2; } else { left0 = -imax; level = 2; } } else { /* usual case is to scan for next start marker * -- on second pass, this is at most one row of mesh, but first * pass hits nearly every point of the mesh, since it can't * know in advance which potential start marks removed */ while (!(data[edge0] & ANY_START)) edge0++; if (data[edge0] & I1_START) left0 = 1; else if (data[edge0] & I0_START) left0 = -1; else if (data[edge0] & J1_START) left0 = imax; else /*data[edge0]&J0_START */ left0 = -imax; if (data[edge0] & (I1_START | I0_START)) level = (data[edge0] & I_BNDY) ? 2 : 0; else level = 2; } /* this start marker will not be unmarked, but it has been visited */ if (!pass2) site->count--; /* if this curve starts on a non-boundary i-edge, we need to * determine the level */ if (!level && two_levels) level = left0 > 0 ? ((data[edge0 - imax] & Z_VALUE) != 0) : ((data[edge0] & Z_VALUE) != 0); /* initialize site for this curve */ site->edge = site->edge0 = edge0; site->left = site->left0 = left0; site->level0 = level0 = level; /* for open curve detection only */ /* single level case just uses zone_crosser */ if (!two_levels) level = 0; /* to generate the curve, alternate between zone_crosser and * edge_walker until closure or first call to edge_walker in * single level case */ site->n = 0; for (;;) { if (level < 2) level = zone_crosser (site, level, pass2); else if (level < 3) level = edge_walker (site, pass2); else break; } n = site->n; /* single level case may have ended at a boundary rather than closing * -- need to recognize this case here in order to place the * OPEN_END mark for zone_crosser, remove this start marker, * and be sure not to make a START_ROW mark for this case * two level case may close with slit_cutter, in which case start * must also be removed and no START_ROW mark made * -- change sign of return n to inform caller */ if (!pass2 && level > 3 && (two_levels || level0 == 0)) { if (!two_levels) data[edge0] |= OPEN_END; data[edge0] &= ~(left0 > 0 ? I1_START : I0_START); mark_row = 0; /* do not mark START_ROW */ n = -n; } else { if (two_levels) mark_row = !two_starts; else mark_row = 1; } /* on first pass, must apply START_ROW mark in column above previous * start marker * -- but skip if we just did second of two start case */ if (!pass2 && mark_row) { data[edge0 - (edge0 - edge00) % imax] |= START_ROW; site->edge00 = edge0; } return n; } /* ------------------------------------------------------------------------ */ /* The sole function of the "region" argument is to specify the value in Csite.reg that denotes a missing zone. We always use zero. */ static void data_init (Csite * site, int region, long nchunk) { Cdata * data = site->data; long imax = site->imax; long jmax = site->jmax; long ijmax = imax * jmax; const double *z = site->z; double zlev0 = site->zlevel[0]; double zlev1 = site->zlevel[1]; int two_levels = zlev1 > zlev0; char *reg = site->reg; long count = 0; int started = 0; int ibndy, jbndy, i_was_chunk; long icsize = imax - 1; long jcsize = jmax - 1; long ichunk, jchunk, irem, jrem, i, j, ij; if (nchunk && two_levels) { /* figure out chunk sizes * -- input nchunk is square root of maximum allowed zones per chunk * -- start points for single level case are wrong, so don't try it */ long inum = (nchunk * nchunk) / (jmax - 1); long jnum = (nchunk * nchunk) / (imax - 1); if (inum < nchunk) inum = nchunk; if (jnum < nchunk) jnum = nchunk; /* ijnum= actual number of chunks, * ijrem= number of those chunks needing one more zone (ijcsize+1) */ inum = (imax - 2) / inum + 1; icsize = (imax - 1) / inum; irem = (imax - 1) % inum; jnum = (jmax - 2) / jnum + 1; jcsize = (jmax - 1) / jnum; jrem = (jmax - 1) % jnum; /* convert ijrem into value of i or j at which to begin adding an * extra zone */ irem = (inum - irem) * icsize; jrem = (jnum - jrem) * jcsize; } else { irem = imax; jrem = jmax; } /* do everything in a single pass through the data array to * minimize cache faulting (z, reg, and data are potentially * very large arrays) * access to the z and reg arrays is strictly sequential, * but we need two rows (+-imax) of the data array at a time */ if (z[0] > zlev0) data[0] = (two_levels && z[0] > zlev1) ? 2 : 1; else data[0] = 0; jchunk = 0; for (j = ij = 0; j < jmax; j++) { ichunk = i_was_chunk = 0; for (i = 0; i < imax; i++, ij++) { /* transfer zonal existence from reg to data array * -- get these for next row so we can figure existence of * points and j-edges for this row */ data[ij + imax + 1] = 0; if (reg) { if (region ? (reg[ij + imax + 1] == region) : (reg[ij + imax + 1] != 0)) data[ij + imax + 1] = ZONE_EX; } else { if (i < imax - 1 && j < jmax - 1) data[ij + imax + 1] = ZONE_EX; } /* translate z values to 0, 1, 2 flags */ if (ij < imax) data[ij + 1] = 0; if (ij < ijmax - 1 && z[ij + 1] > zlev0) data[ij + 1] |= (two_levels && z[ij + 1] > zlev1) ? 2 : 1; /* apply edge boundary marks */ ibndy = i == ichunk || (data[ij] & ZONE_EX) != (data[ij + 1] & ZONE_EX); jbndy = j == jchunk || (data[ij] & ZONE_EX) != (data[ij + imax] & ZONE_EX); if (ibndy) data[ij] |= I_BNDY; if (jbndy) data[ij] |= J_BNDY; /* apply i-edge start marks * -- i-edges are only marked when actually cut * -- no mark is necessary if one of the j-edges which share * the lower endpoint is also cut * -- no I0 mark necessary unless filled region below some cut, * no I1 mark necessary unless filled region above some cut */ if (j) { int v0 = (data[ij] & Z_VALUE); int vb = (data[ij - imax] & Z_VALUE); if (v0 != vb) { /* i-edge is cut */ if (ibndy) { if (data[ij] & ZONE_EX) { data[ij] |= I0_START; count++; } if (data[ij + 1] & ZONE_EX) { data[ij] |= I1_START; count++; } } else { int va = (data[ij - 1] & Z_VALUE); int vc = (data[ij + 1] & Z_VALUE); int vd = (data[ij - imax + 1] & Z_VALUE); if (v0 != 1 && va != v0 && (vc != v0 || vd != v0) && (data[ij] & ZONE_EX)) { data[ij] |= I0_START; count++; } if (vb != 1 && va == vb && (vc == vb || vd == vb) && (data[ij + 1] & ZONE_EX)) { data[ij] |= I1_START; count++; } } } } /* apply j-edge start marks * -- j-edges are only marked when they are boundaries * -- all cut boundary edges marked * -- for two level case, a few uncut edges must be marked */ if (i && jbndy) { int v0 = (data[ij] & Z_VALUE); int vb = (data[ij - 1] & Z_VALUE); if (v0 != vb) { if (data[ij] & ZONE_EX) { data[ij] |= J0_START; count++; } if (data[ij + imax] & ZONE_EX) { data[ij] |= J1_START; count++; } } else if (two_levels && v0 == 1) { if (data[ij + imax] & ZONE_EX) { if (i_was_chunk || !(data[ij + imax - 1] & ZONE_EX)) { /* lower left is a drawn part of boundary */ data[ij] |= J1_START; count++; } } else if (data[ij] & ZONE_EX) { if (data[ij + imax - 1] & ZONE_EX) { /* weird case of open hole at lower left */ data[ij] |= J0_START; count++; } } } } i_was_chunk = (i == ichunk); if (i_was_chunk) ichunk += icsize + (ichunk >= irem); } if (j == jchunk) jchunk += jcsize + (jchunk >= jrem); /* place first START_ROW marker */ if (count && !started) { data[ij - imax] |= START_ROW; started = 1; } } /* place immediate stop mark if nothing found */ if (!count) data[0] |= ALL_DONE; /* initialize site */ site->edge0 = site->edge00 = site->edge = 0; site->left0 = site->left = 0; site->n = 0; site->count = count; } /* ------------------------------------------------------------------------ Original (slightly modified) core contour generation routines are above; below are new routines for interfacing to mpl. ------------------------------------------------------------------------ */ /* Note: index order gets switched in the Python interface; python Z[i,j] -> C z[j,i] so if the array has shape Mi, Nj in python, we have iMax = Nj, jMax = Mi in gcntr.c. On the Python side: Ny, Nx = shape(z), so in C, the x-dimension is the first index, the y-dimension the second. */ /* reg should have the same dimensions as data, which has an extra iMax + 1 points relative to Z. It differs from mask in being the opposite (True where a region exists, versus the mask, which is True where a data point is bad), and in that it marks zones, not points. All four zones sharing a bad point must be marked as not existing. */ void mask_zones (long iMax, long jMax, char *mask, char *reg) { long i, j, ij; long nreg = iMax * jMax + iMax + 1; for (ij = iMax+1; ij < iMax*jMax; ij++) { reg[ij] = 1; } ij = 0; for (j = 0; j < jMax; j++) { for (i = 0; i < iMax; i++, ij++) { if (i == 0 || j == 0) reg[ij] = 0; if (mask[ij] != 0) { reg[ij] = 0; reg[ij + 1] = 0; reg[ij + iMax] = 0; reg[ij + iMax + 1] = 0; } } } for (; ij < nreg; ij++) { reg[ij] = 0; } } static Csite * cntr_new(void) { Csite *site; site = (Csite *) PyMem_Malloc(sizeof(Csite)); if (site == NULL) return NULL; site->data = NULL; site->reg = NULL; site->triangle = NULL; site->xcp = NULL; site->ycp = NULL; site->x = NULL; site->y = NULL; site->z = NULL; return site; } static int cntr_init(Csite *site, long iMax, long jMax, double *x, double *y, double *z, char *mask) { long ijmax = iMax * jMax; long nreg = iMax * jMax + iMax + 1; long i; site->imax = iMax; site->jmax = jMax; site->data = (Cdata *) PyMem_Malloc(sizeof(Cdata) * nreg); if (site->data == NULL) { PyMem_Free(site); return -1; } site->triangle = (short *) PyMem_Malloc(sizeof(short) * ijmax); if (site->triangle == NULL) { PyMem_Free(site->data); PyMem_Free(site); return -1; } for (i = 0; i < ijmax; i++) site->triangle[i] = 0; site->reg = NULL; if (mask != NULL) { site->reg = (char *) PyMem_Malloc(sizeof(char) * nreg); if (site->reg == NULL) { PyMem_Free(site->triangle); PyMem_Free(site->data); PyMem_Free(site); return -1; } mask_zones(iMax, jMax, mask, site->reg); } /* I don't think we need to initialize site->data. */ site->x = x; site->y = y; site->z = z; site->xcp = NULL; site->ycp = NULL; return 0; } void cntr_del(Csite *site) { PyMem_Free(site->triangle); PyMem_Free(site->reg); PyMem_Free(site->data); PyMem_Free(site); site = NULL; } /* Build a list of lists of points, where each point is an (x,y) tuple. */ static PyObject * build_cntr_list_p(long *np, double *xp, double *yp, int nparts, long ntotal) { PyObject *point, *contourList, *all_contours; int start = 0, end = 0; int i, j, k; all_contours = PyList_New(nparts); for (i = 0; i < nparts; i++) { start = end; end += np[i]; contourList = PyList_New(np[i]); for (k = 0, j = start; j < end; j++, k++) { point = Py_BuildValue("(dd)", xp[j], yp[j]); if (PyList_SetItem(contourList, k, point)) goto error; } if (PyList_SetItem(all_contours, i, contourList)) goto error; } return all_contours; error: Py_XDECREF(all_contours); return NULL; } /* Build a list of tuples (X, Y), where X and Y are 1-D arrays. */ static PyObject * build_cntr_list_v(long *np, double *xp, double *yp, int nparts, long ntotal) { PyObject *point, *all_contours; PyArrayObject *xv, *yv; int dims[1]; int i; long j, k; all_contours = PyList_New(nparts); k = 0; for (i = 0; i < nparts; i++) { dims[0] = np[i]; xv = (PyArrayObject *) PyArray_FromDims(1, dims, 'd'); yv = (PyArrayObject *) PyArray_FromDims(1, dims, 'd'); if (xv == NULL || yv == NULL) goto error; for (j = 0; j < dims[0]; j++) { ((double *)xv->data)[j] = xp[k]; ((double *)yv->data)[j] = yp[k]; k++; } point = Py_BuildValue("(NN)", xv, yv); /* "O" increments ref count; "N" does not. */ if (PyList_SetItem(all_contours, i, point)) goto error; } return all_contours; error: Py_XDECREF(all_contours); return NULL; } /* cntr_trace is called once per contour level or level pair. If nlevels is 1, a set of contour lines will be returned; if nlevels is 2, the set of polygons bounded by the levels will be returned. If points is True, the lines will be returned as a list of list of points; otherwise, as a list of tuples of vectors. */ PyObject * cntr_trace(Csite *site, double levels[], int nlevels, int points) { PyObject *c_list; double *xp0; double *yp0; long *nseg0; int iseg; long nchunk = 300; /* hardwired for now */ long n; long nparts = 0; long ntotal = 0; long nparts2 = 0; long ntotal2 = 0; site->zlevel[0] = levels[0]; site->zlevel[1] = levels[0]; if (nlevels == 2) { site->zlevel[1] = levels[1]; } site->n = site->count = 0; data_init (site, 0, nchunk); /* make first pass to compute required sizes for second pass */ for (;;) { n = curve_tracer (site, 0); if (!n) break; if (n > 0) { nparts++; ntotal += n; } else { ntotal -= n; } } xp0 = (double *) PyMem_Malloc(ntotal * sizeof(double)); yp0 = (double *) PyMem_Malloc(ntotal * sizeof(double)); nseg0 = (long *) PyMem_Malloc(nparts * sizeof(long)); if (xp0 == NULL || yp0 == NULL || nseg0 == NULL) goto error; /* second pass */ site->xcp = xp0; site->ycp = yp0; iseg = 0; for (;;iseg++) { n = curve_tracer (site, 1); if (ntotal2 + n > ntotal) { PyErr_SetString(PyExc_RuntimeError, "curve_tracer: ntotal2, pass 2 exceeds ntotal, pass 1"); goto error; } if (n == 0) break; if (n > 0) { /* could add array bounds checking */ nseg0[iseg] = n; site->xcp += n; site->ycp += n; ntotal2 += n; nparts2++; } else { PyErr_SetString(PyExc_RuntimeError, "Negative n from curve_tracer in pass 2"); goto error; } } if (points) { c_list = build_cntr_list_p(nseg0, xp0, yp0, nparts, ntotal); } else { c_list = build_cntr_list_v(nseg0, xp0, yp0, nparts, ntotal); } PyMem_Free(xp0); PyMem_Free(yp0); PyMem_Free(nseg0); site->xcp = NULL; site->ycp = NULL; return c_list; error: PyMem_Free(xp0); PyMem_Free(yp0); PyMem_Free(nseg0); site->xcp = NULL; site->ycp = NULL; return NULL; } /******* Make an extension type. Based on the tutorial.************/ /* site points to the data arrays in the arrays pointed to by xpa, ypa, zpa, and mpa, so we include them in the structure so we can ensure they are not deleted until we have finished using them. */ typedef struct { PyObject_HEAD PyArrayObject *xpa, *ypa, *zpa, *mpa; Csite *site; } Cntr; static int Cntr_clear(Cntr* self) { PyArrayObject *tmp; cntr_del(self->site); tmp = self->xpa; self->xpa = NULL; Py_XDECREF(tmp); tmp = self->ypa; self->ypa = NULL; Py_XDECREF(tmp); tmp = self->zpa; self->zpa = NULL; Py_XDECREF(tmp); tmp = self->mpa; self->mpa = NULL; Py_XDECREF(tmp); return 0; } static void Cntr_dealloc(Cntr* self) { Cntr_clear(self); Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject * Cntr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { Cntr *self; self = (Cntr *)type->tp_alloc(type, 0); if (self != NULL) { self->site = cntr_new(); if (self->site == NULL) { PyErr_SetString(PyExc_MemoryError, "Memory allocation failed in cntr_new."); Py_XDECREF(self); return NULL; } self->xpa = NULL; self->ypa = NULL; self->zpa = NULL; self->mpa = NULL; } return (PyObject *)self; } static int Cntr_init(Cntr *self, PyObject *args, PyObject *kwds) { PyObject *xarg, *yarg, *zarg, *marg; PyArrayObject *xpa, *ypa, *zpa, *mpa; long iMax, jMax; char *mask; static char *kwlist[] = {"x", "y", "z", "mask", NULL}; marg = NULL; if (! PyArg_ParseTupleAndKeywords(args, kwds, "OOO|O", kwlist, &xarg, &yarg, &zarg, &marg)) return -1; if (marg == Py_None) marg = NULL; if (!PyArray_Check(xarg) || !PyArray_Check(yarg) || !PyArray_Check(zarg) || (marg && !PyArray_Check(marg))) { PyErr_SetString(PyExc_TypeError, "Arguments x, y, z, (optional) mask must be arrays."); return -1; } xpa = (PyArrayObject *) PyArray_ContiguousFromObject(xarg, 'd', 2, 2); ypa = (PyArrayObject *) PyArray_ContiguousFromObject(yarg, 'd', 2, 2); zpa = (PyArrayObject *) PyArray_ContiguousFromObject(zarg, 'd', 2, 2); if (marg) mpa = (PyArrayObject *) PyArray_ContiguousFromObject(marg, '1', 2, 2); else mpa = NULL; if (xpa == NULL || ypa == NULL || zpa == NULL || (marg && mpa == NULL)) { PyErr_SetString(PyExc_ValueError, "Arguments x, y, z, mask (if present) must be 2D arrays."); goto error; } iMax = zpa->dimensions[1]; jMax = zpa->dimensions[0]; if (xpa->dimensions[0] != jMax || xpa->dimensions[1] != iMax || ypa->dimensions[0] != jMax || ypa->dimensions[1] != iMax || (mpa && (mpa->dimensions[0] != jMax || mpa->dimensions[1] != iMax))) { PyErr_SetString(PyExc_ValueError, "Arguments x, y, z, mask (if present)" " must have the same dimensions."); goto error; } if (mpa) mask = mpa->data; else mask = NULL; if ( cntr_init(self->site, iMax, jMax, (double *)xpa->data, (double *)ypa->data, (double *)zpa->data, mask)) { PyErr_SetString(PyExc_MemoryError, "Memory allocation failure in cntr_init"); goto error; } self->xpa = xpa; self->ypa = ypa; self->zpa = zpa; self->mpa = mpa; return 0; error: Py_XDECREF(xpa); Py_XDECREF(ypa); Py_XDECREF(zpa); Py_XDECREF(mpa); return -1; } static PyObject * Cntr_trace(Cntr *self, PyObject *args, PyObject *kwds) { double levels[2] = {0.0, -1e100}; int nlevels = 2; int points = 0; static char *kwlist[] = {"level0", "level1", "points", NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "d|di", kwlist, levels, levels+1, &points)) { return NULL; } if (levels[1] == -1e100 || levels[1] <= levels[0]) nlevels = 1; return cntr_trace(self->site, levels, nlevels, points); } static PyMethodDef Cntr_methods[] = { {"trace", (PyCFunction)Cntr_trace, METH_VARARGS | METH_KEYWORDS, "Return a list of contour line segments or polygons.\n\n" " Required argument: level0, a contour level\n" " Optional argument: level1; if given, and if level1 > level0,\n" " then the contours will be polygons surrounding areas between\n" " the levels.\n" " Optional argument: points; if 0 (default), return a list of\n" " vector pairs; otherwise, return a list of lists of points.\n" }, {NULL} /* Sentinel */ }; static PyTypeObject CntrType = { PyVarObject_HEAD_INIT(NULL, 0) "cntr.Cntr", /*tp_name*/ sizeof(Cntr), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)Cntr_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ "Contour engine", /* tp_doc */ 0, /* tp_traverse */ (inquiry)Cntr_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ Cntr_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)Cntr_init, /* tp_init */ 0, /* tp_alloc */ Cntr_new, /* tp_new */ }; struct module_state { PyObject *error; }; #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) static PyObject * error_out(PyObject *m) { struct module_state *st = GETSTATE(m); PyErr_SetString(st->error, "something bad happened"); return NULL; } static PyMethodDef myextension_methods[] = { {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL}, {NULL, NULL} }; static int myextension_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(GETSTATE(m)->error); return 0; } static int myextension_clear(PyObject *m) { Py_CLEAR(GETSTATE(m)->error); return 0; } // HEAVILY influenced by http://python3porting.com/cextensions.html #if PY_MAJOR_VERSION >= 3 #define MOD_ERROR_VAL NULL #define MOD_SUCCESS_VAL(val) val #define MOD_INIT(name) PyMODINIT_FUNC PyInit__cntr(void) #define MOD_DEF(ob, name, doc, methods) \ static struct PyModuleDef moduledef = { \ PyModuleDef_HEAD_INIT, \ "_cntr", \ NULL, \ sizeof(struct module_state), \ myextension_methods, \ NULL, \ myextension_traverse, \ myextension_clear, \ NULL \ }; \ ob = PyModule_Create(&moduledef); #else #define MOD_ERROR_VAL #define MOD_SUCCESS_VAL(val) #define MOD_INIT(name) PyMODINIT_FUNC init_cntr(void) #define MOD_DEF(ob, name, doc, methods) \ ob = Py_InitModule3(name, methods, doc); #endif static PyMethodDef module_methods[] = { {NULL} /* Sentinel */ }; MOD_INIT(void) { if (PyType_Ready(&CntrType) < 0) return MOD_ERROR_VAL; PyObject *m; MOD_DEF(m, "_cntr", "Contouring engine as an extension type", module_methods) if (m == NULL) return MOD_ERROR_VAL; import_array(); Py_INCREF(&CntrType); PyModule_AddObject(m, "Cntr", (PyObject *)&CntrType); return MOD_SUCCESS_VAL(m); } abstract_rendering-0.5.1/abstract_rendering/contour.py000066400000000000000000000040021240657705300232650ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import import numpy as np import abstract_rendering.core as core from abstract_rendering._cntr import Cntr class Contour(core.ShapeShader): def __init__(self, x_range=None, y_range=None, levels=5, points=True): """ x/y_range arguments determine the data values that correspond to the max/min values on the axes of the input grid. It is assumed that the grid is linear between the two. levels as a scalar determines how many levels will be built levels as a list determines where the levels are built points -- Indicates if it should return values as [[(x,y)...], [(x,y)...]] (default, True) or as [[x,x...], [x,x...],[y,y...][y,y...]] (False) """ self.x_range = x_range self.y_range = y_range self.levels = levels self.points = points def fuse(self, grid): x_range = self.x_range if self.x_range else (0, grid.shape[1]-1) y_range = self.y_range if self.y_range else (0, grid.shape[0]-1) xs = np.linspace(x_range[0], x_range[1], num=grid.shape[1]) ys = np.linspace(y_range[0], y_range[1], num=grid.shape[0]) xg, yg = np.meshgrid(xs, ys) c = Cntr(xg, yg, grid) if isinstance(self.levels, list): levels = self.levels else: levels = Contour.nlevels(grid, self.levels) isos = dict() for level in levels: points = c.trace(level, points=self.points) points = [[], []] if len(points) == 0 else points isos[level] = points return isos @classmethod def nlevels(cls, grid, n): "Given grid of values, pick out n values for iso contour levels" # The contouring library outlines places below the given value. # We do n+2 and drop the first and last values because they are # empty contours. return np.linspace(grid.min(), grid.max(), n+2)[1:-1] abstract_rendering-0.5.1/abstract_rendering/core.py000066400000000000000000000212751240657705300225370ustar00rootroot00000000000000""" Core abstract rendering abstractions. This includes the main drivers of execution and the base clases for shared data representations. """ from __future__ import print_function, division, absolute_import from six.moves import range import numpy as np import abstract_rendering.geometry as geometry import abstract_rendering.glyphset as glyphset # ------------------- Basic process function -------------------------------- def render(glyphs, info, aggregator, shader, screen, vt): """ Render a set of glyphs to the described canvas. * glyphs -- Glyphs to render * info -- For each glyph, the piece of information that will be aggregated * aggregator -- Combines a set of info values into a single aggregate value * shader -- Converts aggregates to other aggregates (often colors) * screen -- (width,height) of the canvas * vt -- View transform (converts canvas to pixels) """ projected = glyphs.project(vt) aggregates = aggregator.aggregate(projected, info, screen) # TODO: Add shader specialization here rslt = shader(aggregates) return rslt # ------------------------- Aggregators and related utilities ---------------- class Aggregator(object): out_type = None in_type = None identity = None def aggregate(self, glyphset, info, screen): """ Produce a set of aggregates glyphset -- glyphs to process screen -- (width, height) of the output grid info -- info function to invoke """ raise NotImplementedError() def rollup(self, *vals): """ Combine multiple sets of aggregates. * vals - list of numpy arrays with type out_type """ raise NotImplementedError() class GlyphAggregator(Aggregator): """ Aggregator tha tworks on one glyph at a time. Aggregators need to eventually process all glyphs. This class provides on workflow for realzing that. Each glyph is turned into its own set of aggregates, then combine dinto a larger set of aggregates for the whole glyphset. High-level overview of the control flow: * 'allocate' is used to make an empty set of aggregates for the whole glyphset * 'aggregate' calls 'combine' to include a single glyph into that allocated set of aggregates. * 'aggregate' repeats until all glyphs have been processed * 'glyphAggregates' is a utility for combine to convert a glyph into a set of aggregates. Most instances of 'combine' call 'glyphAggregates' though it is not always required Sub-classes need to implement allocate and combine. """ def allocate(self, glyphset, screen): """ Create an array suitable for processing the passed dataset into the requested grid size. * glyphset - The points that will be processed (already projected) * screen -- The size of the bin-grid to produce """ raise NotImplementedError() def combine(self, existing, points, shapecode, val): """Add a new point to an existing set of aggregates. * existing - out_type numpy array, aggregate values for all glyphs seen * points - points that define a shape * shapecode - Code that determines how points are interpreted * val -- Info value associated with the current set of points """ raise NotImplementedError() def aggregate(self, glyphset, info, screen): # TODO: vectorize pretty much this whole method... (width, height) = screen # co-iterating on number of points in case glyphset.data() is a non-length-carrying placeholder # TODO: Should the default placeholder carry length? infos = [info(data) for (data, _) in zip(glyphset.data(), range(len(glyphset.points())))] aggregates = self.allocate(glyphset, screen) for idx, points in enumerate(glyphset.points()): self.combine(aggregates, points, glyphset.shaper.code, infos[idx]) return aggregates def glyphAggregates(self, glyph, shapeCode, val, default): """Create a set of aggregates for a single glyph. The set of aggregates will be tight to the bound box of the shape but may not be completely filled (thus the need for both 'val' and 'default'). * glyph -- Points that define the glyph * shapeCode -- Code that indicates how to interpret the glyph * val -- Value to place in bins that are hit by the shape * default -- Value to place in bins not hit by the shape """ def scalar(array, val): array.fill(val) def nparray(array, val): array[:] = val if type(val) == np.ndarray: fill = nparray extShape = val.shape else: fill = scalar extShape = () # TODO: These are selectors...rename and move this somewhere else if shapeCode == glyphset.ShapeCodes.POINT: array = np.copy(val) # TODO: Not sure this is always an array...verify elif shapeCode == glyphset.ShapeCodes.RECT: array = np.empty((glyph[3]-glyph[1], glyph[2]-glyph[0])+extShape, dtype=np.int32) fill(array, val) elif shapeCode == glyphset.ShapeCodes.LINE: array = np.empty((glyph[3]-glyph[1], glyph[2]-glyph[0])+extShape, dtype=np.int32) fill(array, default) glyph = [0, 0, array.shape[1]-1, array.shape[0]-1] # Translate shape to be in the corner of the update canvas geometry.bressenham(array, glyph, val) return array # ---------------------- Shaders and related utilities -------------------- class Shader(object): """Shaders take grids and analize them. This interface asserts that instances are callable and accept a grid as their input. """ def __add__(self, other): """Extend this shader by executing another transfer in sequence.""" if (not isinstance(other, Shader)): raise TypeError("Can only extend with Shaders. Received a {0}" .format(str(type(other)))) return Seq(self, other) class ShapeShader(Shader): "Convert a grid into a set of shapes (instead of another grid)." def fuse(self, grid): "Convert aggregates grid into geometry" raise NotImplementedError def __call__(self, grid): return self.fuse(grid) # TODO: Add specialization to Shaders.... class CellShader(Shader): """Cell shaders take a grid and produce a new grid.""" def shade(self, grid): """Execute the actual data shader operation.""" raise NotImplementedError def __call__(self, grid): """Execute shading (by default).""" return self.shade(grid) class Seq(Shader): "Shader that does a sequence of shaders." def __init__(self, *args): self._parts = args def __add__(self, other): if (other is None): return self elif not isinstance(self._parts[-1], CellShader): raise ValueError("Cannot extend: Sequence terminated by non-CellShader.") elif (not isinstance(other, Shader)): raise TypeError("Can only extend with Shaders. Received a " .format(str(type(other)))) return Seq(*(self._parts + (other,))) def __call__(self, grid): for t in self._parts: grid = t(grid) return grid class SequentialShader(Shader): "Data shader that does non-vectorized per-pixel shading." def _pre(self, grid): "Executed exactly once before pixelfunc is called on any cell. " pass def __call__(self, grid): """Execute shading.""" return self.shade(grid) def cellfunc(grid, x, y): """ This method will be called for each pixel in the outgrid. Must be implemented in subclasses. """ raise NotImplementedError def makegrid(self, grid): """Create an output grid. Default implementation creates one of the same width/height of the input suitable for colors (dept 4, unit8). """ (width, height) = grid.shape[0], grid.shape[1] return np.ndarray((width, height, 4), dtype=np.uint8) def shade(self, grid): """Access each element in the out grid sequentially""" outgrid = self.makegrid(grid) self._pre(grid) (height, width) = outgrid.shape for x in range(0, width): for y in range(0, height): outgrid[y, x] = self.cellfunc(grid, x, y) return outgrid abstract_rendering-0.5.1/abstract_rendering/fast_project.py000066400000000000000000000220541240657705300242660ustar00rootroot00000000000000""" This module provides alternative methods of performing the 2d projection needed, they will use the same interface and should be interchangeable. All functions will take as inputs a transform and an array of AABB using floating point numbers. The result will be quantized into integers. """ from __future__ import print_function import ctypes import numpy as np import os import sys import distutils.sysconfig so_ext = distutils.sysconfig.get_config_var('EXT_SUFFIX') \ or distutils.sysconfig.get_config_var('SHLIB_SUFFIX') if not so_ext: so_ext = distutils.sysconfig.get_config_var('SO') or '.so' def _type_lib(lib): from ctypes import c_void_p, c_size_t lib.transform_f.argtypes = [c_void_p, c_void_p, c_void_p, c_size_t, c_size_t] lib.transform_d.argtypes = [c_void_p, c_void_p, c_void_p, c_size_t, c_size_t] if hasattr(lib, "async_transform_f_start"): #assume all the async interface lib.async_transform_f_start.argtypes = [c_void_p, c_void_p, c_size_t, c_size_t] lib.async_transform_f_start.restype = c_void_p lib.async_transform_f_end.argtypes = [c_void_p] lib.async_transform_f_next.argtypes = [c_void_p, c_void_p, c_void_p] lib.async_transform_d_start.argtypes = [c_void_p, c_void_p, c_size_t, c_size_t] lib.async_transform_d_start.restype = c_void_p lib.async_transform_d_end.argtypes = [c_void_p] lib.async_transform_d_next.argtypes = [c_void_p, c_void_p, c_void_p] _lib_filename = 'transform{0}'.format(so_ext) _lib = ctypes.CDLL(os.path.join(os.path.dirname(__file__), _lib_filename)) _type_lib(_lib) try: _lib_filename = "transform_libdispatch{0}".format(so_ext) _lib_dispatch = ctypes.CDLL(os.path.join(os.path.dirname(__file__), _lib_filename)) _type_lib(_lib_dispatch) except OSError: _lib_dispatch = _lib if sys.version_info.major > 2: mk_buff = ctypes.pythonapi.PyMemoryView_FromMemory else: mk_buff = ctypes.pythonapi.PyBuffer_FromMemory mk_buff.restype = ctypes.py_object def _projectRects(viewxform, inputs, outputs, use_dispatch = False): if (inputs.flags.f_contiguous): inputs = inputs.T outputs = outputs.T assert(len(inputs.shape) == 2 and inputs.shape[0] == 4) assert(inputs.shape == outputs.shape) use_lib = _lib_dispatch if use_dispatch else _lib if inputs.dtype == np.float64: inputtype = ctypes.c_double func = use_lib.transform_d elif inputs.dtype == np.float32: inputtype = ctypes.c_float func = use_lib.transform_f else: raise TypeError("ProjectRects only works for np.float32 and np.float64 inputs") assert(outputs.dtype == np.int32) t = ctypes.POINTER(inputtype) cast = ctypes.cast c_xforms = (inputtype * 4)(*viewxform) c_inputs = (t * 4)(*(cast(inputs[i].ctypes.data, t) for i in range(0, 4))) c_outputs = (t* 4)(*(cast(outputs[i].ctypes.data, t) for i in range(0,4))) func(ctypes.byref(c_xforms), ctypes.byref(c_inputs), ctypes.byref(c_outputs), 0, inputs.shape[1]) def _projectRectsGenerator(viewxform, inputs, chunk_size, use_dispatch = False): if (inputs.flags.f_contiguous): inputs = inputs.T # FIXME: outputs is undefined? outputs = outputs.T assert(len(inputs.shape) == 2 and inputs.shape[0] == 4) result_size = inputs.shape[1] chunk_size = min(result_size, chunk_size) use_lib = _lib_dispatch if use_dispatch else _lib if inputs.dtype == np.float64: inputtype = ctypes.c_double func = use_lib.transform_d has_async = hasattr(use_lib, "async_transform_d_start") elif inputs.dtype == np.float32: inputtype = ctypes.c_float func = use_lib.transform_f has_async = hasattr(use_lib, "async_transform_f_start") else: raise TypeError("ProjectRects only works for np.float32 and np.float64 inputs") t = ctypes.POINTER(inputtype) cast = ctypes.cast c_xforms = (inputtype * 4)(*viewxform) c_inputs = (t*4)(*(cast(inputs[i].ctypes.data, t) for i in range(0,4))) if not has_async: print("no async") # simple case: no need to pipeline outputs = np.empty((4, chunk_size), dtype=np.int32) c_outputs = (t*4)(*(cast(outputs[i].ctypes.data, t) for i in range(0, 4))) offset = 0 while offset != result_size: curr_size = min(result_size - offset, chunk_size) func(ctypes.byref(c_xforms), ctypes.byref(c_inputs), ctypes.byref(c_outputs), offset, curr_size) offset += curr_size yield outputs[0:curr_size] else: print("async") if inputs.dtype == np.float64: start_function = use_lib.async_transform_d_start end_function = use_lib.async_transform_d_end next_function = use_lib.async_transform_d_next elif inputs.dtype == np.float32: start_function = use_lib.async_transform_f_start end_function = use_lib.async_transform_f_end next_function = use_lib.async_transform_f_next else: raise TypeError("ProjectRects only works for np.float32 and np.float64 inputs") buff = ctypes.c_void_p(0) count = ctypes.c_size_t(0) total_size = chunk_size * 4 * 4 token = start_function(ctypes.byref(c_xforms), ctypes.byref(c_inputs), ctypes.c_size_t(result_size), ctypes.c_size_t(chunk_size)) while True: next_function(token, ctypes.byref(buff), ctypes.byref(count)) if count.value == 0: break yield np.frombuffer(mk_buff(buff, total_size, PyBuff_READ), dtype='i4').reshape((4,chunk_size))[:,0:count.value] end_function(token) # testing code starts here def _project_element(viewxform, inputs, output): tx, ty, sx, sy = viewxform x, y, w, h = inputs x2 = x + w y2 = y + h np.floor(sx * x + tx, out=output[0,:]) np.floor(sy * y + ty, out=output[1,:]) np.floor(sx * x2 + tx, out=output[2,:]) np.floor(sy * y2 + ty, out=output[3,:]) def report_diffs(a, b, name): last_dim = a.shape[1] if not np.allclose(a, b): for i in xrange(1, last_dim): if not np.allclose(a[:,i], b[:,i]): print('%s::%d fails \nc:\n%s != %s\n' % (name, i, str(a[:,i]), str(b[:,i]))) def simple_test(): from time import time use_shape = (4, 10**8) chunksize = 10**4 mock_in = np.random.random(use_shape) xform = [3.0, 4.0, 2.0, 2.0] t = time() check_sum = 0 for arr in _projectRectsGenerator(xform, mock_in, chunksize): check_sum += arr.shape[1] np.random.random(1000) t = time() - t print("checksum (_projectRectsGenerator) took %f ms" % (t*1000)) chk1 = check_sum t = time() check_sum = 0 for arr in _projectRectsGenerator(xform, mock_in, chunksize, use_dispatch = True): check_sum += arr.shape[1] np.random.random(1000) t = time() - t print("checksum (_projectRectsGenerator libdispatch) took %f ms" % (t*1000)) chk2 = check_sum t = time() out = np.empty(use_shape, dtype=np.int32) res = _projectRects(xform, mock_in, out) t = time() - t print("checksum (_projectRects) took %f ms" % (t*1000)) if not (chk1 == chk2 == out.shape[1]): print('checksums diverge') print('%s == %s' % ('chk1', chk1)) print('%s == %s' % ('chk2', chk2)) t = time() _projectRects(xform, mock_in, out, use_dispatch=True) t = time() - t out0 = np.copy(out) print("c version - libdispatch (double) took %f ms" % (t*1000)) t = time() _projectRects(xform, mock_in, out) t = time() - t out1 = np.copy(out) print("c version (double) took %f ms" % (t*1000)) t = time() _project_element(xform, mock_in, out) t = time() - t out2 = np.copy(out) print("numpy version (double) took %f ms" % (t*1000)) mock_in = mock_in.astype(np.float32) t = time() _projectRects(xform, mock_in, out, use_dispatch=True) t = time() - t out3 = np.copy(out) print("c version - libdispatch (single) took %f ms" % (t*1000)) t = time() _projectRects(xform, mock_in, out) t = time() - t out4 = np.copy(out) print("c version (single) took %f ms" % (t*1000)) t = time() _project_element(xform, mock_in, out) t = time() - t out5 = np.copy(out) print("numpy version (single) took %f ms" % (t*1000)) report_diffs(out0, out2, "libdispatch (double)") report_diffs(out1, out2, "plain C (double)") report_diffs(out3, out5, "libdispatch (single)") report_diffs(out4, out5, "plain C (single)") if __name__ == '__main__': simple_test() abstract_rendering-0.5.1/abstract_rendering/general.py000066400000000000000000000006641240657705300232230ustar00rootroot00000000000000""" Utilities that apply across a broad variety of categories. """ from __future__ import print_function, division, absolute_import import abstract_rendering.core as core class Id(core.CellShader): """ Return the input unchanged. This DOES NOT make a copy of the input It is usually used a zero-cost placeholder. """ def makegrid(self, grid): return grid def shade(self, grid): return grid abstract_rendering-0.5.1/abstract_rendering/geometry.py000066400000000000000000000012041240657705300234300ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import def bressenham(canvas, line, val): """ based on 'optimized and simplified' version at http://en.wikipedia.org/wiki/Bresenham's_line_algorithm """ (x0, y0, x1, y1) = line dx = abs(x1-x0) dy = abs(y1-y0) err = dx - dy sx = 1 if x0 < x1 else -1 sy = 1 if y0 < y1 else -1 while True: canvas[y0, x0] = val if x0 == x1 and y0 == y1: break e2 = err * 2 if e2 > -dy: err = err - dy x0 = x0 + sx if e2 < dx: err = err + dx y0 = y0 + sy abstract_rendering-0.5.1/abstract_rendering/glyphset.py000066400000000000000000000171521240657705300234450ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import from six.moves import map import numpy as np import re from abstract_rendering.fast_project import _projectRects import six def enum(**enums): return type('Enum', (), enums) ShapeCodes = enum(POINT=0, LINE=1, RECT=2) # TODO: Add shapecodes: CIRCLE, POINT_RECT, POINT_CIRCLE, etc class Glyphset(object): """ shaper + shape-params + associated data ==> Glyphset This reference implementation uses numpy arrays for the backing store. fields: _points : Points held by this glyphset _data : Data associated with the points (basis for 'info' values). shapecode: Shapecode that tells how to interpret _points Note: _points[x] should associate with data[x] """ _points = None _data = None shaper = None def __init__(self, points, data, shaper, colMajor=False): self._points = points self._data = data self.shaper = shaper self.shaper.colMajor = colMajor # HACK: This modification is bad form...would rather do a copy # TODO: Add the ability to get points m...n def points(self): """Returns the set of [x,y,w,h] points for this glyphset. Access to raw data is through _points. """ if (type(self.shaper) is Literals): if type(self._points) is list: return np.array(self._points, order="F") elif type(self._points) is np.ndarray: return self._points else: ValueError("Unhandled (literal) points type: %s" % type(self._points)) else: # TODO: Setup the shaper utilities to go directly to fortran order return np.array(self.shaper(self._points), order="F") def project(self, viewxform): """Project the points found in the glyphset according to the view transform. viewxform -- convert canvas space to pixel space [tx,ty,sx,sy] returns a new glyphset with projected points and associated info values """ points = self.points() out = np.empty_like(points, dtype=np.int32) _projectRects(viewxform, points, out) # Ensure visilibity, make sure w/h are always at least one # TODO: There is probably a more numpy-ish way to do this... for i in xrange(0, out.shape[0]): if out[i, 0] == out[i, 2]: out[i, 2] += 1 if out[i, 1] == out[i, 3]: out[i, 3] += 1 return Glyphset(out, self.data(), Literals(self.shaper.code)) def data(self): return self._data def bounds(self): """Compute bounds of the glyph-set. Returns (X,Y,W,H) Assumes a 'simple' layout where the min and max input values determine the min and max positional values. """ minX = float("inf") maxX = float("-inf") minY = float("inf") maxY = float("-inf") for g in self.points(): (x, y, w, h) = g minX = min(minX, x) maxX = max(maxX, x+w) minY = min(minY, y) maxY = max(maxY, y+h) return (minX, minY, maxX-minX, maxY-minY) # points = self.points(); # minX=points[:,0].min() # maxX=points[:,0].max() # minY=points[:,1].min() # maxY=points[:,1].max() # maxW=points[:,2].max() # maxH=points[:,3].max() # # shapes = self.shaper([[minX,maxX],[minY,maxY],[maxW,maxW],[maxH,maxH]]) # minX = shapes[0][0] # minY = shapes[0][1] # maxX = shapes[1][0] # maxY = shapes[1][1] # width = shapes[1][2] # height = shapes[1][3] # # return (minX, minY, maxX+width, maxY+height) # Shapers..... class Shaper(object): fns = None # List of functions to apply code = None colMajor = False # TODO: When getting subsets of the data out of glyphset.points(), remove this colMajor and handle it up in glyphset instead def __call__(self, vals): if not self.colMajor: shapes = [list(map(lambda f: f(val), self.fns)) for val in vals] else: shapes = [list(map(lambda f: f(val), self.fns)) for val in zip(*vals)] return shapes class Literals(Shaper): """Optimization marker, tested in Glyphset to skip conversions. Using this class asserts that the _points value of the Glyphset is the set of points to feed into a geometry renderer, and thus no projection from data space to canvas space is required. Use with caution... """ def __init__(self, code): self.code = code def __call__(self, vals): return vals class ToRect(Shaper): """Creates rectangles using functions to build x,y,w,h.""" code = ShapeCodes.RECT def __init__(self, tox, toy, tow, toh): self.fns = [tox, toy, tow, toh] class ToLine(Shaper): """Creates lines using functions to build x1,y1,x2,y2""" code = ShapeCodes.LINE def __init__(self, tox1, toy1, tox2, toy2): self.fns = [tox1, toy1, tox2, toy2] class ToPoint(Shaper): """Create a single point, using functions to build x,y,0,0 Can accept more than just tox/toy arguments, but ignores them. """ code = ShapeCodes.POINT def __init__(self, tox, toy, *args): self.fns = [tox, toy, lambda x: 0, lambda x: 0] # Utilities for shapers.... def const(v): """Create a function that always returns a specific value. * v -- The value the returned function always returns """ def f(a): return v return f def item(i): """ Get items out of a collection. Suiteable for use with numerically indexed (i.e., array) or object-indexed (i.e., dictionary) sources. * i -- The item parameter that will be used """ def f(a): return a[i] return f def idx(i): "The same as item, but a common name when using numeric indexes" return item(i) def load_csv(filename, skip, xc, yc, vc, width, height, shapecode): """Turn a csv file into a glyphset. This is a fairly naive regulary-expression based parser (it doesn't handle quotes, blank lines or much else). It is useful for getting simple datasets into the system. """ source = open(filename, 'r') glyphs = [] data = [] if shapecode is ShapeCodes.POINT: width = 0 height = 0 for i in range(0, skip): source.readline() for line in source: line = re.split("\s*,\s*", line) x = float(line[xc].strip()) y = float(line[yc].strip()) v = float(line[vc].strip()) if vc >= 0 else 1 g = [x, y, width, height] glyphs.append(g) data.append(v) source.close() return Glyphset(glyphs, data, Literals(shapecode)) def load_hdf(filename, node, xc, yc, vc, width, height, shapecode): """ Load a node from an HDF file. filename : HDF file to load node: Path to relevant HDF table xc: Name/index of the x column yc: Name/index of the y column vc: Name/index of the value column (if applicable) cats: List of expected categories. If cats is an empty list, a coding will be automatically generated Any value not on the list will be assigned category equal to list length. Cats is ignored if vc is not supplied. """ import pandas as pd table = pd.read_hdf(filename, node) x = np.array(table[xc]) y = np.array(table[yc]) w = np.array([width] * len(x)) h = np.array([height] * len(x)) points = np.vstack([x, y, w, h]).T data = table[vc] if vc else ([1] * len(x)) print("Loaded %d items" % len(x)) return Glyphset(points, data, Literals(shapecode)) abstract_rendering-0.5.1/abstract_rendering/infos.py000066400000000000000000000036251240657705300227240ustar00rootroot00000000000000""" Each info function returns callable that can be used on a single entry in the dataset. """ from __future__ import print_function, division, absolute_import def const(v): """Return the value passed.""" def f(data): return v return f def val(default=None): """Return the entire data value. This is the info-version of 'id'. """ def f(data): if data is None: return default else: return data return f def valAt(i, default=None): """Return the value at a given index in the data part of the input. On error returns the default value. """ def f(data): try: return data[i] except: return default return f def key(att, default=None): "Return the value under a given key in the data part of the input." def f(data): return data.get(att, default) return f def attribute(att, default=None): "Return the value under a given attribute in the data part of the input." def f(data): return getattr(data, att, default) return f def encode(cats, defcat=-1): """Create a function that converts values to numbers. The index in the value list passed will be the code-number. * cats : Values to create codes for * defcat : Default category; defaults to length fo cats list """ if defcat < 0: defcat = len(cats) codes = dict(zip(cats, xrange(len(cats)))) def f(val): return codes.get(val, defcat) return f class AutoEncode(object): """Encoded values as numeric codes. Builds up a category->code dictionary incrementally. """ def __init__(self): self.next_code = 0 self.mapping = {} def __call__(self, val): if val not in self.mapping: self.mapping[val] = self.next_code self.next_code = self.next_code + 1 return self.mapping[val] abstract_rendering-0.5.1/abstract_rendering/numeric.py000066400000000000000000000166641240657705300232570ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import from six.moves import reduce import numpy as np import math import abstract_rendering.core as core import abstract_rendering.util as util # ----------- Aggregators ----------- class Count(core.GlyphAggregator): """Count the number of items that fall into a particular grid element.""" out_type = np.int32 identity = 0 def allocate(self, glyphset, screen): (width, height) = screen return np.zeros((height, width), dtype=self.out_type) def combine(self, existing, glyph, shapecode, val): update = self.glyphAggregates(glyph, shapecode, 1, self.identity) existing[glyph[1]:glyph[3], glyph[0]:glyph[2]] += update def rollup(self, *vals): return reduce(lambda x, y: x+y, vals) class Sum(core.GlyphAggregator): """Count the number of items that fall into a particular grid element.""" out_type = np.int32 identity = 0 def allocate(self, glyphset, screen): (width, height) = screen return np.zeros((height, width), dtype=self.out_type) def combine(self, existing, glyph, shapecode, val): update = self.glyphAggregates(glyph, shapecode, val, self.identity) existing[glyph[1]:glyph[3], glyph[0]:glyph[2]] += update def rollup(self, *vals): return reduce(lambda x, y: x+y, vals) # -------------- Shaders ----------------- class Floor(core.CellShader): def shade(self, grid): return np.floor(grid) class Interpolate(core.CellShader): """Interpolate between two numbers. Projects the input values between the low and high values passed. The Default is 0 to 1. Empty values are preserved (default is np.nan). """ def __init__(self, low=0, high=1, empty=np.nan): self.low = low self.high = high self.empty = empty def shade(self, grid): # TODO: Gracefully handle if the whole grid is empty mask = (grid == self.empty) min = grid[~mask].min() max = grid[~mask].max() span = float(max-min) percents = (grid-min)/span return self.low + (percents * (self.high-self.low)) class Power(core.CellShader): """Raise to a power. Power may be fracional.""" def __init__(self, pow): self.pow = pow def shade(self, grid): return np.power(grid, self.pow) class Cuberoot(Power): def __init__(self): super(Cuberoot, self).__init__(1/3.0) class Sqrt(core.CellShader): def shade(self, grid): return np.sqrt(grid) class Spread(core.SequentialShader): """ Spreads the values out in a regular pattern. * factor : How far in each direction to spread TODO: Currently only does square spread. Extend to other shapes. TODO: Restricted to numbers right now...implement corresponding thing for categories...might be 'generic' """ def __init__(self, up=1, down=1, left=1, right=1, factor=np.NaN): if np.isnan(factor): self.up = up self.down = down self.left = left self.right = right else: self.up = factor self.down = factor self.left = factor self.right = factor def makegrid(self, grid): height = grid.shape[0] width = grid.shape[1] others = grid.shape[2:] height = height + self.up + self.down width = width + self.left + self.right return np.zeros((height, width) + others, dtype=grid.dtype) def cellfunc(self, grid, x, y): (height, width) = grid.shape minx = max(0, x-self.left-self.right) maxx = min(x+1, width) miny = max(0, y-self.up-self.down) maxy = min(y+1, height) parts = grid[miny:maxy, minx:maxx] return parts.sum() class BinarySegment(core.CellShader): """ Paint all pixels with aggregate value above divider one color and below the divider another. Divider is part of the 'high' region. TODO: Extend so out can be something other than colors """ in_type = (1, np.number) out_type = (4, np.int32) def __init__(self, low, high, divider): self.high = high self.low = low self.divider = float(divider) def shade(self, grid): (width, height) = grid.shape[0], grid.shape[1] outgrid = np.ndarray((width, height, 4), dtype=np.uint8) mask = (grid >= self.divider) outgrid[mask] = self.high outgrid[~mask] = self.low return outgrid class InterpolateColors(core.CellShader): """ High-definition interpolation between two colors. Zero-values are treated separately from other values. TODO: Remove log, just provide a shader to pre-transform the values TODO: Can this be combined with 'Interpolate'? Detect type at construction * low -- Color ot use for lowest value * high -- Color to use for highest values * log -- Set to desired log base to use log-based interpolation (use True or "e" for base-e; default is False) * reserve -- color to use for empty cells """ in_type = (1, np.number) out_type = (4, np.int32) def __init__(self, low, high, log=False, reserve=util.Color(255, 255, 255, 255), empty=np.nan): self.low = low self.high = high self.reserve = reserve self.log = log self.empty = empty # TODO: there are issues with zeros here.... def _log(self, grid): mask = (grid == self.empty) min = grid[~mask].min() max = grid[~mask].max() grid[mask] = 1 if (self.log == 10): min = math.log10(min) max = math.log10(max) span = float(max-min) percents = (np.log10(grid)-min)/span elif (self.log == math.e or self.log): min = math.log(min) max = math.log(max) span = float(max-min) percents = (np.log(grid)-min)/span elif (self.log == 2): min = math.log(min, self.log) max = math.log(max, self.log) span = float(max-min) percents = (np.log2(grid)-min)/span else: rebase = math.log(self.log) min = math.log(min, self.log) max = math.log(max, self.log) span = float(max-min) percents = ((np.log(grid)/rebase)-min)/span grid[mask] = 0 colorspan = (np.array(self.high, dtype=np.uint8) - np.array(self.low, dtype=np.uint8)) outgrid = (percents[:, :, np.newaxis] * colorspan[np.newaxis, np.newaxis, :] + np.array(self.low, dtype=np.uint8)).astype(np.uint8) outgrid[mask] = self.reserve return outgrid def _linear(self, grid): mask = (grid == self.empty) min = grid[~mask].min() max = grid[~mask].max() span = float(max-min) percents = (grid-min)/span colorspan = (np.array(self.high, dtype=np.int32) - np.array(self.low, dtype=np.int32)) outgrid = (percents[:, :, np.newaxis] * colorspan[np.newaxis, np.newaxis, :] + np.array(self.low, dtype=np.uint8)).astype(np.uint8) outgrid[mask] = self.reserve return outgrid def shade(self, grid): if (self.log): return self._log(grid) else: return self._linear(grid) abstract_rendering-0.5.1/abstract_rendering/numpyglyphs.py000066400000000000000000000177711240657705300242140ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import from six.moves import range import numpy as np from scipy.ndimage.filters import convolve from abstract_rendering.fast_project import _projectRects import abstract_rendering.glyphset as glyphset import abstract_rendering.core as ar class Glyphset(glyphset.Glyphset): # TODO: Default data is list of None (?) """ points: Base array of points (x, y, w, h) data: Base array of data associated with points. points[n] is associated with data[n] vt: view transform clean_nan: Remove entries with nans in points? Default is false. """ def __init__(self, points, data, vt=(0, 0, 1, 1), clean_nan=False): if clean_nan: mask = ~np.isnan(points).any(axis=1) points = points[mask] data = data[mask] self._points = points self._data = data self.vt = vt self.shaper = glyphset.ToPoint(glyphset.idx(0), glyphset.idx(1)) if not is_identity_transform(vt): self.projected = np.empty_like(points, dtype=np.int32) _projectRects(vt, points, self.projected) # points must be at least 1 wide for general compatability self.projected[:, 2] = self.projected[:, 0]+1 self.projected[:, 3] = self.projected[:, 1]+1 else: self.projected = points def data(self): return self._data def points(self): return self.projected def project(self, vt): """ Project the points found in the glyphset with to the transform. vt -- convert canvas space to pixel space [tx,ty,sx,sy] returns a new glyphset with projected points and associated info values """ nvt = (self.vt[0]+vt[0], self.vt[1]+vt[1], self.vt[2]*vt[2], self.vt[3]*vt[3]) return Glyphset(self._points, self._data, nvt) def bounds(self): (xmax, ymax, _, _) = self.projected.max(axis=0) (xmin, ymin, _, _) = self.projected.min(axis=0) bounds = (xmin, ymin, xmax-xmin, ymax-ymin) return bounds class PointCount(ar.Aggregator): def aggregate(self, glyphset, info, screen): sparse = glyphset.points() dense = np.histogram2d(sparse[:, 1], sparse[:, 0], bins=(screen[1], screen[0]), range=((0, screen[1]), (0, screen[0]))) return dense[0] def rollup(self, *vals): return reduce(lambda x, y: x+y, vals) # TODO: IS there a faster option for the coder? 'vectorize' is only # a little better than a list comprehension class PointCountCategories(ar.Aggregator): def aggregate(self, glyphset, info, screen): points = glyphset.points() coder = np.vectorize(info) coded = coder(glyphset.data()) coded = np.array(coded) cats = coded.max() (width, height) = screen dims = (height, width, cats+1) # Need cats+1 to do proper categorization... ranges = ((0, screen[1]), (0, screen[0]), (0, cats+1)) data = np.hstack([np.fliplr(points[:, 0:2]), coded[:, np.newaxis]]) dense = np.histogramdd(data, bins=dims, range=ranges) return dense[0] def rollup(self, *vals): """NOTE: Assumes co-registration of categories...""" return reduce(lambda x, y: x+y, vals) class Spread(ar.CellShader): """ Spreads the values out in a regular pattern. Spreads categories inside their category plane (not between planes). TODO: Spread beyond the bounds of the input plot? * shape: Shape of the spread. Supports "rect" and "circle" * factor : How wide to spread? * anti_alias: Can a value be fractionally spread into a cell (default is false) """ def __init__(self, factor=1, anti_alias=False, shape="circle"): self.factor = factor self.anti_alias = anti_alias self.shape = shape def make_k(self): """Construct the weights matrix""" if self.shape == "rect": if not self.anti_alias or (self.factor % 2) == 1: kShape = (self.factor+1, self.factor+1) k = np.ones(kShape) else: kShape = (self.factor, self.factor) k = np.ones(kShape) k[0] = .5 k[:, 0] = .5 k[-1] = .5 k[:, -1] = .5 return k if self.shape == "circle": if not self.anti_alias or (self.factor % 2) == 1: kShape = (self.factor+1, self.factor+1) k = np.ones(kShape) r = self.factor//2 rr = r**2 for x in range(0, r): for y in range(0, r): if ((x - r)**2 + (y - r)**2) > rr: k[x, y] = 0 k[x, -(y+1)] = 0 k[-(x+1), -(y+1)] = 0 k[-(x+1), y] = 0 return k else: kShape = (self.factor+1, self.factor+1) k = np.ones(kShape) r = self.factor//2 rr = r**2 for x in range(0, r): for y in range(0, r): if ((x - r)**2 + (y - r)**2) == rr: k[x, y] = .5 k[x, -(y+1)] = .5 k[-(x+1), -(y+1)] = .5 k[-(x+1), y] = .5 elif ((x - r)**2 + (y - r)**2) > rr: k[x, y] = 0 k[x, -(y+1)] = 0 k[-(x+1), -(y+1)] = 0 k[-(x+1), y] = 0 return k return k def shade(self, grid): k = self.make_k() out_dtype = grid.dtype if not self.anti_alias else np.float64 out = np.empty_like(grid, dtype=out_dtype) if len(grid.shape) == 3: cats = grid.shape[2] for cat in range(cats): convolve(grid[:, :, cat], k, output=out[:, :, cat], mode='constant', cval=0.0) else: convolve(grid, k, mode='constant', cval=0.0, output=out) return out class Log10(ar.CellShader): def shade(self, grid): mask = (grid == 0) out = np.log10(grid) out[mask] = 0 return out def is_identity_transform(vt): return vt == (0, 0, 1, 1) def load_csv(filename, skip, xc, yc, vc): """Turn a csv file into a glyphset. This is a fairly naive regulary-expression based parser (it doesn't handle quotes, blank lines or much else). It is useful for getting simple datasets into the system. """ import re source = open(filename, 'r') points = [] data = [] for i in range(0, skip): source.readline() for line in source: line = re.split("\s*,\s*", line) x = float(line[xc].strip()) y = float(line[yc].strip()) v = float(line[vc].strip()) if vc >= 0 else 1 g = [x, y, 0, 0] points.append(g) data.append(v) source.close() return Glyphset(np.array(points, order="F"), np.array(data)) def load_hdf(filename, node, xc, yc, vc=None): """ Load a node from an HDF file. filename : HDF file to load node: Path to relevant HDF table xc: Name/index of the x column yc: Name/index of the y column vc: Name/index of the value column (if applicable) cats: List of expected categories. If cats is an empty list, a coding will be automatically generated Any value not on the list will be assigned category equal to list length. This parameter is ignored if vc is not supplied. """ import pandas as pd table = pd.read_hdf(filename, node) points = table[[xc, yc]] a = np.zeros((len(points), 4), order="F") a[:, :2] = points data = table[vc] if vc else None print("Loaded %d items" % len(a)) return Glyphset(a, data) abstract_rendering-0.5.1/abstract_rendering/test/000077500000000000000000000000001240657705300222055ustar00rootroot00000000000000abstract_rendering-0.5.1/abstract_rendering/test/__init__.py000066400000000000000000000003661240657705300243230ustar00rootroot00000000000000from __future__ import print_function import unittest def run_all(): suite = unittest.defaultTestLoader.discover('.', pattern='*[T|t]est*.py') result = suite.run(unittest.TestResult()) print(result) return result.wasSuccessful() abstract_rendering-0.5.1/abstract_rendering/test/categoriesTests.py000066400000000000000000000200621240657705300257270ustar00rootroot00000000000000from __future__ import print_function from six.moves import reduce import unittest import abstract_rendering.categories as categories from abstract_rendering.glyphset import ShapeCodes from abstract_rendering.util import Color import numpy as np import operator class _GlyphsetShim(object): def __init__(self, depth): self.depth = depth def data(self): return range(self.depth) class CountCategories(unittest.TestCase): def test_allocate(self): op = categories.CountCategories() (width, height, depth) = (6, 3, 7) screen = (width, height) glyphset = _GlyphsetShim(depth) out = op.allocate(glyphset, screen) expected = np.zeros((height, width, depth)) self.assertTrue(np.array_equal(out, expected)) def test_combine_points(self): op = categories.CountCategories() (width, height, depth) = (1, 1, 3) screen = (width, height) glyphset = _GlyphsetShim(depth) out = op.allocate(glyphset, screen) glyph = [0, 0, 1, 1] existing = op.allocate(glyphset, screen) op.combine(existing, glyph, ShapeCodes.POINT, 1) expected = np.zeros((height, width, depth)) expected[0, 0, 1] = 1 self.assertTrue(np.array_equal(existing, expected)) (width, height, depth) = (3, 4, 3) screen = (width, height) glyphset = _GlyphsetShim(depth) glyph = [2, 1, 3, 2] existing = op.allocate(glyphset, screen) op.combine(existing, glyph, ShapeCodes.POINT, 2) expected = np.zeros((height, width, depth), dtype=np.int) expected[1, 2, 2] = 1 self.assertTrue(np.array_equal(existing, expected)) def test_combine_rect(self): op = categories.CountCategories() (width, height, depth) = (3, 4, 2) screen = (width, height) glyphset = _GlyphsetShim(depth) glyph = [0, 0, 2, 2] existing = op.allocate(glyphset, screen) op.combine(existing, glyph, ShapeCodes.RECT, 0) expected = np.array([[[1, 1, 0], [1, 1, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]], dtype=np.int).transpose((1, 2, 0)) self.assertEqual(existing.shape, expected.shape) self.assertTrue(np.array_equal(existing, expected)) def test_rollup(self): op = categories.CountCategories() (width, height, depth) = (8, 5, 3) ones = np.ones((depth, height, width)) zeros = np.zeros((depth, height, width)) twos = np.empty((depth, height, width)) twos.fill(2) threes = np.empty((depth, height, width)) threes.fill(3) out = op.rollup(ones, zeros) self.assertTrue(np.array_equal(out, ones)) out = op.rollup(ones, ones) self.assertTrue(np.array_equal(out, twos)) out = op.rollup(twos, ones) self.assertTrue(np.array_equal(out, threes)) class ToCounts(unittest.TestCase): def test(self): """Can the output of categories.CountCategories can be transformed to vanilla counts?""" op = categories.ToCounts() (width, height, depth) = (4, 5, 3) screen = (width, height) glyphset = _GlyphsetShim(depth) aggregator = categories.CountCategories() aggs = aggregator.allocate(glyphset, screen) aggs.fill(1) out = op.shade(aggs) expected = np.empty((height, width), dtype=np.int32) expected.fill(depth) self.assertTrue(np.array_equal(out, expected)) self.assertEquals((height, width), out.shape, "Unexpected out shape") shape = aggs.shape aggs = np.arange(0, reduce(operator.mul, shape)) aggs = aggs.reshape((depth, height, width)).transpose((1, 2, 0)) out = op.shade(aggs) self.assertEquals((height, width), out.shape, "Unexpected out shape") self.assertEquals(out[0, 0], 0+20+40) self.assertEquals(out[4, 0], 16+36+56) self.assertEquals(out[0, 3], 3+23+43) self.assertEquals(out[4, 3], 19+39+59) class Select(unittest.TestCase): def test(self): op0 = categories.Select(0) op1 = categories.Select(1) op2 = categories.Select(2) (width, height, depth) = (5, 4, 3) screen = (width, height) glyphset = _GlyphsetShim(depth) aggregator = categories.CountCategories() aggs = aggregator.allocate(glyphset, screen) aggs[:, :, 0] = 1 aggs[:, :, 1] = 2 aggs[:, :, 2] = 3 expected = np.empty((height, width, depth), dtype=np.int) expected[:, :, 0] = 1 expected[:, :, 1] = 2 expected[:, :, 2] = 3 self.assertTrue(np.array_equal(op0.shade(aggs), expected[:, :, 0])) self.assertTrue(np.array_equal(op1.shade(aggs), expected[:, :, 1])) self.assertTrue(np.array_equal(op2.shade(aggs), expected[:, :, 2])) class MinPercent(unittest.TestCase): def test_uniform(self): op5 = categories.MinPercent(.5) op1 = categories.MinPercent(.1) (width, height, depth) = (4, 6, 4) screen = (width, height) glyphset = _GlyphsetShim(depth) aggregator = categories.CountCategories() aggs = aggregator.allocate(glyphset, screen) aggs.fill(2) above = np.empty((height, width, 4), dtype=np.uint8) above[:] = op5.above out = op1.shade(aggs) self.assertTrue(np.array_equal(out, above)) below = np.empty((height, width, 4), dtype=np.uint8) below[:] = op5.below out = op5.shade(aggs) self.assertTrue(np.array_equal(out, below)) def test_mixed(self): op0_5 = categories.MinPercent(.5) op0_25 = categories.MinPercent(.25) op1_5 = categories.MinPercent(.5, cat=1) op2_25 = categories.MinPercent(.25, cat=2) aggs = np.array([[[0, 1, 2, 3, 4]], [[1, 2, 3, 4, 0]], [[2, 3, 4, 0, 1]], [[3, 4, 0, 1, 2]]]).transpose((1, 2, 0)) above = op0_5.above below = op0_5.below expected0_5 = np.array([[below, below, below, below, above]]) expected0_25 = np.array([[below, below, below, above, above]]) expected1_5 = np.array([[below, below, below, above, below]]) expected2_25 = np.array([[above, above, above, below, below]]) self.assertTrue(np.array_equal(op0_5.shade(aggs), expected0_5)) self.assertTrue(np.array_equal(op0_25.shade(aggs), expected0_25)) self.assertTrue(np.array_equal(op1_5.shade(aggs), expected1_5)) self.assertTrue(np.array_equal(op2_25.shade(aggs), expected2_25)) class HDAlpha(unittest.TestCase): red = Color(255, 0, 0, 255) green = Color(0, 255, 0, 255) blue = Color(0, 0, 255, 255) def test_empty(self): op = categories.HDAlpha([self.red, self.green, self.blue]) aggs = np.zeros((3, 3, 3)) expected = np.empty((3, 3, 4), dtype=np.int) expected[:] = op.background self.assertTrue(np.array_equal(op.shade(aggs), expected)) def test_simple(self): op = categories.HDAlpha([self.red, self.green, self.blue]) aggs = np.array([[[1, 0, 0, 0]], [[0, 1, 0, 0]], [[0, 0, 1, 0]]]).transpose((1, 2, 0)) expected = np.array([[self.red, self.green, self.blue, op.background]]) self.assertTrue(np.array_equal(op.shade(aggs), expected)) def test_blend(self): op = categories.HDAlpha([self.red, self.green, self.blue]) aggs = np.array([[[1, 0, 0]], [[1, 1, 0]], [[0, 1, 1]]]).transpose((1, 2, 0)) expected = np.array([[[127, 127, 0, 255], [ 0, 127, 127, 255], [ 0, 0, 255, 127]]], dtype=np.uint8) self.assertTrue(np.array_equal(op.shade(aggs), expected)) if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/contourTests.py000066400000000000000000000045441240657705300253020ustar00rootroot00000000000000from __future__ import print_function import unittest import numpy as np from abstract_rendering.contour import Contour class ContourTests(unittest.TestCase): pyramid2 = np.array( [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]]) pyramid4 = np.array( [[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 2, 2, 2, 2, 1, 0], [0, 1, 2, 3, 3, 3, 1, 0], [0, 1, 2, 3, 3, 3, 1, 0], [0, 1, 2, 3, 3, 3, 1, 0], [0, 1, 2, 2, 2, 2, 1, 0], [0, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]]) def test_nlevels(self): self.assertListEqual(Contour.nlevels(self.pyramid2, 1).tolist(), [.5]) self.assertListEqual(Contour.nlevels(self.pyramid2, 3).tolist(), [.25, .5, .75]) self.assertListEqual(Contour.nlevels(self.pyramid4, 2).tolist(), [1,2]) self.assertListEqual(Contour.nlevels(self.pyramid4, 3).tolist(), [.75, 1.5, 2.25]) def test_fuse2(self): c = Contour(levels=1) contours = c.fuse(self.pyramid2) self.assertEquals(len(contours), 1) expected0 = [[(1.0, 0.5), (2.0, 0.5), (2.5, 1.0), (2.5, 2.0), (2.0, 2.5), (1.0, 2.5), (0.5, 2.0), (0.5, 1.0), (1.0, 0.5)]] self.assertListEqual(contours[.5], expected0) def test_fuse4(self): c = Contour(levels=3) levels = c.fuse(self.pyramid4) self.assertEquals(len(levels), 3) self.assertEquals(len(levels[.75][0]), 27) self.assertEquals(len(levels[1.5][0]), 19) self.assertEquals(len(levels[2.25][0]), 13) expected2 = [[(3.0, 2.25), (4.0, 2.25), (5.0, 2.25), (5.375, 3.0), (5.375, 4.0), (5.375, 5.0), (5.0, 5.75), (4.0, 5.75), (3.0, 5.75), (2.25, 5.0), (2.25, 4.0), (2.25, 3.0), (3.0, 2.25)]] self.assertListEqual(levels[2.25], expected2) if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/coretests.py000066400000000000000000000014571240657705300246010ustar00rootroot00000000000000from __future__ import print_function import unittest import abstract_rendering.core as core import abstract_rendering.numeric as numeric import numpy as np class Seq(unittest.TestCase): def test_extend(self): op1 = numeric.Cuberoot() op2 = numeric.Cuberoot() op3 = numeric.Cuberoot() seq1 = core.Seq(op1, op2) seq2 = seq1+op3 self.assertIsInstance(seq2, core.Seq) self.assertIsNot(seq1, seq2) def test_call(self): op1 = numeric.Cuberoot() op2 = numeric.Cuberoot() op3 = op1 + op2 rslt = op3(np.array([[1]])) self.assertEquals(rslt, [[1]]) start = [[(3**3)**3]] rslt = op3(np.array(start)) self.assertEquals(rslt, op2(op1(start))) if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/generalTests.py000066400000000000000000000005301240657705300252150ustar00rootroot00000000000000from __future__ import print_function import unittest import numpy as np import abstract_rendering.general as general class IdTests(unittest.TestCase): def test(self): op = general.Id() aggs = np.zeros((4, 3)) out = op.shade(aggs) self.assertIs(aggs, out) if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/geometryTests.py000066400000000000000000000071761240657705300254500ustar00rootroot00000000000000from __future__ import print_function import abstract_rendering.geometry as geometry import numpy as np import unittest class BressenhamTests(unittest.TestCase): def test_vertical(self): out = np.zeros((10, 1)) geometry.bressenham(out, [0, 0, 0, 9], 1) expected = np.ones((10, 1)) self.assertTrue(np.array_equal(out, expected), "Simple vertical") geometry.bressenham(out, [0, 9, 0, 0], 1) expected = np.ones((10, 1)) self.assertTrue(np.array_equal(out, expected), "Reverse vertical") expected.fill(7) geometry.bressenham(out, [0, 0, 0, 9], 7) self.assertTrue(np.array_equal(out, expected), "Vertical: Another value") out.fill(0) expected.fill(7) expected[0, 0] = 0 expected[9, 0] = 0 geometry.bressenham(out, [0, 1, 0, 8], 7) self.assertTrue(np.array_equal(out, expected), "Vertical: Not space filling") def test_horizontal(self): out = np.zeros((1, 10)) geometry.bressenham(out, [0, 0, 9, 0], 1) expected = np.ones((1, 10)) self.assertTrue(np.array_equal(out, expected), "Simple horizontal") geometry.bressenham(out, [9, 0, 0, 0], 1) expected = np.ones((1, 10)) self.assertTrue(np.array_equal(out, expected), "Reverse horizontal") expected.fill(7) geometry.bressenham(out, [0, 0, 9, 0], 7) self.assertTrue(np.array_equal(out, expected), "Horizontal: Another value") out.fill(0) expected.fill(7) expected[0, 0] = 0 expected[0, 9] = 0 geometry.bressenham(out, [1, 0, 8, 0], 7) self.assertTrue(np.array_equal(out, expected), "Horizontal: Not space filling") def test_diag(self): out = np.zeros((10, 11), dtype=np.int) geometry.bressenham(out, [2, 2, 6, 5], 1) expected = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) self.assertTrue(np.array_equal(out, expected)) out = np.zeros((10, 11), dtype=np.int) geometry.bressenham(out, [7, 3, 1, 8], 1) expected = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) self.assertTrue(np.array_equal(out, expected)) def test_compound(self): cats = [1, 2] out = np.zeros((5, 1, len(cats))) geometry.bressenham(out, [0, 0, 0, 4], cats) expected = np.empty(out.shape) expected[:, :, 0] = 1 expected[:, :, 1] = 2 self.assertTrue(np.array_equal(out, expected), "Complex value") if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/glyphsetTests.py000066400000000000000000000107751240657705300254530ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import from six.moves import range import numpy as np import unittest import abstract_rendering.glyphset as glyphset class UtilTests(unittest.TestCase): def _consts(self, f, condition, val): self.assertEqual(val, f(3), condition) self.assertEqual(val, f(4), condition) self.assertEqual(val, f(10), condition) self.assertEqual(val, f("Stuff"), "String (%s)" % condition) self.assertEqual(val, f(object()), "Object (%s)" % condition) self.assertEqual(val, f(None), "None (%s)" % condition) def test_const(self): f = glyphset.const(3) self._consts(f, "Number", 3) f = glyphset.const("two") self._consts(f, "String", "two") f = glyphset.const(None) self._consts(f, "None", None) o = object() f = glyphset.const(o) self._consts(f, "Object", o) def test_item(self): f = glyphset.item(2) self.assertEquals(2, f([0, 1, 2, 3, 4])) self.assertEquals(20, f([0, 10, 20, 30, 40])) self.assertIsNone(f([0, 1, None, 3, 4]), "None from list") self.assertEquals(3, f(range(1, 20)), "Function source") class ShaperTests(unittest.TestCase): def test_Literals(self): f = glyphset.Literals(glyphset.ShapeCodes.LINE) l = [1, 2, 3, 4] self.assertIs(f(l), l) o = object() self.assertIs(f(o), o) self.assertIs(f(f), f) self.assertIs(f(0), 0) def test_ToRect(self): f = glyphset.ToRect(glyphset.item(3), glyphset.item(2), glyphset.item(1), glyphset.item(0)) self.assertEquals(f([[1, 2, 3, 4, 5, 6]]), [[4, 3, 2, 1]], "Lists are indexable") self.assertEquals(f(["ABCDEF"]), [["D", "C", "B", "A"]], "Strings are indexable") self.assertEquals(f(["ABCDEF", "abcdef"]), [["D", "C", "B", "A"], ["d", "c", "b", "a"]], "multiple items") f = glyphset.ToRect(glyphset.item(2), glyphset.item(4), glyphset.item(1), glyphset.item(1)) self.assertEquals(f([[1, 2, 3, 4, 5, 6]]), [[3, 5, 2, 2]]) self.assertEquals(f(["ABCDEF"]), [["C", "E", "B", "B"]]) def test_ToLine(self): f = glyphset.ToLine(glyphset.item(3), glyphset.item(2), glyphset.item(1), glyphset.item(0)) self.assertEquals(f([[1, 2, 3, 4, 5, 6]]), [[4, 3, 2, 1]], "Lists are indexable") self.assertEquals(f(["ABCDEF"]), [["D", "C", "B", "A"]], "Strings are indexable") self.assertEquals(f(["ABCDEF", "abcdef"]), [["D", "C", "B", "A"], ["d", "c", "b", "a"]], "multiple items") f = glyphset.ToLine(glyphset.item(2), glyphset.item(4), glyphset.item(1), glyphset.item(1)) self.assertEquals(f([[1, 2, 3, 4, 5, 6]]), [[3, 5, 2, 2]]) self.assertEquals(f(["ABCDEF"]), [["C", "E", "B", "B"]]) def test_ToPoint(self): f = glyphset.ToPoint(glyphset.item(3), glyphset.item(2)) self.assertEquals(f([[1, 2, 3, 4, 5, 6]]), [[4, 3, 0, 0]], "Lists are indexable") self.assertEquals(f(["ABCDEF"]), [["D", "C", 0, 0]], "Strings are indexable") self.assertEquals(f(["ABCDEF", "abcdef"]), [["D", "C", 0, 0], ["d", "c", 0, 0]], "multiple items") f = glyphset.ToPoint(glyphset.item(2), glyphset.item(4)) self.assertEquals(f([[1, 2, 3, 4, 5, 6]]), [[3, 5, 0, 0]]) self.assertEquals(f(["ABCDEF"]), [["C", "E", 0, 0]]) class GlyphsetTests(object): def test_bounds(self): self.assertTrue(np.array_equal(self._glyphset.bounds(), self._bounds)) def test_points(self): self.assertTrue(np.array_equal(self._glyphset.points(), self._points)) def test_data(self): self.assertEquals(self._glyphset.data(), self._data) class ArrayGlyphset(GlyphsetTests, unittest.TestCase): def setUp(self): self._data = [1, 2, 3, 4, 5, 6] points = np.array([[0, 0], [1, 1], [.5, .5]]) self._points = np.array([[0, 0, 0, 0], [1, 1, 0, 0], [.5, .5, 0, 0]]) self._glyphset = glyphset.Glyphset(points, self._data, glyphset.ToPoint(glyphset.item(0), glyphset.item(1))) self._bounds = [0.0, 0.0, 1.0, 1.0] class ColumnGlyphset(GlyphsetTests, unittest.TestCase): def setUp(self): self._data = [1, 2, 3, 4, 5, 6] points = [[0, 1, .5], [0, 1, .5]] self._points = np.array([[0, 0, 0, 0], [1, 1, 0, 0], [.5, .5, 0, 0]]) self._glyphset = glyphset.Glyphset(points, self._data, glyphset.ToPoint(glyphset.item(0), glyphset.item(1)), colMajor=True) self._bounds = [0.0, 0.0, 1.0, 1.0] if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/infosTests.py000066400000000000000000000032031240657705300247160ustar00rootroot00000000000000from __future__ import print_function import unittest import abstract_rendering.infos as infos class Const(unittest.TestCase): def test(self): info = infos.const(3) self.assertTrue(callable(info)) self.assertEqual(3, info(3)) self.assertEqual(3, info(23)) self.assertEqual(3, info(None)) self.assertEqual(3, info([])) self.assertEqual(3, info(object())) self.assertEqual(3, info(self)) class Val(unittest.TestCase): def test(self): info = infos.val(15) self.assertTrue(callable(info)) self.assertEqual(3, info(3)) self.assertEqual(0, info(0)) self.assertEqual(15, info(None)) class ValAt(unittest.TestCase): def test(self): info = infos.valAt(3, "Nothing") self.assertTrue(callable(info)) self.assertEqual(3, info([0, 1, 2, 3])) self.assertEqual("three", info(["zero", "one", "two", "three"])) self.assertEqual("Nothing", info(None)) class Key(unittest.TestCase): def test(self): info = infos.key("val", "seven") self.assertTrue(callable(info)) self.assertEqual(3, info({"val": 3, "other": 6})) self.assertEqual("seven", info({"value": 3, "other": 6})) class Attribute(unittest.TestCase): class Has(): val = 13 other = 6 class HasNot(): value = 13 other = 6 def test(self): info = infos.attribute("val", "seven") self.assertTrue(callable(info)) self.assertEqual(13, info(self.Has())) self.assertEqual("seven", info(self.HasNot())) if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/numericTests.py000066400000000000000000000251021240657705300252440ustar00rootroot00000000000000from __future__ import print_function import unittest import numpy as np import abstract_rendering.numeric as numeric import abstract_rendering.util as util import abstract_rendering.core as core from abstract_rendering.glyphset import ShapeCodes class CountTests(unittest.TestCase): def test_allocate(self): op = numeric.Count() init = op.allocate(None, (10, 10)) self.assertEquals(init.shape, (10, 10)) self.assertTrue(np.array_equal(init, np.zeros((10, 10)))) def test_combine(self): op = numeric.Count() glyph = [0, 0, 1, 1] existing = np.zeros((1, 1)) op.combine(existing, glyph, ShapeCodes.POINT, 10) self.assertTrue(np.array_equal(existing, np.ones((1, 1)))) existing = np.zeros((1, 1)) op.combine(existing, glyph, ShapeCodes.POINT, 20) self.assertTrue(np.array_equal(existing, np.ones((1, 1))), "Not input value invariant") existing = np.ones((1, 1)) op.combine(existing, glyph, ShapeCodes.POINT, 20) self.assertTrue(np.array_equal(existing, np.array([[2]])), "Count up from non-zero") glyph = [1, 2, 2, 3] existing = np.ones((3, 1)) expected = np.array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 2, 1, 1]]) op.combine(existing, glyph, ShapeCodes.POINT, 3) glyph = [5, 5, 6, 6] existing = np.ones((10, 10)) expected = np.ones((10, 10)) expected[5, 5] = 2 op.combine(existing, glyph, ShapeCodes.POINT, 20) self.assertTrue(np.array_equal(existing, expected), "Setting in the middle") def test_rollup(self): op = numeric.Count() ones = np.ones((5, 5)) twos = np.empty((5, 5)) twos.fill(2) result = op.rollup(ones, ones) self.assertTrue(np.array_equal(result, twos)) class SumTests(unittest.TestCase): def test_allocate(self): op = numeric.Sum() init = op.allocate(None, (10, 10)) self.assertEquals(init.shape, (10, 10)) self.assertTrue(np.array_equal(init, np.zeros((10, 10)))) def test_combine(self): op = numeric.Sum() glyph = [0, 0, 1, 1] existing = np.ones((1, 1)) expected = np.empty((1, 1)) expected.fill(11) op.combine(existing, glyph, ShapeCodes.POINT, 10) self.assertTrue(np.array_equal(existing, expected)) existing = np.ones((1, 1)) expected = np.empty((1, 1)) expected.fill(21) op.combine(existing, glyph, ShapeCodes.POINT, 20) self.assertTrue(np.array_equal(existing, expected)) glyph = [1, 2, 2, 3] existing = np.ones((3, 1)) expected = np.array([[1, 1, 1, 1], [1, 1, 1, 1], [1, 4, 1, 1]]) op.combine(existing, glyph, ShapeCodes.POINT, 3) glyph = [5, 5, 6, 6] existing = np.ones((10, 10)) expected = np.ones((10, 10)) expected[5, 5] = 21 op.combine(existing, glyph, ShapeCodes.POINT, 20) self.assertTrue(np.array_equal(existing, expected), "Setting in the middle") def test_rollup(self): op = numeric.Count() ones = np.ones((5, 5)) twos = np.empty((5, 5)) twos.fill(2) result = op.rollup(ones, ones) self.assertTrue(np.array_equal(result, twos)) def _test_extend(op1, tester): op2 = numeric.Cuberoot() tester.assertIsInstance(op1 + op2, core.Seq) tester.assertIsInstance(op2 + op1, core.Seq) class FloorTests(unittest.TestCase): def test(self): op = numeric.Floor() a = np.array([[1.1, 1.5, 1.9], [2.3, 0, 0.1]]) expected = np.array([[1, 1, 1], [2, 0, 0]], dtype=float) out = op.shade(a) self.assertTrue(np.array_equal(out, expected), "Unequal:\n %s \n = \n %s" % (out, expected)) def extend(self): _test_extend(numeric.Floor(), self) class InterpolateTests(unittest.TestCase): def _run_test(self, low, high, msg): op = numeric.Interpolate(low, high) (width, height) = (5, 10) aggs = np.arange(0, width*height).reshape(height, width) out = op.shade(aggs) expected = np.linspace(low, high, width*height).reshape(height, width) self.assertTrue(np.allclose(out, expected), msg) def test_0to1(self): self._run_test(0, 1, "Zero to One") def test_0to10(self): self._run_test(0, 10, "Zero to Ten") def test_1to11(self): self._run_test(1, 11, "One to Eleven") def test_extend(self): _test_extend(numeric.Interpolate(1,2), self) class PowerTests(unittest.TestCase): def test(self): op = numeric.Power(2) out = op.shade([0, 0, 0]) self.assertTrue(np.array_equal(out, [0, 0, 0])) a = np.array([[1, 1, 1], [2, 2, 2], [5, 5, 5]]) expected = np.array([[1, 1, 1], [4, 4, 4], [25, 25, 25]], dtype=float) out = op.shade(a) self.assertTrue(np.array_equal(out, expected), "Unequal:\n %s \n = \n %s" % (out, expected)) def test_extend(self): _test_extend(numeric.Power(3), self) class CuberootTests(unittest.TestCase): def test(self): op = numeric.Cuberoot() out = op.shade([1, 1, 1]) self.assertTrue(np.array_equal(out, [1, 1, 1])) a = np.array([[27], [64], [125]]) # Calculates in-place because of floating point round-off expected = np.array([[pow(27, 1/3.0)], [pow(64, 1/3.0)], [pow(125, 1/3.0)]], dtype=float) out = op.shade(a) self.assertTrue(np.array_equal(out, expected), "Unequal:\n %s \n = \n %s" % (out, expected)) def test_extend(self): _test_extend(numeric.Cuberoot(), self) class SqrtTests(unittest.TestCase): def test(self): op = numeric.Sqrt() out = op.shade([1, 1, 1]) self.assertTrue(np.array_equal(out, [1, 1, 1])) a = np.array([[4, 4, 4], [9, 9, 9], [25, 25, 25]]) expected = np.array([[2, 2, 2], [3, 3, 3], [5, 5, 5]], dtype=float) out = op.shade(a) self.assertTrue(np.array_equal(out, expected), "Unequal:\n %s \n = \n %s" % (out, expected)) def test_extend(self): _test_extend(numeric.Sqrt(), self) class BinarySegmentTests(unittest.TestCase): def test(self): w = util.Color(255, 255, 255, 255) b = util.Color(0, 0, 0, 255) op = numeric.BinarySegment(b, w, 5) aggs = np.array([[0, 0, 0, 0, 0], [1, 1, 1, 1, 1], [5, 5, 5, 5, 5], [6, 6, 6, 6, 6], [9, 9, 9, 9, 9], [0, 1, 5, 6, -1]]) out = op.shade(aggs) expected = np.array([[b, b, b, b, b], [b, b, b, b, b], [w, w, w, w, w], [w, w, w, w, w], [w, w, w, w, w], [b, b, w, w, b]]) self.assertTrue(np.array_equal(out, expected)) def test_extend(self): _test_extend(numeric.BinarySegment(None, None, 3), self) class InterpolateColorsTests(unittest.TestCase): def test_linear(self): red = util.Color(255, 0, 0, 255) white = util.Color(255, 255, 255, 255) op = numeric.InterpolateColors(white, red) aggs = np.arange(0, 256).reshape((32, 8)) out = op.shade(aggs) var = np.arange(0, 256)[::-1].reshape((32, 8)) const = np.empty((32, 8), dtype=np.int) const.fill(255) expected = np.dstack((const, var, var, const)) self.assertTrue(np.array_equal(out, expected)) def test_extend(self): _test_extend(numeric.InterpolateColors(None, None), self) class SpreadTests(unittest.TestCase): def run_spread(self, spread, in_vals, expected): op = numeric.Spread(factor=spread) out = op.shade(in_vals) self.assertTrue(np.array_equal(out, expected), 'incorrect value spreading\ni %s' % str(out)) def test_spread_oneseed(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]) self.run_spread(1, a, ex) def test_spread_twoseeds(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0, 0, 0], [0, 1, 2, 2, 1, 0], [0, 1, 2, 2, 1, 0], [0, 1, 2, 2, 1, 0], [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]]) self.run_spread(1, a, ex) def test_spread_two(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]]) self.run_spread(2, a, ex) def test_spread_zero(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) self.run_spread(0, a, ex) def test_extend(self): _test_extend(numeric.Spread(), self) if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/numpyglyphTests.py000066400000000000000000000143551240657705300260260ustar00rootroot00000000000000from __future__ import print_function import unittest import numpy as np import abstract_rendering.numpyglyphs as npg class SpreadTests(unittest.TestCase): def run_spread(self, spread, in_vals, expected, **kwargs): op = npg.Spread(factor=spread, **kwargs) out = op.shade(in_vals) self.assertTrue(np.array_equal(out, expected), 'incorrect value spreading\n %s' % str(out)) def test_spread_oneseed(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]]) self.run_spread(2, a, ex, shape="rect") def test_spread_twoseeds(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[1, 2, 2, 1], [1, 2, 2, 1], [1, 2, 2, 1], [0, 0, 0, 0]]) self.run_spread(2, a, ex, shape="rect") def test_spread_two_anti_alias(self): a = np.asarray([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [.5, .5, 0, 0], [.5, .5, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=np.float64) self.run_spread(2, a, ex, anti_alias=True, shape="rect") def test_spread_two(self): a = np.asarray([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) self.run_spread(2, a, ex, shape="rect") def test_spread_three(self): a = np.asarray([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) self.run_spread(3, a, ex, shape="rect") def test_spread_four(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]) self.run_spread(4, a, ex, shape="rect") def test_spread_zero(self): a = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) self.run_spread(0, a, ex, shape="rect") def test_spread_cats(self): a = np.asarray([[[0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]]]).T b = np.asarray([[[1, 1, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1]]]).T self.run_spread(2, a, b, shape="rect") def test_spread_circle2(self): a = np.asarray([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) self.run_spread(2, a, ex, shape="circle") def test_spread_circle4(self): a = np.asarray([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) ex = np.asarray([[0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 1, 1, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) self.run_spread(4, a, ex, shape="circle") if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/test/test_init.py000066400000000000000000000010041240657705300245540ustar00rootroot00000000000000import abstract_rendering as ar import unittest import os class InitTests(unittest.TestCase): def test_version_report(self): version_file = os.path.join(os.path.dirname(__file__), '', '../_version.txt') with open(version_file) as f: expected = f.readline().strip() self.assertEquals(ar.__version__, expected) parts = dict(zip(["major", "minor", "micro"], map(int, expected.split(".")))) self.assertEquals(ar.__version_info__, parts) abstract_rendering-0.5.1/abstract_rendering/test/utilTests.py000066400000000000000000000062401240657705300245610ustar00rootroot00000000000000from __future__ import print_function import unittest import abstract_rendering.util as util class EmptyListTests(unittest.TestCase): def test_without_length(self): ls = util.EmptyList() self.assertIsNone(ls[0]) self.assertIsNone(ls[-1]) self.assertIsNone(ls[30]) self.assertIsNone(ls[9048]) self.assertIsNone(ls[100398384]) self.assertIsNone(ls[3]) self.assertIsNone(ls[490]) def test_with_length(self): ls = util.EmptyList(7) self.assertIsNone(ls[0]) self.assertIsNone(ls[1]) self.assertIsNone(ls[2]) self.assertIsNone(ls[3]) self.assertIsNone(ls[4]) self.assertIsNone(ls[5]) self.assertIsNone(ls[6]) self.assertRaises(IndexError, ls.__getitem__, -1) self.assertRaises(IndexError, ls.__getitem__, 8) class ColorTest(unittest.TestCase): def _test(self, r, g, b, a): c = util.Color(r, g, b, a) self.assertEqual(util.Color(r, g, b, a), c) self.assertEqual(c, [r, g, b, a]) def test1(self): self._test(0, 0, 0, 0) def test2(self): self._test(10, 30, 40, 20) def test3(self): self._test(255, 255, 255, 255) def test_RedError(self): self.assertRaises(ValueError, util.Color, 256, 0, 0, 0) self.assertRaises(ValueError, util.Color, -1, 0, 0, 0) def test_GreenError(self): self.assertRaises(ValueError, util.Color, 0, 256, 0, 0) self.assertRaises(ValueError, util.Color, 0, -1, 0, 0) def test_BlueError(self): self.assertRaises(ValueError, util.Color, 0, 0, 256, 0) self.assertRaises(ValueError, util.Color, 0, 0, -1, 0) def test_AlphaError(self): self.assertRaises(ValueError, util.Color, 0, 0, 0, 256) self.assertRaises(ValueError, util.Color, 0, 0, 0, -1) class ZoomFitTest(unittest.TestCase): def test_scale(self): self.assertEqual(util.zoom_fit((10, 10), (0, 0, 10, 10)), [0., 0., 1., 1.]) self.assertEqual(util.zoom_fit((10, 10), (0, 0, 20, 20)), [0., 0., .5, .5]) self.assertEqual(util.zoom_fit((10, 10), (0, 0, 5, 5)), [0., 0., 2., 2.]) self.assertEqual(util.zoom_fit((10, 10), (0, 0, 10, 20)), [0., 0., .5, .5]) self.assertEqual(util.zoom_fit((10, 10), (0, 0, 10, 20), False), [0., 0., 1., .5]) def test_pan(self): self.assertEqual(util.zoom_fit((10, 10), (0, 0, 10, 10)), [0., 0., 1., 1.]) self.assertEqual(util.zoom_fit((10, 10), (5, 5, 10, 10)), [-5., -5., 1., 1.]) self.assertEqual(util.zoom_fit((10, 10), (-4, -7, 10, 10)), [4., 7., 1., 1.]) def test_pan_scale(self): self.assertEqual(util.zoom_fit((10, 10), (0, 0, 20, 20)), [0., 0., .5, .5]) self.assertEqual(util.zoom_fit((10, 10), (5, 5, 20, 20)), [-2.5, -2.5, .5, .5]) self.assertEqual(util.zoom_fit((10, 10), (-4, -7, 20, 20)), [2., 3.5, .5, .5]) if __name__ == '__main__': unittest.main() abstract_rendering-0.5.1/abstract_rendering/transform.cpp000066400000000000000000000037031240657705300237500ustar00rootroot00000000000000/* This has been tested on mac using the following compile line: clang -O3 -march=native -std=c++11 -fPIC -dynamiclib transform.cpp -o libtransform.dylib */ #include #include #define RESTRICT __restrict__ namespace { template inline void transf_single(IT tx, IT ty, IT sx, IT sy, IT x, IT y, IT w, IT h, OT& x0, OT& y0, OT& x1, OT& y1) { x0 = x*sx + tx; y0 = y*sy + ty; x1 = (x + w)*sx + tx; y1 = (y + h)*sy + ty; } template inline void transform(INPUT_TYPE* xtransform, INPUT_TYPE** in_arrays, OUTPUT_TYPE * RESTRICT * out_arrays, size_t offset, size_t count) { INPUT_TYPE tx = xtransform[0]; INPUT_TYPE ty = xtransform[1]; INPUT_TYPE sx = xtransform[2]; INPUT_TYPE sy = xtransform[3]; INPUT_TYPE *x = in_arrays[0] + offset; INPUT_TYPE *y = in_arrays[1] + offset; INPUT_TYPE *w = in_arrays[2] + offset; INPUT_TYPE *h = in_arrays[3] + offset; OUTPUT_TYPE * RESTRICT x0 = out_arrays[0]; OUTPUT_TYPE * RESTRICT y0 = out_arrays[1]; OUTPUT_TYPE * RESTRICT x1 = out_arrays[2]; OUTPUT_TYPE * RESTRICT y1 = out_arrays[3]; for (size_t i = 0; i < count; i++) { transf_single(tx, ty, sx, sy, x[i], y[i], w[i], h[i], x0[i], y0[i], x1[i], y1[i]); } } } extern "C" void transform_f(float* xtr, float** in, int32_t *RESTRICT* out, size_t offset, size_t count) { transform(xtr, in, out, offset, count); } extern "C" void transform_d(double* xtr, double** in, int32_t * RESTRICT * out, size_t offset, size_t count) { transform(xtr, in, out, offset, count); } abstract_rendering-0.5.1/abstract_rendering/transform_libdispatch.cpp000066400000000000000000000221111240657705300263100ustar00rootroot00000000000000/* This has been tested on mac using the following compile line: clang -O3 -march=native -std=c++11 -fPIC -dynamiclib transform_libdispatch.cpp -o libtransform_libdispatch.dylib */ #include #include #include #define RESTRICT __restrict__ #define STRIDE (1<<4) namespace { template inline void transf_single(IT tx, IT ty, IT sx, IT sy, IT x, IT y, IT w, IT h, int32_t& x0, int32_t& y0, int32_t& x1, int32_t& y1) { x0 = x*sx + tx; y0 = y*sx + ty; x1 = (x + w)*sx + tx; y1 = (y + h)*sy + ty; } //////////////////////////////////////////////////////////////////////// template struct transform_params_t { IT xtr[4]; IT const *in[4]; int32_t * RESTRICT out[4]; size_t in_offset; size_t out_offset; size_t count; }; template std::ostream& operator<<(std::ostream& ost, const transform_params_t& obj) { return ost << "transform params" << std::endl << "xtr: " << obj.xtr[0] << ", " << obj.xtr[1] << ", " << obj.xtr[2] << ", " << obj.xtr[3] << std::endl << "in_offset: " << obj.in_offset << std::endl << "out_offset: " << obj.out_offset << std::endl << "count: " << obj.count << std::endl; } //////////////////////////////////////////////////////////////////////// template void transform(const transform_params_t* arg, size_t idx, size_t stride) { size_t count = arg->count; count = (idx != count/stride) ? stride : count % stride; size_t off = idx*stride; const IN_T tx = arg->xtr[0]; const IN_T ty = arg->xtr[1]; const IN_T sx = arg->xtr[2]; const IN_T sy = arg->xtr[3]; IN_T const *x = arg->in[0] + arg->in_offset + off; IN_T const *y = arg->in[1] + arg->in_offset + off; IN_T const *w = arg->in[2] + arg->in_offset + off; IN_T const *h = arg->in[3] + arg->in_offset + off; int32_t * RESTRICT x0 = arg->out[0] + arg->out_offset + off; int32_t * RESTRICT y0 = arg->out[1] + arg->out_offset + off; int32_t * RESTRICT x1 = arg->out[2] + arg->out_offset + off; int32_t * RESTRICT y1 = arg->out[3] + arg->out_offset + off; for (size_t i = 0; i < count; i++) { transf_single(tx, ty, sx, sy, x[i], y[i], w[i], h[i], x0[i], y0[i], x1[i], y1[i]); } } inline dispatch_queue_t get_queue() { return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); } class semaphore { public: semaphore(long count); ~semaphore(); void wait(); void signal(); private: dispatch_semaphore_t impl; }; semaphore::semaphore(long count) { impl = dispatch_semaphore_create(count); } semaphore::~semaphore() { dispatch_release(impl); } void semaphore::wait() { dispatch_semaphore_wait(impl, DISPATCH_TIME_FOREVER); } void semaphore::signal() { dispatch_semaphore_signal(impl); } //////////////////////////////////////////////////////////////////////// template struct async_context_t { semaphore sema; transform_params_t tp; size_t chunk_size; size_t current_chunk; size_t total_size; bool task_running; async_context_t(); ~async_context_t(); bool init(IT* _xtr, IT** _in,size_t _count,size_t _cs); void alloc_buffer(); void next(void** buff, size_t* current_count); static void task(void*); }; template async_context_t::async_context_t(): sema(1) { tp.out[0]=nullptr; } template async_context_t::~async_context_t() { free(tp.out[0]); } template void async_context_t::next(void** return_buff, size_t* count) { *return_buff = nullptr; *count = 0; if (task_running) { sema.wait(); size_t done_chunk = current_chunk - 1; *return_buff = tp.out[0] + 4 * chunk_size * (done_chunk & 1); *count = std::min(chunk_size, total_size - (done_chunk) * chunk_size); task_running = false; } // if not all the chunks have been processed, start a new task size_t curr_offset = current_chunk*chunk_size; if (curr_offset < total_size) { tp.in_offset = curr_offset; tp.out_offset = 4*(current_chunk & 1) * chunk_size; tp.count = std::min(chunk_size, total_size - curr_offset); dispatch_async_f(get_queue(), this, task); current_chunk++; task_running = true; } } template void async_context_t::task(void* arg) { async_context_t* ctxt = (async_context_t*) arg; transform(&ctxt->tp, 0, ctxt->tp.count); ctxt->sema.signal(); } template bool async_context_t::init(IT *_xtr, IT** _in, size_t _total, size_t _cs) { int32_t* buff = (int32_t*) malloc(4*2*_cs*sizeof(int32_t)); if (!buff) return false; chunk_size = _cs; current_chunk = 0; total_size = _total; // these 3 will be updated for each task run tp.in_offset = 0; tp.in_offset = 0; tp.count = 0; for (size_t i=0;i<4;i++) { tp.xtr[i] = _xtr[i]; tp.in[i] = _in[i]; tp.out[i] = buff + _cs*i; } task_running = false; void *dummy; size_t dummy2; next(&dummy, &dummy2); return true; } //////////////////////////////////////////////////////////////////////// template void transform_task(void* ctxt, size_t idx) { transform((const transform_params_t*)ctxt, idx, STRIDE); } template void transform_dispatch(IN_T *xtr, IN_T **in, OUT_T **RESTRICT out, size_t offset, size_t count) { } } // namespace extern "C" void transform_f(float* xtr, float** in, int32_t** RESTRICT out, size_t offset, size_t count) { transform_params_t params; for (size_t i=0; i<4;i++) { params.xtr[i] = xtr[i]; params.in[i] = in[i] + offset; params.out[i] = out[i]; } params.in_offset = offset; params.out_offset = offset; params.count = count; dispatch_queue_t queue = get_queue(); dispatch_apply_f(count/STRIDE, queue, ¶ms, transform_task); } extern "C" void transform_d(double* xtr, double** in, int32_t** RESTRICT out, size_t offset, size_t count) { transform_params_t params; for (size_t i=0; i<4;i++) { params.xtr[i] = xtr[i]; params.in[i] = in[i] + offset; params.out[i] = out[i]; } params.in_offset = offset; params.out_offset = offset; params.count = count; dispatch_queue_t queue = get_queue(); dispatch_apply_f(count/STRIDE, queue, ¶ms, transform_task); } extern "C" void * async_transform_f_start(float* xtr, float** in, size_t total, size_t chunk_size) { async_context_t* rv = new async_context_t(); if (! rv->init(xtr, in, total, chunk_size)) { delete(rv); rv = nullptr; } return rv; } extern "C" void async_transform_f_end(void *arg) { async_context_t *ctxt = (async_context_t*) arg; delete(ctxt); } extern "C" void async_transform_f_next(void *arg, void** buff_out, size_t* count_out) { async_context_t *ctxt = (async_context_t*)arg; ctxt->next(buff_out, count_out); } extern "C" void * async_transform_d_start(double *xtr, double **in, size_t total, size_t cs) { async_context_t* rv = new async_context_t(); if (! rv->init(xtr, in, total, cs)) { delete(rv); rv = nullptr; } return rv; } extern "C" void async_transform_d_end(void *arg) { async_context_t *ctxt = (async_context_t*)arg; delete(ctxt); } extern "C" void async_transform_d_next(void *arg, void** buff_out, size_t* count_out) { async_context_t *ctxt = (async_context_t*)arg; ctxt->next(buff_out, count_out); } abstract_rendering-0.5.1/abstract_rendering/util.py000066400000000000000000000030541240657705300225570ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import class EmptyList(object): """ Utility that can be numerically indexed, but always returns None. If a no length or a negative length are passed at construction, the list will ALWAYS return None. If a non-negative length is passsed at construction, an indexed 0 <= index < length will return None. Others raise an IndexError """ def __init__(self, length=-1): self.length = length def __getitem__(self, idx): if self.length < 0: return None if idx >= self.length or idx < 0: raise IndexError return None class Color(list): def __init__(self, r, g, b, a): list.__init__(self, [r, g, b, a]) self.r = r self.g = g self.b = b self.a = a if ((r > 255 or r < 0) or (g > 255 or g < 0) or (b > 255 or b < 0) or (a > 255 or a < 0)): raise ValueError def zoom_fit(screen, bounds, balanced=True): """What affine transform will zoom-fit the given items? screen: (w,h) of the viewing region bounds: (x,y,w,h) of the items to fit balance: Should the x and y scales match? returns: [translate x, translate y, scale x, scale y] """ (sw, sh) = screen (gx, gy, gw, gh) = bounds x_scale = sw/gw y_scale = sh/gh if (balanced): x_scale = min(x_scale, y_scale) y_scale = x_scale return [-gx*x_scale, -gy*y_scale, x_scale, y_scale] abstract_rendering-0.5.1/data/000077500000000000000000000000001240657705300162775ustar00rootroot00000000000000abstract_rendering-0.5.1/data/circlepoints.csv000066400000000000000000002246241240657705300215240ustar00rootroot00000000000000r,theta,x,y,Series -0.853294531,1.927182965,0.297706106,-0.799676579,0 -0.163814032,0.23290767,-0.159390955,-0.037809533,0 -0.755897419,0.728931051,-0.563813927,-0.503482635,0 -0.641920626,2.65381943,0.567058975,-0.300842498,0 0.839803199,0.301101867,0.802020692,0.249062686,0 0.39814582,1.757265727,-0.073812517,0.391243922,0 0.958748534,2.586220078,-0.814652517,0.505509672,0 -0.722496075,1.701232817,0.093972852,-0.716358626,0 -0.552744202,1.182877261,-0.209082635,-0.511674315,0 0.510551282,3.103377167,-0.510178517,0.019506217,0 0.685409849,1.655266066,-0.057827566,0.682966056,0 0.683016418,2.096473003,-0.342736569,0.590798672,0 -0.633849219,1.113800586,-0.279688588,-0.568804998,0 0.215537323,0.337044357,0.203410377,0.071278019,0 0.765391068,1.811793276,-0.182676562,0.74327166,0 0.158927863,1.19532421,0.058280722,0.147856089,0 -0.786464031,0.018010027,-0.786336485,-0.014163472,0 -0.168958096,2.420989544,0.12695645,-0.111484968,0 0.369973492,0.448349033,0.333406788,0.160375493,0 -0.496787812,1.03529416,-0.253497394,-0.427243726,0 0.729898246,1.926272994,-0.254031794,0.684265517,0 -0.242412604,2.613619252,0.209403234,-0.122123528,0 0.384030231,1.684279846,-0.043487619,0.381560015,0 -0.283669843,1.414484246,-0.044160676,-0.280211374,0 0.813852485,2.69575635,-0.734298695,0.350943435,0 0.354072643,0.970587627,0.199985437,0.292187032,0 -0.147148694,1.728517813,0.023112408,-0.145322245,0 -0.100366247,0.021760173,-0.100342486,-0.002183815,0 0.607986334,2.476785645,-0.478507045,0.375071179,0 -0.130149306,1.982537099,0.052086432,-0.119272149,0 -0.541877293,2.389358003,0.395659193,-0.37024965,0 0.187842765,1.273728548,0.054984899,0.179615047,0 0.815662305,2.339064102,-0.566796079,0.58655537,0 0.55175485,0.824612921,0.374553948,0.40514535,0 0.664636247,1.004045585,0.356838981,0.560720324,0 -0.047807202,0.284629367,-0.045883718,-0.013424346,0 -0.057780406,0.388241637,-0.053480165,-0.021873437,0 -0.312595541,0.034113784,-0.312413667,-0.010661749,0 -0.092326539,2.08311289,0.045258257,-0.080472852,0 0.293454242,1.281219007,0.083795028,0.281236174,0 0.393080623,0.907093607,0.242152507,0.30963614,0 0.757979,0.957630964,0.43618589,0.619898406,0 0.035331234,0.330064514,0.033424105,0.011450996,0 0.638805982,0.177633709,0.628754097,0.112877665,0 0.113393244,1.417128402,0.017356407,0.112057052,0 -0.786863079,0.98301037,-0.436331254,-0.654804202,0 -0.017843816,0.15353226,-0.01763392,-0.002728851,0 -0.886444733,2.130012548,0.47027841,-0.751413656,0 0.780056285,2.588450612,-0.663732741,0.409812954,0 -0.594064853,1.799608385,0.134746208,-0.578581463,0 0.96001845,0.909613473,0.589500163,0.757710355,0 -0.420070805,1.130687028,-0.178966273,-0.380040201,0 -0.17378253,2.389704917,0.126930901,-0.118696732,0 -0.321899074,1.35030162,-0.070403312,-0.314105695,0 0.970856232,2.619386856,-0.841461536,0.484256449,0 -0.635986284,0.49260932,-0.560368687,-0.300774813,0 -0.19401177,0.869717741,-0.12514579,-0.148253492,0 -0.814872611,0.802775561,-0.566102566,-0.586127339,0 -0.770604244,3.081436659,0.769210355,-0.046328511,0 -0.631316144,0.831292686,-0.425457385,-0.46641836,0 -0.170092412,2.676729767,0.152042723,-0.07625247,0 -0.262518953,2.0416231,0.119084702,-0.233955198,0 -0.812783729,2.071753663,0.390351952,-0.712911456,0 0.050360164,1.200622394,0.018219179,0.04694899,0 0.863306401,2.789019852,-0.810202177,0.298111346,0 0.468353512,2.05001882,-0.215952836,0.415595218,0 0.492620357,0.704205415,0.375438895,0.318936439,0 -0.799735239,2.288119573,0.525721885,-0.60265492,0 -0.195997833,0.183276322,-0.192715233,-0.035720996,0 0.101707248,2.212259738,-0.060858423,0.081489978,0 0.330189715,1.414093909,0.051530029,0.326143992,0 0.727393097,1.188459098,0.271383058,0.674871804,0 -0.195078916,1.291733223,-0.053735486,-0.18753208,0 0.293581686,2.645965423,-0.258255173,0.139622606,0 0.506818868,2.327765357,-0.348043326,0.368417166,0 0.095579507,1.109986236,0.042501707,0.085609854,0 0.721897724,1.774751301,-0.146215984,0.706935081,0 -0.501461436,0.97177724,-0.282740315,-0.414151526,0 0.408480809,1.678601899,-0.043951258,0.406109416,0 0.768031384,1.795555186,-0.171172148,0.748713765,0 0.874420649,1.284042512,0.247321212,0.8387155,0 -0.314528012,0.584952043,-0.262234134,-0.173669598,0 -0.671441379,2.304765396,0.449746223,-0.498559786,0 -0.605185997,1.72533277,0.09315149,-0.597973988,0 0.830511949,0.712252624,0.628607532,0.542773128,0 0.129059155,2.980346281,-0.127384993,0.020720258,0 0.162032495,1.999378052,-0.067337662,0.14737764,0 0.718112348,2.701234839,-0.649603854,0.306104846,0 0.663920651,1.824959131,-0.16693302,0.642591626,0 0.42589838,1.391310658,0.076032881,0.419056596,0 0.696202947,2.138788918,-0.374516056,0.586886929,0 -0.619027173,2.086669877,0.305362951,-0.538468299,0 -0.872949988,0.456042908,-0.783736439,-0.384446195,0 -0.144530144,1.229651046,-0.048354958,-0.136201177,0 0.16409571,1.311565469,0.042063832,0.158612849,0 -0.721073093,0.252683227,-0.698175484,-0.180270348,0 -0.096126901,2.013383608,0.041169122,-0.086864748,0 -0.079534705,1.918629021,0.027110287,-0.074771663,0 -0.291594578,2.639312434,0.255578882,-0.140381028,0 0.226002167,2.14350456,-0.122472864,0.189940457,0 -0.871742183,2.998166016,0.862791151,-0.124602818,0 0.1669414,2.598450814,-0.142916716,0.086280029,0 0.029439105,1.216952629,0.010200825,0.027615287,0 -0.818954155,2.225078261,0.498407003,-0.649827952,0 0.448011462,0.062947057,0.44712417,0.028182383,0 0.2311472,2.478436359,-0.182156272,0.14229589,0 -0.848601713,2.720367485,0.774424317,-0.34697528,0 0.062650796,0.487014616,0.055366634,0.029319927,0 0.213252568,2.937021563,-0.208805869,0.043321665,0 0.125755967,2.547022932,-0.104174935,0.070442503,0 0.47682849,1.71117929,-0.066718949,0.472137682,0 -0.716733117,2.060718747,0.337264098,-0.632423347,0 -0.243763694,2.01815922,0.105449602,-0.219775158,0 -0.486323795,1.775905345,0.099051461,-0.476129858,0 -0.736395176,1.824102162,0.184544804,-0.712896256,0 -0.334829492,2.250630741,0.210495335,-0.260389137,0 0.234195358,0.510458371,0.204340286,0.114422521,0 -0.900683398,2.175895486,0.512348016,-0.740763184,0 -0.109056456,2.904224019,0.105998523,-0.025644174,0 0.849328656,1.085226928,0.39639189,0.751154203,0 0.419684301,0.730067328,0.312719154,0.279895772,0 0.665821595,1.981018093,-0.265538111,0.610579977,0 0.310792039,1.932994938,-0.110123271,0.290627867,0 0.292389488,1.932706425,-0.103523786,0.273449151,0 -0.336908935,1.804076378,0.077883227,-0.327783211,0 -0.121308283,0.818640815,-0.082879558,-0.088581478,0 0.26759421,0.624373943,0.217107014,0.156432752,0 -0.267986887,2.415096403,0.200321904,-0.178011533,0 -0.554482767,1.419068143,-0.083808233,-0.548112506,0 0.685450678,2.621003282,-0.594646409,0.340937354,0 -0.913372369,1.644585084,0.067335469,-0.910886941,0 0.710558922,2.044017531,-0.323841388,0.632471925,0 0.051606791,1.360503219,0.01077274,0.050469882,0 -0.434427415,0.961019705,-0.248789784,-0.356133153,0 0.26232834,1.5659887,0.001261172,0.262325309,0 -0.29143166,1.726272567,0.045128371,-0.287916381,0 0.17536262,1.231696181,0.058332379,0.165376486,0 0.742129511,1.728679242,-0.116683395,0.732899172,0 -0.050108112,1.988146441,0.020310794,-0.045807145,0 -0.285280861,2.691910545,0.256919758,-0.124005676,0 0.207935096,0.094948902,0.206998502,0.019713557,0 0.038233741,2.866821184,-0.036799487,0.010373846,0 0.551249409,2.798778335,-0.519173526,0.185296414,0 -0.033753664,1.06963147,-0.016216862,-0.029602757,0 -0.835679516,1.879122197,0.253598548,-0.796271329,0 0.542267866,1.087203103,0.252134689,0.480085969,0 -0.613982618,1.078560642,-0.290166545,-0.54108967,0 0.153670487,1.847721815,-0.042013445,0.147815726,0 -0.48653069,1.415078374,-0.075455755,-0.480643882,0 0.31563356,1.094558447,0.144698713,0.280511723,0 0.835146525,2.37307604,-0.600422345,0.580484906,0 0.310704399,2.443559758,-0.23803311,0.19969342,0 0.478574367,1.166403938,0.188299981,0.439973342,0 0.936678792,1.332385264,0.221205063,0.91018431,0 0.121785861,1.072822035,0.058170631,0.106995204,0 0.085445195,2.554020078,-0.071115075,0.047365889,0 -0.821554772,2.626706246,0.715039099,-0.404563135,0 -0.861251588,2.67943005,0.770897959,-0.384019056,0 0.112530124,1.308729249,0.029154035,0.108687952,0 -0.60710505,2.438545807,0.463145756,-0.392520765,0 0.037674382,2.605783713,-0.03239454,0.019234158,0 0.117347956,0.154615496,0.115948091,0.018071608,0 -0.063679881,1.602590522,0.002024309,-0.063647698,0 -0.259580386,1.735492796,0.042558961,-0.256067788,0 -0.427141936,2.867414331,0.411187329,-0.11565126,0 -0.436328452,0.826845824,-0.295481612,-0.321050051,0 0.657796702,1.831885127,-0.169798776,0.63550364,0 -0.021424463,1.804349857,0.004958393,-0.020842791,0 0.591623679,2.182705603,-0.339847188,0.484275196,0 -0.748251021,0.560060949,-0.633935275,-0.397499253,0 0.58506269,0.502805437,0.512651887,0.281933316,0 0.770246828,0.14363066,0.762315471,0.110251071,0 0.889884587,3.105739879,-0.88931271,0.031897996,0 0.856824207,1.309043099,0.22172422,0.827638865,0 -0.032638631,1.580723966,0.000324019,-0.032637022,0 -0.213569555,0.347467056,-0.200806262,-0.072724135,0 0.256753504,2.377480979,-0.185375329,0.177646698,0 -0.383344566,0.245148537,-0.371883057,-0.093037888,0 0.120539272,2.722157801,-0.110090836,0.049088938,0 0.986777794,1.230589911,0.329269677,0.930221422,0 0.213505846,0.440226394,0.193149175,0.090984296,0 -0.944549823,0.062271287,-0.942719068,-0.058780327,0 0.751806259,1.985091663,-0.302635836,0.688203605,0 -0.313096941,1.564104249,-0.002095253,-0.31308993,0 -0.027718897,2.435930614,0.021099135,-0.017976755,0 0.232384712,2.910395028,-0.226201574,0.053249434,0 0.002987748,1.271854673,0.000879919,0.002855238,0 -0.877577175,1.040043886,-0.444214129,-0.756845761,0 0.727208843,2.508968938,-0.586478647,0.42997151,0 -0.997809263,2.602950535,0.856525484,-0.511847067,0 0.792371978,2.456222462,-0.613442329,0.501539491,0 0.317527902,1.926360282,-0.110537528,0.297666632,0 0.011640092,0.961407238,0.0066624,0.00954485,0 0.50523358,2.187132227,-0.292049834,0.412271592,0 0.760538461,0.09190499,0.757328767,0.069798923,0 -0.902205078,0.199365799,-0.88433454,-0.178679669,0 0.425461204,3.052312248,-0.423766656,0.037934905,0 -0.992150699,1.675204284,0.103400327,-0.986747882,0 -0.611478356,1.671688352,0.061588678,-0.608368814,0 -0.270559419,0.918125228,-0.16431362,-0.21494984,0 -0.304193751,0.961440865,-0.174101962,-0.249444072,0 0.526857197,1.565304451,0.00289342,0.526849252,0 -0.271900187,0.198266024,-0.266573551,-0.053556077,0 0.325742788,3.122271667,-0.32568199,0.00629328,0 -0.706480931,1.844850457,0.191199517,-0.680116203,0 -0.443956214,0.624114264,-0.360262051,-0.259438575,0 0.881632917,1.475573508,0.083824759,0.877638883,0 -0.993483718,1.706389029,0.134296741,-0.984364913,0 0.907871965,0.905992174,0.560070759,0.71452939,0 0.438325707,0.81060686,0.30203217,0.317657037,0 0.846312986,1.736967821,-0.13998677,0.834655243,0 -0.059980097,1.049874422,-0.029850893,-0.052024381,0 -0.504768549,1.668688857,0.049334188,-0.502351894,0 0.709528818,0.139321454,0.702653807,0.098533101,0 0.278392594,0.393437635,0.257122467,0.106726161,0 -0.728433956,0.113350724,-0.723759364,-0.082391818,0 -0.985743322,0.010507658,-0.985688905,-0.010357663,0 -0.688694457,0.34310958,-0.648552595,-0.231688555,0 0.105651374,2.218320741,-0.063730365,0.084265375,0 0.274332773,1.777150803,-0.056208889,0.268512628,0 0.139845079,0.81602866,0.095810584,0.101867454,0 0.301049543,0.886562353,0.190287275,0.233284334,0 -0.390105798,1.02397633,-0.202844701,-0.33322149,0 0.566660047,1.402677769,0.09481794,0.558670894,0 0.314905362,1.329836567,0.075147368,0.305807554,0 -0.823269068,1.860297597,0.235022149,-0.789009853,0 0.263737374,2.113745493,-0.136263416,0.225808955,0 -0.461318769,1.641592831,0.03263248,-0.460163154,0 0.116458856,2.988214747,-0.115091704,0.017792264,0 0.371417779,1.771059166,-0.073884996,0.363994744,0 0.926746273,2.967704823,-0.912770538,0.160339012,0 0.840330139,2.895810896,-0.81507604,0.204464644,0 0.841422307,0.655018374,0.667278799,0.512572436,0 -0.638430613,0.525980055,-0.552135422,-0.320531003,0 0.594830211,3.012613606,-0.589889389,0.076508096,0 0.183716734,0.640404646,0.147314006,0.109774415,0 0.039835508,2.627487378,-0.034686093,0.019589349,0 -0.591662403,1.865595017,0.171905873,-0.566138472,0 0.349364124,1.716511614,-0.050727731,0.345661668,0 0.783339736,0.459128605,0.702216298,0.347150417,0 0.474312728,2.132726504,-0.252723573,0.401376829,0 -0.761516371,1.836630924,0.2000615,-0.734767024,0 0.826688466,2.822629795,-0.784991256,0.25923454,0 0.392691231,0.789760349,0.276460726,0.278883255,0 -0.702328347,1.52981134,-0.02877686,-0.701738555,0 0.636464791,1.689684582,-0.07549006,0.631972057,0 0.008509974,0.866814742,0.005508147,0.006486907,0 0.860902379,2.508113248,-0.693863856,0.509613437,0 -0.232859163,2.641896747,0.20438708,-0.111576482,0 0.055970333,2.978403537,-0.055226721,0.009093263,0 0.637558671,0.551442399,0.543053166,0.334027422,0 0.556042124,0.196710597,0.545318729,0.108675335,0 0.224594548,0.685383449,0.173875797,0.142161592,0 -0.078351984,2.280644192,0.051063429,-0.059426927,0 -0.834368147,1.205654137,-0.297937942,-0.779360756,0 -0.894507306,0.096403091,-0.890353947,-0.086099763,0 -0.214883763,1.23415188,-0.070980782,-0.202821992,0 0.68140206,1.778225264,-0.140331098,0.666795283,0 0.719671969,2.792543227,-0.676274481,0.246131203,0 -0.078512438,2.272119362,0.050658505,-0.059982655,0 -0.348488733,2.449787649,0.268369712,-0.222310806,0 -0.899718422,1.296735096,-0.243502783,-0.866140655,0 -0.357926917,0.610886841,-0.29319213,-0.205304779,0 0.521122887,1.621519711,-0.026421783,0.520452642,0 0.946842682,1.049705571,0.471363303,0.821174586,0 0.008507537,2.866914921,-0.008188612,0.002307557,0 0.65017699,1.336855601,0.150719281,0.632466455,0 -0.22856259,0.87152297,-0.147116997,-0.174921259,0 0.129809497,1.336720427,0.030108558,0.126269474,0 0.157307762,0.934294299,0.093501545,0.126503728,0 0.770612856,1.510320577,0.046574989,0.769204098,0 -0.242946186,0.215581388,-0.237322514,-0.051969929,0 0.044591354,1.150877536,0.018179284,0.040717349,0 0.665079143,0.273407708,0.640375683,0.179580767,0 -0.734131533,2.769639144,0.683930994,-0.266809865,0 -0.477381384,1.02600133,-0.247399454,-0.408272576,0 0.236837742,2.429983757,-0.179360103,0.154667611,0 0.860735888,2.266897377,-0.55193029,0.660484082,0 -0.219613767,2.453536441,0.169647649,-0.139462833,0 0.837477215,1.744428832,-0.144683708,0.824884665,0 -0.031835745,1.616424377,0.001452099,-0.031802611,0 0.544835376,1.147937794,0.223583482,0.496846066,0 0.287159992,0.129913256,0.284740134,0.03720104,0 0.178557819,0.037768977,0.178430478,0.006742343,0 -0.063170482,0.83702456,-0.042303725,-0.046913801,0 -0.883825393,0.538421984,-0.758780829,-0.453209642,0 -0.044908555,1.470738248,-0.00448597,-0.044683939,0 -0.772799363,0.364509187,-0.722025551,-0.275495841,0 0.299370556,0.584871065,0.249610163,0.165280054,0 -0.796295128,2.874710112,0.768104478,-0.210003434,0 0.785796333,1.009968372,0.417955251,0.665424139,0 0.758816445,2.781799653,-0.710229219,0.26716447,0 -0.805536424,1.311828571,-0.206284075,-0.778675677,0 0.989444808,0.923365016,0.596773267,0.789216508,0 0.432462331,1.385142591,0.079827822,0.425030807,0 0.800275992,1.017521308,0.420526191,0.68088133,0 -0.373074621,3.135437149,0.373067553,-0.002296448,0 0.612680728,2.925860896,-0.598478797,0.131151834,0 -0.535935067,2.101007217,0.271030556,-0.462351418,0 -0.631031487,0.915152501,-0.384720778,-0.500190623,0 -0.973074401,1.459850363,-0.107737336,-0.967091752,0 -0.304281627,2.815481268,0.288244545,-0.097480208,0 0.148210266,2.990945548,-0.146531661,0.022243091,0 -0.528893394,1.251371291,-0.166083491,-0.502139917,0 -0.246934672,0.531975923,-0.212809903,-0.12525445,0 0.48210585,0.01449941,0.482055174,0.006990006,0 0.296176835,2.723363357,-0.270649215,0.12029015,0 -0.451482279,1.839050604,0.119664726,-0.435335046,0 0.664039189,2.842822188,-0.634621668,0.195456857,0 -0.751931208,0.290605493,-0.720403152,-0.21545264,0 0.480675821,2.624400434,-0.417808657,0.237666092,0 -0.235542534,1.824878615,0.059205327,-0.227980294,0 0.181561114,2.296229779,-0.120458504,0.135846189,0 0.850733842,0.622313889,0.691248324,0.495907073,0 -0.852921318,3.104110253,0.85232224,-0.031962053,0 0.55169554,0.910650875,0.338317223,0.435785987,0 -0.818370843,1.655363265,0.069124656,-0.81544627,0 0.946372225,2.215477838,-0.56871662,0.756426992,0 -0.365287949,1.821955921,0.090784041,-0.353826996,0 -0.020869288,2.155618979,0.011520922,-0.017401021,0 0.794176887,1.70655831,-0.107488126,0.786869259,0 0.797232773,1.207577353,0.28324487,0.745219724,0 0.231159609,0.096102684,0.230092967,0.022180879,0 0.605233419,0.604144416,0.498100095,0.343807775,0 0.541304263,0.104312433,0.538361944,0.056362421,0 -0.10886424,1.784237275,0.02306006,-0.106393873,0 -0.058092303,1.378737699,-0.011088663,-0.057024181,0 -0.183838949,0.398509347,-0.169433413,-0.071337772,0 -0.659904156,2.876340996,0.636825037,-0.172995282,0 0.297437926,2.728992806,-0.272477352,0.119270334,0 0.479857683,3.080676536,-0.478967637,0.029212992,0 0.623772058,2.06266918,-0.294593534,0.549823817,0 0.184791876,1.915646426,-0.06246993,0.173912465,0 0.111322112,1.709118474,-0.015349258,0.110258845,0 -0.909277702,1.382215868,-0.170457481,-0.893157425,0 0.871126768,0.884030915,0.552328514,0.673643125,0 0.951304199,1.161181704,0.378862473,0.872606959,0 -0.782412689,0.142902957,-0.77443735,-0.111428928,0 -0.863499784,1.413009695,-0.135684071,-0.852772954,0 -0.498473171,2.973656578,0.491460574,-0.083318703,0 0.911090911,0.730524447,0.678602889,0.607934838,0 -0.049381984,1.800341362,0.011236106,-0.048086696,0 -0.384558519,0.882149096,-0.244384355,-0.296920093,0 -0.324377692,0.169542371,-0.319726793,-0.054732669,0 0.107971113,0.209097126,0.105619365,0.022412296,0 0.096652555,1.402998944,0.016142047,0.095295072,0 0.060677103,1.395201523,0.010599915,0.05974406,0 0.021018416,0.934611404,0.012487693,0.016906547,0 -0.695604216,1.550082577,-0.014407541,-0.695454994,0 0.084769643,0.231591878,0.082506484,0.019456938,0 0.978685283,1.092992735,0.450028717,0.86907942,0 -0.57158317,1.471012243,-0.056940302,-0.568739943,0 -0.657525459,0.898572931,-0.409458986,-0.514473584,0 0.870978722,0.284890643,0.835871655,0.244790751,0 -0.000411604,2.9088696,0.000400508,-9.49E-05,0 0.490677478,2.388385382,-0.357948685,0.335614551,0 0.557128687,0.8802188,0.354881219,0.429478398,0 0.580628965,0.380135586,0.539180381,0.215440276,0 0.989902369,0.124920921,0.982188577,0.123338144,0 -0.667610632,2.859064011,0.641142249,-0.186119782,0 -0.333609646,2.211888012,0.199522162,-0.267369226,0 -0.150671334,2.148431916,0.082273278,-0.126225824,0 0.249730095,2.321513843,-0.170356777,0.182602544,0 0.980421604,1.64192834,-0.069680567,0.977942299,0 0.32841257,1.580785109,-0.003280387,0.328396186,0 -0.305118474,1.027845515,-0.157643941,-0.261238724,0 0.701078294,2.603442901,-0.601986831,0.359336375,0 -0.858372611,0.869576174,-0.553779461,-0.655844378,0 -0.846246787,0.784747447,-0.598776095,-0.597997335,0 -0.397854131,0.931022922,-0.237524357,-0.319170941,0 0.328255772,1.319187321,0.081723418,0.317920013,0 -0.616539071,1.280402837,-0.176533177,-0.59072537,0 0.158267973,1.169466985,0.061826181,0.145692397,0 0.530898428,2.171449484,-0.300053931,0.437973491,0 0.101994878,0.212083556,0.099709627,0.021469639,0 -0.013007442,1.160650647,-0.005186626,-0.01192864,0 0.980208825,0.255224797,0.948456497,0.247466392,0 -0.198336358,0.357669136,-0.185784717,-0.069435939,0 -0.888602154,2.77506235,0.829578024,-0.318455791,0 -0.955684151,0.360559039,-0.894233413,-0.337162866,0 0.517506584,1.363630378,0.10644452,0.50644114,0 0.694359949,0.390583285,0.642065719,0.264362161,0 -0.118238802,0.503208897,-0.103581875,-0.057019378,0 0.347519309,1.345905726,0.077496708,0.338768255,0 -0.460646151,0.442738099,-0.416231574,-0.197347797,0 -0.857988341,0.223278516,-0.83669027,-0.18998259,0 -0.569488066,0.556490317,-0.483560395,-0.300808913,0 0.227957287,1.05697844,0.112042311,0.198522153,0 0.885617091,2.487387601,-0.702765437,0.538923346,0 -0.414244676,2.980449685,0.408877947,-0.066464097,0 -0.677177059,1.740000178,0.114035007,-0.667506394,0 0.111858305,2.01853966,-0.048427087,0.100832027,0 0.600515401,0.873702883,0.385526031,0.46042201,0 0.358887233,2.097289545,-0.180342472,0.31028477,0 -0.470998463,1.0673605,-0.227227521,-0.41256176,0 -0.563020823,2.507781334,0.453668794,-0.333432261,0 0.149682876,0.300073594,0.142994257,0.044244838,0 0.252202767,1.987106529,-0.101987917,0.230661441,0 0.741233744,0.180735393,0.729160358,0.133239016,0 0.451089951,2.612707462,-0.389457579,0.227606981,0 -0.546927172,3.082634996,0.545976887,-0.032226867,0 -0.884465636,1.384028264,-0.164231239,-0.869084324,0 0.946523641,2.224877229,-0.575893471,0.751168232,0 -0.751099852,1.910665067,0.250389158,-0.708135762,0 0.148805821,0.275950116,0.143176015,0.040543817,0 0.108877528,0.360363702,0.101884176,0.038391806,0 -0.129873404,1.453173952,-0.015240819,-0.128976039,0 0.883930248,1.465606864,0.092808774,0.879044489,0 0.741844376,1.813072061,-0.177977751,0.720178449,0 -0.0629979,0.687122147,-0.048702082,-0.039960514,0 -0.76297142,1.207160935,-0.271369287,-0.713080709,0 -0.017788278,0.253054985,-0.017221758,-0.004453523,0 0.40212523,0.12824734,0.398822806,0.051430238,0 0.279593335,2.040258499,-0.126489901,0.249344617,0 -0.12348454,1.598751554,0.003451589,-0.123436292,0 0.261511038,2.620885044,-0.226852291,0.130100196,0 0.81889261,2.243213207,-0.510070662,0.640634863,0 0.055425741,1.37660066,0.010695915,0.054383915,0 0.661589962,0.058401703,0.66046202,0.03861602,0 0.695443687,1.617166362,-0.032236193,0.694696157,0 0.058191425,2.093606936,-0.029055983,0.050418169,0 -0.802344906,0.561818213,-0.679014787,-0.427429839,0 -0.467629801,0.649340787,-0.372458987,-0.28275773,0 0.140732582,0.9016831,0.087295108,0.110386701,0 0.033625478,1.976715414,-0.013277468,0.030893068,0 0.795526972,1.67678596,-0.084159832,0.791062757,0 0.701343048,1.714642114,-0.10053769,0.694099592,0 0.045002129,1.423419742,0.006608278,0.044514293,0 -0.466073434,0.561828368,-0.394429787,-0.248293353,0 -0.541658911,2.858419307,0.520086602,-0.151341674,0 -0.224549042,0.858487222,-0.146761474,-0.169950998,0 0.032051146,0.263633078,0.030943767,0.008352202,0 -0.111942204,0.269948885,-0.107888164,-0.02985299,0 -0.55759221,2.023848955,0.244064932,-0.501339587,0 -0.587561578,0.126334735,-0.582878933,-0.074032137,0 -0.769497297,2.950857398,0.755542548,-0.145881966,0 -0.192404458,2.700703455,0.174005312,-0.082107409,0 -0.402603468,2.919522153,0.392716941,-0.088673313,0 0.903923469,0.633032305,0.728776844,0.534754102,0 -0.35821594,2.403210144,0.264921552,-0.241112486,0 0.002566002,2.978261146,-0.002531852,0.000417248,0 0.438927724,2.730863566,-0.402422087,0.175254132,0 -0.590873325,2.368089387,0.422750674,-0.412811281,0 0.047903121,2.109981519,-0.024595233,0.041106977,0 0.383575875,1.420153528,0.057564644,0.379231807,0 0.336802256,0.936241488,0.1996628,0.271238873,0 -0.51573654,2.970494196,0.508205927,-0.087811815,0 -0.794335126,0.801925131,-0.552320606,-0.570885488,0 -0.232368804,0.841225684,-0.15488534,-0.173221802,0 -0.838062438,0.606084557,-0.688790745,-0.477405446,0 0.773946465,3.002650855,-0.766488025,0.107187862,0 0.022357198,0.091402954,0.022263871,0.00204067,0 -0.422163983,1.736638968,0.069692295,-0.416371724,0 -0.634661522,0.96953483,-0.359017349,-0.523356275,0 0.326539261,1.311631878,0.083683194,0.315634302,0 -0.504240443,0.5371036,-0.433240477,-0.257994407,0 0.781980427,1.378085097,0.14976539,0.767504864,0 -0.231440642,0.832091971,-0.155836056,-0.171113689,0 0.978107456,2.734709558,-0.898253582,0.38708487,0 0.009710465,2.983719631,-0.009589705,0.00152666,0 -0.474519097,2.365492259,0.338640856,-0.33240148,0 0.680679158,1.375893564,0.131827908,0.667791524,0 -0.709108676,1.484278193,-0.061274249,-0.706456355,0 -0.952247692,1.224861635,-0.322884477,-0.895835522,0 -0.667760025,0.667269424,-0.52453511,-0.413238878,0 -0.265017124,2.581018785,0.22445629,-0.14090227,0 0.681565146,1.624134139,-0.036335959,0.680595876,0 -0.207394622,0.940661236,-0.122208092,-0.167564052,0 -0.660728093,1.643991248,0.048318769,-0.658958959,0 0.223286228,0.550984535,0.190241989,0.116896216,0 -0.917519073,0.176910193,-0.903198584,-0.161473114,0 -0.39617667,2.380441354,0.286848697,-0.273265034,0 -0.260510583,0.847652051,-0.172391652,-0.195312268,0 -0.229697484,1.905198784,0.075387814,-0.216973758,0 0.917024579,2.72615248,-0.839021329,0.370104427,0 -0.085263376,0.480209931,-0.075619915,-0.039388727,0 0.517316039,1.483160422,0.045277452,0.515330803,0 0.746331924,1.643267938,-0.054040543,0.744372864,0 0.273588269,2.410365625,-0.203646953,0.182697727,0 0.47166722,0.113005047,0.468658795,0.053187406,0 0.698199344,0.260625968,0.674620359,0.179915798,0 -0.41838,0.75503839,-0.304683241,-0.28672277,0 0.94108708,1.189778961,0.349957412,0.873598708,0 -0.456719417,0.502951752,-0.400160927,-0.220145086,0 0.032869813,2.642343984,-0.028857807,0.015736951,0 0.470427482,1.002063864,0.25335553,0.396374812,0 -0.088198133,2.525538869,0.071984229,-0.050962548,0 0.617039067,2.703636782,-0.558803196,0.261679572,0 0.263893089,2.564374096,-0.22113811,0.144005205,0 0.344735066,0.754863545,0.251092973,0.236208774,0 0.42868622,2.84933247,-0.410507834,0.123511916,0 0.797261872,0.868318962,0.515119268,0.608505245,0 0.385510966,0.978338957,0.215269813,0.319808712,0 0.24922435,2.327329971,-0.171068783,0.181240857,0 -0.155847049,1.499309663,-0.011131499,-0.155449003,0 -0.961288931,1.245648911,-0.307082289,-0.910920895,0 0.274950608,0.650768504,0.218755784,0.166564534,0 0.530279709,1.037358826,0.269645243,0.456604876,0 0.565603755,2.745400657,-0.521790515,0.218271084,0 -0.388810629,2.628517376,0.338747023,-0.190851144,0 0.520079077,2.752257348,-0.481157172,0.197408261,0 -0.770743535,1.126814446,-0.33106417,-0.696018758,0 -0.899899164,0.361308,-0.841797398,-0.318112631,0 -0.888844698,1.300022508,-0.237745639,-0.856458936,0 0.174676977,0.767028106,0.12576329,0.12122558,0 0.793886552,1.669916202,-0.078561148,0.789989876,0 -0.042246299,1.593966437,0.000978764,-0.04223496,0 0.391627791,1.323218166,0.095971009,0.379686571,0 -0.72689878,2.271138773,0.468471411,-0.555802459,0 0.589799986,1.603714853,-0.01941184,0.589480452,0 0.755889718,2.399125688,-0.556941712,0.511062809,0 -0.207522019,0.75444089,-0.15121187,-0.142127966,0 -0.993023106,1.548700831,-0.021939553,-0.992780714,0 -0.580853595,2.956805243,0.570964756,-0.106724627,0 0.537992193,2.911098133,-0.523764203,0.122909155,0 -0.543829129,3.020115467,0.539821497,-0.065900474,0 -0.118373729,2.885745583,0.114520579,-0.029956247,0 -0.5718391,0.840487962,-0.381473514,-0.426002247,0 -0.774512253,0.737765954,-0.573118236,-0.520965178,0 0.683024834,2.028109036,-0.301581797,0.612838758,0 -0.569823343,2.038094868,0.256691798,-0.50873172,0 -0.136877962,1.652596064,0.011184099,-0.136420279,0 0.960064304,2.910802709,-0.93460916,0.21961144,0 -0.349830805,1.376715066,-0.067470162,-0.343262828,0 -0.419937428,2.362443879,0.298790489,-0.295079119,0 0.448192452,1.583394224,-0.005646133,0.448156887,0 0.807914524,0.046944081,0.807024468,0.037912876,0 0.415255935,2.441483231,-0.317575983,0.267549969,0 -0.472031982,0.628579037,-0.381809604,-0.277552911,0 0.877892259,0.327916123,0.831114257,0.282743542,0 -0.287445589,0.145298698,-0.28441669,-0.041618668,0 0.947335505,2.559356554,-0.791247888,0.520933143,0 0.63223917,1.19282523,0.233318721,0.587612749,0 -0.469018532,1.353035486,-0.101328587,-0.457942028,0 -0.251852594,1.253870196,-0.078489169,-0.239309798,0 -0.973041425,2.305526621,0.652314376,-0.722008013,0 -0.600598832,1.275129261,-0.175001307,-0.574537639,0 0.70531897,2.000825513,-0.294045597,0.641102205,0 0.707439644,2.651447338,-0.624148855,0.333030113,0 -0.628616627,1.203207255,-0.225903825,-0.586622813,0 0.210795742,1.95034052,-0.078099219,0.195794169,0 -0.63381004,0.632677455,-0.511134336,-0.374775744,0 -0.113313171,2.067187389,0.053965996,-0.099637071,0 0.314981501,1.392287916,0.055928709,0.309976331,0 0.14827992,0.191129896,0.145579775,0.02816849,0 0.298759059,2.222291625,-0.181160356,0.237566623,0 0.60509206,2.494295592,-0.482692023,0.364890136,0 -0.518587817,1.782065859,0.108748577,-0.507057266,0 0.595476,1.35406873,0.12804814,0.581545648,0 0.202454891,0.262419647,0.195523869,0.052520467,0 -0.131860696,1.076837714,-0.062517135,-0.116098454,0 0.224270986,2.64238454,-0.196901389,0.107365348,0 -0.76260125,0.106641911,-0.758269018,-0.081171197,0 -0.914296224,2.156730157,0.505585411,-0.761788014,0 -0.247902365,1.673611694,0.02544329,-0.246593231,0 0.346742994,1.38599577,0.063714195,0.340838972,0 0.544538815,1.689182617,-0.06431545,0.540727328,0 -0.836551694,2.983739451,0.826150874,-0.131504641,0 0.492215963,2.110645621,-0.253002315,0.422216038,0 0.77956551,1.818201463,-0.190906967,0.755828627,0 0.543916218,1.212830632,0.190571711,0.509438195,0 -0.773488431,1.688393135,0.090750268,-0.768146302,0 0.296557877,3.084758637,-0.296079049,0.016845503,0 -0.616806543,1.536076449,-0.021411146,-0.616434809,0 -0.093756406,0.001576229,-0.093756289,-0.000147781,0 -0.280445942,1.494468429,-0.02138507,-0.279629407,0 -0.806451753,2.410911953,0.600580984,-0.538207127,0 -0.807256641,0.4312078,-0.733361652,-0.337407724,0 -0.882063343,1.017826853,-0.463274195,-0.750608261,0 0.24007278,1.649707607,-0.018924795,0.239325702,0 -0.129157945,1.341961204,-0.029298597,-0.125790966,0 0.673454168,1.569128607,0.001123132,0.673453231,0 0.329658445,1.019959692,0.172543328,0.280897651,0 0.908483711,0.740690967,0.670463225,0.613042998,0 -0.628132511,1.93723108,0.225053072,-0.586431212,0 -0.052448568,1.414174004,-0.008181073,-0.051806585,0 -0.885350234,2.856760746,0.849678499,-0.248779994,0 -0.116695238,2.535061205,0.09588032,-0.066518739,0 0.630483228,2.768454427,-0.587098369,0.229836041,0 0.137939228,3.057835553,-0.137455672,0.011539886,0 -0.89661183,1.413943036,-0.140060546,-0.885604775,0 -0.976281281,0.977535084,-0.545807583,-0.809456127,0 0.834645749,1.892198098,-0.263661973,0.791906491,0 -0.549190934,2.634455675,0.480068989,-0.266729166,0 0.45890433,2.491768992,-0.36537527,0.277658237,0 -0.369622483,1.114620262,-0.162825513,-0.331826208,0 -0.553427576,1.963042913,0.211556182,-0.511396191,0 -0.265142057,2.136459382,0.142109701,-0.223841781,0 0.229002397,2.93650708,-0.224203322,0.046636554,0 -0.271100617,2.670102168,0.241521446,-0.123137872,0 0.882286266,0.921514557,0.53344305,0.702757118,0 0.391356699,1.601034893,-0.011832262,0.39117779,0 -0.110088497,2.363323076,0.07839726,-0.077287429,0 0.517608539,3.010507887,-0.513167814,0.067656446,0 0.425384971,0.179325525,0.418563591,0.075874197,0 0.031884009,2.107982905,-0.016315712,0.027393202,0 -0.356086661,2.246271551,0.222649686,-0.277893555,0 0.948076671,0.561224902,0.802645336,0.504588782,0 -0.606890504,1.052520769,-0.300643175,-0.527190444,0 0.066703844,0.813108379,0.0458418,0.048455467,0 -0.374267415,2.020502609,0.162694434,-0.33705581,0 0.879137439,2.125971452,-0.463386427,0.747098158,0 -0.670453083,2.738316558,0.616669526,-0.263108405,0 0.690283596,1.689594751,-0.08181185,0.685418313,0 0.39371272,1.272480073,0.115716595,0.376323498,0 -0.681785655,0.058122055,-0.680634384,-0.039604476,0 0.126764428,0.761205622,0.091778067,0.087441446,0 -0.210890373,0.81515936,-0.144618583,-0.153493372,0 0.901954864,0.590193568,0.749373839,0.501957595,0 0.863949671,1.210302767,0.304746247,0.808417441,0 -0.240178581,2.461804187,0.186788254,-0.150983107,0 -0.174995619,2.074176374,0.084415973,-0.15328865,0 -0.268888494,0.918787068,-0.16315743,-0.21373038,0 -0.072736923,0.404452608,-0.066868358,-0.028623113,0 -0.201709296,1.107674287,-0.090112307,-0.180461664,0 -0.445200916,1.932074187,0.157365119,-0.416461372,0 -0.261698515,1.814646072,0.063184557,-0.253956344,0 -0.726230017,2.108517618,0.371960628,-0.623742999,0 0.324137662,2.887001185,-0.313689495,0.081634092,0 0.323115874,1.611436983,-0.013128027,0.322849071,0 0.726585718,0.679975933,0.564984228,0.456858434,0 0.137375175,1.807347309,-0.032194018,0.133549556,0 -0.337257119,0.674034248,-0.263502388,-0.210496689,0 -0.436427537,0.820077979,-0.297715237,-0.31911539,0 -0.973274251,0.993223231,-0.531400256,-0.815399616,0 0.498951986,1.474770096,0.047838879,0.496653326,0 -0.49183544,0.368961531,-0.45873608,-0.177378998,0 -0.998906935,0.155458326,-0.986860787,-0.154663672,0 -0.076302665,0.689125163,-0.058890594,-0.048517982,0 -0.293365922,0.955626898,-0.169300564,-0.239584814,0 -0.012258943,0.944041253,-0.007190111,-0.009928947,0 0.889546704,2.437962249,-0.678277922,0.57552793,0 0.221188924,1.999544676,-0.091955484,0.20116841,0 0.223848074,1.023101258,0.116562356,0.191105148,0 -0.514881915,1.767814285,0.100785999,-0.504921349,0 0.593531685,0.488872415,0.524007146,0.278740691,0 0.007768472,1.295130043,0.002114486,0.007475166,0 -0.40074137,2.193123342,0.233603162,-0.325612051,0 0.12798385,2.128213111,-0.067702917,0.108610224,0 -0.051286962,1.292863125,-0.01407154,-0.049318802,0 0.103616012,2.583986813,-0.087920717,0.054829057,0 -0.598889446,0.727918947,-0.447107252,-0.398451596,0 -0.631076333,1.344268117,-0.141737088,-0.614953605,0 -0.452019937,1.592592399,0.009851479,-0.451912571,0 -0.022418231,0.789700479,-0.015783736,-0.015920137,0 -0.932917856,0.105289283,-0.927751545,-0.098044866,0 0.615982286,1.199356441,0.223575391,0.573975801,0 0.863540954,0.420912909,0.788167914,0.352837523,0 -0.57661414,2.382360016,0.418255399,-0.39692101,0 -0.28648787,2.419075626,0.21490706,-0.189447237,0 0.705751831,1.68800272,-0.082529368,0.700909802,0 0.424016529,1.795456142,-0.094460172,0.413360972,0 -0.077022316,1.112710752,-0.034061723,-0.069081374,0 -0.411341268,2.140090982,0.221728609,-0.346465096,0 0.85273402,0.808777762,0.588713215,0.616905227,0 -0.140969836,0.008115962,-0.140965193,-0.001144093,0 0.734356884,2.168678169,-0.413364362,0.606967822,0 0.959735103,0.462499893,0.858905214,0.428221089,0 0.44807785,2.806909053,-0.42321593,0.147180285,0 -0.420508634,2.208293778,0.250280974,-0.337915589,0 -0.321587142,0.34315224,-0.30283821,-0.108200316,0 -0.266203016,1.879711882,0.08093256,-0.253601985,0 0.713566798,0.045512454,0.71282789,0.032464965,0 0.542148674,2.687051097,-0.4871002,0.238030628,0 -0.572298183,2.130057967,0.303638795,-0.485106887,0 0.40234198,2.04970891,-0.185404966,0.357077117,0 -0.387281207,0.540338666,-0.332107001,-0.199227692,0 -0.239823432,0.97142525,-0.135289983,-0.198019946,0 -0.096719098,2.302393905,0.064614089,-0.071969462,0 0.953503424,1.022805957,0.496749458,0.813884976,0 0.185058513,1.651391307,-0.014898646,0.18445781,0 0.946245306,0.14417113,0.936428324,0.135949153,0 -0.097640557,0.488496177,-0.086220478,-0.045822565,0 -0.617227807,0.892882228,-0.387106589,-0.480748015,0 -0.716903166,1.955264216,0.268885949,-0.664567902,0 -0.044071526,1.389088709,-0.007964136,-0.043345956,0 -0.519204414,1.045434779,-0.260394423,-0.449185894,0 -0.172920326,0.905413296,-0.106754179,-0.136033027,0 -0.918572934,1.272114852,-0.270299561,-0.877903402,0 -0.216662766,1.4425909,-0.027701311,-0.2148846,0 -0.749081434,2.14596558,0.407482935,-0.628554414,0 0.632215199,0.319938636,0.600133261,0.198836935,0 -0.983478862,2.682834307,0.881790134,-0.435519037,0 0.76839294,2.050789952,-0.354823514,0.681562898,0 -0.536656066,3.038404301,0.533801488,-0.055278434,0 0.808236819,3.060367037,-0.805572073,0.06557737,0 -0.234692442,2.157735442,0.129976196,-0.195414254,0 -0.453017791,2.58807101,0.385372504,-0.238145232,0 0.6933874,1.212804794,0.24295865,0.649428349,0 0.355596704,2.795510562,-0.334513,0.120623668,0 0.875202735,2.974088318,-0.862953327,0.14591567,0 -0.161263133,3.125533163,0.161242338,-0.002589692,0 0.924956568,2.203175474,-0.546709921,0.74609176,0 0.090003686,1.334844811,0.021040004,0.087509896,0 -0.915322111,2.634936209,0.80033191,-0.444165962,0 -0.104165694,0.849657624,-0.068774392,-0.078234103,0 -0.511403977,0.178589233,-0.503270241,-0.090846529,0 0.675286803,0.413842581,0.618280689,0.271553411,0 -0.855707562,0.153053387,-0.845704492,-0.130458207,0 -0.604864015,2.597861143,0.517633074,-0.312916088,0 -0.751672749,1.833421104,0.195146439,-0.725899297,0 0.757932102,1.808645294,-0.178578428,0.736594065,0 0.669482353,2.169227768,-0.377151003,0.553139893,0 -0.289304859,2.889784931,0.280181226,-0.072081775,0 -0.117346849,2.065028471,0.055664161,-0.103304328,0 0.11575735,1.025885239,0.060001903,0.098992604,0 -0.770038507,0.872949013,-0.494803436,-0.590024459,0 -0.286833233,0.510355506,-0.250282333,-0.140114444,0 -0.154376191,1.393255375,-0.027264335,-0.151949546,0 -0.508504736,1.065762438,-0.246033456,-0.445022028,0 -0.972391983,2.422289277,0.731496347,-0.640670946,0 -0.401696535,1.785108686,0.085431039,-0.392506871,0 0.965283566,1.204380342,0.345833728,0.901205524,0 0.254232606,2.15727092,-0.140699485,0.211749552,0 -0.748528508,3.026166806,0.743547672,-0.086207813,0 0.836397242,2.917805399,-0.815540808,0.185616639,0 -0.914875798,2.845470961,0.875056213,-0.266972564,0 -0.053432031,1.459409396,-0.005939331,-0.053100907,0 -0.058048961,1.874348742,0.017351536,-0.055395001,0 -0.255002643,1.000072977,-0.137762856,-0.214587379,0 -0.492615083,0.436038143,-0.446522109,-0.208056786,0 0.343552774,0.499335505,0.301605305,0.164507595,0 -0.597096491,1.748477303,0.105535334,-0.587695936,0 0.303376679,2.563267307,-0.254041329,0.165832484,0 -0.234641204,0.613677184,-0.191827618,-0.135124608,0 0.438632619,2.512142245,-0.354569193,0.258223279,0 -0.245994184,2.549771547,0.204156996,-0.137233595,0 0.328917513,3.013604416,-0.326227192,0.041982734,0 -0.663461528,2.630709167,0.578746029,-0.324398263,0 -0.215754286,1.868059829,0.063195472,-0.206291648,0 -0.816863088,1.260097422,-0.249734775,-0.77775179,0 -0.841142706,2.768390117,0.78324221,-0.306680114,0 0.791561738,1.891147524,-0.24926272,0.751290943,0 0.291419178,0.328191437,0.275865218,0.093933587,0 -0.66768966,2.36802926,0.477682218,-0.466507429,0 -0.3411273,2.730890555,0.312759404,-0.136196145,0 0.217243522,0.770436383,0.155895433,0.151298915,0 0.915499635,2.544100489,-0.756888452,0.515033449,0 -0.970582526,0.555565757,-0.824609032,-0.51190857,0 0.903677762,1.154032052,0.365812209,0.826326161,0 -0.431100816,3.004314512,0.427045081,-0.058995014,0 -0.029974823,0.578494208,-0.025097527,-0.016389147,0 -0.858196718,2.987521633,0.848030966,-0.131700748,0 -0.354648455,2.69984716,0.320604619,-0.151618617,0 0.631920269,0.506424716,0.552604353,0.306515343,0 -0.406559849,1.21967921,-0.139835033,-0.381755255,0 -0.655428848,1.229825197,-0.219177027,-0.617696046,0 0.617339063,2.433414655,-0.468898811,0.401548782,0 -0.62594635,0.032927844,-0.625607042,-0.020607339,0 -0.216689162,2.602701983,0.185979649,-0.111201453,0 0.439050765,0.888049633,0.27700872,0.340634325,0 0.815452996,0.991837363,0.446177432,0.682560831,0 -0.908921775,0.18106196,-0.894063645,-0.163673429,0 0.58208632,2.077432032,-0.282450588,0.508965765,0 0.613299932,1.676564615,-0.064746806,0.609872657,0 -0.040978252,2.071432246,0.019668886,-0.035949299,0 0.318239917,0.911572233,0.194923129,0.25155838,0 -0.203150328,1.853405041,0.056650871,-0.195091606,0 -0.747084254,0.028274227,-0.746785652,-0.021120415,0 0.406869049,2.925378948,-0.397395808,0.087286851,0 0.017427676,1.103434512,0.007851736,0.015558732,0 -0.921405025,0.395935269,-0.850121688,-0.355359446,0 0.108659689,1.990674622,-0.044295049,0.099221352,0 0.158193279,0.8112839,0.108926822,0.114717309,0 -0.116425681,1.959513069,0.044125473,-0.10773988,0 0.170129743,0.986205539,0.093887489,0.141877655,0 -0.906924967,1.889012397,0.283752055,-0.861392864,0 0.696297309,0.823657437,0.473163636,0.510828853,0 -0.51700091,2.990655265,0.5111229,-0.077738805,0 0.931587621,1.566498667,0.004003634,0.931579017,0 -0.356205267,2.995250023,0.352397794,-0.051942151,0 -0.238401821,1.256687037,-0.073658883,-0.226737287,0 -0.411955003,0.792473901,-0.289227766,-0.293350002,0 -0.311126213,2.645864548,0.27367365,-0.147994101,0 0.656690863,1.605261334,-0.022628375,0.656300881,0 -0.204807537,1.426042796,-0.029543189,-0.202665555,0 -0.257715764,1.020885034,-0.134685248,-0.219720957,0 -0.285261143,2.344037651,0.199243087,-0.20414728,0 0.232048987,2.237045991,-0.143416027,0.182424163,0 0.479768105,1.305352146,0.125861366,0.462964741,0 -0.199265491,2.946232877,0.195475041,-0.038681314,0 0.622954172,1.678102734,-0.066718761,0.619371058,0 -0.122932554,0.096066354,-0.122365734,-0.011791526,0 -0.606321518,0.483435281,-0.536839104,-0.281832503,0 0.494396397,2.562833999,-0.413880133,0.2704275,0 0.519059926,1.980014515,-0.206529891,0.476202279,0 0.558819595,3.049726585,-0.556463209,0.051264381,0 0.646057391,2.574617911,-0.544968562,0.346986194,0 -0.319672793,1.923116339,0.110311485,-0.300036783,0 0.98459532,1.838888531,-0.260811694,0.949423617,0 -0.311065472,2.304812238,0.208369323,-0.230963099,0 0.843942927,0.523193277,0.731047063,0.42167506,0 -0.736399176,1.42218913,-0.109031869,-0.728282773,0 -0.711743619,0.112881385,-0.70721384,-0.080172091,0 -0.549934899,2.475287047,0.432309587,-0.339907068,0 -0.460780843,2.083732773,0.226122626,-0.401481685,0 0.080709871,2.287577611,-0.053023271,0.060849125,0 -0.889580893,1.957785891,0.33572989,-0.823795852,0 -0.581296037,2.531145676,0.476309251,-0.333218517,0 -0.460502207,2.530771236,0.377232898,-0.264116684,0 0.286124012,2.654628024,-0.252864189,0.133890449,0 0.765192041,1.157287151,0.307473449,0.700698893,0 0.317761566,1.914068503,-0.106949061,0.299222845,0 0.922163477,1.877449527,-0.278373179,0.879143817,0 -0.968122322,2.58445187,0.821713592,-0.511905854,0 0.950844242,1.356278698,0.20241205,0.929050125,0 0.026888679,0.809738172,0.0185448,0.01947027,0 -0.171709079,1.614791733,0.007551974,-0.171542926,0 0.017712229,1.963884112,-0.006784537,0.01636133,0 0.963362938,0.46902565,0.85932854,0.435456782,0 0.744150308,2.636970472,-0.651397333,0.359779371,0 0.208916542,0.664750777,0.164432057,0.128872884,0 -0.309454817,1.411474759,-0.049094512,-0.305535616,0 -0.948628115,0.42899038,-0.862669286,-0.394584597,0 -0.212809923,2.411030895,0.158500759,-0.142005537,0 -0.79790051,1.714643314,0.114380172,-0.789659674,0 -0.170706316,2.752108121,0.157921251,-0.064819169,0 0.857654396,1.116898472,0.376057467,0.770812457,0 0.903538369,2.592720699,-0.770820865,0.471398745,0 0.453008471,1.714064373,-0.064679841,0.448367252,0 -0.070909561,0.480848249,-0.062868623,-0.032797899,0 -0.196312766,1.747443049,0.034497939,-0.193257845,0 0.199617024,0.232981103,0.19422386,0.0460874,0 -0.011077745,2.171952487,0.006265532,-0.00913562,0 -0.938398771,1.460210381,-0.103562332,-0.932666659,0 -0.844407115,0.958299524,-0.485459928,-0.690906675,0 0.445188777,0.419940688,0.406507715,0.181506267,0 -0.898715659,0.213642626,-0.878283436,-0.190546691,0 0.026961178,3.011909674,-0.026734783,0.003486614,0 -0.29675152,2.542012811,0.244989977,-0.167455592,0 0.967307658,2.53329307,-0.793792925,0.552790102,0 0.188958576,1.253290897,0.058992423,0.179513892,0 0.15087763,2.846225637,-0.14434393,0.043919119,0 0.761330916,0.293138441,0.728853844,0.219992814,0 -0.21554996,1.463258548,-0.023135113,-0.214304811,0 -0.428791627,0.230461479,-0.417454841,-0.09794751,0 -0.792394354,2.995663259,0.783972144,-0.115223655,0 -0.90545955,1.603638669,0.029732066,-0.904971271,0 -0.100700131,1.160189312,-0.040196064,-0.092329804,0 -0.087419538,1.322633189,-0.021472318,-0.084741461,0 0.202595746,2.877300149,-0.195561127,0.052923358,0 0.742482303,1.746677765,-0.129916617,0.731027799,0 0.901763302,1.284226548,0.254895626,0.864988597,0 -0.343874698,1.047135407,-0.171955856,-0.297793539,0 0.10058681,3.007095805,-0.099678403,0.013487858,0 -0.243219592,2.753866358,0.22516567,-0.091957549,0 -0.203274125,2.615937568,0.175831187,-0.101998841,0 0.226392656,1.157922133,0.090838618,0.207369188,0 0.382584635,3.032351192,-0.38030408,0.041711028,0 -0.00218907,2.75327696,0.002026089,-0.000828847,0 0.874988031,1.062918642,0.425527601,0.764545823,0 -0.252064838,0.653653665,-0.200106043,-0.153278355,0 -0.491284553,1.991139063,0.200480147,-0.448517806,0 -0.936867796,2.66262725,0.831444127,-0.43176606,0 0.762579198,1.673889076,-0.078477203,0.758530396,0 0.594969578,2.046596445,-0.27252572,0.528884231,0 0.981762562,3.077033066,-0.979717308,0.063338166,0 -0.113476511,0.841116597,-0.075646954,-0.084584023,0 0.087166364,1.480619079,0.007849774,0.086812188,0 -0.700461222,2.690063507,0.630261645,-0.305640609,0 -0.109313106,2.357440599,0.077392298,-0.077199659,0 -0.188531135,2.813898522,0.178498833,-0.060680767,0 0.449537692,2.856577362,-0.431402152,0.126397469,0 0.256324433,1.473903713,0.024797102,0.255122164,0 -0.565367688,0.929393962,-0.338270616,-0.453005091,0 -0.823162399,1.998191824,0.34120245,-0.749117629,0 -0.160930375,1.424039553,-0.023532936,-0.159200461,0 0.882456737,0.956302526,0.508776018,0.721024865,0 -0.237742081,1.289877185,-0.065911348,-0.228422834,0 0.077596683,0.826176733,0.052586661,0.057060391,0 -0.845407116,2.672829155,0.754211022,-0.381940997,0 -0.183452125,1.364103926,-0.037648748,-0.179547359,0 -0.274987952,0.310569412,-0.261832449,-0.084036554,0 -0.929317106,3.041014795,0.924620625,-0.093311217,0 0.835606762,0.006986726,0.835586367,0.005838108,0 -0.371478236,0.242777193,-0.360584296,-0.089303108,0 -0.10684935,1.055176766,-0.052684632,-0.092957589,0 0.408085918,0.309003865,0.388757735,0.12410294,0 0.735559571,0.796611872,0.514254117,0.525918802,0 0.135720709,3.0761323,-0.135430027,0.008877982,0 -0.423508596,0.230152097,-0.412341398,-0.096613158,0 0.994322496,0.71889504,0.748261349,0.654814614,0 0.543067069,2.281836555,-0.354417673,0.411472909,0 0.588357834,2.081241233,-0.287451332,0.51335823,0 0.8144692,2.465139121,-0.635121305,0.509883326,0 -0.272132594,1.427371678,-0.038896845,-0.269338419,0 0.497414566,1.97614255,-0.196148944,0.457107036,0 0.434630087,1.093554544,0.199639028,0.386066796,0 -0.685678919,1.025813808,-0.355458106,-0.58634897,0 0.781998139,0.574880529,0.656297622,0.425199389,0 0.172619144,1.808623612,-0.040667625,0.167760285,0 0.934313389,1.605928809,-0.032817996,0.933736841,0 -0.904136203,3.123973538,0.903995869,-0.015929256,0 0.023009769,2.794038501,-0.021633982,0.007837109,0 -0.65025223,1.524188673,-0.03029576,-0.649546095,0 0.766958959,3.053171024,-0.763962722,0.067727427,0 0.423908441,1.850760389,-0.117134851,0.407403722,0 -0.93777119,1.913947097,0.315518589,-0.883098423,0 0.409444886,2.201310576,-0.241392412,0.330718639,0 -0.476794834,2.808373288,0.450568367,-0.155953392,0 0.027377045,0.881990484,0.01740128,0.021135232,0 -0.358810933,2.423553856,0.270219605,-0.236064928,0 -0.61699398,3.038280424,0.61370419,-0.063629692,0 -0.231378693,0.901496016,-0.143555996,-0.181460122,0 -0.388779209,1.248203374,-0.123253437,-0.368724645,0 0.883903956,1.054073025,0.436678514,0.768503793,0 -0.814110705,1.693239895,0.099433725,-0.808015578,0 -0.863632343,0.57052745,-0.726846996,-0.466427131,0 -0.348470824,0.741768513,-0.256918798,-0.235424396,0 0.640008455,1.829756014,-0.163890207,0.618668589,0 0.358773377,0.658717696,0.283710016,0.219606382,0 0.5749508,2.217629762,-0.3465013,0.458808534,0 -0.118344792,0.402754328,-0.108875423,-0.046385687,0 0.409982656,1.781712403,-0.085832232,0.400897251,0 0.404872155,0.797076029,0.282925171,0.289611481,0 -0.272489729,0.721874041,-0.20452226,-0.180059149,0 0.215427909,1.943855576,-0.078516139,0.200610069,0 -0.842281552,1.05660012,-0.414263677,-0.733364724,0 -0.924134759,0.65714737,-0.731672616,-0.564517702,0 -0.213927566,0.465999259,-0.191117118,-0.096121022,0 0.929308638,1.672426,-0.094282835,0.924513543,0 0.143374821,2.140257913,-0.077304646,0.120749041,0 0.282203898,0.849800589,0.186292091,0.211977115,0 -0.575956647,0.751534627,-0.420818085,-0.393240637,0 -0.562594923,2.397792478,0.414014065,-0.380927028,0 -0.889555971,0.256024469,-0.860560334,-0.225268145,0 -0.969542086,3.12434168,0.969397823,-0.016724715,0 0.612344023,1.656598242,-0.052475847,0.610091376,0 -0.555974397,2.157998621,0.308028786,-0.462845327,0 -0.522669544,1.662980515,0.048113656,-0.520450313,0 0.397011005,1.483054275,0.034789881,0.395483757,0 0.811690404,0.794500766,0.568703628,0.579152394,0 -0.521751979,0.299228166,-0.498567563,-0.153803487,0 0.242955988,0.40802705,0.223010631,0.096404722,0 -0.666434579,1.011055701,-0.353854385,-0.564731903,0 -0.373174247,2.928875222,0.364763209,-0.078783375,0 0.362114061,2.205556001,-0.214727851,0.291579394,0 0.846383948,3.061988179,-0.84370365,0.067304813,0 -0.09303033,2.460854564,0.072294651,-0.058550199,0 -0.033992533,0.767576133,-0.024460887,-0.023604179,0 -0.814489228,0.227525666,-0.793497809,-0.183722423,0 0.409004819,1.750086522,-0.072938317,0.402448685,0 0.763869674,0.854539538,0.501530774,0.576162965,0 -0.694853532,2.622849359,0.603440635,-0.344500844,0 0.397449626,1.371091576,0.07884604,0.389550391,0 -0.918636218,0.728302126,-0.685583343,-0.611447447,0 0.313779126,2.919903225,-0.306100126,0.068993133,0 0.769812382,1.269497625,0.228450026,0.73513379,0 -0.617054289,2.007203308,0.260820168,-0.559221634,0 0.350909263,2.145585588,-0.190774603,0.294520562,0 0.925927603,1.569480682,0.001218192,0.925926802,0 0.372324087,1.435021445,0.050397082,0.368897492,0 0.509700675,1.723883176,-0.077724053,0.503739764,0 0.855200425,3.124590649,-0.855076822,0.014539421,0 -0.567974493,0.508386704,-0.496143296,-0.276472158,0 -0.570242173,2.518398336,0.463047078,-0.332811567,0 -0.389955384,1.359210461,-0.081894789,-0.381259026,0 0.691989722,0.411338715,0.634268352,0.27668291,0 0.60643435,2.749282523,-0.560362506,0.231854443,0 -0.128363795,0.589196656,-0.106720037,-0.071330903,0 0.235908864,2.626000423,-0.205240918,0.116314907,0 0.056569922,0.544680854,0.048383841,0.029311431,0 0.263064379,1.497349999,0.019303746,0.262355165,0 0.454804903,2.842612193,-0.434628524,0.133960988,0 0.369421508,2.46393706,-0.287795878,0.231615594,0 0.168590668,0.181144015,0.165832227,0.03037245,0 -0.398575023,0.833406564,-0.26798512,-0.295035632,0 0.155141094,0.129060912,0.153850815,0.019967112,0 0.724719124,0.581879317,0.605453013,0.398301969,0 0.282479969,2.845769266,-0.270209724,0.082350699,0 0.231602737,0.289332082,0.221976089,0.066079071,0 -0.751087294,0.063123436,-0.749591412,-0.047379732,0 -0.700686565,2.883633056,0.677502608,-0.178750884,0 -0.895180887,0.156840017,-0.884193255,-0.13982528,0 -0.702511919,2.641343331,0.616428218,-0.336955855,0 -0.6636611,2.553037605,0.551995956,-0.368437946,0 -0.048694212,0.160337236,-0.048069636,-0.007774086,0 0.848293165,1.466714076,0.088132935,0.843702483,0 -0.425307633,1.92252009,0.14652552,-0.399270403,0 0.298394002,0.092437944,0.297120055,0.027543663,0 -0.531982213,0.694521161,-0.408753989,-0.340477975,0 -0.800937215,1.835576907,0.209603268,-0.773024509,0 0.730574548,2.052068622,-0.338188307,0.647586164,0 -0.337860105,0.646771497,-0.269623679,-0.203598924,0 -0.49485158,2.999722121,0.489879927,-0.069969589,0 0.522488614,1.597332661,-0.013863305,0.522304662,0 -0.039348181,0.399264194,-0.03625334,-0.015296232,0 0.621138025,3.099781506,-0.620595176,0.025962927,0 -0.104208254,1.253431166,-0.032519685,-0.099004193,0 -0.472292076,0.860423877,-0.307989303,-0.358053619,0 0.092260232,2.781260925,-0.086335272,0.032529544,0 0.324049811,1.385696099,0.059639764,0.31851433,0 -0.429221063,0.695078617,-0.329643216,-0.274892836,0 0.916829553,2.190955846,-0.532829231,0.746102835,0 -0.311980637,0.618031513,-0.254270658,-0.180771541,0 0.915498241,1.307681345,0.238111559,0.883990902,0 -0.278727458,0.775974441,-0.198938619,-0.19522403,0 0.699336297,2.746506404,-0.645461786,0.269166005,0 0.740532653,0.90430277,0.457822279,0.582054441,0 0.205833062,1.98180878,0.167761939,0.438690622,1 -0.300572907,0.857283454,0.053276904,0.022746626,1 0.388073698,0.411834295,0.605626124,0.40534238,1 -0.060195926,2.671190989,0.303657824,0.222716536,1 -0.313775623,1.260965145,0.154330484,-0.048835214,1 0.199051988,3.102418234,0.051100729,0.257795752,1 0.190124151,2.215493281,0.135743704,0.401962796,1 0.159500519,1.420466363,0.273887497,0.407701627,1 -0.259893564,2.730118103,0.488200783,0.146052649,1 0.236018168,0.650761985,0.437781347,0.392978115,1 -0.496531005,0.05828638,-0.245687811,0.221075389,1 -0.452418532,1.545327798,0.238478811,-0.20227181,1 -0.060817455,2.952425298,0.309732541,0.238563815,1 0.464527701,2.886148891,-0.199454364,0.367374443,1 -0.097394333,0.006637681,0.152607812,0.249353532,1 0.271327531,2.421804961,0.045976429,0.428865903,1 -0.2161856,0.207978914,0.03847315,0.205361394,1 0.366878764,0.616217391,0.549398921,0.462038472,1 -0.441495006,0.560357586,-0.123975017,0.015350203,1 0.201921029,0.4764072,0.429436774,0.342598845,1 -0.162307402,2.602902027,0.389321613,0.166734275,1 0.277329473,3.018774031,-0.025240425,0.283975656,1 0.023165625,3.081423565,0.226876296,0.251393014,1 -0.093617202,0.914003413,0.192839197,0.175859437,1 0.431530662,0.324352991,0.659029412,0.387526915,1 -0.109089073,1.716356878,0.265823051,0.14206457,1 -0.118876157,0.230044833,0.134255496,0.222893719,1 -0.207812488,2.422667795,0.406381854,0.113139684,1 0.194074475,1.855028327,0.195577568,0.436287683,1 0.243176273,2.450406592,0.062634992,0.405013075,1 -0.499426139,0.029446239,-0.249209633,0.235295903,1 0.288935339,1.449665158,0.284913549,0.53681819,1 0.073917833,1.535681382,0.252595087,0.323872265,1 0.350798557,1.217183587,0.371477777,0.579093873,1 0.366519566,0.959923168,0.460229365,0.550233586,1 -0.402345238,2.838758946,0.634036613,0.130010125,1 0.316462567,1.99071688,0.120982037,0.538968721,1 0.290199709,2.973061369,-0.036088213,0.298676539,1 -0.046373296,1.754242992,0.258459393,0.204404811,1 0.020460191,1.291261698,0.255645138,0.269666007,1 -0.464162349,0.625690603,-0.126230903,-0.021840016,1 -0.298869914,2.538158025,0.496086921,0.080399137,1 -0.244295236,1.552627775,0.245561754,0.005745084,1 0.441923807,0.760149177,0.570276869,0.554498569,1 -0.16620488,1.253711314,0.198177614,0.092080709,1 0.093851786,0.114621001,0.343235949,0.260733846,1 0.11695505,2.167534417,0.184277425,0.346742064,1 -0.056032184,1.263098017,0.233029765,0.196599468,1 -0.396984776,1.174603161,0.096799921,-0.116233052,1 0.493474472,0.556185638,0.669095571,0.510530145,1 0.278047297,2.221021493,0.08167972,0.471311054,1 0.235377225,1.959275236,0.160843555,0.467838395,1 0.35372517,1.138016072,0.398351043,0.571112853,1 0.302805164,2.355461297,0.036041461,0.464272515,1 0.487869293,0.213319335,0.726811042,0.353284446,1 0.251994092,2.980378673,0.001273479,0.290449226,1 0.364482171,2.896753471,-0.103611972,0.33835059,1 0.199930797,2.638911393,0.074801853,0.346322028,1 -0.364564373,2.976621044,0.609614689,0.190129662,1 0.331816695,0.561771181,0.530820768,0.42675411,1 0.043904081,1.58889539,0.249205421,0.29389689,1 0.070707071,2.570189699,0.190525238,0.288239279,1 -0.107682768,2.367605554,0.327007115,0.174730598,1 0.174167194,0.92811933,0.354385454,0.389419828,1 -0.061988809,1.280246313,0.232241494,0.190609362,1 -0.097305873,2.760984023,0.340342539,0.213852268,1 0.215266208,2.210317197,0.121526745,0.422725688,1 0.171350636,1.336632661,0.289758412,0.416674261,1 -0.246638728,1.937999659,0.338544934,0.019803439,1 0.423049354,0.423508687,0.635674051,0.423857073,1 -0.129178104,2.989780992,0.377692391,0.230464498,1 0.199506663,2.25964973,0.1231831,0.404014227,1 0.064713432,0.059617797,0.314598461,0.253855787,1 0.157486402,0.085798852,0.406907094,0.26349558,1 -0.174648761,0.812744355,0.129927555,0.123174144,1 -0.463794434,2.288739177,0.555101,-0.09931169,1 -0.052101819,2.703742681,0.297186812,0.227909181,1 -0.435334107,0.48844689,-0.134427325,0.045717311,1 -0.45551458,1.918812061,0.405345581,-0.178207057,1 -0.076090193,1.282592955,0.228372873,0.177048065,1 0.409966238,0.981150636,0.477968523,0.590738417,1 -0.218758412,0.396580275,0.048220017,0.165500999,1 -0.043547656,1.387246344,0.242051635,0.20718386,1 -0.048448552,0.13550513,0.201995565,0.243455045,1 -0.228793432,2.215248185,0.387450017,0.067095853,1 0.084527818,2.643664539,0.175736058,0.290371015,1 -0.485125527,1.585062201,0.256920505,-0.235076162,1 -0.183397302,1.99858267,0.326083773,0.083129302,1 -0.457997053,1.428090229,0.184862642,-0.2033414,1 -0.048442878,3.003559193,0.297982113,0.243334476,1 0.118922879,1.305157829,0.281220279,0.364751668,1 0.296338208,1.554300829,0.254888025,0.546297892,1 0.077342914,2.080683677,0.212250553,0.317504856,1 0.345943991,2.090448317,0.078211791,0.550276632,1 0.432498018,0.852468281,0.534638522,0.575630845,1 -0.350212056,0.895838057,0.031164836,-0.023422119,1 -0.472824116,0.45588856,-0.174534676,0.041834314,1 0.10397809,0.572309733,0.337409423,0.306311952,1 -0.408827505,2.515637374,0.581315371,0.010479534,1 -0.482127951,0.498508069,-0.173451463,0.019487051,1 0.313662619,0.686045709,0.492698657,0.448699775,1 0.246849199,3.087920422,0.003506266,0.263242587,1 -0.205886154,2.137261855,0.360489424,0.07627264,1 0.439861321,0.01497813,0.689811982,0.256588054,1 0.061670978,3.0979064,0.188387862,0.252693317,1 -0.07990654,1.331203247,0.231037591,0.172376021,1 -0.144998686,1.572424825,0.25023613,0.105001506,1 -0.43539776,0.731278288,-0.074075845,-0.040768045,1 -0.255706303,0.535135412,0.030041545,0.119600646,1 -0.074463212,2.567654156,0.312531905,0.20957067,1 -0.317248918,0.160781978,-0.063157168,0.199211574,1 0.346355067,1.122608516,0.400087094,0.562146915,1 0.104038651,0.140640656,0.353011414,0.264583875,1 -0.093556543,0.797519011,0.184652222,0.183048565,1 0.454936697,0.006183154,0.704928,0.252812926,1 -0.071254947,2.504006234,0.307255829,0.207584938,1 -0.291357113,2.401012597,0.465044074,0.05341665,1 -0.069113643,2.105779767,0.285235987,0.190543118,1 0.135788658,3.038858234,0.114927293,0.263925643,1 0.316585065,1.079207635,0.399436714,0.529096349,1 0.478622611,1.864528562,0.111426015,0.708123187,1 0.455805122,0.058913178,0.705014355,0.276837398,1 -0.182831708,2.743127717,0.41850825,0.179060567,1 0.326557134,1.60015236,0.240414955,0.576416434,1 -0.318833701,0.297369789,-0.054840238,0.156579669,1 -0.300614406,1.476410715,0.221668435,-0.049276366,1 0.405653905,1.101789661,0.433355742,0.611850469,1 0.356833576,0.376323669,0.58186307,0.381137728,1 0.041766685,0.220518723,0.290755268,0.25913587,1 -0.442076254,2.538632582,0.614120802,-0.00069395,1 -0.361025911,0.910805797,0.028651631,-0.035209761,1 -0.003592495,0.70602122,0.247266293,0.247669149,1 -0.120751529,0.170924447,0.131008069,0.229460962,1 -0.150775816,1.212514185,0.197128051,0.108798358,1 -0.066605657,0.705677495,0.199301616,0.206802923,1 0.475904022,2.152217618,-0.011372314,0.647704855,1 -0.059451385,2.816705435,0.306341289,0.231023005,1 -0.398120744,0.170746339,-0.142331362,0.182352166,1 0.083931161,2.05869323,0.210655655,0.32413813,1 -0.08282949,2.385755044,0.310274795,0.193187383,1 -0.075633262,1.867961871,0.272146263,0.177681722,1 -0.401333486,1.210998707,0.108696572,-0.12563534,1 -0.375753244,1.66511619,0.285388469,-0.124083088,1 0.300087642,0.42891193,0.522905343,0.37480091,1 0.105316734,2.529497278,0.163803957,0.310513276,1 -0.368908805,0.02773498,-0.118766927,0.239769633,1 0.329344942,1.686106126,0.212107404,0.577157825,1 0.044309475,2.847020987,0.207599085,0.26286437,1 0.484230337,0.54744173,0.663464386,0.502044085,1 -0.195878284,1.135586687,0.167417616,0.072381161,1 0.465920745,2.095034873,0.016781528,0.653350077,1 -0.321700101,0.345139676,-0.052728869,0.14115981,1 -0.246172439,2.23206012,0.401178126,0.055716588,1 0.03406132,2.9946914,0.216305541,0.254985674,1 -0.375427635,0.783863497,-0.015874518,-0.01505971,1 0.095516134,1.485495781,0.258137701,0.345168848,1 -0.290614669,2.645518655,0.505583401,0.111674258,1 0.434460064,2.00655565,0.06661489,0.643859682,1 0.290655886,0.832328635,0.445656625,0.464940292,1 0.428041738,0.518483497,0.62178494,0.462121869,1 0.095469652,1.880074289,0.220941813,0.340939959,1 -0.412941193,0.669134904,-0.07389397,-0.00615059,1 0.316930298,1.369737527,0.313293172,0.560545951,1 0.477802207,2.372604247,-0.093355598,0.582267787,1 -0.014374525,0.607895039,0.238200641,0.241790121,1 -0.351250226,2.904255194,0.591403777,0.167415606,1 0.119824481,2.638741679,0.145008332,0.307746479,1 0.12616051,1.836519313,0.216869373,0.371732641,1 -0.201816646,2.332172965,0.389237063,0.103907568,1 -0.158184427,0.95243412,0.158300264,0.121106745,1 -0.182807795,2.034749016,0.331804011,0.086516687,1 0.268409902,1.431897346,0.287162098,0.515824855,1 -0.36407274,1.213758267,0.122756351,-0.091112904,1 -0.390388026,2.438368466,0.547772815,-0.002456257,1 -0.1274166,2.838878566,0.371623082,0.212015585,1 0.060150319,0.180770026,0.309170202,0.260814252,1 0.244583678,0.857168374,0.410099774,0.43490332,1 -0.268799583,2.459238228,0.4586127,0.080489065,1 -0.42819294,2.738836711,0.643930774,0.082167529,1 0.264092534,1.720513122,0.210608459,0.511138226,1 -0.134191959,2.927437337,0.381126512,0.221481241,1 -0.378901252,0.677366803,-0.045249615,0.012526162,1 -0.015611701,2.605983165,0.263425403,0.24203233,1 0.009239803,2.694623552,0.241667903,0.253993761,1 0.112369387,0.892580725,0.320501062,0.337501311,1 0.339607448,2.521554628,-0.026391682,0.447334378,1 -0.012320528,2.431140314,0.259339785,0.241964838,1 -0.391548807,1.3629829,0.169215311,-0.133124395,1 0.398360222,2.055931758,0.064233407,0.602394154,1 0.06416007,0.948924687,0.287376925,0.302148634,1 0.148987712,0.722285238,0.361785021,0.348495926,1 0.385728262,1.093077491,0.427340341,0.592544443,1 -0.125692342,1.746614251,0.271985289,0.126245356,1 -0.491249762,1.419034547,0.175732912,-0.235603468,1 -0.164382288,1.31024479,0.207652901,0.091165936,1 -0.144677107,0.344901602,0.113843112,0.20108408,1 0.232168812,0.911315576,0.392251356,0.433485447,1 -0.229177564,1.089993023,0.144007313,0.046805743,1 0.225617617,2.249759348,0.108315214,0.425581122,1 0.09035442,1.063545139,0.293892044,0.328977273,1 0.470430888,0.451727668,0.67324398,0.455352753,1 0.123356985,1.431873563,0.267082023,0.372168532,1 -0.086470457,1.749625358,0.26538114,0.164908517,1 0.325769128,2.757073393,-0.051981099,0.372200413,1 0.150762322,0.668617261,0.368300115,0.343457801,1 -0.317734453,3.124699511,0.567689117,0.244632722,1 -0.431986262,0.418398529,-0.144723466,0.074484999,1 0.187408171,2.008031274,0.170644605,0.419777925,1 0.001626445,3.06193456,0.248378713,0.250129423,1 -0.153169537,2.912539944,0.399169043,0.215222079,1 0.342146671,1.939204808,0.126782323,0.569189205,1 0.018250776,1.263791072,0.255515481,0.267397422,1 0.040836449,1.004987441,0.271892372,0.284472302,1 -0.156344801,2.890364192,0.401436788,0.211133614,1 -0.244246559,2.225622474,0.398751372,0.056274909,1 0.41338172,1.758573592,0.17283168,0.656115128,1 -0.004135,0.314727557,0.246068108,0.24871998,1 -0.012688919,1.919519484,0.25433578,0.23807483,1 0.230603525,2.578834712,0.054958557,0.37303179,1 -0.165128426,0.321122647,0.093312663,0.197880181,1 0.343907695,2.633439293,-0.050453069,0.417333369,1 0.488888019,1.618838502,0.22652179,0.738323939,1 -0.106423865,1.761944435,0.270219068,0.145514459,1 -0.125203286,2.224609596,0.326150852,0.150617353,1 0.431616002,2.328363002,-0.046587373,0.563573442,1 -0.328900637,2.248663961,0.456264617,-0.006184577,1 -0.2086343,0.832767937,0.109624453,0.095653064,1 0.266183716,2.507308368,0.035590072,0.407740779,1 0.18733516,0.830366871,0.376377234,0.388286865,1 -0.180652109,1.649494736,0.264202363,0.069907031,1 -0.352594892,0.29210505,-0.087658905,0.148463693,1 -0.460435729,2.322868522,0.564548279,-0.086244615,1 -0.015580012,1.751965501,0.252807202,0.234674975,1 0.033440757,1.722420346,0.244948984,0.283057094,1 -0.483389031,1.545481627,0.237764459,-0.233234153,1 -0.202988462,1.351869354,0.205914492,0.051856659,1 0.397849305,2.403500947,-0.044310596,0.517703833,1 -0.339800081,2.41458631,0.503887556,0.024156683,1 -0.181478516,2.182562872,0.354225745,0.101435382,1 -0.211115201,0.989215943,0.134024881,0.073593084,1 0.052325615,0.619277817,0.292608636,0.280372259,1 -0.091142223,2.415122644,0.318130981,0.189460143,1 0.230017282,1.631455638,0.236055865,0.479594232,1 0.1926991,2.753902277,0.071602124,0.322850128,1 0.014923717,1.52033097,0.250752811,0.264904718,1 0.490370132,2.816480904,-0.214682111,0.406631421,1 -0.302508729,2.879440514,0.542173357,0.17160191,1 0.412508073,0.86537692,0.517450928,0.564058771,1 -0.06099326,1.408103172,0.240120532,0.189812178,1 -0.067127923,1.042513282,0.21616409,0.192023373,1 -0.150617029,1.938600317,0.304156938,0.109456357,1 -0.381729357,2.457498549,0.545837146,0.008758037,1 0.275743479,0.304984257,0.51301838,0.332799744,1 -0.240307783,0.537227638,0.043544193,0.127021017,1 0.167501529,3.080138741,0.082814663,0.260287146,1 0.474865094,2.279293767,-0.058991655,0.610584269,1 0.318103269,0.271356728,0.556463275,0.335264008,1 0.39702602,1.06069995,0.443852463,0.596483597,1 -0.424669353,2.410785477,0.566224037,-0.033454438,1 -0.184332105,2.357163316,0.3804687,0.119783859,1 -0.437605892,2.323151352,0.549042368,-0.069487994,1 -0.479015592,1.451742229,0.193105855,-0.225624846,1 0.0269814,0.33875402,0.275448032,0.258966248,1 0.291305252,2.533678698,0.01088463,0.416380857,1 0.003183293,2.58527851,0.247296725,0.251680969,1 -0.26035452,0.694412538,0.049935836,0.083390258,1 -0.350943224,0.879434066,0.026243082,-0.020358999,1 -0.348212061,2.212944313,0.458550106,-0.028852098,1 -0.096582444,1.998958285,0.290100971,0.162136011,1 -0.291466765,1.00456465,0.093641002,0.00402289,1 0.046468119,2.137372813,0.225058393,0.289207173,1 -0.474525997,2.556440899,0.64557829,-0.012092997,1 -0.402245845,2.685437829,0.611117385,0.072810965,1 -0.239710968,1.4586828,0.223181423,0.011793972,1 0.296747581,1.004060645,0.409318122,0.500353476,1 0.033489036,1.666779684,0.246790543,0.283334891,1 0.339172417,1.716399606,0.200789694,0.585583484,1 0.22006485,2.527365416,0.070158812,0.376829354,1 0.112175961,1.447657455,0.263778339,0.361326563,1 0.03960174,3.056823552,0.21054046,0.253352985,1 -0.259101257,1.460372075,0.221447047,-0.007523184,1 0.468088843,2.37745167,-0.087949375,0.573878658,1 -0.412112528,0.30951434,-0.142529605,0.124472135,1 -0.196757423,2.614319281,0.420034275,0.150995814,1 0.274369024,1.914253238,0.157607846,0.50834483,1 -0.023000513,1.688560272,0.252702375,0.227158792,1 0.000122762,0.655756412,0.2500973,0.250074855,1 0.128464843,1.520516416,0.25645648,0.378302494,1 -0.174264827,0.304389159,0.083746091,0.197771007,1 0.202887261,2.055081821,0.155540533,0.429556815,1 0.274208086,1.415947168,0.292291405,0.520927133,1 0.209495624,0.83928972,0.389941309,0.405900117,1 -0.134301579,0.673989304,0.145065055,0.166181318,1 -0.023180348,0.083986535,0.226901358,0.248055451,1 0.336903405,2.38586393,0.004811148,0.481054822,1 -0.035798954,0.908167549,0.227976789,0.221776901,1 0.487881234,2.420188325,-0.11633977,0.572216186,1 0.200391928,2.311920721,0.114711839,0.397831115,1 -0.321133243,0.769530883,0.019350171,0.02655601,1 -0.436718769,1.709859982,0.310536152,-0.182502783,1 0.373930187,0.845584913,0.498025526,0.529834099,1 -0.439290689,3.051202243,0.687497315,0.210346384,1 -0.130386131,1.591635282,0.252716914,0.119642179,1 0.055203396,1.774333281,0.238841487,0.304063875,1 -0.093326,2.844306831,0.339232261,0.222662372,1 -0.294630339,2.197016379,0.422678792,0.01127616,1 0.015886911,0.169726882,0.26565863,0.252683508,1 0.186791086,1.009281021,0.349460545,0.408109171,1 -0.46565539,2.149878163,0.504832564,-0.139737484,1 -0.018947116,2.751036865,0.267520352,0.242786787,1 0.075513099,1.277595039,0.271824673,0.322290468,1 -0.133675612,0.629336597,0.141934206,0.171317388,1 0.268684696,2.407452648,0.050526552,0.430005027,1 -0.146081794,0.371745089,0.113896341,0.196936975,1 0.195425868,2.281141184,0.122563718,0.398159589,1 -0.041137339,0.155031938,0.209356037,0.243647915,1 0.319102007,1.372463842,0.312874194,0.562846491,1 0.22113326,0.123651704,0.469444878,0.277273878,1 0.329277013,1.176230987,0.376576376,0.553976598,1 0.450412177,1.733533663,0.177024229,0.694461096,1 -0.245902384,2.224111019,0.399464842,0.054735453,1 0.004317337,0.600421333,0.253562225,0.252439253,1 0.362855139,0.727314002,0.521039335,0.491249934,1 -0.065453076,2.70004435,0.309175543,0.222029297,1 -0.374277984,2.403489798,0.52687081,-0.00184631,1 0.177126193,0.477813311,0.407288515,0.331449441,1 -0.019042572,2.301076745,0.262702892,0.235813524,1 -0.38265918,2.384085503,0.528021461,-0.012929867,1 0.23418965,1.794024715,0.198155316,0.478378898,1 0.315574005,2.021322649,0.112586645,0.534085414,1 0.18913507,0.980526135,0.35526984,0.407131586,1 -0.200875216,0.272311638,0.056526688,0.195972881,1 0.27287315,2.474935388,0.035550882,0.4187345,1 -0.318472313,1.443706934,0.209634414,-0.065903836,1 0.177268103,1.828101459,0.204889641,0.421432307,1 -0.114387946,0.275532504,0.139926715,0.218879685,1 -0.117640299,0.494130812,0.146431684,0.194207134,1 -0.316630723,1.497292634,0.226747424,-0.065775763,1 0.21348672,1.20621969,0.326119499,0.449455262,1 0.205608642,2.598870815,0.073936063,0.356190414,1 -0.098298133,0.320651675,0.156712101,0.219017895,1 0.470469172,2.259909181,-0.049149104,0.613113006,1 0.152326144,1.57462037,0.2494175,0.402325031,1 -0.073571912,0.228750563,0.178344601,0.233316773,1 -0.197578167,1.940961317,0.321477705,0.065804263,1 -0.108938143,1.671646982,0.260967869,0.141615384,1 0.20282091,2.85771912,0.055296438,0.306805319,1 0.363461521,0.412791032,0.582932469,0.395808945,1 -0.057197491,2.547134118,0.297385368,0.217965959,1 -0.04931392,2.514149686,0.289921163,0.221048947,1 0.252786056,2.581889526,0.035785869,0.384212876,1 0.469231094,1.563815601,0.253275547,0.719219661,1 0.19053647,1.293645043,0.302133971,0.433265369,1 -0.291642159,1.847517815,0.329677611,-0.030547014,1 0.471977764,1.655966497,0.209850155,0.720266945,1 0.445982699,0.785720366,0.565255765,0.565458983,1 -0.125288798,3.004983695,0.374121545,0.232937613,1 -0.0401599,2.329804553,0.277638133,0.220863233,1 0.393639088,0.492392373,0.596876505,0.436087135,1 -0.162875236,1.928671324,0.307052696,0.097444002,1 0.305672864,1.055136725,0.400729976,0.515925505,1 -0.285086008,2.374105691,0.455164374,0.052056544,1 0.142689169,0.0354549,0.392599494,0.25505797,1 -0.102284313,3.080564047,0.352093893,0.243761605,1 0.358766856,2.251032429,0.024344046,0.528914049,1 0.190888067,0.803185516,0.382556115,0.387357673,1 0.477498193,1.478051485,0.294222034,0.725446039,1 -0.249289008,0.234572369,0.007538065,0.192058482,1 -0.034641554,1.717586754,0.255066807,0.215730995,1 -0.313974947,0.511151017,-0.023843306,0.096409275,1 0.098721178,0.491459166,0.337037052,0.296587793,1 0.26660358,2.944692224,-0.011452174,0.302155817,1 0.23284862,2.57138793,0.053990248,0.375692708,1 0.326828102,2.06504266,0.094963105,0.537715431,1 -0.343139052,1.84474256,0.342830305,-0.080343674,1 0.296661542,1.19520762,0.358821464,0.52598181,1 0.203599157,0.671240233,0.409428502,0.376630049,1 0.134134282,2.327395654,0.157923182,0.347539044,1 -0.287930437,2.284990807,0.438597016,0.032433684,1 -0.007846674,2.86646279,0.25755156,0.247868279,1 0.403938521,0.40828716,0.620735676,0.410378887,1 0.353527592,2.953500615,-0.097292349,0.316104331,1 0.162031435,0.492519969,0.392773042,0.326616214,1 -0.38486615,0.733039233,-0.036011044,-0.007525991,1 0.138993107,2.233022947,0.164536705,0.359613452,1 -0.136538463,0.704138593,0.14593455,0.161608067,1 0.085108261,1.265920912,0.275547316,0.331183439,1 -0.493462973,2.95905371,0.735264568,0.160423188,1 0.21910655,2.286757394,0.106190992,0.415307741,1 -0.225501042,0.548615193,0.057591794,0.132399821,1 -0.401606135,1.826876841,0.351723153,-0.13850983,1 -0.466407322,1.634031079,0.2794735,-0.215475137,1 -0.251432445,0.072944569,-0.000763817,0.231675629,1 -0.325408428,1.791336448,0.321185272,-0.067526853,1 -0.245361077,0.24439217,0.011929931,0.190630814,1 -0.254370489,2.116269399,0.381973151,0.032543262,1 0.40104828,3.102980429,-0.150749355,0.265481519,1 -0.075874705,0.590845156,0.186988321,0.207733002,1 0.286442733,2.303906163,0.05831717,0.46285472,1 0.362648644,1.738191811,0.189577366,0.607579563,1 -0.238236747,1.95572859,0.339457031,0.029196496,1 -0.298062467,0.793135959,0.040875135,0.037613501,1 0.41763613,1.465267469,0.293990908,0.665312819,1 -0.353575269,1.310446798,0.158983249,-0.091659804,1 0.458172787,2.194292487,-0.017516577,0.621963956,1 0.260222475,2.384077366,0.06093652,0.428803628,1 0.428360846,2.117958775,0.027138396,0.615821979,1 0.392631963,2.397179156,-0.038775079,0.516024081,1 -0.469320806,0.998201881,-0.004284816,-0.144463244,1 -0.413730763,1.341987961,0.156158785,-0.152947851,1 0.132700985,0.793041815,0.3431138,0.344548251,1 -0.159540075,2.816623962,0.401189863,0.199062186,1 0.247190094,2.029160842,0.140622824,0.471674482,1 -0.07651613,2.384324141,0.305605426,0.197438087,1 -0.492454103,0.53170339,-0.174468203,0.000324635,1 0.299891824,1.42735581,0.292869277,0.546811945,1 0.299002407,2.415006068,0.02651174,0.448633927,1 -0.237841719,2.998099017,0.485397287,0.215988227,1 0.008975291,3.121418573,0.241026535,0.250181056,1 0.447133651,2.998310507,-0.192551722,0.313847283,1 -0.487211635,2.252384448,0.556956539,-0.128355469,1 -0.035230417,1.851576905,0.259762551,0.216149227,1 -0.3685204,1.329385556,0.161896824,-0.107833922,1 -0.211746253,1.750838305,0.287917586,0.041676376,1 -0.416011732,2.81710558,0.644301904,0.117366029,1 0.087915362,0.681497246,0.318277742,0.305382857,1 -0.130459996,3.133355966,0.38045557,0.248925454,1 0.055812358,1.452853018,0.256567443,0.305424616,1 0.072385199,1.981947666,0.221070171,0.316352709,1 0.440779404,1.698321375,0.193941816,0.687200141,1 0.061097828,1.309723533,0.265770397,0.309027444,1 -0.429664876,0.634606145,-0.096011385,-0.004731285,1 0.267554704,1.701256472,0.215193704,0.515281061,1 -0.335792885,1.674674233,0.284818763,-0.083982807,1 -0.411970322,3.065452198,0.660776727,0.218662692,1 -0.036046931,2.182916383,0.270712706,0.22049805,1 0.154434394,0.529057386,0.383320619,0.3279461,1 0.495861549,1.480701157,0.294614316,0.743850421,1 0.194756036,2.45804733,0.098998135,0.372997359,1 -0.221106183,1.838539458,0.308494891,0.036771738,1 -0.050302128,3.007876637,0.299853098,0.243293826,1 0.398415893,2.0443357,0.0683068,0.604574118,1 0.12896813,0.821364278,0.337856067,0.344414458,1 0.217501893,1.354629417,0.296651399,0.462439922,1 -0.346440147,0.423608526,-0.065818852,0.107594843,1 0.475118712,2.611816785,-0.159989607,0.490096464,1 0.461473188,2.705535373,-0.168290367,0.444911961,1 -0.393077808,0.346058176,-0.119774997,0.11667103,1 0.378739907,1.508794327,0.273467589,0.628012155,1 0.052226639,3.113326942,0.197794222,0.251476027,1 -0.258261992,2.276746683,0.417549363,0.053463826,1 -0.229210512,1.669954971,0.272690976,0.021915414,1 -0.42480703,2.347324829,0.547707847,-0.053036385,1 0.429079045,0.113890223,0.676299263,0.298762332,1 -0.209073098,1.056462661,0.147145479,0.067976629,1 -0.464973502,0.049928168,-0.214394075,0.226794369,1 -0.457389032,1.660970898,0.291188986,-0.205530673,1 0.447035545,3.024137725,-0.193955513,0.302385884,1 0.043752947,0.508289354,0.288221626,0.271293841,1 0.335655492,1.161501139,0.38357841,0.557930865,1 -0.396823338,0.35339391,-0.122301061,0.112665803,1 -0.345105726,2.271082319,0.472398691,-0.013887825,1 -0.192841092,2.033086149,0.336006885,0.077400745,1 -0.355658734,2.641928458,0.562177144,0.079592941,1 -0.193728313,0.4226949,0.073322345,0.170528839,1 0.128528234,1.257021796,0.289670376,0.372252886,1 -0.32713631,0.605320191,-0.019010711,0.063851129,1 -0.477282242,2.0356664,0.463968811,-0.176632965,1 -0.22186284,0.622038127,0.069693724,0.120722134,1 0.005817436,0.883959314,0.253688804,0.254498364,1 -0.332683758,0.341701532,-0.063449934,0.138520755,1 -0.109638679,2.24556308,0.31849295,0.164388343,1 -0.469964962,0.469510565,-0.169109978,0.037364416,1 -0.379843293,2.404400196,0.531220301,-0.00533521,1 0.14244734,2.147557141,0.172321812,0.36940412,1 0.170466784,0.838666898,0.36394936,0.376785125,1 -0.283579828,2.645165269,0.499348839,0.114934552,1 -0.101890864,1.515286388,0.244346949,0.148266077,1 -0.000254022,2.153208544,0.250139722,0.249787857,1 -0.365821206,0.986525653,0.048216247,-0.055136808,1 -0.362259126,1.645047538,0.27687347,-0.111260973,1 -0.270717608,0.793840571,0.060196645,0.056964486,1 0.242989853,2.400695037,0.070706776,0.414006123,1 -0.466324679,0.224636581,-0.204608329,0.146125204,1 -0.070839646,0.53215433,0.188956345,0.214056606,1 -0.137937667,2.101463663,0.319811496,0.131032967,1 -0.243355619,1.192659315,0.160155603,0.023836471,1 -0.024642069,0.475651289,0.228093332,0.238715964,1 0.267486301,2.147752503,0.104092814,0.474187454,1 0.182130571,1.391566934,0.282468665,0.429213088,1 0.404502629,0.799151995,0.532065662,0.539933336,1 0.03528385,2.405752987,0.223845231,0.273682866,1 -0.24426036,2.477857408,0.442403051,0.099520136,1 0.451072416,2.68015933,-0.153897123,0.450831866,1 -0.119425217,0.58245092,0.150265974,0.184307485,1 0.189356724,1.756467066,0.215043653,0.436102183,1 0.243402148,2.276072522,0.09221598,0.435334316,1 0.492933488,1.418681072,0.324693866,0.73724147,1 -0.456149245,2.0072946,0.442845608,-0.163379614,1 -0.472095948,0.182532924,-0.21425305,0.164304672,1 abstract_rendering-0.5.1/examples/000077500000000000000000000000001240657705300172045ustar00rootroot00000000000000abstract_rendering-0.5.1/examples/blazeDemo.py000066400000000000000000000066451240657705300214730ustar00rootroot00000000000000#!/usr/bin/env python """ Draws a colormapped image plot - Left-drag pans the plot. - Mousewheel up and down zooms the plot in and out. - Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular region to zoom. If you use a sequence of zoom boxes, pressing alt-left-arrow and alt-right-arrow moves you forwards and backwards through the "zoom history". """ # Abstract rendering imports import abstract_rendering.util as util import abstract_rendering.core as core import abstract_rendering.numeric as numeric import abstract_rendering.categories as categories import abstract_rendering.infos as infos import abstract_rendering.glyphset as glyphset import abstract_rendering.blazeglyphs as blzg from timer import Timer # Enthought library imports from enable.api import Component, ComponentEditor from traits.api import HasTraits, Instance from traitsui.api import Item, Group, View # Chaco imports from chaco.api import ArrayPlotData, Plot #=============================================================================== # # Create the Chaco plot. #=============================================================================== def _create_plot_component(): red = util.Color(255,0,0,255) green = util.Color(0,255,0,255) blue = util.Color(0,0,255,255) purple = util.Color(125,0,255,255) white = util.Color(255,255,255,255) black = util.Color(0,0,0,255) shape = glyphset.ShapeCodes.RECT glyphs = blzg.load_csv("../data/circlepoints.csv", "x", "y", "series", schema="{r:float32, theta:float32, x:float32, y:float32, series:int32}") screen = (800,600) ivt = util.zoom_fit(screen,glyphs.bounds()) with Timer("Abstract-Render") as arTimer: image = core.render(glyphs, infos.val(), blzg.CountCategories("int32"), categories.HDAlpha([red, blue, green, purple, black]), screen, ivt) # image = core.render(glyphs, # infos.valAt(4,0), # blzg.Count(), # numeric.BinarySegment(white, black, 1), # screen, # ivt) # Create a plot data object and give it this data pd = ArrayPlotData() pd.set_data("imagedata", image) # Create the plot plot = Plot(pd) img_plot = plot.img_plot("imagedata")[0] # Tweak some of the plot properties plot.title = "Abstract Rendering" plot.padding = 50 return plot #=============================================================================== # Attributes to use for the plot view. size=(800,600) title="Basic Colormapped Image Plot" #=============================================================================== # # Demo class that is used by the demo.py application. #=============================================================================== class Demo(HasTraits): plot = Instance(Component) traits_view = View( Group( Item('plot', editor=ComponentEditor(size=size), show_label=False), orientation = "vertical"), resizable=True, title=title ) def _plot_default(self): return _create_plot_component() demo = Demo() if __name__ == "__main__": demo.configure_traits() abstract_rendering-0.5.1/examples/demo.py000066400000000000000000000075101240657705300205050ustar00rootroot00000000000000#!/usr/bin/env python """ Draws a colormapped image plot - Left-drag pans the plot. - Mousewheel up and down zooms the plot in and out. - Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular region to zoom. If you use a sequence of zoom boxes, pressing alt-left-arrow and alt-right-arrow moves you forwards and backwards through the "zoom history". """ # Abstract rendering imports from __future__ import print_function, division, absolute_import import abstract_rendering.util as util import abstract_rendering.core as core import abstract_rendering.numeric as numeric import abstract_rendering.categories as categories import abstract_rendering.infos as infos import abstract_rendering.glyphset as glyphset import abstract_rendering.blazeglyphs as blzg import abstract_rendering.numpyglyphs as npg from timer import Timer # Enthought library imports from enable.api import Component, ComponentEditor from traits.api import HasTraits, Instance from traitsui.api import Item, Group, View # Chaco imports from chaco.api import ArrayPlotData, Plot #=============================================================================== # # Create the Chaco plot. #=============================================================================== def _create_plot_component(): red = util.Color(255,0,0,255) green = util.Color(0,255,0,255) blue = util.Color(0,0,255,255) white = util.Color(255,255,255,255) black = util.Color(0,0,0,255) shape = glyphset.ShapeCodes.POINT #glyphs = glyphset.load_csv("../data/checkerboard.csv", 2, 0, 1, 3,1,1, shape) #glyphs = glyphset.load_csv("../data/circlepoints.csv", 1, 2, 3, 4,.1,.1, shape) #glyphs = glyphset.load_csv("../data/sourceforge.csv", 1, 1, 2, -1,.1,.1, shape) glyphs = glyphset.load_hdf("../data/CensusTracts.hdf5", "__data__", "LON", "LAT", None, .1, .1, shape) #glyphs = glyphset.load_hdf("../data/tweets-subset.hdf", "test", "longitude", "latitude", None, .1, .1, shape) screen = (800,600) ivt = util.zoom_fit(screen,glyphs.bounds()) with Timer("Abstract-Render") as arTimer: # image = core.render(glyphs, # infos.val(), # categories.CountCategories(), # categories.HDAlpha([red, blue]), # screen, # ivt) image = core.render(glyphs, infos.valAt(4,0), numeric.Count(), numeric.BinarySegment(white, black, 1), screen, ivt) print("screen x image -- {0} x {1}".format(screen, image.shape)) # Create a plot data object and give it this data pd = ArrayPlotData() pd.set_data("imagedata", image) # Create the plot plot = Plot(pd) img_plot = plot.img_plot("imagedata")[0] # Tweak some of the plot properties plot.title = "Abstract Rendering" plot.padding = 50 return plot #=============================================================================== # Attributes to use for the plot view. size=(800,600) title="Basic Colormapped Image Plot" #=============================================================================== # # Demo class that is used by the demo.py application. #=============================================================================== class Demo(HasTraits): plot = Instance(Component) traits_view = View( Group( Item('plot', editor=ComponentEditor(size=size), show_label=False), orientation = "vertical"), resizable=True, title=title ) def _plot_default(self): return _create_plot_component() demo = Demo() if __name__ == "__main__": demo.configure_traits() abstract_rendering-0.5.1/examples/numpyDemo.py000066400000000000000000000072671240657705300215470ustar00rootroot00000000000000#!/usr/bin/env python """ Draws a colormapped image plot - Left-drag pans the plot. - Mousewheel up and down zooms the plot in and out. - Pressing "z" brings up the Zoom Box, and you can click-drag a rectangular region to zoom. If you use a sequence of zoom boxes, pressing alt-left-arrow and alt-right-arrow moves you forwards and backwards through the "zoom history". """ # Abstract rendering imports from __future__ import print_function, division, absolute_import import abstract_rendering.util as util import abstract_rendering.core as core import abstract_rendering.numeric as numeric import abstract_rendering.categories as categories import abstract_rendering.infos as infos import abstract_rendering.numpyglyphs as npg from timer import Timer # Enthought library imports from enable.api import Component, ComponentEditor from traits.api import HasTraits, Instance from traitsui.api import Item, Group, View # Chaco imports from chaco.api import ArrayPlotData, Plot #=============================================================================== # # Create the Chaco plot. #=============================================================================== def _create_plot_component(): red = util.Color(255,0,0,255) green = util.Color(0,255,0,255) blue = util.Color(0,0,255,255) purple = util.Color(125,0,255,255) white = util.Color(255,255,255,255) black = util.Color(0,0,0,255) clear = util.Color(0,0,0,0) with Timer("Loeading") as arTimer: #glyphs = npg.load_csv("../data/circlepoints.csv", 1, 2, 3, 4) #glyphs = npg.load_hdf("../data/CensusTracts.hdf5", "__data__", "LAT", "LON") glyphs = npg.load_hdf("../data/tweets-subset.hdf", "test", "longitude", "latitude", vc="lang_primary") screen = (800,600) ivt = util.zoom_fit(screen,glyphs.bounds()) with Timer("Abstract-Render") as arTimer: image = core.render(glyphs, infos.encode(["Arabic","English","Turkish","Russian"]), npg.PointCountCategories(), npg.Spread(2) + categories.HDAlpha([red, blue, green, purple, black], alphamin=.3, log=True), screen, ivt) # image = core.render(glyphs, # infos.valAt(4,0), # npg.PointCount(), # npg.Spread(1) + numeric.BinarySegment(white, black, 1), # screen, # ivt) # Create a plot data object and give it this data pd = ArrayPlotData() pd.set_data("imagedata", image) # Create the plot plot = Plot(pd) img_plot = plot.img_plot("imagedata")[0] # Tweak some of the plot properties plot.title = "Abstract Rendering" plot.padding = 50 return plot #=============================================================================== # Attributes to use for the plot view. size=(800,600) title="Basic Colormapped Image Plot" #=============================================================================== # # Demo class that is used by the demo.py application. #=============================================================================== class Demo(HasTraits): plot = Instance(Component) traits_view = View( Group( Item('plot', editor=ComponentEditor(size=size), show_label=False), orientation = "vertical"), resizable=True, title=title ) def _plot_default(self): return _create_plot_component() demo = Demo() if __name__ == "__main__": demo.configure_traits() abstract_rendering-0.5.1/examples/timer.py000066400000000000000000000010271240657705300206760ustar00rootroot00000000000000from __future__ import print_function, division, absolute_import import time class Timer(object): def __init__(self, name, verbose=True): self.verbose = verbose self.name = name def __enter__(self): self.start = time.time() return self def __exit__(self, *args): self.end = time.time() self.secs = self.end - self.start self.msecs = self.secs * 1000 # millisecs if self.verbose: print("{0} elapsed time: {1} ms".format(self.name, self.msecs)) abstract_rendering-0.5.1/setup.py000066400000000000000000000144671240657705300171140ustar00rootroot00000000000000from __future__ import print_function from distutils.core import setup, Extension from os.path import abspath, join, dirname import sys import os, os.path from numpy import get_include numpy_include_dir = get_include() # Version reporting/recording # The ABSTRACT_RENDERING_VERSION is read from _version.txt whenver setup is run # This version is also used in pypi. # If the file is not found, it is created with version -1.-1.-1 if not os.path.isfile('abstract_rendering/_version.txt'): with open('abstract_rendering/_version.txt', 'w') as f: f.write('-1.-1.-1') with open('abstract_rendering/_version.txt', 'r') as f: ABSTRACT_RENDERING_VERSION = f.read().strip() # Flag to indicate that libdispatch should be used (OS X only) DISPATCH_FLAG = "--dispatch" if DISPATCH_FLAG in sys.argv: transform = Extension('abstract_rendering.transform_libdispatch', ['abstract_rendering/transform_libdispatch.cpp'], extra_compile_args=['-O3', '-Wall', '-fno-rtti', '-fno-exceptions', '-fPIC', '-lstdc++']) del sys.argv[sys.argv.index(DISPATCH_FLAG)] else: transform = Extension('abstract_rendering.transform', ['abstract_rendering/transform.cpp'], extra_compile_args=['-O3', '-Wall', '-fno-rtti', '-fno-exceptions', '-fPIC', '-lstdc++']) def getsitepackages(): """Returns a list containing all global site-packages directories (and possibly site-python).""" _is_64bit = (getattr(sys, 'maxsize', None) or getattr(sys, 'maxint')) > 2**32 _is_pypy = hasattr(sys, 'pypy_version_info') _is_jython = sys.platform[:4] == 'java' prefixes = [sys.prefix, sys.exec_prefix] sitepackages = [] seen = set() for prefix in prefixes: if not prefix or prefix in seen: continue seen.add(prefix) if sys.platform in ('os2emx', 'riscos') or _is_jython: sitedirs = [os.path.join(prefix, "Lib", "site-packages")] elif _is_pypy: sitedirs = [os.path.join(prefix, 'site-packages')] elif sys.platform == 'darwin' and prefix == sys.prefix: if prefix.startswith("/System/Library/Frameworks/"): # Apple's Python sitedirs = [os.path.join("/Library/Python", sys.version[:3], "site-packages"), os.path.join(prefix, "Extras", "lib", "python")] else: # any other Python distros on OSX work this way sitedirs = [os.path.join(prefix, "lib", "python" + sys.version[:3], "site-packages")] elif os.sep == '/': sitedirs = [os.path.join(prefix, "lib", "python" + sys.version[:3], "site-packages"), os.path.join(prefix, "lib", "site-python"), os.path.join(prefix, "python" + sys.version[:3], "lib-dynload")] lib64_dir = os.path.join(prefix, "lib64", "python" + sys.version[:3], "site-packages") if (os.path.exists(lib64_dir) and os.path.realpath(lib64_dir) not in [os.path.realpath(p) for p in sitedirs]): if _is_64bit: sitedirs.insert(0, lib64_dir) else: sitedirs.append(lib64_dir) try: # sys.getobjects only available in --with-pydebug build sys.getobjects sitedirs.insert(0, os.path.join(sitedirs[0], 'debug')) except AttributeError: pass # Debian-specific dist-packages directories: if sys.version[0] == '2': sitedirs.append(os.path.join(prefix, "lib", "python" + sys.version[:3], "dist-packages")) else: sitedirs.append(os.path.join(prefix, "lib", "python" + sys.version[0], "dist-packages")) sitedirs.append(os.path.join(prefix, "local/lib", "python" + sys.version[:3], "dist-packages")) sitedirs.append(os.path.join(prefix, "lib", "dist-python")) else: sitedirs = [prefix, os.path.join(prefix, "lib", "site-packages")] if sys.platform == 'darwin': # for framework builds *only* we add the standard Apple # locations. Currently only per-user, but /Library and # /Network/Library could be added too if 'Python.framework' in prefix: home = os.environ.get('HOME') if home: sitedirs.append( os.path.join(home, 'Library', 'Python', sys.version[:3], 'site-packages')) for sitedir in sitedirs: sitepackages.append(os.path.abspath(sitedir)) return sitepackages site_packages = getsitepackages()[0] old_dir = join(site_packages, "abstract_rendering") path_file = join(site_packages, "abstract_rendering.pth") path = abspath(dirname(__file__)) if 'develop' in sys.argv: print("Develop mode.") if os.path.isdir(old_dir): print(" - Removing package %s." % old_dir) import shutil shutil.rmtree(old_dir) with open(path_file, "w+") as f: f.write(path) print(" - writing path '%s' to %s" % (path, path_file)) print() sys.exit() setup(name='abstract_rendering', version= ABSTRACT_RENDERING_VERSION, description='Rendering as a binning process', author='Joseph Cottam', author_email='jcottam@indiana.edu', url='https://github.com/JosephCottam/AbstractRendering', packages=['abstract_rendering'], package_dir={'abstract_rendering': 'abstract_rendering'}, package_data={'abstract_rendering': ['*.txt']}, ext_modules=[ transform, Extension('abstract_rendering._cntr', ['abstract_rendering/cntr.c'], include_dirs=[numpy_include_dir], define_macros=[('NUMPY', None)], extra_compile_args=['-O3', '-Wall', '-fno-rtti', '-fno-exceptions', '-fPIC']) ]) abstract_rendering-0.5.1/sphinx/000077500000000000000000000000001240657705300166775ustar00rootroot00000000000000abstract_rendering-0.5.1/sphinx/Makefile000066400000000000000000000152261240657705300203450ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/AbstractRendering.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/AbstractRendering.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/AbstractRendering" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/AbstractRendering" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." abstract_rendering-0.5.1/sphinx/api.rst000066400000000000000000000026741240657705300202130ustar00rootroot00000000000000 Abstract Rendering API ======================= Abstract rendering modules are grouped either by data type or by task. Two modules used directly by every project are `Core`_ and `Glyphset`_. `Core`_ has general control flow and utilities. Core.render(...) is the main driver for AR application. `Glyphset`_ has interfaces for accessing visual representations and the related info values. Familiarity with these two modules is essential. Other modules may be approached as need (or curiosity) dictates. In addition to the modules shown here, there are a number of internal utility modules. Developers for AR should familiarize themselves with those modules as well. Categories ----------- .. automodule:: abstract_rendering.categories :members: :show-inheritance: Contour ----------- .. automodule:: abstract_rendering.contour :members: :show-inheritance: Core ----------- .. automodule:: abstract_rendering.core :members: :show-inheritance: General ----------- .. automodule:: abstract_rendering.general :members: :show-inheritance: Geometry ----------- .. automodule:: abstract_rendering.geometry :members: :show-inheritance: Glyphset ----------- .. automodule:: abstract_rendering.glyphset :members: :show-inheritance: Infos ----------- .. automodule:: abstract_rendering.infos :members: :show-inheritance: Numeric ----------- .. automodule:: abstract_rendering.numeric :members: :show-inheritance: abstract_rendering-0.5.1/sphinx/conf.py000066400000000000000000000201611240657705300201760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Abstract Rendering documentation build configuration file, created by # sphinx-quickstart on Mon Jun 30 11:31:58 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.pngmath', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Abstract Rendering' copyright = u'2014, Joseph Cottam' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '0.0.2' # The full version, including alpha/beta/rc tags. release = '0.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'AbstractRenderingdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'AbstractRendering.tex', u'Abstract Rendering Documentation', u'Joseph Cottam', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'abstractrendering', u'Abstract Rendering Documentation', [u'Joseph Cottam'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'AbstractRendering', u'Abstract Rendering Documentation', u'Joseph Cottam', 'AbstractRendering', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False abstract_rendering-0.5.1/sphinx/examples.rst000066400000000000000000000042031240657705300212460ustar00rootroot00000000000000Abstract Rendering Examples =========================== The four function roles of abstract rendering (AR) are combined into recipes to do data analysis. Here are some common AR recipes. High Definition Heatmap ----------------------- Heatmaps convert discrete events in a 2D space into a color-based representation of the distribution of that event. For example, population is a distribution of events in a geographic region (i.e., 'someone resides here' is an event and physical space is the 2D space). A heatmap of population shows the distribution of people. Instead of trying to show individual people as dots, it shows the number of people in each sub-region via colors. Using naive alpha composition, individual pixels quickly saturate and additional values no longer contribute additional color. This is a silent failure of the system, essentially mis-representing all values over a threshold as equal. Surprisingly, that threshold is often very low. At 90% transparent, standard alpha composition saturates at just 25 items. Even at the minimum opacity (just above truly transparent), only it is common to only get 256 items before saturation occurs. The abstract rendering recipe for doing HD Perceptual Correction --------------------- Linear color scales are easy to describe, but not perceptually accurate. In a single-color heatmap, the color scale can adjusted to more directly reflect perceptual effects by taking the cube-root of the aggregate values. High Definition Alpha --------------------- Extending the idea of heatmaps to multiple event types leads to overlapping distributions of different types of events. These different event types are often represented as different colors. Composing each color component separately is a straightforward change to the HD heatmap recipe. (Perceptual correction in a multi-color environment is not at all straightforward, conceptually nor computationally.) ISO Contours --------------- Taking value distributions in another direction are ISO contours. ISO contours identify regions that all have *at least* a given value in them, essentially identifying dividing lines between regions. abstract_rendering-0.5.1/sphinx/index.rst000066400000000000000000000123261240657705300205440ustar00rootroot00000000000000.. Abstract Rendering documentation master file, created by sphinx-quickstart on Mon Jun 30 11:31:58 2014. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Abstract Rendering ============================================== .. toctree:: :hidden: :maxdepth: 2 examples.rst api.rst Abstract rendering (AR) is a framework for analyzing and improving visualizations. The basic idea is that visualizations are useful when the pixels meaningfully correspond to source data. By making that link more explicit, AR enables a number of useful techniques for working with data of all sizes. InfoVis Reference Model ----------------------- AR focuses on information visualization style visualizations, 2D representations of abstract data, rather than scientific visualization. AR interrupts the standard visualization pipeline and provides the opportunity for further analysis. To understand the process and opportunities, first an overview of the InfoVis Reference Model (Chi'99) The InfoVis reference model defines four stages: - Source Data: Raw data - Data Tables: Organized and schematized - Visual Abstractions: Geometric representations such as points, shapes and colors - Views: Displayed on the screen The transitions between these four stages are: - Data Transformations: Convert source data into tables (or tables into further tables) - Visual Mappings: Convert data tables into visual abstractions - View Transformations: Convert visual mappings into concrete representations Abstract rendering steps in as a type of view transformation. However, instead of producing an image to be displayed on the screen, it builds a data table! This new data table is a grid structure that correspond to pixels on the screen. Instead of using colors, it uses other data values to describe the values that underly the visual abstractions that would have painted onto corresponding pixels. For example, the Anderson's Iris dataset data is often presented as petal width vs. petal length. Each data point also has a species associated with it. Visual mapping places each observation at an X/Y position and colors it according to the species. View transformations put those mappings at a specific location on the screen and fill in the points with colors. Otherwise said, standard rendering produces a table of colors. *Abstract* rendering retains the visual mappings and the view transformations but is does not necessarily produce a grid of colors. Instead, the grid may be populated by a dictionary with keys for each species and values for the number of observations whose visual abstraction touched that pixel (under the current view transformation). This new data table is rich with information both about the underlying dataset and how it is being visualized, providing many opportunities to improve the visualization. Abstract Rendering ------------------- Abstract rendering is achieved by four different function types, cooperating in (at least) two phases. When properly combined, instances of the four function roles first produce a grid of bin values and then produce a new visual representation. The four function roles are: - Selector: Determines which visual abstractions correspond to which bins. The selector often corresponds to classical visualization algorithms such as applying affine transforms or running the Bressenham line algorithm. - Info: Because AR does not (necessarily) combine colors, some alternative value must be provided for each visual abstraction. The info function provides that data value. This may be as simple as a constant for all inputs or returning the category from the source data. - Aggregator: Combines info values that land in the same bin. Max, Sum, Last, First are all useful aggregator functions. - Shader: Transforms sets of bin values into new forms. This may be new sets of bin values, an image or new geometric abstractions (such as ISO contours). The first three function roles (Selector, Info and Aggregator) transform visual abstractions into grids of values, called 'bin values', 'bin grids' or sometimes 'aggregates'. This first phase is called 'aggregation' and is executed on the visual abstractions. Shaders are run on the results of aggregation to analyze and re-represent the resulting values. A typical shader pipeline is usually three or four stages long. Shader chains typically end with a new image, that can be directly displayed. However, if a shader chain ends with a new set of visual abstractions, a new round of abstract rendering could be applied. Whether working with one shader or a chain of many, whether it ends in an image, a geometric representation or a boolean value, all shader chains start with a grid of bin values. Shading is, therefore, considered the second phase of abstract rendering. Contact ------- For questions, please contact Joseph Cottam (jcottam at indiana.edu). Thanks ------ Abstract rendering is developed with funding from `DARPA `_'s `XDATA `_ program and support from `Continuum Analytics `_. Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` abstract_rendering-0.5.1/sphinx/make.bat000066400000000000000000000151031240657705300203040ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\AbstractRendering.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\AbstractRendering.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end