using Cairo ;
using Gtk ;
using GLib ;
public class ClockWidget : DrawingArea {
private Time time ;
private int minute_offset ;
private bool dragging ;
public signal void time_changed (int hour, int minute) ;
public ClockWidget () {
add_events (Gdk.EventMask.BUTTON_PRESS_MASK
| Gdk.EventMask.BUTTON_RELEASE_MASK
| Gdk.EventMask.POINTER_MOTION_MASK);
update () ;
Timeout.add (1000, update) ;
set_size_request (100, 100) ;
}
public override bool draw (Cairo.Context cr) {
int y = get_allocated_height () / 2 ;
int x = get_allocated_width () / 2 ;
var radius = double.min (get_allocated_width () / 2,
get_allocated_height () / 2) - 5 ;
// clock back
cr.arc (x, y, radius, 0, 2 * 3.14) ;
cr.set_source_rgb (1, 1, 1) ;
cr.fill_preserve () ;
cr.set_source_rgb (0, 0, 0) ;
cr.stroke () ;
// clock ticks
for (int i = 0; i < 12; i++) {
int inset ;
cr.save () ;
if (i % 3 == 0) {
inset = (int) (0.2 * radius) ;
} else {
inset = (int) (0.1 * radius) ;
cr.set_line_width (0.5 * cr.get_line_width ()) ;
}
cr.move_to (x + (radius - inset) * Math.cos (i * Math.PI / 6),
y + (radius - inset) * Math.sin (i * Math.PI / 6));
cr.line_to (x + radius * Math.cos (i * Math.PI / 6),
y + radius * Math.sin (i * Math.PI / 6));
cr.stroke ();
cr.restore ();
}
// clock hands
var hours = this.time.hour ;
var minutes = this.time.minute + this.minute_offset ;
var seconds = this.time.second ;
/* hour hand: the hour hand is rotated 30 degrees (pi/6r) per hour + 1/2 a degree (pi/360r) per minute */
cr.save () ;
cr.set_line_width (2.5 * cr.get_line_width ()) ;
cr.move_to (x, y) ;
cr.line_to (x + radius / 2 * Math.sin (Math.PI / 6 * hours
+ Math.PI / 360 * minutes),
y + radius / 2 * -Math.cos (Math.PI / 6 * hours
+ Math.PI / 360 * minutes));
cr.stroke ();
cr.restore ();
// minute hand:
// the minute hand is rotated 6 degrees (pi/30 r) per minute
cr.move_to (x, y);
cr.line_to (x + radius * 0.75 * Math.sin (Math.PI / 30 * minutes),
y + radius * 0.75 * -Math.cos (Math.PI / 30 * minutes));
cr.stroke ();
// seconds hand:
// operates identically to the minute hand
cr.save ();
cr.set_source_rgb (1, 0, 0); // red
cr.move_to (x, y);
cr.line_to (x + radius * 0.7 * Math.sin (Math.PI / 30 * seconds),
y + radius * 0.7 * -Math.cos (Math.PI / 30 * seconds));
cr.stroke ();
cr.restore ();
return false ;
}
public override bool button_press_event (Gdk.EventButton event) {
var minutes = this.time.minute + this.minute_offset;
// From
// http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
var px = event.x - get_allocated_width () / 2;
var py = get_allocated_height () / 2 - event.y;
var lx = Math.sin (Math.PI / 30 * minutes);
var ly = Math.cos (Math.PI / 30 * minutes);
var u = lx * px + ly * py;
// on opposite side of origin
if (u < 0) {
return false;
}
var d2 = Math.pow (px - u * lx, 2) + Math.pow (py - u * ly, 2);
if (d2 < 25) { // 5 pixels away from the line
this.dragging = true;
print ("got minute hand\n");
}
return false;
}
public override bool button_release_event (Gdk.EventButton event) {
if (this.dragging) {
this.dragging = false;
emit_time_changed_signal ((int) event.x, (int) event.y);
}
return false;
}
public override bool motion_notify_event (Gdk.EventMotion event) {
if (this.dragging) {
emit_time_changed_signal ((int) event.x, (int) event.y);
}
return false;
}
private void emit_time_changed_signal (int x, int y) {
// decode the minute hand
// normalise the coordinates around the origin
x -= get_allocated_width () / 2;
y -= get_allocated_height () / 2;
// phi is a bearing from north clockwise, use the same geometry as
// we did to position the minute hand originally
var phi = Math.atan2 (x, -y);
if (phi < 0) {
phi += Math.PI * 2;
}
var hour = this.time.hour;
var minute = (int) (phi * 30 / Math.PI);
// update the offset
this.minute_offset = minute - this.time.minute;
redraw_canvas ();
time_changed (hour, minute);
}
private bool update () {
// update the time
this.time = Time.local (time_t ());
redraw_canvas ();
return true; // keep running this event
}
private void redraw_canvas () {
var window = get_window ();
if (null == window) {
return;
}
var region = window.get_clip_region ();
// redraw the cairo canvas completely by exposing it
window.invalidate_region (region, true);
window.process_updates (true);
}
static int main (string[] args) {
Gtk.init (ref args);
var window = new Window ();
var clock = new ClockWidget ();
window.add (clock);
window.destroy.connect (Gtk.main_quit);
window.show_all ();
Gtk.main ();
return 0;
}
}
How do I solve it??
This is the error displayed:
/usr/bin/ld: /tmp/ccSTGo5z.o: undefined reference to symbol 'pow##GLIBC_2.2.5'
//lib/x86_64-linux-gnu/libm.so.6: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
error: cc exited with status 256
Compilation failed: 1 error(s), 1 warning(s)
You need to link against libm which is the library which provides the pow() function, which you’re using.
Typically this is achieved by passing -lm in your linker flags. I can’t give a more concrete answer because you haven’t said what build system you’re using.
valac -X -lm --pkg gtk+-3.0 clock_widget.vala
I had to compile it with this code.
Related
I would like this code to return a newly constructed geopoint.
I need this,
GeoPoint prjTest=new GeoPoint(vxi+x,vyi+y);
to stick somewhere and return prjTest. I'm new to programming and I don't know well synthax.I tried many things, I can keep guessing for a long time. Please help. Thanks.
public class ProjectileTest
{
public ProjectileTest(float vi, float angle) /** renamed velocity -> vi */
{
//Starting location
double xi = 0, yi = 100;
final double gravity = -9.81;
//timeSlice declares the interval before checking the new location.
double timeSlice = 0.001; /** renamed time -> timeSlice */
double totalTime = 0; /** renamed recordedTime -> totalTime */
double vxi = vi * Math.cos(Math.toRadians(angle)); /** renamed xSpeed -> vxi */
double vyi = vi * Math.sin(Math.toRadians(angle)); /** renamed ySpeed -> vyi */
//This (secondsTillImpact) seems to give a very accurate time whenever the angle is positive.
double secondsTillImpact = Math.sqrt(2 * yi / -(gravity));
/** Not sure I agree. Does this formula take into account the upward motion
* of the projectile along its parabolic arc? My suspicion is that this
* formula only "works" when the initial theta is: 180 <= angle <= 360.
*
* Compare with the result predicted by quadratic(). Discarding the zero
* intercept which can't work for us (i.e. the negative one, because time
* only moves forward) leaves us with an expected result very close to the
* observed result.
*/
double y;
double x;/** Current position along the y-axis */
do {
// x = x + (xSpeed * time);
x = vxi * totalTime; /** Current position along the x-axis */
// y = y + (ySpeed * time);
y = yi + vyi * totalTime + .5 * gravity * (totalTime * totalTime);
// ySpeed = ySpeed + (gravity * time);
double vy = vyi + gravity * totalTime; /** Current velocity of vector y-component */
System.out.println("X: " + round2(x) + " Y: " + round2(y) + " YSpeed: " + round2(vy));
totalTime += timeSlice;
}
while (y > 0);
////////////////////////////++++++++ GeoPoint prjTest=new GeoPoint(vxi+x,vyi+y);
System.out.println("Incorrectly expected seconds: " + secondsTillImpact + "\nResult seconds: " + totalTime);
quadratic((.5 * gravity), vyi, yi);
}
public double round2(double n) {
return (int) (n * 100.0 + 0.5) / 100.0;
}
public void quadratic(double a, double b, double c) {
if (b * b - 4 * a * c < 0) {
System.out.println("No roots in R.");
} else {
double dRoot = Math.sqrt(b * b - 4 * a * c); /** root the discriminant */
double x1 = (-b + dRoot) / (2 * a); /** x-intercept 1 */
double x2 = (-b - dRoot) / (2 * a); /** x-intercept 2 */
System.out.println("x-int one: " + x1 + " x-int two: " + x2);
}
}
}
When some values are small in QML pie chart, slice labels are messed up:
How can I arrange slice labels like this?
Note that this is available in telerik and /or dev components for c#.
I used of #luffy 's comment and with some modification, I reached to following code and result:
import QtQuick 2.4
Rectangle {
id: root
// public
property string fontFamily: "sans-serif"
property int fontPointSize: 9
property double donutHoleSize: 0.4 //0~1
property string title: 'title'
property variant points: []//[['Zero', 60, 'red'], ['One', 40, 'blue']] // y values don't need to add to 100
width: 500
height: 700
// private
onPointsChanged: myCanvas.requestPaint()
Canvas {
id: myCanvas
anchors.fill: parent
property double factor: Math.min(width, height)
Text { // title
text: title
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: 0.03 * myCanvas.factor
}
onPaint: {
var context = getContext("2d")
var total = 0 // automatically calculated from points.y
var start = -Math.PI / 2 // Start from vertical. 0 is 3 o'clock and positive is clockwise
var radius = 0.25 * myCanvas.factor
var pixelSize = 0.03 * myCanvas.factor // text
context.font = root.fontPointSize + 'pt ' + root.fontFamily
var i = 0;
for(i = 0; i < points.length; i++) total += points[i][1] // total
context.clearRect(0, 0, width, height) // new points data
//--------------------------------------------------------
var end = 0;
var center = 0;
var angle = 0;
var midSlice = 0;
var point = 0;
var topRightCnt = 0
var bottomRightCnt = 0
var topLeftCnt = 0
var bottomLeftCnt = 0
var itemsPos = []
center = Qt.vector2d(width / 2, height / 2) // center
for(i = 0; i < points.length; i++) {
end = start + 2 * Math.PI * points[i][1] / total // radians
angle = (start + end) / 2 // of line
midSlice = Qt.vector2d(Math.cos((end + start) / 2), Math.sin((end + start) / 2)).times(radius) // point on edge/middle of slice
point = midSlice.times(1 + 1.4 * (1 - Math.abs(Math.cos(angle)))).plus(center) // elbow of line
if(point.x<center.x && point.y<=center.y) {
topLeftCnt++;
itemsPos[i] = "tl"
}
else if(point.x<center.x && point.y>center.y) {
bottomLeftCnt++;
itemsPos[i] = "bl"
}
else if(point.x>=center.x && point.y<=center.y) {
topRightCnt++;
itemsPos[i] = "tr"
}
else {
bottomRightCnt++;
itemsPos[i] = "br"
}
start = end // radians
}
//--------------------------------------------------------
end = 0;
angle = 0;
midSlice = 0;
point = 0;
var itemPosCounterTR = 0;
var itemPosCounterTL = 0;
var itemPosCounterBR = 0;
var itemPosCounterBL = 0;
for(i = 0; i < points.length; i++) {
end = start + 2 * Math.PI * points[i][1] / total // radians
// pie
context.fillStyle = points[i][2]
context.beginPath()
midSlice = Qt.vector2d(Math.cos((end + start) / 2), Math.sin((end + start) / 2)).times(radius) // point on edge/middle of slice
context.arc(center.x, center.y, radius, start, end) // x, y, radius, startingAngle (radians), endingAngle (radians)
context.lineTo(center.x, center.y) // center
context.fill()
// text
context.fillStyle = points[i][2]
angle = (start + end) / 2 // of line
point = midSlice.times(1 + 1.4 * (1 - Math.abs(Math.cos(angle)))).plus(center) // elbow of line
//---------------------------------------------
var textX = 0;
var textY = 0;
var dis = 0;
var percent = points[i][1] / total * 100
var text = points[i][0] + ': ' + (percent < 1? '< 1': Math.round(percent)) + '%' // display '< 1%' if < 1
var textWidth = context.measureText(text).width
var textHeight = 15
var diameter = radius * 2
var topCircle = center.y - radius
var leftCircle = center.x - radius
if(itemsPos[i] === "tr") {
textX = leftCircle + 1.15 * diameter
dis = Math.floor((1.15*radius) / topRightCnt) //Math.floor((height/2) / topRightCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle -(0.15*diameter) + (itemPosCounterTR*dis) + (textHeight/2)
itemPosCounterTR++
}
else if(itemsPos[i] === "br") {
textX = leftCircle + 1.15 * diameter
dis = Math.floor((1.15*radius) / bottomRightCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle+(1.15*diameter) - ((bottomRightCnt-itemPosCounterBR-1)*dis) - (textHeight/2)
itemPosCounterBR++
}
else if(itemsPos[i] === "tl") {
textX = leftCircle - (0.15 * diameter) - textWidth
dis = Math.floor((1.15*radius) / topLeftCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle-(0.15*diameter) + ((topLeftCnt-itemPosCounterTL-1)*dis) + (textHeight/2)
itemPosCounterTL++;
}
else {
textX = leftCircle - (0.15 * diameter) - textWidth //-0.2 * width - textWidth
dis = Math.floor((1.15*radius) / bottomLeftCnt)
dis = (dis < 20 ? 20 : dis)
textY = topCircle+(1.15*diameter) - (itemPosCounterBL*dis) - (textHeight/2)
itemPosCounterBL++
}
//---------------------------------------------
context.fillText(text, textX, textY)
// line
context.lineWidth = 1
context.strokeStyle = points[i][2]
context.beginPath()
context.moveTo(center.x + midSlice.x, center.y + midSlice.y) // center
var endLineX = (point.x < center.x ? (textWidth + 0.5 * pixelSize) : (-0.5 * pixelSize)) + textX;
context.lineTo(endLineX, textY+3)
context.lineTo(endLineX + (point.x < center.x? -1: 1) * ((0.5 * pixelSize)+textWidth), textY+3) // horizontal
context.stroke()
start = end // radians
}
if(root.donutHoleSize > 0) {
root.donutHoleSize = Math.min(0.99, root.donutHoleSize);
var holeRadius = root.donutHoleSize * radius;
context.fillStyle = root.color
context.beginPath()
context.arc(center.x, center.y, holeRadius, 0, 2*Math.PI) // x, y, radius, startingAngle (radians), endingAngle (radians)
//context.lineTo(center.x, center.y) // center
context.fill()
}
}
}
}
And it's result:
Thanks #luffy.
There is a code for a drawing circle with LineRenderer.
but I want to draw multiple circles with different radius, I used "for loop" but there is one circle instead of multiple
public float ThetaScale = 0.01f;
public float radius = 3f;
private int Size;
private LineRenderer LineDrawer;
private float Theta = 0f;
void Start ()
{
LineDrawer = GetComponent<LineRenderer>();
}
void Update ()
{
Theta = 0f;
Size = (int)((1f / ThetaScale) + 1f);
LineDrawer.SetVertexCount(Size);
for (int l = 0; l < 5; l++)
{
for(int i = 0; i < Size; i++)
{
Theta += (2.0f * Mathf.PI * ThetaScale);
float x = l * radius * Mathf.Cos(Theta);
float y = l * radius * Mathf.Sin(Theta);
LineDrawer.SetPosition(i, new Vector3(x, 0, y));
}
}
}
In every loop you always overwrite the same positions indices in the same line renderer. So you will always only have the last circle.
Note that it is also quite expensive to use SetPoisition repeatedly. As it says in the API you should rather work on an array and then use SetPoisitions to assign all positions at once.
One thing is a bit unclear though: If you use one single LineRenderer you won't get independent circles but they will always be connected at some point. Otherwise you would need 5 separated LineRenderer instances.
Option A: 5 circles but connected to each other since part of a single LineRenderer
void Start ()
{
LineDrawer = GetComponent<LineRenderer>();
LineDrawer.loop = false;
Theta = 0f;
// Use one position more to close the circle
Size = (int)((1f / ThetaScale) + 1f) + 1;
LineDrawer.positionCount = 5 * Size;
var positions = new Vector3[5 * Size];
for (int l = 0; l < 5; l++)
{
for(int i = 0; i < Size; i++)
{
Theta += (2.0f * Mathf.PI * ThetaScale);
float x = l * radius * Mathf.Cos(Theta);
float y = l * radius * Mathf.Sin(Theta);
positions[5 * l + i] = new Vector3(x, 0, y);
}
}
LineDrawer.SetPositions(positions);
}
Option B: 5 separated circles in 5 separated LineRenderers
// Drag 5 individual LineRenderer here via the Inspector
public LineRenderer[] lines = new LineRenderer[5];
void Start ()
{
foreach(var line in lines)
{
line.loop = true;
Theta = 0f;
Size = (int)((1f / ThetaScale) + 1f);
line.positionCount = Size;
var positions = new Vector3[Size];
for(int i = 0; i < Size; i++)
{
Theta += (2.0f * Mathf.PI * ThetaScale);
float x = l * radius * Mathf.Cos(Theta);
float y = l * radius * Mathf.Sin(Theta);
positions[5 * l + i] = new Vector3(x, 0, y);
}
line.SetPositions(positions);
}
}
You missed few details here and there. Here, this will work:
using UnityEngine;
[ExecuteAlways]
[RequireComponent( typeof(LineRenderer) )]
public class CircularBehaviour : MonoBehaviour
{
[SerializeField][Min(3)] int _numSegments = 16;
[SerializeField][Min(1)] int _numCircles = 5;
[SerializeField] float _radius = 3f;
LineRenderer _lineRenderer;
void Awake ()
{
_lineRenderer = GetComponent<LineRenderer>();
_lineRenderer.loop = false;
_lineRenderer.useWorldSpace = false;
}
void Update ()
{
const float TAU = 2f * Mathf.PI;
float theta = TAU / (float)_numSegments;
int numVertices = _numSegments + 1;
_lineRenderer.positionCount = numVertices * _numCircles;
int vert = 0;
for( int l=1 ; l<=_numCircles ; l++ )
{
float r = _radius * (float)l;
for( int i=0 ; i<numVertices ; i++ )
{
float f = theta * (float)i;
Vector3 v = new Vector3{ x=Mathf.Cos(f) , y=Mathf.Sin(f) } * r;
_lineRenderer.SetPosition( vert++ , v );
}
}
}
}
But
as #derHugo explained, this is not what you're looking for exactly as all circles will be drawn connected.
I've got a question that's driving me nuts! :) I've been working on it day and night now :) :)
What is my goal?
Say 2 outside. 2 inside. With Illustrator it is easy :)
My approach so far
Work clockwise. Get angle between P1 & P2
Use trigonometry to calculate the X & Y offset
Add the X & Y offset to P1 & P2. This is how I get the angle between P1 and P2:
float getAngle = (atan((P1.y-P2.y)/(P1.x-p2.x))) * (180/PI) ;
// ( COS(angle) = (adjacent side) / (hypotenuse) ) || 2 = 6 / 3
// ( COS(angle) * (hypotenuse) = (adjacent side) || 2 * 3 = 6
// ( SIN(angle) = (opposite side) / (hypotenuse) ) || 2 = 6 / 3
// ( SIN(angle) * (hypotenuse) = (opposite side) || 2 * 3 = 6
My Problem
I know how to offset the path. But only on 1 side. Always +x and -Y. So this is the result. Almost like just moving the path entirely. Instead of offsetting all around.:
It needs to stay outside the centre/original line.
What would I like from you?
Is there a logic/formula to do this?
Or is there a library that already has this??
I just cannot wrap my head around how I can keep the line offset outside the first/centre line.
Could you get away with scaling the vertices ?
void setup(){
size(400,400);
PVector[] originalPath = randomPath(7,100);
PVector[] insetPath = scalePoints(originalPath,0.75);
PVector[] outsetPath = scalePoints(originalPath,1.25);
background(255);
noFill();
translate(width * .5, height * .5);
stroke(0,192,0);
drawPath(originalPath);
stroke(192,0,0);
drawPath(insetPath);
stroke(0,0,192);
drawPath(outsetPath);
fill(0);
text("original path",originalPath[0].x,originalPath[0].y);
text("inset path",insetPath[1].x,insetPath[1].y);
text("outset path",outsetPath[2].x,outsetPath[2].y);
text("click\nto\nreset",0,0);
}
void drawPath(PVector[] pts){
beginShape();
for(PVector p : pts) vertex(p.x,p.y);
endShape(CLOSE);
}
PVector[] scalePoints(PVector[] pts,float scale){
int numPoints = pts.length;
PVector[] result = new PVector[numPoints];
for(int i = 0 ; i < numPoints; i++){
result[i] = pts[i].get();
result[i].mult(scale);
}
return result;
}
PVector[] randomPath(int numPoints,float r){
PVector[] result = new PVector[numPoints];
float ai = TWO_PI / numPoints;
for(int i = 0 ; i < numPoints; i++){
float radius = random(r-r*.25,r+r*.25);
result[i] = new PVector(cos(ai * i) * radius, sin(ai * i) * radius);
}
return result;
}
void mousePressed(){
setup();
}
void draw(){}
I am looking to create smooth paths for my 2D game. Looking at CatmullRomSpline it is just the thing i need. Every post, even here on SE is giving it a type and passing all the control points and a Boolean with the constructor. This seems to be obsolete now, CatmullRomSpline does not accept any type parameters anymore and without it it can only work with V3 paths. Neither does the constructor accept a list of control points.
cp = new Vector2[]
{
new Vector2(0,100), new Vector2(100,600), new Vector2(300,300), new Vector2(600, 400)
};
CatmullRomSpline<Vector2> path = new CatmullRomSpline<Vector2>(cp, true);
This gives the following error: The type CatmullRomSpline is not generic; it cannot be parameterized with arguments <Vector2>.
Am i missing something or does CatmullRomSpline work differently nowadays, and how?
This is the CatmullRomSpline Class from badlogic. It surely looks like things changed, i am getting this class from "import com.badlogic.gdx.math.CatmullRomSpline;"
public class CatmullRomSpline implements Serializable { private
static final long serialVersionUID = -3290464799289771451L; private
List controlPoints = new ArrayList(); Vector3 T1 =
new Vector3(); Vector3 T2 = new Vector3();
/** Adds a new control point * * #param point the point */
public void add (Vector3 point) { controlPoints.add(point); }
/** #return all control points */ public List
getControlPoints () { return controlPoints; }
/** Returns a path, between every two control points numPoints are
generated and the control points themselves are added too. * The
first and the last controlpoint are omitted. if there's less than 4
controlpoints an empty path is returned. * * #param numPoints
number of points returned for a segment * #return the path */
public List getPath (int numPoints) { ArrayList
points = new ArrayList();
if (controlPoints.size() < 4) return points;
Vector3 T1 = new Vector3(); Vector3 T2 = new Vector3();
for (int i = 1; i <= controlPoints.size() - 3; i++) {
points.add(controlPoints.get(i)); float increment = 1.0f /
(numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
for (int j = 0; j < numPoints; j++) {
float h1 = 2 * t * t * t - 3 * t * t + 1; // calculate basis
// function 1
float h2 = -2 * t * t * t + 3 * t * t; // calculate basis
// function 2
float h3 = t * t * t - 2 * t * t + t; // calculate basis
// function 3
float h4 = t * t * t - t * t; // calculate basis function 4
Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
points.add(point);
t += increment; } }
if (controlPoints.size() >= 4)
points.add(controlPoints.get(controlPoints.size() - 2));
return points; }
/** Returns a path, between every two control points numPoints are
generated and the control points themselves are added too. * The
first and the last controlpoint are omitted. if there's less than 4
controlpoints an empty path is returned. * * #param points the
array of Vector3 instances to store the path in * #param numPoints
number of points returned for a segment */ public void getPath
(Vector3[] points, int numPoints) { int idx = 0; if
(controlPoints.size() < 4) return;
for (int i = 1; i <= controlPoints.size() - 3; i++) {
points[idx++].set(controlPoints.get(i)); float increment = 1.0f
/ (numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
for (int j = 0; j < numPoints; j++) {
float h1 = 2 * t * t * t - 3 * t * t + 1; // calculate basis
// function 1
float h2 = -2 * t * t * t + 3 * t * t; // calculate basis
// function 2
float h3 = t * t * t - 2 * t * t + t; // calculate basis
// function 3
float h4 = t * t * t - t * t; // calculate basis function 4
Vector3 point = points[idx++].set(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
t += increment; } }
points[idx].set(controlPoints.get(controlPoints.size() - 2)); }
/** Returns all tangents for the points in a path. Same semantics as
getPath. * * #param numPoints number of points returned for a
segment * #return the tangents of the points in the path */ public
List getTangents (int numPoints) { ArrayList
tangents = new ArrayList();
if (controlPoints.size() < 4) return tangents;
Vector3 T1 = new Vector3(); Vector3 T2 = new Vector3();
for (int i = 1; i <= controlPoints.size() - 3; i++) { float
increment = 1.0f / (numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
tangents.add(new Vector3(T1).nor());
for (int j = 0; j < numPoints; j++) {
float h1 = 6 * t * t - 6 * t; // calculate basis function 1
float h2 = -6 * t * t + 6 * t; // calculate basis function 2
float h3 = 3 * t * t - 4 * t + 1; // calculate basis function 3
float h4 = 3 * t * t - 2 * t; // calculate basis function 4
Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
tangents.add(point.nor());
t += increment; } }
if (controlPoints.size() >= 4)
tangents.add(T1.set(controlPoints.get(controlPoints.size() -
1)).sub(controlPoints.get(controlPoints.size() - 3))
.mul(0.5f).cpy().nor());
return tangents; }
/** Returns all tangent's normals in 2D space for the points in a
path. The controlpoints have to lie in the x/y plane for this * to
work. Same semantics as getPath. * * #param numPoints number of
points returned for a segment * #return the tangents of the points
in the path */ public List getTangentNormals2D (int
numPoints) { ArrayList tangents = new ArrayList();
if (controlPoints.size() < 4) return tangents;
Vector3 T1 = new Vector3(); Vector3 T2 = new Vector3();
for (int i = 1; i <= controlPoints.size() - 3; i++) { float
increment = 1.0f / (numPoints + 1); float t = increment;
T1.set(controlPoints.get(i + 1)).sub(controlPoints.get(i -
1)).mul(0.5f); T2.set(controlPoints.get(i +
2)).sub(controlPoints.get(i)).mul(0.5f);
Vector3 normal = new Vector3(T1).nor(); float x = normal.x;
normal.x = normal.y; normal.y = -x; tangents.add(normal);
for (int j = 0; j < numPoints; j++) {
float h1 = 6 * t * t - 6 * t; // calculate basis function 1
float h2 = -6 * t * t + 6 * t; // calculate basis function 2
float h3 = 3 * t * t - 4 * t + 1; // calculate basis function 3
float h4 = 3 * t * t - 2 * t; // calculate basis function 4
Vector3 point = new Vector3(controlPoints.get(i)).mul(h1);
point.add(controlPoints.get(i + 1).tmp().mul(h2));
point.add(T1.tmp().mul(h3));
point.add(T2.tmp().mul(h4));
point.nor();
x = point.x;
point.x = point.y;
point.y = -x;
tangents.add(point);
t += increment; } }
return tangents; }
/** Returns the tangent's normals using the tangent and provided up
vector doing a cross product. * * #param numPoints number of
points per segment * #param up up vector * #return a list of
tangent normals */ public List getTangentNormals (int
numPoints, Vector3 up) { List tangents =
getTangents(numPoints); ArrayList normals = new
ArrayList();
for (Vector3 tangent : tangents) normals.add(new
Vector3(tangent).crs(up).nor());
return normals; }
public List getTangentNormals (int numPoints, List
up) { List tangents = getTangents(numPoints);
ArrayList normals = new ArrayList();
int i = 0; for (Vector3 tangent : tangents) normals.add(new
Vector3(tangent).crs(up.get(i++)).nor());
return normals; } }
Your code should work fine according to the api and the source.
The class IS generic. You must be using some old version of the class.
Update to the latest version and the error should be solved.
Hope this helps.