Loading files
3d097a032This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// abv 06.01.99 fix of misprint
//: p6 abv 26.02.99: make ConvertToPeriodic() return Null if nothing done
#include <ShapeCustom_Surface.hxx>
#include <ElSLib.hxx>
#include <Geom_BezierSurface.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_ConicalSurface.hxx>
#include <Geom_Curve.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_Plane.hxx>
#include <Geom_SphericalSurface.hxx>
#include <Geom_Surface.hxx>
#include <Geom_ToroidalSurface.hxx>
#include <gp_Ax3.hxx>
#include <gp_Cylinder.hxx>
#include <gp_Pln.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <ShapeAnalysis_Geom.hxx>
#include <ShapeAnalysis_Surface.hxx>
#include <NCollection_Array1.hxx>
#include <NCollection_Array2.hxx>
#include <Standard_Integer.hxx>
//=================================================================================================
ShapeCustom_Surface::ShapeCustom_Surface()
: myGap(0)
{
}
//=================================================================================================
ShapeCustom_Surface::ShapeCustom_Surface(const occ::handle<Geom_Surface>& S)
: myGap(0)
{
Init(S);
}
//=================================================================================================
void ShapeCustom_Surface::Init(const occ::handle<Geom_Surface>& S)
{
mySurf = S;
}
//=================================================================================================
occ::handle<Geom_Surface> ShapeCustom_Surface::ConvertToAnalytical(const double tol,
const bool substitute)
{
occ::handle<Geom_Surface> newSurf;
int nUP, nVP, nCP, i, j, UDeg, VDeg;
double U1, U2, V1, V2, C1, C2, DU, DV, U = 0, V = 0;
occ::handle<Geom_Curve> iso;
bool uClosed = true;
// seuls cas traites : BSpline et Bezier
occ::handle<Geom_BSplineSurface> theBSplneS = occ::down_cast<Geom_BSplineSurface>(mySurf);
if (theBSplneS.IsNull())
{
occ::handle<Geom_BezierSurface> theBezierS = occ::down_cast<Geom_BezierSurface>(mySurf);
if (!theBezierS.IsNull())
{ // Bezier :
nUP = theBezierS->NbUPoles();
nVP = theBezierS->NbVPoles();
UDeg = theBezierS->UDegree();
VDeg = theBezierS->VDegree();
}
else
{
return newSurf; // non reconnu : terminus
}
}
else
{ // BSpline :
nUP = theBSplneS->NbUPoles();
nVP = theBSplneS->NbVPoles();
UDeg = theBSplneS->UDegree();
VDeg = theBSplneS->VDegree();
}
mySurf->Bounds(U1, U2, V1, V2);
// mySurf->Bounds(U1, U2, V1, V2);
NCollection_Array1<gp_Pnt> p1(1, 3), p2(1, 3), p3(1, 3);
NCollection_Array1<double> R(1, 3);
gp_Pnt origPnt, resPnt;
gp_Vec origD1U, resD1U, resD1V;
bool aCySpCo = false;
bool aToroid = false;
bool aPlanar = false;
if (nUP == 2 && nVP == 2)
{
if (UDeg == 1 && VDeg == 1)
{
aPlanar = true;
}
}
else if (mySurf->IsUClosed())
{ // VRAI IsUClosed
if (mySurf->IsVClosed())
{
aToroid = true;
}
else
{
aCySpCo = true;
}
}
else
{
if (mySurf->IsVClosed())
{ // VRAI IsVClosed
aCySpCo = true;
uClosed = false;
}
}
if (aPlanar)
{
// NearestPlane ...
NCollection_Array1<gp_Pnt> Pnts(1, 4);
Pnts.SetValue(1, mySurf->Value(U1, V1));
Pnts.SetValue(2, mySurf->Value(U2, V1));
Pnts.SetValue(3, mySurf->Value(U1, V2));
Pnts.SetValue(4, mySurf->Value(U2, V2));
gp_Pln aPln; // double Dmax;
int It = ShapeAnalysis_Geom::NearestPlane(Pnts, aPln, myGap /*Dmax*/);
// ICI, on fabrique le plan, et zou
if (It == 0 || myGap /*Dmax*/ > tol)
{
return newSurf; // pas un plan
}
// IL RESTE a verifier l orientation ...
// On regarde sur chaque surface les vecteurs P(U0->U1),P(V0->V1)
// On prend la normale : les deux normales doivent etre dans le meme sens
// Sinon, inverser la normale (pas le Pln entier !) et refaire la Plane
newSurf = new Geom_Plane(aPln);
gp_Vec uold(Pnts(1), Pnts(2));
gp_Vec vold(Pnts(1), Pnts(3));
gp_Vec nold = uold.Crossed(vold);
gp_Vec unew(newSurf->Value(U1, V1), newSurf->Value(U2, V1));
gp_Vec vnew(newSurf->Value(U1, V1), newSurf->Value(U1, V2));
gp_Vec nnew = unew.Crossed(vnew);
if (nold.Dot(nnew) < 0.0)
{
gp_Ax3 ax3 = aPln.Position();
ax3.ZReverse();
ax3.XReverse();
aPln = gp_Pln(ax3);
newSurf = new Geom_Plane(aPln);
}
if (substitute)
{
Init(newSurf);
}
return newSurf;
}
else if (aCySpCo)
{
if (!uClosed)
{
C1 = U1;
C2 = U2;
U1 = V1;
U2 = V2;
V1 = C1;
V2 = C2;
nCP = nUP;
nUP = nVP;
nVP = nCP;
}
for (i = 1; i <= 3; i++)
{
if (i == 1)
{
V = V1;
}
else if (i == 2)
{
V = V2;
}
else if (i == 3)
{
V = 0.5 * (V1 + V2);
}
if (uClosed)
{
iso = mySurf->VIso(V);
}
else
{
iso = mySurf->UIso(V);
}
iso->D0(U1, p1(i));
iso->D0(0.5 * (U1 + U2), p2(i));
p3(i).SetCoord(0.5 * (p1(i).X() + p2(i).X()),
0.5 * (p1(i).Y() + p2(i).Y()),
0.5 * (p1(i).Z() + p2(i).Z()));
R(i) = p3(i).Distance(p1(i));
// std::cout<<"sphere, i="<<i<<" V="<<V<<" R="<<R(i)<<"
// p1="<<p1(i).X()<<","<<p1(i).Y()<<","<<p1(i).Z()<<"
// p2="<<p2(i).X()<<","<<p2(i).Y()<<","<<p2(i).Z()<<"
// p3="<<p3(i).X()<<","<<p3(i).Y()<<","<<p3(i).Z()<<std::endl;
}
iso->D1(0., origPnt, origD1U);
gp_Vec xVec(p3(3), p1(3));
gp_Vec aVec(p3(1), p3(2));
// gp_Dir xDir(xVec); ne sert pas. Null si R3 = 0
gp_Dir aDir(aVec);
gp_Ax3 aAx3(p3(1), aDir, xVec);
// CKY 3-FEV-1997 : verification du sens de description
// gp_Dir AXY = aAx3.YDirection(); // AXY not used (skl)
if (aAx3.YDirection().Dot(origD1U) < 0)
{
#ifdef OCCT_DEBUG
std::cout << " Surface Analytique : sens a inverser" << std::endl;
#endif
aAx3.YReverse(); // mais X reste !
}
if (nVP > 2)
{
if ((std::abs(R(1)) < tol) && (std::abs(R(2)) < tol) && (std::abs(R(3)) > tol))
{
// deja fait gp_Ax3 aAx3(p3(1), aDir, xVec);
// gp_Ax3 aAx3(p3(3), aDir);
occ::handle<Geom_SphericalSurface> anObject = new Geom_SphericalSurface(aAx3, R(3));
if (!uClosed)
{
anObject->UReverse();
}
newSurf = anObject;
}
}
else if (nVP == 2)
{
// deja fait gp_Ax3 aAx3(p3(1), aDir, xVec);
// gp_Ax3 aAx3(p3(1), aDir);
if (std::abs(R(2) - R(1)) < tol)
{
occ::handle<Geom_CylindricalSurface> anObject = new Geom_CylindricalSurface(aAx3, R(1));
if (!uClosed)
{
anObject->UReverse();
}
newSurf = anObject;
}
else
{
gp_Vec aVec2(p1(1), p1(2));
double angle = aVec.Angle(aVec2);
if (R(1) < R(2))
{
occ::handle<Geom_ConicalSurface> anObject = new Geom_ConicalSurface(aAx3, angle, R(1));
// if (!uClosed) anObject->UReverse();
anObject->UReverse();
newSurf = anObject;
}
else
{
aDir.Reverse();
gp_Vec anotherXVec(p3(2), p1(2));
gp_Dir anotherXDir(anotherXVec);
gp_Ax3 anotherAx3(p3(2), aDir, anotherXDir);
occ::handle<Geom_ConicalSurface> anObject =
new Geom_ConicalSurface(anotherAx3, angle, R(2));
// if (!uClosed) anObject->UReverse();
anObject->UReverse();
newSurf = anObject;
}
}
}
}
else if (aToroid)
{
// test by iso U and isoV
bool isFound = false;
for (j = 1; (j <= 2) && !isFound; j++)
{
if (j == 2)
{
C1 = U1;
C2 = U2;
U1 = V1;
U2 = V2;
V1 = C1;
V2 = C2;
}
for (i = 1; i <= 3; i++)
{
if (i == 1)
{
U = U1;
}
else if (i == 2)
{
U = 0.5 * (U1 + U2);
}
else if (i == 3)
{
U = 0.25 * (U1 + U2);
}
iso = mySurf->UIso(U);
iso->D0(V1, p1(i));
iso->D0(0.5 * (V1 + V2), p2(i));
p3(i).SetCoord(0.5 * (p1(i).X() + p2(i).X()),
0.5 * (p1(i).Y() + p2(i).Y()),
0.5 * (p1(i).Z() + p2(i).Z()));
R(i) = p3(i).Distance(p1(i));
}
if ((std::abs(R(1) - R(2)) < tol) && (std::abs(R(1) - R(3)) < tol))
{
gp_Pnt p10(0.5 * (p3(1).X() + p3(2).X()),
0.5 * (p3(1).Y() + p3(2).Y()),
0.5 * (p3(1).Z() + p3(2).Z()));
gp_Vec aVec(p10, p3(1));
gp_Vec aVec2(p10, p3(3));
double RR1 = R(1), RR2 = R(2), RR3;
aVec ^= aVec2;
if (aVec.Magnitude() <= gp::Resolution())
{
aVec.SetCoord(0., 0., 1.);
}
gp_Dir aDir(aVec);
gp_Ax3 aAx3(p10, aDir);
RR1 = p10.Distance(p3(1));
// modif empirique (pourtant NON DEMONTREE) : inverser roles RR1,RR2
// CKY, 24-JAN-1997
if (RR1 < RR2)
{
RR3 = RR1;
RR1 = RR2;
RR2 = RR3;
}
occ::handle<Geom_ToroidalSurface> anObject = new Geom_ToroidalSurface(aAx3, RR1, RR2);
if (j == 2)
{
anObject->UReverse();
}
anObject->D1(0., 0., resPnt, resD1U, resD1V);
#ifdef OCCT_DEBUG
if (resD1U.Dot(origD1U) < 0 && j != 2)
std::cout << " Tore a inverser !" << std::endl;
#endif
newSurf = anObject;
isFound = true;
}
}
}
if (newSurf.IsNull())
{
return newSurf;
}
//---------------------------------------------------------------------
// verification
//---------------------------------------------------------------------
occ::handle<GeomAdaptor_Surface> NHS = new GeomAdaptor_Surface(newSurf);
GeomAdaptor_Surface& SurfAdapt = *NHS;
const int NP = 21;
double S = 0., T = 0.; // U,V deja fait
gp_Pnt P3d, P3d2;
bool onSurface = true;
double dis;
myGap = 0.;
DU = (U2 - U1) / (NP - 1);
DV = (V2 - V1) / (NP - 1);
for (j = 1; (j <= NP) && onSurface; j++)
{
V = V1 + DV * (j - 1);
if (uClosed)
{
iso = mySurf->VIso(V);
}
else
{
iso = mySurf->UIso(V);
}
for (i = 1; i <= NP; i++)
{
U = U1 + DU * (i - 1);
iso->D0(U, P3d);
switch (SurfAdapt.GetType())
{
case GeomAbs_Cylinder: {
gp_Cylinder Cylinder = SurfAdapt.Cylinder();
ElSLib::Parameters(Cylinder, P3d, S, T);
break;
}
case GeomAbs_Cone: {
gp_Cone Cone = SurfAdapt.Cone();
ElSLib::Parameters(Cone, P3d, S, T);
break;
}
case GeomAbs_Sphere: {
gp_Sphere Sphere = SurfAdapt.Sphere();
ElSLib::Parameters(Sphere, P3d, S, T);
break;
}
case GeomAbs_Torus: {
gp_Torus Torus = SurfAdapt.Torus();
ElSLib::Parameters(Torus, P3d, S, T);
break;
}
default:
break;
}
newSurf->D0(S, T, P3d2);
dis = P3d.Distance(P3d2);
if (dis > myGap)
{
myGap = dis;
}
if (dis > tol)
{
onSurface = false;
newSurf.Nullify();
// The presumption is rejected
break;
}
}
}
if (substitute && !NHS.IsNull())
{
Init(newSurf);
}
return newSurf;
}
//%pdn 30 Nov 98: converting bspline surfaces with degree+1 at ends to periodic
// UKI60591, entity 48720
occ::handle<Geom_Surface> ShapeCustom_Surface::ConvertToPeriodic(const bool substitute,
const double preci)
{
occ::handle<Geom_Surface> newSurf;
occ::handle<Geom_BSplineSurface> BSpl = occ::down_cast<Geom_BSplineSurface>(mySurf);
if (BSpl.IsNull())
{
return newSurf;
}
ShapeAnalysis_Surface sas(mySurf);
bool uclosed = sas.IsUClosed(preci);
bool vclosed = sas.IsVClosed(preci);
if (!uclosed && !vclosed)
{
return newSurf;
}
bool converted = false; //: p6
if (uclosed && !BSpl->IsUPeriodic() && BSpl->NbUPoles() > 3)
{
bool set = true;
// if degree+1 at ends, first change it to 1 by rearranging knots
if (BSpl->UMultiplicity(1) == BSpl->UDegree() + 1
&& BSpl->UMultiplicity(BSpl->NbUKnots()) == BSpl->UDegree() + 1)
{
const NCollection_Array2<gp_Pnt>& oldPoles = BSpl->Poles();
const NCollection_Array2<double>& oldWeights = BSpl->WeightsArray();
int nbUKnots = BSpl->NbUKnots();
const NCollection_Array1<double>& oldUKnots = BSpl->UKnots();
const NCollection_Array1<double>& oldVKnots = BSpl->VKnots();
const NCollection_Array1<int>& oldUMults = BSpl->UMultiplicities();
const NCollection_Array1<int>& oldVMults = BSpl->VMultiplicities();
NCollection_Array1<double> newUKnots(1, nbUKnots + 2);
NCollection_Array1<int> newUMults(1, nbUKnots + 2);
double a =
0.5 * (BSpl->UKnot(2) - BSpl->UKnot(1) + BSpl->UKnot(nbUKnots) - BSpl->UKnot(nbUKnots - 1));
newUKnots(1) = oldUKnots(1) - a;
newUKnots(nbUKnots + 2) = oldUKnots(nbUKnots) + a;
newUMults(1) = newUMults(nbUKnots + 2) = 1;
for (int i = 2; i <= nbUKnots + 1; i++)
{
newUKnots(i) = oldUKnots(i - 1);
newUMults(i) = oldUMults(i - 1);
}
newUMults(2) = newUMults(nbUKnots + 1) = BSpl->UDegree();
occ::handle<Geom_BSplineSurface> res = new Geom_BSplineSurface(oldPoles,
oldWeights,
newUKnots,
oldVKnots,
newUMults,
oldVMults,
BSpl->UDegree(),
BSpl->VDegree(),
BSpl->IsUPeriodic(),
BSpl->IsVPeriodic());
BSpl = res;
}
else if (BSpl->UMultiplicity(1) > BSpl->UDegree()
|| BSpl->UMultiplicity(BSpl->NbUKnots()) > BSpl->UDegree() + 1)
{
set = false;
}
if (set)
{
BSpl->SetUPeriodic(); // make periodic
converted = true;
}
}
if (vclosed && !BSpl->IsVPeriodic() && BSpl->NbVPoles() > 3)
{
bool set = true;
// if degree+1 at ends, first change it to 1 by rearranging knots
if (BSpl->VMultiplicity(1) == BSpl->VDegree() + 1
&& BSpl->VMultiplicity(BSpl->NbVKnots()) == BSpl->VDegree() + 1)
{
const NCollection_Array2<gp_Pnt>& oldPoles = BSpl->Poles();
const NCollection_Array2<double>& oldWeights = BSpl->WeightsArray();
int nbVKnots = BSpl->NbVKnots();
const NCollection_Array1<double>& oldUKnots = BSpl->UKnots();
const NCollection_Array1<double>& oldVKnots = BSpl->VKnots();
const NCollection_Array1<int>& oldUMults = BSpl->UMultiplicities();
const NCollection_Array1<int>& oldVMults = BSpl->VMultiplicities();
NCollection_Array1<double> newVKnots(1, nbVKnots + 2);
NCollection_Array1<int> newVMults(1, nbVKnots + 2);
double a =
0.5 * (BSpl->VKnot(2) - BSpl->VKnot(1) + BSpl->VKnot(nbVKnots) - BSpl->VKnot(nbVKnots - 1));
newVKnots(1) = oldVKnots(1) - a;
newVKnots(nbVKnots + 2) = oldVKnots(nbVKnots) + a;
newVMults(1) = newVMults(nbVKnots + 2) = 1;
for (int i = 2; i <= nbVKnots + 1; i++)
{
newVKnots(i) = oldVKnots(i - 1);
newVMults(i) = oldVMults(i - 1);
}
newVMults(2) = newVMults(nbVKnots + 1) = BSpl->VDegree();
occ::handle<Geom_BSplineSurface> res = new Geom_BSplineSurface(oldPoles,
oldWeights,
oldUKnots,
newVKnots,
oldUMults,
newVMults,
BSpl->UDegree(),
BSpl->VDegree(),
BSpl->IsUPeriodic(),
BSpl->IsVPeriodic());
BSpl = res;
}
else if (BSpl->VMultiplicity(1) > BSpl->VDegree()
|| BSpl->VMultiplicity(BSpl->NbVKnots()) > BSpl->VDegree() + 1)
{
set = false;
}
if (set)
{
BSpl->SetVPeriodic(); // make periodic
converted = true;
}
}
#ifdef OCCT_DEBUG
std::cout << "Warning: ShapeCustom_Surface: Closed BSplineSurface is caused to be periodic"
<< std::endl;
#endif
if (!converted)
{
return newSurf;
}
newSurf = BSpl;
if (substitute)
{
mySurf = newSurf;
}
return newSurf;
}