/* * Copyright (C) 2013-2015 F(X)yz, * Sean Phillips, Jason Pollastrini and Jose Pereda * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.fxyz.shapes.primitives.helper; import java.util.ArrayList; import java.util.List; import org.fxyz.geometry.Point3D; import org.fxyz.utils.GaussianQuadrature; /** Spring base on the curve of a torus stretched over a cylinder * * Ecuation: r[t]={R*Cos[t],R*Sin[t],h t}; * * Tube around helix: S[t,u]=r[t]+a·cos(u)·n[t]+a·sin(u)·b[t] according * Frenet-Serret trihedron * http://www.usciences.edu/~lvas/math430/Curves.pdf * * @author jpereda */ public class SpringHelper { public static final int tR = 0; public static final int tN = 1; public static final int tB = 2; private final double R, h; private double arc; private List<Point3D[]> trihedrons; private int subDivLength; public SpringHelper(double R, double h){ this.R=R; this.h=h; } public void calculateTrihedron(int subDivLength, double arc){ // Create points trihedrons=new ArrayList<>(); this.subDivLength=subDivLength; this.arc=arc; for (int t = 0; t <= subDivLength; t++) { // 0 - length trihedrons.add(getTrihedron((float) t / subDivLength * arc)); } } /* t [0,<=2Pi] */ private Point3D[] getTrihedron(double t){ // r[t] Point3D vR = new Point3D((float)(R*Math.cos(t)), (float)(R*Math.sin(t)), (float)(h*t)); // r'[t] Point3D dR= new Point3D((float)(-R*Math.sin(t)), (float)(R*Math.cos(t)), (float)(h)); float nT=dR.magnitude(); // || r'[t] || // r''[t] Point3D ddR= new Point3D((float)(-R*Math.cos(t)), (float)(-R*Math.sin(t)), (float)(0)); // (|| r'[t] ||^2)'[t] float dn=0f; // T'[t]=r''[t]/||r't||-r'[t]*(|| r'[t] ||^2)'[t]/2/|| r'[t] ||^3 Point3D dT=ddR.multiply(1f/nT).substract(dR.multiply(dn/((float)(Math.pow(nT,3d)*2d)))); // T[t]=r'[t]/||r'[t]|| Point3D T=dR.normalize(); // N[t]=T'[t]/||T'[t]|| Point3D N=dT.normalize(); // B[t]=T[t]xN[t]/||T[t]xN[t]|| Point3D B=T.crossProduct(N).normalize(); // R,N,B return new Point3D[]{vR,N,B}; } public Point3D getS(int t, float cu, float su){ Point3D[] trihedron = trihedrons.get(t); // S[t,u] Point3D p = trihedron[SpringHelper.tR] .add(trihedron[SpringHelper.tN].multiply(cu) .add(trihedron[SpringHelper.tB].multiply(su))); p.f=((float)(t*arc)/(float)subDivLength); // [0-<=2Pi] return p; } public double getLength(double arc){ // [0-<=2Pi] GaussianQuadrature gauss = new GaussianQuadrature(5,0,arc); // || r'[t] || return gauss.NIntegrate(t->Math.sqrt(R*R+h*h)); } public double getKappa(double t){ // r'[t] Point3D dR= new Point3D((float)(-R*Math.sin(t)), (float)(R*Math.cos(t)), (float)(h)); float nT=dR.magnitude(); // || r'[t] || // r''[t] Point3D ddR= new Point3D((float)(-R*Math.cos(t)), (float)(-R*Math.sin(t)), (float)(0)); // || r''[t]xr'[t] || float nddRxdR=ddR.crossProduct(dR).magnitude(); // kappa[t] = || r''[t]xr'[t] || / || r'[t] ||^3 return nddRxdR/(float)Math.pow(nT,3d); } public double getTau(double t){ Point3D dR= new Point3D((float)(-R*Math.sin(t)), (float)(R*Math.cos(t)), (float)(h)); // r''[t] Point3D ddR= new Point3D((float)(-R*Math.cos(t)), (float)(-R*Math.sin(t)), (float)(0)); // r'''[t] Point3D dddR= new Point3D((float)(R*Math.sin(t)), (float)(-R*Math.cos(t)), (float)(0)); // r'[t]xr''[t] . r'''[t] float dRxddRxdddR=dR.crossProduct(ddR).dotProduct(dddR); // || r''[t]xr'[t] || float ndRxddR=dR.crossProduct(ddR).magnitude(); // tau[t] = r'[t]xr''[t].r'''[t] / || r''[t]xr'[t] ||^2 return Math.abs(dRxddRxdddR/(float)Math.pow(ndRxddR,2d)); } }