1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-21 10:13:43 +03:00
occt/src/GeometryTest/GeometryTest_APICommands.cxx
dpasukhi a5a7b3185b Coding - Apply .clang-format formatting #286
Update empty method guards to new style with regex (see PR).
Used clang-format 18.1.8.
New actions to validate code formatting is added.
Update .clang-format with disabling of include sorting.
  It is temporary changes, then include will be sorted.
Apply formatting for /src and /tools folder.
The files with .hxx,.cxx,.lxx,.h,.pxx,.hpp,*.cpp extensions.
2025-01-26 00:43:57 +00:00

783 lines
20 KiB
C++

// Created on: 1995-01-17
// Created by: Remi LEQUETTE
// Copyright (c) 1995-1999 Matra Datavision
// 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.
#include <Geom_BSplineCurve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <DrawTrSurf.hxx>
#include <Draw_Appli.hxx>
#include <GeometryTest.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <GeomAPI_ProjectPointOnSurf.hxx>
#include <Extrema_GenLocateExtPS.hxx>
#include <GeomAPI_ExtremaCurveCurve.hxx>
#include <GeomAPI_ExtremaCurveSurface.hxx>
#include <GeomAPI_ExtremaSurfaceSurface.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <GeomAPI_PointsToBSplineSurface.hxx>
#include <Geom_Line.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <Draw_Marker3D.hxx>
#include <Draw_Color.hxx>
#include <Draw_MarkerShape.hxx>
#include <Message.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array2OfPnt.hxx>
#include <TColStd_Array2OfReal.hxx>
#include <Precision.hxx>
#include <stdio.h>
#ifdef _WIN32
Standard_IMPORT Draw_Viewer dout;
#endif
//=================================================================================================
static void showProjSolution(Draw_Interpretor& di,
const Standard_Integer i,
const gp_Pnt& P,
const gp_Pnt& P1,
const Standard_Real U,
const Standard_Real V,
const Standard_Boolean isSurface)
{
char name[100];
Sprintf(name, "%s%d", "ext_", i);
di << name << " ";
char* temp = name; // portage WNT
if (P.Distance(P1) > Precision::Confusion())
{
Handle(Geom_Line) L = new Geom_Line(P, gp_Vec(P, P1));
Handle(Geom_TrimmedCurve) CT = new Geom_TrimmedCurve(L, 0., P.Distance(P1));
DrawTrSurf::Set(temp, CT);
}
else
{
DrawTrSurf::Set(temp, P1);
if (isSurface)
di << " Point on surface ";
else
di << " Point on curve ";
}
if (isSurface)
di << " Parameters: " << U << " " << V << "\n";
else
di << " parameter " << i << " = " << U << "\n";
}
//=================================================================================================
static Standard_Integer proj(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 5)
{
Message::SendFail() << " Use proj curve/surf x y z [{extrema algo: g(grad)/t(tree)}|{u v}]";
return 1;
}
gp_Pnt P(Draw::Atof(a[2]), Draw::Atof(a[3]), Draw::Atof(a[4]));
Handle(Geom_Curve) GC = DrawTrSurf::GetCurve(a[1]);
Handle(Geom_Surface) GS;
Extrema_ExtAlgo aProjAlgo = Extrema_ExtAlgo_Grad;
if (n == 6 && a[5][0] == 't')
aProjAlgo = Extrema_ExtAlgo_Tree;
if (GC.IsNull())
{
GS = DrawTrSurf::GetSurface(a[1]);
if (GS.IsNull())
return 1;
if (n <= 6)
{
Standard_Real U1, U2, V1, V2;
GS->Bounds(U1, U2, V1, V2);
GeomAPI_ProjectPointOnSurf proj(P, GS, U1, U2, V1, V2, aProjAlgo);
if (!proj.IsDone())
{
di << "projection failed.";
return 0;
}
Standard_Real UU, VV;
for (Standard_Integer i = 1; i <= proj.NbPoints(); i++)
{
gp_Pnt P1 = proj.Point(i);
proj.Parameters(i, UU, VV);
showProjSolution(di, i, P, P1, UU, VV, Standard_True);
}
}
else if (n == 7)
{
const gp_XY aP2d(Draw::Atof(a[5]), Draw::Atof(a[6]));
GeomAdaptor_Surface aGAS(GS);
Extrema_GenLocateExtPS aProjector(aGAS, Precision::PConfusion(), Precision::PConfusion());
aProjector.Perform(P, aP2d.X(), aP2d.Y(), Standard_False);
if (!aProjector.IsDone())
{
di << "projection failed.";
return 0;
}
const Extrema_POnSurf& aP = aProjector.Point();
Standard_Real UU, VV;
aP.Parameter(UU, VV);
showProjSolution(di, 1, P, aP.Value(), UU, VV, Standard_True);
}
}
else
{
GeomAPI_ProjectPointOnCurve proj(P, GC, GC->FirstParameter(), GC->LastParameter());
if (proj.NbPoints() == 0)
{
std::cout << "No project point was found." << std::endl;
return 0;
}
for (Standard_Integer i = 1; i <= proj.NbPoints(); i++)
{
gp_Pnt P1 = proj.Point(i);
Standard_Real UU = proj.Parameter(i);
showProjSolution(di, i, P, P1, UU, UU, Standard_False);
}
}
return 0;
}
//=================================================================================================
static Standard_Integer appro(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 3)
return 1;
Handle(Geom_Curve) GC;
Standard_Integer Nb = Draw::Atoi(a[2]);
TColgp_Array1OfPnt Points(1, Nb);
Handle(Draw_Marker3D) mark;
if (n == 4)
{
GC = DrawTrSurf::GetCurve(a[3]);
if (GC.IsNull())
return 1;
Standard_Real U, U1, U2;
U1 = GC->FirstParameter();
U2 = GC->LastParameter();
Standard_Real Delta = (U2 - U1) / (Nb - 1);
for (Standard_Integer i = 1; i <= Nb; i++)
{
U = U1 + (i - 1) * Delta;
Points(i) = GC->Value(U);
mark = new Draw_Marker3D(Points(i), Draw_X, Draw_vert);
dout << mark;
}
}
else
{
Standard_Integer id, XX, YY, b;
dout.Select(id, XX, YY, b);
Standard_Real zoom = dout.Zoom(id);
Points(1) = gp_Pnt(((Standard_Real)XX) / zoom, ((Standard_Real)YY) / zoom, 0.);
mark = new Draw_Marker3D(Points(1), Draw_X, Draw_vert);
dout << mark;
for (Standard_Integer i = 2; i <= Nb; i++)
{
dout.Select(id, XX, YY, b);
Points(i) = gp_Pnt(((Standard_Real)XX) / zoom, ((Standard_Real)YY) / zoom, 0.);
mark = new Draw_Marker3D(Points(i), Draw_X, Draw_vert);
dout << mark;
}
}
dout.Flush();
Standard_Integer Dmin = 3;
Standard_Integer Dmax = 8;
Standard_Real Tol3d = 1.e-3;
Handle(Geom_BSplineCurve) TheCurve;
GeomAPI_PointsToBSpline aPointToBSpline(Points, Dmin, Dmax, GeomAbs_C2, Tol3d);
TheCurve = aPointToBSpline.Curve();
DrawTrSurf::Set(a[1], TheCurve);
di << a[1];
return 0;
}
//=================================================================================================
static Standard_Integer grilapp(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 12)
return 1;
Standard_Integer i, j;
Standard_Integer Nu = Draw::Atoi(a[2]);
Standard_Integer Nv = Draw::Atoi(a[3]);
TColStd_Array2OfReal ZPoints(1, Nu, 1, Nv);
Standard_Real X0 = Draw::Atof(a[4]);
Standard_Real dX = Draw::Atof(a[5]);
Standard_Real Y0 = Draw::Atof(a[6]);
Standard_Real dY = Draw::Atof(a[7]);
Standard_Integer Count = 8;
for (j = 1; j <= Nv; j++)
{
for (i = 1; i <= Nu; i++)
{
if (Count > n)
return 1;
ZPoints(i, j) = Draw::Atof(a[Count]);
Count++;
}
}
Handle(Geom_BSplineSurface) S = GeomAPI_PointsToBSplineSurface(ZPoints, X0, dX, Y0, dY);
DrawTrSurf::Set(a[1], S);
di << a[1];
return 0;
}
//=================================================================================================
static Standard_Integer surfapp(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 5)
return 1;
Standard_Integer i, j;
Standard_Integer Nu = Draw::Atoi(a[2]);
Standard_Integer Nv = Draw::Atoi(a[3]);
TColgp_Array2OfPnt Points(1, Nu, 1, Nv);
Standard_Boolean IsPeriodic = Standard_False;
Standard_Boolean RemoveLast = Standard_False;
if (n >= 5 && n <= 6)
{
Handle(Geom_Surface) Surf = DrawTrSurf::GetSurface(a[4]);
if (Surf.IsNull())
return 1;
Standard_Real U, V, U1, V1, U2, V2;
Surf->Bounds(U1, U2, V1, V2);
for (j = 1; j <= Nv; j++)
{
V = V1 + (j - 1) * (V2 - V1) / (Nv - 1);
for (i = 1; i <= Nu; i++)
{
U = U1 + (i - 1) * (U2 - U1) / (Nu - 1);
Points(i, j) = Surf->Value(U, V);
}
}
if (n == 6)
{
Standard_Integer ip = Draw::Atoi(a[5]);
if (ip > 0)
IsPeriodic = Standard_True;
}
if (IsPeriodic)
{
for (j = 1; j <= Nv; j++)
{
Standard_Real d = Points(1, j).Distance(Points(Nu, j));
if (d <= Precision::Confusion())
{
RemoveLast = Standard_True;
break;
}
}
}
}
else if (n >= 16)
{
Standard_Integer Count = 4;
for (j = 1; j <= Nv; j++)
{
for (i = 1; i <= Nu; i++)
{
if (Count > n)
return 1;
Points(i, j) =
gp_Pnt(Draw::Atof(a[Count]), Draw::Atof(a[Count + 1]), Draw::Atof(a[Count + 2]));
Count += 3;
}
}
}
char name[100];
Standard_Integer Count = 1;
for (j = 1; j <= Nv; j++)
{
for (i = 1; i <= Nu; i++)
{
Sprintf(name, "point_%d", Count++);
char* temp = name; // portage WNT
DrawTrSurf::Set(temp, Points(i, j));
}
}
GeomAPI_PointsToBSplineSurface anApprox;
if (RemoveLast)
{
TColgp_Array2OfPnt Points1(1, Nu - 1, 1, Nv);
for (j = 1; j <= Nv; j++)
{
for (i = 1; i <= Nu - 1; i++)
{
Points1(i, j) = Points(i, j);
}
}
anApprox.Init(Points1, Approx_ChordLength, 3, 8, GeomAbs_C2, 1.e-3, IsPeriodic);
}
else
{
anApprox.Init(Points, Approx_ChordLength, 3, 8, GeomAbs_C2, 1.e-3, IsPeriodic);
}
if (anApprox.IsDone())
{
const Handle(Geom_BSplineSurface)& S = anApprox.Surface();
DrawTrSurf::Set(a[1], S);
di << a[1];
}
return 0;
}
//=================================================================================================
static Standard_Integer surfint(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 5)
return 1;
Handle(Geom_Surface) Surf = DrawTrSurf::GetSurface(a[2]);
if (Surf.IsNull())
return 1;
Standard_Integer i, j;
Standard_Integer Nu = Draw::Atoi(a[3]);
Standard_Integer Nv = Draw::Atoi(a[4]);
TColgp_Array2OfPnt Points(1, Nu, 1, Nv);
Standard_Real U, V, U1, V1, U2, V2;
Surf->Bounds(U1, U2, V1, V2);
for (j = 1; j <= Nv; j++)
{
V = V1 + (j - 1) * (V2 - V1) / (Nv - 1);
for (i = 1; i <= Nu; i++)
{
U = U1 + (i - 1) * (U2 - U1) / (Nu - 1);
Points(i, j) = Surf->Value(U, V);
}
}
char name[100];
Standard_Integer Count = 1;
for (j = 1; j <= Nv; j++)
{
for (i = 1; i <= Nu; i++)
{
Sprintf(name, "point_%d", Count++);
char* temp = name; // portage WNT
DrawTrSurf::Set(temp, Points(i, j));
}
}
Standard_Boolean IsPeriodic = Standard_False;
if (n > 5)
{
Standard_Integer ip = Draw::Atoi(a[5]);
if (ip > 0)
IsPeriodic = Standard_True;
}
Standard_Boolean RemoveLast = Standard_False;
if (IsPeriodic)
{
for (j = 1; j <= Nv; j++)
{
Standard_Real d = Points(1, j).Distance(Points(Nu, j));
if (d <= Precision::Confusion())
{
RemoveLast = Standard_True;
break;
}
}
}
const Approx_ParametrizationType ParType = Approx_ChordLength;
GeomAPI_PointsToBSplineSurface anApprox;
if (RemoveLast)
{
TColgp_Array2OfPnt Points1(1, Nu - 1, 1, Nv);
for (j = 1; j <= Nv; j++)
{
for (i = 1; i <= Nu - 1; i++)
{
Points1(i, j) = Points(i, j);
}
}
anApprox.Interpolate(Points1, ParType, IsPeriodic);
}
else
{
anApprox.Interpolate(Points, ParType, IsPeriodic);
}
if (anApprox.IsDone())
{
const Handle(Geom_BSplineSurface)& S = anApprox.Surface();
DrawTrSurf::Set(a[1], S);
di << a[1];
}
else
{
di << "Interpolation not done \n";
}
return 0;
}
//=================================================================================================
static Standard_Integer extrema(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 3)
{
return 1;
}
Handle(Geom_Curve) GC1, GC2;
Handle(Geom_Surface) GS1, GS2;
Standard_Boolean isInfinitySolutions = Standard_False;
Standard_Real aMinDist = RealLast();
Standard_Real U1f, U1l, U2f, U2l, V1f = 0., V1l = 0., V2f = 0., V2l = 0.;
GC1 = DrawTrSurf::GetCurve(a[1]);
if (GC1.IsNull())
{
GS1 = DrawTrSurf::GetSurface(a[1]);
if (GS1.IsNull())
return 1;
GS1->Bounds(U1f, U1l, V1f, V1l);
}
else
{
U1f = GC1->FirstParameter();
U1l = GC1->LastParameter();
}
GC2 = DrawTrSurf::GetCurve(a[2]);
if (GC2.IsNull())
{
GS2 = DrawTrSurf::GetSurface(a[2]);
if (GS2.IsNull())
return 1;
GS2->Bounds(U2f, U2l, V2f, V2l);
}
else
{
U2f = GC2->FirstParameter();
U2l = GC2->LastParameter();
}
NCollection_Vector<gp_Pnt> aPnts1, aPnts2;
NCollection_Vector<Standard_Real> aPrms[4];
if (!GC1.IsNull() && !GC2.IsNull())
{
GeomAPI_ExtremaCurveCurve Ex(GC1, GC2, U1f, U1l, U2f, U2l);
// Since GeomAPI cannot provide access to flag directly.
isInfinitySolutions = Ex.Extrema().IsParallel();
if (isInfinitySolutions)
{
aMinDist = Ex.LowerDistance();
}
else
{
for (Standard_Integer aJ = 1; aJ <= Ex.NbExtrema(); ++aJ)
{
gp_Pnt aP1, aP2;
Ex.Points(aJ, aP1, aP2);
aPnts1.Append(aP1);
aPnts2.Append(aP2);
Standard_Real aU1, aU2;
Ex.Parameters(aJ, aU1, aU2);
aPrms[0].Append(aU1);
aPrms[2].Append(aU2);
}
}
}
else if (!GC1.IsNull() && !GS2.IsNull())
{
GeomAPI_ExtremaCurveSurface Ex(GC1, GS2, U1f, U1l, U2f, U2l, V2f, V2l);
isInfinitySolutions = Ex.Extrema().IsParallel();
if (isInfinitySolutions)
{
aMinDist = Ex.LowerDistance();
}
else
{
for (Standard_Integer aJ = 1; aJ <= Ex.NbExtrema(); ++aJ)
{
gp_Pnt aP1, aP2;
Ex.Points(aJ, aP1, aP2);
aPnts1.Append(aP1);
aPnts2.Append(aP2);
Standard_Real aU1, aU2, aV2;
Ex.Parameters(aJ, aU1, aU2, aV2);
aPrms[0].Append(aU1);
aPrms[2].Append(aU2);
aPrms[3].Append(aV2);
}
}
}
else if (!GS1.IsNull() && !GC2.IsNull())
{
GeomAPI_ExtremaCurveSurface Ex(GC2, GS1, U2f, U2l, U1f, U1l, V1f, V1l);
isInfinitySolutions = Ex.Extrema().IsParallel();
if (isInfinitySolutions)
{
aMinDist = Ex.LowerDistance();
}
else
{
for (Standard_Integer aJ = 1; aJ <= Ex.NbExtrema(); ++aJ)
{
gp_Pnt aP2, aP1;
Ex.Points(aJ, aP2, aP1);
aPnts1.Append(aP1);
aPnts2.Append(aP2);
Standard_Real aU1, aV1, aU2;
Ex.Parameters(aJ, aU2, aU1, aV1);
aPrms[0].Append(aU1);
aPrms[1].Append(aV1);
aPrms[2].Append(aU2);
}
}
}
else if (!GS1.IsNull() && !GS2.IsNull())
{
GeomAPI_ExtremaSurfaceSurface Ex(GS1, GS2, U1f, U1l, V1f, V1l, U2f, U2l, V2f, V2l);
// Since GeomAPI cannot provide access to flag directly.
isInfinitySolutions = Ex.Extrema().IsParallel();
if (isInfinitySolutions)
{
aMinDist = Ex.LowerDistance();
}
else
{
for (Standard_Integer aJ = 1; aJ <= Ex.NbExtrema(); ++aJ)
{
gp_Pnt aP1, aP2;
Ex.Points(aJ, aP1, aP2);
aPnts1.Append(aP1);
aPnts2.Append(aP2);
Standard_Real aU1, aV1, aU2, aV2;
Ex.Parameters(aJ, aU1, aV1, aU2, aV2);
aPrms[0].Append(aU1);
aPrms[1].Append(aV1);
aPrms[2].Append(aU2);
aPrms[3].Append(aV2);
}
}
}
char aName[100];
char* aName2 = aName; // portage WNT
// Output points.
const Standard_Integer aPntCount = aPnts1.Size();
if (aPntCount == 0 || isInfinitySolutions)
{
// Infinity solutions flag may be set with 0 number of
// solutions in analytic extrema Curve/Curve.
if (isInfinitySolutions)
di << "Infinite number of extremas, distance = " << aMinDist << "\n";
else
di << "No solutions!\n";
}
for (Standard_Integer aJ = 1; aJ <= aPntCount; aJ++)
{
gp_Pnt aP1 = aPnts1(aJ - 1), aP2 = aPnts2(aJ - 1);
if (aP1.Distance(aP2) < 1.e-16)
{
di << "Extrema " << aJ << " is point : " << aP1.X() << " " << aP1.Y() << " " << aP1.Z()
<< "\n";
continue;
}
Handle(Geom_Line) aL = new Geom_Line(aP1, gp_Vec(aP1, aP2));
Handle(Geom_TrimmedCurve) aCT = new Geom_TrimmedCurve(aL, 0., aP1.Distance(aP2));
Sprintf(aName, "%s%d", "ext_", aJ);
DrawTrSurf::Set(aName2, aCT);
di << aName << " ";
}
if (n >= 4)
{
// Output points.
for (Standard_Integer aJ = 1; aJ <= aPntCount; aJ++)
{
gp_Pnt aP1 = aPnts1(aJ - 1), aP2 = aPnts2(aJ - 1);
Sprintf(aName, "%s%d%s", "ext_", aJ, "_2");
DrawTrSurf::Set(aName2, aP1);
di << aName << " ";
Sprintf(aName, "%s%d%s", "ext_", aJ, "_3");
DrawTrSurf::Set(aName2, aP2);
di << aName << " ";
}
// Output parameters.
for (Standard_Integer aJ = 0; aJ < 4; ++aJ)
{
for (Standard_Integer aPrmCount = aPrms[aJ].Size(), aK = 0; aK < aPrmCount; ++aK)
{
Standard_Real aP = aPrms[aJ](aK);
Sprintf(aName, "%s%d%s%d", "prm_", aJ + 1, "_", aK + 1);
Draw::Set(aName2, aP);
di << aName << " ";
}
}
}
return 0;
}
//=================================================================================================
static Standard_Integer totalextcc(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if (n < 3)
return 1;
Handle(Geom_Curve) GC1, GC2;
Standard_Real U1f, U1l, U2f, U2l;
GC1 = DrawTrSurf::GetCurve(a[1]);
if (GC1.IsNull())
{
return 1;
}
else
{
U1f = GC1->FirstParameter();
U1l = GC1->LastParameter();
}
GC2 = DrawTrSurf::GetCurve(a[2]);
if (GC2.IsNull())
{
return 1;
}
else
{
U2f = GC2->FirstParameter();
U2l = GC2->LastParameter();
}
char name[100];
GeomAPI_ExtremaCurveCurve Ex(GC1, GC2, U1f, U1l, U2f, U2l);
gp_Pnt P1, P2;
if (Ex.TotalNearestPoints(P1, P2))
{
if (P1.Distance(P2) < 1.e-16)
{
di << "Extrema is point : " << P1.X() << " " << P1.Y() << " " << P1.Z() << "\n";
}
else
{
di << "Extrema is segment of line\n";
Handle(Geom_Line) L = new Geom_Line(P1, gp_Vec(P1, P2));
Handle(Geom_TrimmedCurve) CT = new Geom_TrimmedCurve(L, 0., P1.Distance(P2));
Sprintf(name, "%s%d", "ext_", 1);
char* temp = name; // portage WNT
DrawTrSurf::Set(temp, CT);
di << name << " ";
}
Standard_Real u1, u2;
Ex.TotalLowerDistanceParameters(u1, u2);
di << "Parameters on curves : " << u1 << " " << u2 << "\n";
}
else
{
di << "Curves are infinite and parallel\n";
}
di << "Minimal distance : " << Ex.TotalLowerDistance() << "\n";
return 0;
}
void GeometryTest::APICommands(Draw_Interpretor& theCommands)
{
static Standard_Boolean done = Standard_False;
if (done)
return;
done = Standard_True;
theCommands.Add("proj",
"proj curve/surf x y z [{extrema algo: g(grad)/t(tree)}|{u v}]\n"
"\t\tOptional parameters are relevant to surf only.\n"
"\t\tIf initial {u v} are given then local extrema is called",
__FILE__,
proj);
theCommands.Add("appro", "appro result nbpoint [curve]", __FILE__, appro);
theCommands.Add("surfapp", "surfapp result nbupoint nbvpoint x y z ....", __FILE__, surfapp);
theCommands.Add("surfint",
"surfint result surf nbupoint nbvpoint [uperiodic]",
__FILE__,
surfint);
theCommands.Add("grilapp",
"grilapp result nbupoint nbvpoint X0 dX Y0 dY z11 z12 .. z1nu .... ",
__FILE__,
grilapp);
theCommands.Add("extrema",
"extrema curve/surface curve/surface [extended_output = 0|1]",
__FILE__,
extrema);
theCommands.Add("totalextcc", "totalextcc curve curve", __FILE__, totalextcc);
}