Skip to content

Commit 4a486d6

Browse files
author
Spencer Cohen
committed
First commit
Nearest neighbor and linear methods are working, and all clipping types
0 parents  commit 4a486d6

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

Readme.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
####Table of Contents
2+
[        What is this for?](#rm-what)<br/>
3+
[        Future Plans](#rm-future)<br/>
4+
5+
<a name = "rm-what" />
6+
# What is this for?
7+
8+
Smooth.js takes an array of numbers or vectors and returns a parametric function that interpolates that array.
9+
10+
<a name = "rm-future" />
11+
# Future Plans
12+
Currently, Smooth.js only works with uniform arrays. Ultimately, support for non-uniform arrays (objects with
13+
numeric keys) is desired.

Smooth.coffee

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
###
2+
Abstract scalar interpolation class which provides common functionality for all interpolators
3+
4+
Subclasses must override interpolate().
5+
###
6+
7+
8+
###Constants (these are accessible by Smooth.WHATEVER in user space)###
9+
Enum =
10+
###Interpolation methods###
11+
METHOD_NEAREST: 0 #Rounds to nearest whole index
12+
METHOD_LINEAR: 1 # Default: linear interpolation
13+
METHOD_CUBIC: 2
14+
15+
###Input clipping types###
16+
CLIP_CLAMP: 0 # Default: clamp to [0, arr.length-1]
17+
CLIP_ZERO: 1 # When out of bounds, clip to zero
18+
CLIP_PERIODIC: 2 # Repeat the array infinitely in either direction
19+
CLIP_MIRROR: 3 # Repeat infinitely in either direction, flipping each time
20+
21+
22+
defaultConfig =
23+
method: Enum.METHOD_LINEAR
24+
clip: Enum.CLIP_CLAMP
25+
26+
27+
28+
###Index clipping functions###
29+
clipClamp = (i, n) -> Math.max 0, Math.min i, n - 1
30+
31+
clipPeriodic = (i, n) ->
32+
i = i % n #wrap
33+
i += n if i < 0 #if negative, wrap back around
34+
i
35+
36+
clipMirror = (i, n) ->
37+
period = 2*(n - 1) #period of index mirroring function
38+
i = clipPeriodic i, period
39+
i = period - i if i > n - 1 #flip when out of bounds
40+
i
41+
42+
getFraction = (x) -> x - Math.floor x
43+
44+
class AbstractInterpolator
45+
46+
constructor: (@array, config) ->
47+
@length = @array.length #cache length
48+
49+
#Set the clipping helper method
50+
@clipHelper = switch config.clip
51+
when Enum.CLIP_CLAMP
52+
@clipHelperClamp
53+
when Enum.CLIP_ZERO
54+
@clipHelperZero
55+
when Enum.CLIP_PERIODIC
56+
@clipHelperPeriodic
57+
when Enum.CLIP_MIRROR
58+
@clipHelperMirror
59+
else
60+
err = new Error
61+
err.message = "The clipping type #{config.clip} is invalid."
62+
63+
# Get input array value at i, applying the clipping method
64+
getClippedInput: (i) ->
65+
#Normal behavior for indexes within bounds
66+
if 0 <= i < @length
67+
@array[i]
68+
else
69+
@clipHelper i
70+
71+
clipHelperClamp: (i) -> @array[clipClamp i, @length]
72+
73+
clipHelperZero: (i) -> 0
74+
75+
clipHelperPeriodic: (i) -> @array[clipPeriodic i, @length]
76+
77+
clipHelperMirror: (i) -> @array[clipMirror i, @length]
78+
79+
interpolate: (t) ->
80+
err = new Error
81+
err.message = 'Subclasses of AbstractInterpolator must override the interpolate() method.'
82+
throw err
83+
84+
85+
#Nearest neighbor interpolator (round to whole index)
86+
class NearestInterpolator extends AbstractInterpolator
87+
interpolate: (t) -> @getClippedInput Math.round t
88+
89+
90+
#Linear interpolator (first order Bezier)
91+
class LinearInterpolator extends AbstractInterpolator
92+
interpolate: (t) ->
93+
i = Math.floor t
94+
a = @getClippedInput i
95+
b = @getClippedInput i+1
96+
t = getFraction t
97+
return (1-t)*a + (t)*b
98+
99+
100+
101+
102+
#Extract a column from a two dimensional array
103+
getColumn = (arr, i) -> (row[i] for row in arr)
104+
105+
Smooth = (arr, config = {}) ->
106+
config[k] ?= v for own k,v of defaultConfig #fill in defaults
107+
108+
#Get the interpolator class according to the configuration
109+
interpolatorClass = switch config.method
110+
when Enum.METHOD_NEAREST then NearestInterpolator
111+
when Enum.METHOD_LINEAR then LinearInterpolator
112+
when Enum.METHOD_CUBIC then CubicInterpolator
113+
else
114+
err = new Error
115+
err.message = "The interpolation method #{config.method} is invalid."
116+
117+
#Make sure there's at least one element in the input array
118+
if not arr.length
119+
err = new Error
120+
err.message = 'Array must have at least one element.'
121+
122+
#See what type of data we're dealing with
123+
dataType = Object.prototype.toString.call arr[0]
124+
switch dataType
125+
when '[object Number]' #scalar
126+
interpolator = new interpolatorClass arr, config
127+
return (t) -> interpolator.interpolate t
128+
129+
when '[object Array]' # vector
130+
interpolators = (new interpolatorClass(getColumn(arr, i), config) for i in [0...arr[0].length])
131+
return (t) -> (interpolator.interpolate(t) for interpolator in interpolators)
132+
133+
else
134+
err = new Error
135+
err.message = 'Invalid element type: #{dataType}'
136+
137+
138+
139+
#Copy enums to Smooth
140+
Smooth[k] = v for own k,v of Enum
141+
142+
143+
root = exports ? window
144+
root.Smooth = Smooth

Smooth.js MIT license.txt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Smooth.js Copyright (c) 2012 Spencer Cohen
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4+
documentation files (the "Software"), to deal in the Software without restriction, including without
5+
limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
6+
Software, and to permit persons to whom the Software is furnished to do so, subject to the following
7+
conditions:
8+
9+
The above copyright notice and this permission notice shall be included in all copies or substantial portions
10+
of the Software.
11+
12+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13+
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
14+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
15+
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
16+
DEALINGS IN THE SOFTWARE.

0 commit comments

Comments
 (0)