スプライン その 2
Vd3A b_spline (const Vd3& q0,const Vd3& q1,const Vd3& q2,const Vd3& q3,const long div_c)
{
Vd3A vd3a ;
for (long index=0 ; index<=div_c ; index++) {
double t = 1./div_c*index ;
double n0 = 1./6 * (1.-t)*(1.-t)*(1.-t) ;
double n1 = 1./2 * t*t*t - t*t + 2./3 ;
double n2 =-1./2 * t*t*t + 1./2 * t*t + 1./2 *t + 1./6 ;
double n3 = 1./6 * t*t*t ;
double px = (n0*q0.x) + (n1*q1.x) + (n2*q2.x) + (n3*q3.x) ;
double py = (n0*q0.y) + (n1*q1.y) + (n2*q2.y) + (n3*q3.y) ;
double pz = (n0*q0.z) + (n1*q1.z) + (n2*q2.z) + (n3*q3.z) ;
vd3a.push_back(Vd3(px,py,pz)) ;
}
return vd3a ;
}
Vd3A b_spline (const Vd3A& pnts,const long div_n=2)
{
Vd3A vd3a ;
if (pnts.size() < 3) { return pnts ; }
else {
{ // 0,1,2
{
Vd3 p0 = pnts[0] ;
Vd3 p1 = pnts[0] ;
Vd3 p2 = pnts[1] ;
Vd3 p3 = pnts[2] ;
{ // is close ?
Vd3 p_0 = pnts[0] ;
Vd3 p_l = pnts[pnts.size()-1] ;
if (p_0 == p_l) {
p0 = pnts[pnts.size()-2] ;
}
}
Vd3A vd_0 = ::b_spline(p0,p1,p2,p3,div_n) ;
vd3a.insert(vd3a.end(),vd_0.begin(),vd_0.end()) ;
}
}
{ // 1 - (n-2)
for (size_t index=3 ; index<pnts.size() ; index++) {
Vd3 p0 = pnts[index-3] ;
Vd3 p1 = pnts[index-2] ;
Vd3 p2 = pnts[index-1] ;
Vd3 p3 = pnts[index-0] ;
Vd3A vd__ = ::b_spline(p0,p1,p2,p3,div_n) ;
vd3a.insert(vd3a.end(),vd__.begin(),vd__.end()) ;
}
}
{ // n-3,n-2,n-1
{
Vd3 p0 = pnts[pnts.size()-3] ;
Vd3 p1 = pnts[pnts.size()-2] ;
Vd3 p2 = pnts[pnts.size()-1] ;
Vd3 p3 = pnts[pnts.size()-1] ;
{ // is close ?
Vd3 p_0 = pnts[0] ;
Vd3 p_l = pnts[pnts.size()-1] ;
if (p_0 == p_l) {
p3 = pnts[1] ;
}
}
Vd3A vd_l = ::b_spline(p0,p1,p2,p3,div_n) ;
vd3a.insert(vd3a.end(),vd_l.begin(),vd_l.end()) ;
}
}
}
return vd3a ;
}
曲面に関して私が理解できる記述があまり見つけられない.
この本の 193 ページをコードにするとこんな感じか?
v_Vd3A b_spline (const v_Vd3A& v_pnts_,const long div_n=2)
{
v_Vd3A v_pnts = v_pnts_ ;
{
v_pnts = ::transpose(v_pnts) ;
for (size_t index=0 ; index<v_pnts.size() ; index++) {
Vd3A pnts = v_pnts[index] ;
pnts = ::b_spline(pnts,div_n) ;
v_pnts[index] = pnts ;
}
}
{
v_pnts = ::transpose(v_pnts) ;
for (size_t index=0 ; index<v_pnts.size() ; index++) {
Vd3A pnts = v_pnts[index] ;
pnts = ::b_spline(pnts,div_n) ;
v_pnts[index] = pnts ;
}
}
return v_pnts ;
}
// 行列の入替
v_Vd3A transpose (const v_Vd3A& v_pnts_)
{
if (v_pnts_.size() == 0) { return v_pnts_ ; }
v_Vd3A v_pnts ;
long count_v = v_pnts_.size() ;
for (size_t index1=0 ; index1<v_pnts_[0].size() || 0<count_v ; index1++) {
Vd3A t_pnts ;
for (size_t index2=0 ; index2<v_pnts_.size() ; index2++) {
Vd3A pnts = v_pnts_[index2] ;
if (index1 < pnts.size()) {
Vd3 pnt = pnts[index1] ;
t_pnts.push_back(pnt) ;
}
else {
count_v-- ;
break ;
}
}
v_pnts.push_back(t_pnts) ;
}
return v_pnts ;
}
Kodatuno にあるサンプルデータの形式(拡張子inp)を利用させてもらってデータを定義.
3,3
0,0,0
0,0,100
0,100,100
50,0,0
50,0,100
50,100,100
100,0,0
100,0,100
100,100,100
そのまま表示すると,00_01_11_flat.html
ここまでの B-Spline で表示すると,00_01_11_BS_1.html
一見うまくいっているように見えたが,データの大きさが 83.3333,83.3333,83.3333 になっている.
本当は,100,100,100 でなければならない.
3 点の処理がうまくなかったので,5 点として指定する様にしてみた.
Vd3A b_spline (const Vd3A& pnts,const long div_n=2)
{
Vd3A vd3a ;
if (pnts.size() < 3) { return pnts ; }
if (pnts.size()== 3) {
Vd3A v_pnt ;
v_pnt.push_back(pnts[0]) ;
v_pnt.push_back(pnts[0]) ;
v_pnt.push_back(pnts[1]) ;
v_pnt.push_back(pnts[2]) ;
v_pnt.push_back(pnts[2]) ;
vd3a = ::b_spline(v_pnt,div_n) ;
}
else {
// 4 点以上の時の処理
}
return vd3a ;
}
00_01_11_BS_2.html
Kodatuno にあるサンプルを少し編集したデータ
与えられた頂点を単純に結んで面に. FreeSurf_e_0.html 単純に結んで四角形にして,さらに平均の位置から 4 つの三角形に分割している.
B-Spline で表示すると, FreeSurf_e_1.html
inp ファイルで与えている制御点の付近が滑らかでない.
次の様な 3 点を与えて,曲線に.
L_00_01_11.inp
0,0,0
0,10,0
10,10,0
見た目はわからないが,そのデータを見ると頂点が連続している部分がある(頂点番号の 4,8,12).
1 1 ; PartsA Exporter Ver.1.20 2015/06/18 "c:\Temp\Test_3D\Read_3D\Debug.060\Read_3D.exe"
8355711 0 "" "'0' '0.3' '8355711' '1.5' '1.5' " "'1' '16777215' '11' " "'0.2' '0' '2.5' "
80 "0 0 1 " "0 0 0 " "10 10 0 " "1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 " 0 0
17 1 ; P3A_
0 0 0
0 0.026041666666667 0
0 0.208333333333333 0
0 0.703125 0
0 1.66666666666667 0
0.026041666666667 3.17708333333333 0
0.208333333333333 5 0
0.703125 6.82291666666667 0
1.66666666666667 8.33333333333333 0
3.17708333333333 9.296875 0
5 9.79166666666667 0
6.82291666666667 9.97395833333333 0
8.33333333333333 10 0
9.296875 10 0
9.79166666666667 10 0
9.97395833333333 10 0
10 10 0
0 1 ; TextA
0 1 ; LineA
0 1 ; CircleA
1 1 ; FaceA
20 20 20 "0 1 2 3 4 4 5 6 7 8 8 9 10 11 12 12 13 14 15 16 " "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 " 0 -1
0 1 ; FaceA ; * * *
0 1 ; FaceA
0 1 ; EdgeA
0 1 ; PointA
0 1 ; TextA
0 1 ; TextHA
0 1 ; TextVA
0 1 ; PointA
連続する部分をスキップする様に変更
inline Vd3A b_spline (const Vd3A& pnts,const long div_n=2)
{
Vd3A vd3a ;
if (pnts.size() < 3) { return pnts ; }
if (pnts.size()== 3) {
Vd3A v_pnt ;
v_pnt.push_back(pnts[0]) ;
v_pnt.push_back(pnts[0]) ;
v_pnt.push_back(pnts[1]) ;
v_pnt.push_back(pnts[2]) ;
v_pnt.push_back(pnts[2]) ;
vd3a = ::b_spline(v_pnt,div_n) ;
}
else { // 3 <
{ // 0,1,2
{
Vd3 p0 = pnts[0] ;
Vd3 p1 = pnts[0] ;
Vd3 p2 = pnts[1] ;
Vd3 p3 = pnts[2] ;
{ // is close ?
Vd3 p_0 = pnts[0] ;
Vd3 p_l = pnts[pnts.size()-1] ;
if (p_0 == p_l) {
p0 = pnts[pnts.size()-2] ;
}
}
Vd3A vd_0 = ::b_spline(p0,p1,p2,p3,div_n) ;
vd3a.insert(vd3a.end(),vd_0.begin(),vd_0.end()) ;
}
}
{ // 1 - (n-2)
for (size_t index=3 ; index<pnts.size() ; index++) {
Vd3 p0 = pnts[index-3] ;
Vd3 p1 = pnts[index-2] ;
Vd3 p2 = pnts[index-1] ;
Vd3 p3 = pnts[index-0] ;
Vd3A vd__ = ::b_spline(p0,p1,p2,p3,div_n) ;
if (vd3a.size()>0 && vd__.size()>0) {
Vd3 pl = vd3a[vd3a.size()-1] ;
Vd3 pn = vd__[0] ;
if (::V3_is_near(pl,pn)) {
vd3a.pop_back() ;
}
}
vd3a.insert(vd3a.end(),vd__.begin(),vd__.end()) ;
}
}
{ // n-3,n-2,n-1
{
Vd3 p0 = pnts[pnts.size()-3] ;
Vd3 p1 = pnts[pnts.size()-2] ;
Vd3 p2 = pnts[pnts.size()-1] ;
Vd3 p3 = pnts[pnts.size()-1] ;
{ // is close ?
Vd3 p_0 = pnts[0] ;
Vd3 p_l = pnts[pnts.size()-1] ;
if (p_0 == p_l) {
p3 = pnts[1] ;
}
}
Vd3A vd_l = ::b_spline(p0,p1,p2,p3,div_n) ;
if (vd3a.size()>0 && vd_l.size()>0) {
Vd3 pl = vd3a[vd3a.size()-1] ;
Vd3 pn = vd_l[0] ;
if (::V3_is_near(pl,pn)) {
vd3a.pop_back() ;
}
}
vd3a.insert(vd3a.end(),vd_l.begin(),vd_l.end()) ;
}
}
}
return vd3a ;
}
FreeSurf_e_2.html
もう一つ購入した本