You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
477 lines
18 KiB
477 lines
18 KiB
/****************************************************************************
|
|
* Indirect predicates for geometric constructions *
|
|
* *
|
|
* Consiglio Nazionale delle Ricerche *
|
|
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
|
* Sezione di Genova *
|
|
* IMATI-GE / CNR *
|
|
* *
|
|
* Authors: Marco Attene *
|
|
* Copyright(C) 2019: IMATI-GE / CNR *
|
|
* All rights reserved. *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Lesser 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 Lesser *
|
|
* General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Lesser General Public License *
|
|
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
|
* *
|
|
****************************************************************************/
|
|
|
|
/* Should include incircle and insphere toexpansionObject:: */
|
|
|
|
|
|
#include "implicit_point.h"
|
|
|
|
#pragma intrinsic(fabs)
|
|
|
|
inline int orient2d_filtered(double p1x, double p1y, double p2x, double p2y, double p3x, double p3y)
|
|
{
|
|
double dl = (p2x - p1x) * (p3y - p1y);
|
|
double dr = (p2y - p1y) * (p3x - p1x);
|
|
double det = dl - dr;
|
|
double eb = 3.3306690738754706e-016 * (fabs(dl) + fabs(dr));
|
|
return ((det >= eb) - (-det >= eb));
|
|
}
|
|
|
|
inline int orient2d_interval(interval_number p1x,
|
|
interval_number p1y,
|
|
interval_number p2x,
|
|
interval_number p2y,
|
|
interval_number p3x,
|
|
interval_number p3y)
|
|
{
|
|
setFPUModeToRoundUP();
|
|
interval_number a11(p2x - p1x);
|
|
interval_number a12(p2y - p1y);
|
|
interval_number a21(p3x - p1x);
|
|
interval_number a22(p3y - p1y);
|
|
interval_number d1(a11 * a22);
|
|
interval_number d2(a12 * a21);
|
|
interval_number d(d1 - d2);
|
|
setFPUModeToRoundNEAR();
|
|
|
|
if (!d.signIsReliable()) return Filtered_Sign::UNCERTAIN;
|
|
return d.sign();
|
|
}
|
|
|
|
inline int orient2d_exact(double p1x, double p1y, double p2x, double p2y, double p3x, double p3y)
|
|
{
|
|
double acx[2], acy[2], bcx[2], bcy[2], dtl[2], dtr[2], B[4];
|
|
double s[2], t[2], u[4], C1[8], C2[12], D[16];
|
|
int C1l, C2l, Dl;
|
|
|
|
|
|
acx[1] = (p1x - p3x);
|
|
bcx[1] = (p2x - p3x);
|
|
acy[1] = (p1y - p3y);
|
|
bcy[1] = (p2y - p3y);
|
|
|
|
expansionObject::Two_Prod(acx[1], bcy[1], dtl);
|
|
expansionObject::Two_Prod(acy[1], bcx[1], dtr);
|
|
expansionObject::Two_Two_Diff(dtl, dtr, B);
|
|
|
|
double dsm = (fabs(dtl[1]) + fabs(dtr[1]));
|
|
double det = expansionObject::To_Double(4, B);
|
|
double eb = 2.2204460492503146e-16 * dsm;
|
|
Dl = ((det >= eb) - (-det >= eb));
|
|
if (Dl) return Dl;
|
|
|
|
expansionObject::Two_Diff_Back(p1x, p3x, acx);
|
|
expansionObject::Two_Diff_Back(p2x, p3x, bcx);
|
|
expansionObject::Two_Diff_Back(p1y, p3y, acy);
|
|
expansionObject::Two_Diff_Back(p2y, p3y, bcy);
|
|
|
|
if ((acx[0] == 0.0) && (acy[0] == 0.0) && (bcx[0] == 0.0) && (bcy[0] == 0.0)) return ((det > 0) - (det < 0));
|
|
|
|
eb = 1.1093356479670487e-31 * dsm + 3.3306690738754706e-16 * fabs(det);
|
|
det += (acx[1] * bcy[0] + bcy[1] * acx[0]) - (acy[1] * bcx[0] + bcx[1] * acy[0]);
|
|
Dl = ((det >= eb) - (-det >= eb));
|
|
if (Dl) return Dl;
|
|
|
|
expansionObject::Two_Prod(acx[0], bcy[1], s);
|
|
expansionObject::Two_Prod(acy[0], bcx[1], t);
|
|
expansionObject::Two_Two_Diff(s, t, u);
|
|
C1l = expansionObject::Gen_Sum(4, B, 4, u, C1);
|
|
|
|
expansionObject::Two_Prod(acx[1], bcy[0], s);
|
|
expansionObject::Two_Prod(acy[1], bcx[0], t);
|
|
expansionObject::Two_Two_Diff(s, t, u);
|
|
C2l = expansionObject::Gen_Sum(C1l, C1, 4, u, C2);
|
|
|
|
expansionObject::Two_Prod(acx[0], bcy[0], s);
|
|
expansionObject::Two_Prod(acy[0], bcx[0], t);
|
|
expansionObject::Two_Two_Diff(s, t, u);
|
|
Dl = expansionObject::Gen_Sum(C2l, C2, 4, u, D);
|
|
|
|
det = D[Dl - 1];
|
|
return ((det > 0) - (det < 0));
|
|
}
|
|
|
|
inline int orient2d(double p1x, double p1y, double p2x, double p2y, double p3x, double p3y)
|
|
{
|
|
int ret = orient2d_filtered(p1x, p1y, p2x, p2y, p3x, p3y);
|
|
if (ret) return ret;
|
|
// ret = orient2d_interval(p1x, p1y, p2x, p2y, p3x, p3y);
|
|
// if (ret != Filtered_Sign::UNCERTAIN) return ret;
|
|
return orient2d_exact(p1x, p1y, p2x, p2y, p3x, p3y);
|
|
}
|
|
|
|
inline int orient3d_filtered(double px,
|
|
double py,
|
|
double pz,
|
|
double qx,
|
|
double qy,
|
|
double qz,
|
|
double rx,
|
|
double ry,
|
|
double rz,
|
|
double sx,
|
|
double sy,
|
|
double sz)
|
|
{
|
|
double fadx, fbdx, fcdx, fady, fbdy, fcdy, fadz, fbdz, fcdz, eb;
|
|
double fbdxcdy, fcdxbdy, fcdxady, fadxcdy, fadxbdy, fbdxady, det;
|
|
|
|
fadx = qx - px;
|
|
fbdx = rx - px;
|
|
fcdx = sx - px;
|
|
fady = qy - py;
|
|
fbdy = ry - py;
|
|
fcdy = sy - py;
|
|
fadz = qz - pz;
|
|
fbdz = rz - pz;
|
|
fcdz = sz - pz;
|
|
|
|
fbdxcdy = fbdx * fcdy * fadz;
|
|
fcdxbdy = fcdx * fbdy * fadz;
|
|
fcdxady = fcdx * fady * fbdz;
|
|
fadxcdy = fadx * fcdy * fbdz;
|
|
fadxbdy = fadx * fbdy * fcdz;
|
|
fbdxady = fbdx * fady * fcdz;
|
|
|
|
det = (fbdxcdy - fcdxbdy) + (fcdxady - fadxcdy) + (fadxbdy - fbdxady);
|
|
eb = 7.7715611723761027e-016
|
|
* (fabs(fbdxcdy) + fabs(fcdxbdy) + fabs(fcdxady) + fabs(fadxcdy) + fabs(fadxbdy) + fabs(fbdxady));
|
|
return ((det >= eb) - (-det >= eb));
|
|
}
|
|
|
|
inline int orient3d_interval(interval_number px,
|
|
interval_number py,
|
|
interval_number pz,
|
|
interval_number qx,
|
|
interval_number qy,
|
|
interval_number qz,
|
|
interval_number rx,
|
|
interval_number ry,
|
|
interval_number rz,
|
|
interval_number sx,
|
|
interval_number sy,
|
|
interval_number sz)
|
|
{
|
|
setFPUModeToRoundUP();
|
|
interval_number qx_px(qx - px);
|
|
interval_number qy_py(qy - py);
|
|
interval_number rx_px(rx - px);
|
|
interval_number ry_py(ry - py);
|
|
interval_number rz_pz(rz - pz);
|
|
interval_number qz_pz(qz - pz);
|
|
interval_number sx_px(sx - px);
|
|
interval_number sy_py(sy - py);
|
|
interval_number sz_pz(sz - pz);
|
|
interval_number tmp_a(qx_px * ry_py);
|
|
interval_number tmp_b(qy_py * rx_px);
|
|
interval_number m01(tmp_a - tmp_b);
|
|
interval_number tmq_a(qx_px * rz_pz);
|
|
interval_number tmq_b(qz_pz * rx_px);
|
|
interval_number m02(tmq_a - tmq_b);
|
|
interval_number tmr_a(qy_py * rz_pz);
|
|
interval_number tmr_b(qz_pz * ry_py);
|
|
interval_number m12(tmr_a - tmr_b);
|
|
interval_number mt1(m01 * sz_pz);
|
|
interval_number mt2(m02 * sy_py);
|
|
interval_number mt3(m12 * sx_px);
|
|
interval_number mtt(mt1 - mt2);
|
|
interval_number m012(mtt + mt3);
|
|
setFPUModeToRoundNEAR();
|
|
|
|
if (!m012.signIsReliable()) return Filtered_Sign::UNCERTAIN;
|
|
return m012.sign();
|
|
}
|
|
|
|
inline void supo3d1(double* c1,
|
|
double* c2,
|
|
double* c3,
|
|
double* c4,
|
|
double* c5,
|
|
double* c6,
|
|
double* a1,
|
|
double* a2,
|
|
double& i,
|
|
double* k1,
|
|
double* k2,
|
|
double* k3,
|
|
double* k4,
|
|
int& l1,
|
|
int& l2)
|
|
{
|
|
if (c1[0] == 0.0) {
|
|
if (c2[0] == 0.0) {
|
|
a1[0] = a2[0] = 0.0;
|
|
l1 = l2 = 1;
|
|
} else {
|
|
i = -c2[0];
|
|
expansionObject::Two_Prod(i, c3[1], a1);
|
|
expansionObject::Two_Prod(c2[0], c4[1], a2);
|
|
l1 = l2 = 2;
|
|
}
|
|
} else {
|
|
if (c2[0] == 0.0) {
|
|
i = -c1[0];
|
|
expansionObject::Two_Prod(c1[0], c5[1], a1);
|
|
expansionObject::Two_Prod(i, c6[1], a2);
|
|
l1 = l2 = 2;
|
|
} else {
|
|
expansionObject::Two_Prod(c1[0], c5[1], k1);
|
|
expansionObject::Two_Prod(c2[0], c3[1], k2);
|
|
expansionObject::Two_Two_Diff(k1, k2, a1);
|
|
expansionObject::Two_Prod(c2[0], c4[1], k3);
|
|
expansionObject::Two_Prod(c1[0], c6[1], k4);
|
|
expansionObject::Two_Two_Diff(k3, k4, a2);
|
|
l1 = l2 = 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void supo3d2(double* c1,
|
|
double* c2,
|
|
double* c3,
|
|
double* c4,
|
|
double* u,
|
|
int& fl,
|
|
double fin[2][192],
|
|
int& wh,
|
|
double* c5,
|
|
double& i,
|
|
double* c6,
|
|
double* c7)
|
|
|
|
{
|
|
if (c1[0] != 0.0) {
|
|
if (c2[0] != 0.0) {
|
|
expansionObject::Two_Prod(c1[0], c2[0], c3);
|
|
expansionObject::Two_One_Prod(c3, c4[1], u);
|
|
fl = expansionObject::Gen_Sum(fl, fin[wh], 4, u, fin[!wh]);
|
|
wh = !wh;
|
|
if (c4[0] != 0.0) {
|
|
expansionObject::Two_One_Prod(c3, c4[0], u);
|
|
fl = expansionObject::Gen_Sum(fl, fin[wh], 4, u, fin[!wh]);
|
|
wh = !wh;
|
|
}
|
|
}
|
|
if (c5[0] != 0.0) {
|
|
i = -c1[0];
|
|
expansionObject::Two_Prod(i, c5[0], c6);
|
|
expansionObject::Two_One_Prod(c6, c7[1], u);
|
|
fl = expansionObject::Gen_Sum(fl, fin[wh], 4, u, fin[!wh]);
|
|
wh = !wh;
|
|
if (c7[0] != 0.0) {
|
|
expansionObject::Two_One_Prod(c6, c7[0], u);
|
|
fl = expansionObject::Gen_Sum(fl, fin[wh], 4, u, fin[!wh]);
|
|
wh = !wh;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
inline int orient3d_exact(double pdx,
|
|
double pdy,
|
|
double pdz,
|
|
double pax,
|
|
double pay,
|
|
double paz,
|
|
double pbx,
|
|
double pby,
|
|
double pbz,
|
|
double pcx,
|
|
double pcy,
|
|
double pcz)
|
|
{
|
|
double eb, det;
|
|
double adx[2], bdx[2], cdx[2], ady[2], bdy[2], cdy[2], adz[2], bdz[2], cdz[2];
|
|
double bdxcdy[2], cdxbdy[2], cdxady[2], adxcdy[2], adxbdy[2], bdxady[2];
|
|
double bc[4], ca[4], ab[4];
|
|
double bdxt_cdy[2], cdxt_bdy[2], cdxt_ady[2];
|
|
double adxt_cdy[2], adxt_bdy[2], bdxt_ady[2];
|
|
double bdyt_cdx[2], cdyt_bdx[2], cdyt_adx[2];
|
|
double adyt_cdx[2], adyt_bdx[2], bdyt_adx[2];
|
|
double bdxt_cdyt[2], cdxt_bdyt[2], cdxt_adyt[2];
|
|
double adxt_cdyt[2], adxt_bdyt[2], bdxt_adyt[2];
|
|
double u[4], v[12], w[16];
|
|
double adet[8], bdet[8], cdet[8], abdet[16];
|
|
double fin[2][192];
|
|
int wh = 0;
|
|
double at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
|
|
double bct[8], cat[8], abt[8];
|
|
int alen, blen, clen, finlen, vlen, wlen;
|
|
int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen;
|
|
int bctlen, catlen, abtlen;
|
|
int ablen;
|
|
double inv;
|
|
int ri;
|
|
|
|
|
|
adx[1] = pax - pdx;
|
|
bdx[1] = pbx - pdx;
|
|
cdx[1] = pcx - pdx;
|
|
ady[1] = pay - pdy;
|
|
bdy[1] = pby - pdy;
|
|
cdy[1] = pcy - pdy;
|
|
adz[1] = paz - pdz;
|
|
bdz[1] = pbz - pdz;
|
|
cdz[1] = pcz - pdz;
|
|
|
|
expansionObject::Two_Prod(bdx[1], cdy[1], bdxcdy);
|
|
expansionObject::Two_Prod(cdx[1], bdy[1], cdxbdy);
|
|
expansionObject::Two_Two_Diff(bdxcdy, cdxbdy, bc);
|
|
alen = expansionObject::Gen_Scale(4, bc, adz[1], adet);
|
|
|
|
expansionObject::Two_Prod(cdx[1], ady[1], cdxady);
|
|
expansionObject::Two_Prod(adx[1], cdy[1], adxcdy);
|
|
expansionObject::Two_Two_Diff(cdxady, adxcdy, ca);
|
|
blen = expansionObject::Gen_Scale(4, ca, bdz[1], bdet);
|
|
|
|
expansionObject::Two_Prod(adx[1], bdy[1], adxbdy);
|
|
expansionObject::Two_Prod(bdx[1], ady[1], bdxady);
|
|
expansionObject::Two_Two_Diff(adxbdy, bdxady, ab);
|
|
clen = expansionObject::Gen_Scale(4, ab, cdz[1], cdet);
|
|
|
|
ablen = expansionObject::Gen_Sum(alen, adet, blen, bdet, abdet);
|
|
finlen = expansionObject::Gen_Sum(ablen, abdet, clen, cdet, fin[wh]);
|
|
|
|
double xx1 = bdxcdy[1] * adz[1];
|
|
double xx2 = cdxbdy[1] * adz[1];
|
|
double yy1 = cdxady[1] * bdz[1];
|
|
double yy2 = adxcdy[1] * bdz[1];
|
|
double zz1 = adxbdy[1] * cdz[1];
|
|
double zz2 = bdxady[1] * cdz[1];
|
|
double pm = fabs(xx1) + fabs(xx2) + fabs(yy1) + fabs(yy2) + fabs(zz1) + fabs(zz2);
|
|
|
|
det = expansionObject::To_Double(finlen, fin[wh]);
|
|
eb = 3.3306690738754731e-016 * pm;
|
|
ri = (det >= eb) - (-det >= eb);
|
|
if (ri) return ri;
|
|
|
|
expansionObject::Two_Diff_Back(pax, pdx, adx);
|
|
expansionObject::Two_Diff_Back(pbx, pdx, bdx);
|
|
expansionObject::Two_Diff_Back(pcx, pdx, cdx);
|
|
expansionObject::Two_Diff_Back(pay, pdy, ady);
|
|
expansionObject::Two_Diff_Back(pby, pdy, bdy);
|
|
expansionObject::Two_Diff_Back(pcy, pdy, cdy);
|
|
expansionObject::Two_Diff_Back(paz, pdz, adz);
|
|
expansionObject::Two_Diff_Back(pbz, pdz, bdz);
|
|
expansionObject::Two_Diff_Back(pcz, pdz, cdz);
|
|
|
|
if ((adx[0] == 0.0) && (bdx[0] == 0.0) && (cdx[0] == 0.0) && (ady[0] == 0.0) && (bdy[0] == 0.0) && (cdy[0] == 0.0)
|
|
&& (adz[0] == 0.0) && (bdz[0] == 0.0) && (cdz[0] == 0.0))
|
|
return (det > 0) - (det < 0);
|
|
|
|
eb = 3.2047474274603644e-031 * pm + 1.1102230246251565e-016 * fabs(det);
|
|
det += (adz[1] * ((bdx[1] * cdy[0] + cdy[1] * bdx[0]) - (bdy[1] * cdx[0] + cdx[1] * bdy[0]))
|
|
+ adz[0] * (bdx[1] * cdy[1] - bdy[1] * cdx[1]))
|
|
+ (bdz[1] * ((cdx[1] * ady[0] + ady[1] * cdx[0]) - (cdy[1] * adx[0] + adx[1] * cdy[0]))
|
|
+ bdz[0] * (cdx[1] * ady[1] - cdy[1] * adx[1]))
|
|
+ (cdz[1] * ((adx[1] * bdy[0] + bdy[1] * adx[0]) - (ady[1] * bdx[0] + bdx[1] * ady[0]))
|
|
+ cdz[0] * (adx[1] * bdy[1] - ady[1] * bdx[1]));
|
|
ri = (det >= eb) - (-det >= eb);
|
|
if (ri) return ri;
|
|
|
|
// Filters did not work. Compute exactly...
|
|
supo3d1(adx, ady, bdx, cdx, bdy, cdy, at_b, at_c, inv, adxt_bdy, adyt_bdx, adyt_cdx, adxt_cdy, at_blen, at_clen);
|
|
|
|
supo3d1(bdx, bdy, cdx, adx, cdy, ady, bt_c, bt_a, inv, bdxt_cdy, bdyt_cdx, bdyt_adx, bdxt_ady, bt_alen, bt_clen);
|
|
|
|
supo3d1(cdx, cdy, adx, bdx, ady, bdy, ct_a, ct_b, inv, cdxt_ady, cdyt_adx, cdyt_bdx, cdxt_bdy, ct_alen, ct_blen);
|
|
|
|
bctlen = expansionObject::Gen_Sum(bt_clen, bt_c, ct_blen, ct_b, bct);
|
|
wlen = expansionObject::Gen_Scale(bctlen, bct, adz[1], w);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], wlen, w, fin[(!wh)]);
|
|
wh = !wh;
|
|
|
|
catlen = expansionObject::Gen_Sum(ct_alen, ct_a, at_clen, at_c, cat);
|
|
wlen = expansionObject::Gen_Scale(catlen, cat, bdz[1], w);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], wlen, w, fin[(!wh)]);
|
|
wh = !wh;
|
|
|
|
abtlen = expansionObject::Gen_Sum(at_blen, at_b, bt_alen, bt_a, abt);
|
|
wlen = expansionObject::Gen_Scale(abtlen, abt, cdz[1], w);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], wlen, w, fin[(!wh)]);
|
|
wh = !wh;
|
|
|
|
if (adz[0] != 0.0) {
|
|
vlen = expansionObject::Gen_Scale(4, bc, adz[0], v);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], vlen, v, fin[(!wh)]);
|
|
wh = !wh;
|
|
}
|
|
if (bdz[0] != 0.0) {
|
|
vlen = expansionObject::Gen_Scale(4, ca, bdz[0], v);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], vlen, v, fin[(!wh)]);
|
|
wh = !wh;
|
|
}
|
|
if (cdz[0] != 0.0) {
|
|
vlen = expansionObject::Gen_Scale(4, ab, cdz[0], v);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], vlen, v, fin[(!wh)]);
|
|
wh = !wh;
|
|
}
|
|
|
|
supo3d2(adx, bdy, adxt_bdyt, cdz, u, finlen, fin, wh, cdy, inv, adxt_cdyt, bdz);
|
|
supo3d2(bdx, cdy, bdxt_cdyt, adz, u, finlen, fin, wh, ady, inv, bdxt_adyt, cdz);
|
|
supo3d2(cdx, ady, cdxt_adyt, bdz, u, finlen, fin, wh, bdy, inv, cdxt_bdyt, adz);
|
|
|
|
if (adz[0] != 0.0) {
|
|
wlen = expansionObject::Gen_Scale(bctlen, bct, adz[0], w);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], wlen, w, fin[!wh]);
|
|
wh = !wh;
|
|
}
|
|
if (bdz[0] != 0.0) {
|
|
wlen = expansionObject::Gen_Scale(catlen, cat, bdz[0], w);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], wlen, w, fin[!wh]);
|
|
wh = !wh;
|
|
}
|
|
if (cdz[0] != 0.0) {
|
|
wlen = expansionObject::Gen_Scale(abtlen, abt, cdz[0], w);
|
|
finlen = expansionObject::Gen_Sum(finlen, fin[wh], wlen, w, fin[!wh]);
|
|
wh = !wh;
|
|
}
|
|
|
|
det = fin[wh][finlen - 1];
|
|
return (det > 0) - (det < 0);
|
|
}
|
|
|
|
inline int orient3d(double px,
|
|
double py,
|
|
double pz,
|
|
double qx,
|
|
double qy,
|
|
double qz,
|
|
double rx,
|
|
double ry,
|
|
double rz,
|
|
double sx,
|
|
double sy,
|
|
double sz)
|
|
{
|
|
int ret;
|
|
ret = orient3d_filtered(px, py, pz, qx, qy, qz, rx, ry, rz, sx, sy, sz);
|
|
if (ret) return ret;
|
|
// ret = orient3d_interval(px, py, pz, qx, qy, qz, rx, ry, rz, sx, sy, sz);
|
|
// if (ret != Filtered_Sign::UNCERTAIN) return ret;
|
|
return orient3d_exact(px, py, pz, qx, qy, qz, rx, ry, rz, sx, sy, sz);
|
|
}
|
|
|