/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.redgeek.android.eventrend.graph.plugins; import net.redgeek.android.eventrend.R; import net.redgeek.android.eventrend.primitives.Tuple; import android.graphics.Path; /** * Interpolates a cubic spline, with the controls points set such that the slope * of the path entering and exiting a point will be as close to 0 as possible * while being monotonically increasing on the X-axis. * * <p> * Note that this uses the native cubicTo() routines to draw the path, and as * such, to prevent re-calculating the cubics for interpolate{X,Y}, a linear * interpolation (approximation) is used. * * @author barclay */ public class CubicInterpolator implements TimeSeriesInterpolator { public static final String NAME = "Cubic"; public static final int HELP_RES_ID = R.string.interpolation_help_cubic; public CubicInterpolator() { } public String getName() { return NAME; } public int getHelpResId() { return HELP_RES_ID; } // This is the same StepMid, but we'll be generating control // point for a cubic curve, since android alread has a cubicTo public Tuple[] interpolate(Tuple first, Tuple second) { if (first.equals(second) == true) return new Tuple[] { new Tuple(first) }; if (first.x == second.x) return null; Tuple[] result = new Tuple[2]; Tuple r1 = new Tuple(first); Tuple r2 = new Tuple(second); r1.x = first.x + ((second.x - first.x) / 2.0f); r2.x = r1.x; result[0] = r1; result[1] = r2; return result; } // To interpolate a position on the line, since I don't want to // re-calculate the cubics that cubicTo already has, I just use // linear interpolation public Float interpolateX(Tuple first, Tuple second, float atY) { if (first.equals(second) == true) return first.x; if (first.x == second.x) return null; float slope = (second.y - first.y) / (second.x - first.x); return new Float(first.x + (slope * (atY - first.y))); } public Float interpolateY(Tuple first, Tuple second, float atX) { if (first.equals(second) == true) return first.y; if (first.x == second.x) return null; float slope = (second.y - first.y) / (second.x - first.x); return new Float(first.y + (slope * (atX - first.x))); } public void updatePath(Path path, Tuple first, Tuple second) { if (first == null && second != null) path.moveTo(second.x, second.y); else if (first != null && second == null) path.moveTo(first.x, first.y); else { Tuple[] controls = interpolate(first, second); if (controls != null && controls.length == 2) { path.cubicTo(controls[0].x, controls[0].y, controls[1].x, controls[1].y, second.x, second.y); } } } }