Printing to a STL(stereolithography) file in binary mode - c++

I am trying to print to a stl file and can't print correctly.
There are lot of samples for Hex format printing in C++ but no sample program for binary format. My program is as follow. What is wrong with my program?
string name = "Create by stlwrite.m ";
name = name + currentDateTime();
pFile.setf(ios::left);
pFile.width(sizeof(unsigned char)*80);
//header
pFile << name;
unsigned int size = faces.rows;
//size
pFile.write((char*)&size,sizeof(size));
int height = 25;
unsigned short ** data= new unsigned short *[height];
for(int i = 0; i < height; i++)
{
data[i] = new unsigned short[142000];
}
for(int j = 0; j < 142000; j++)
{
int i = 0;
//for one facets
for(int k = 0; k < (*facets[j]).cols; k++)
{
for(int l = 0; l < (*facets[j]).rows; l++)
{
float f = (*facets[j]).at<float>(l,k);
data[i][j] = *reinterpret_cast<unsigned int *>(&f);
data[i+1][j] = *reinterpret_cast<unsigned int *>(&f)>>16;
i = i + 2;
}
}
//then for the last row
data[height-1][j] = (unsigned short)0;
}
for (int i = 0; i < height; i++)
for (int j = 0; j < faces.rows; j++)
pFile.write ((char*)&data[i][j], sizeof(unsigned short) );
pFile.close();
EDIT1: I follow the idea of Matlab stlwrite.mat program.link

This is the C code to print in binary mode.
The calling function is:
stl_write_binary(X, Y, path)
Where X is 3xM Vertices matrix and Y is 3xN faces matrix. Both are in OpenCV's Mat structure.
Path is the path to store the STL file you can modify it according to your requirement.
The whole code is:
int stl_write_binary(Mat &vertemp, Mat &faces, PathToFolders &path)
{
Mat vertices(vertemp.cols,vertemp.rows,vertemp.type());
vertices = vertemp.t();
cv::Mat** facets = new cv::Mat*[faces.rows];
for(int i = 0; i < faces.rows; i++)
{
facets[i] = new cv::Mat(3,4,CV_32F);
for(int j = 0; j < 3; j++)
{
vertices(Range::all(),Range(faces.at<int>(i,j),faces.at<int>(i,j)+1)).convertTo((*(facets[i]))(Range::all(),Range(j+1,j+2)), CV_32F);
}
}
//Compute their normals
Mat V1(3,faces.rows,CV_32F);
Mat V2(3,faces.rows,CV_32F);
for(int i = 0; i < faces.rows; i++)
{
V1(Range::all(),Range(i,i+1)) = ((*(facets[i]))(Range::all(),Range(2,3))) - ((*(facets[i]))(Range::all(),Range(1,2)));
V2(Range::all(),Range(i,i+1)) = ((*(facets[i]))(Range::all(),Range(3,4))) - ((*(facets[i]))(Range::all(),Range(1,2)));
}
Mat V3(3,faces.rows,CV_32F);
Mat V4(3,faces.rows,CV_32F);
Mat V5(3,faces.rows,CV_32F);
Mat V6(3,faces.rows,CV_32F);
V1(Range(1,2),Range::all()).copyTo(V3(Range(0,1),Range::all()));
V1(Range(2,3),Range::all()).copyTo(V3(Range(1,2),Range::all()));
V1(Range(0,1),Range::all()).copyTo(V3(Range(2,3),Range::all()));
V2(Range(2,3),Range::all()).copyTo(V4(Range(0,1),Range::all()));
V2(Range(0,1),Range::all()).copyTo(V4(Range(1,2),Range::all()));
V2(Range(1,2),Range::all()).copyTo(V4(Range(2,3),Range::all()));
V2(Range(1,2),Range::all()).copyTo(V5(Range(0,1),Range::all()));
V2(Range(2,3),Range::all()).copyTo(V5(Range(1,2),Range::all()));
V2(Range(0,1),Range::all()).copyTo(V5(Range(2,3),Range::all()));
V1(Range(2,3),Range::all()).copyTo(V6(Range(0,1),Range::all()));
V1(Range(0,1),Range::all()).copyTo(V6(Range(1,2),Range::all()));
V1(Range(1,2),Range::all()).copyTo(V6(Range(2,3),Range::all()));
Mat normals(3,faces.rows,CV_32F);
normals = V3.mul(V4) - V5.mul(V6);
V1.release();
V2.release();
V3.release();
V4.release();
V5.release();
V6.release();
Mat normalsqu(3,faces.rows,CV_32F);
Mat normalsqu_colm_summed(1,faces.rows,CV_32F);
normalsqu = normals.mul(normals);
cv::reduce(normalsqu, normalsqu_colm_summed, 0, CV_REDUCE_SUM, CV_32F);
cv::sqrt(normalsqu_colm_summed,normalsqu_colm_summed);//check mem leak
normalsqu.release();
normalsqu_colm_summed = 1/normalsqu_colm_summed;
for(int i = 0; i < faces.rows; i++)
{
normals(Range::all(),Range(i,i+1)) = normals(Range::all(),Range(i,i+1)) * normalsqu_colm_summed.at<float>(i);
}
normalsqu_colm_summed.release();
for(int i = 0; i < faces.rows; i++)
{
normals(Range::all(),Range(i,i+1)).copyTo(((*(facets[i]))(Range::all(),Range(0,1))));
}
normals.release();
//write to stl file
//get file paths
std::vector<std::string> masktoken;
split(path.pathtoimages, '/', masktoken);
path.pathtoSTL = path.pathtoSTL+masktoken[0];
for(int i = 1; i < masktoken.size()-1; i++)
{
path.pathtoSTL = path.pathtoSTL+"/"+masktoken[i];
}
path.pathtoSTL = path.pathtoSTL+"/"+"mesh.stl";
cout<<"Saving file to "<<path.pathtoSTL<<endl;
const char * c = path.pathtoSTL.c_str();
ofstream pFile;
pFile.open (c, ios::out | ios::binary);
if (pFile.is_open())
{
string name = "Create by stlwrite.m ";
name = name + currentDateTime();
pFile.setf(ios::left);
pFile.width(sizeof(unsigned char)*80);
//header
pFile << name;
unsigned int size = faces.rows;
//size
pFile.write((char*)&size,sizeof(size));
int height = (*facets[0]).rows * (*facets[0]).cols * 2 + 1;
unsigned short ** data= new unsigned short *[height];
for(int i = 0; i < height; i++)
{
data[i] = new unsigned short[faces.rows];
}
for(int j = 0; j < faces.rows; j++)
{
int i = 0;
//for one facets
for(int k = 0; k < (*facets[j]).cols; k++)
{
for(int l = 0; l < (*facets[j]).rows; l++)
{
float f = (*facets[j]).at<float>(l,k);
data[i][j] = *reinterpret_cast<unsigned int *>(&f);
data[i+1][j] = *reinterpret_cast<unsigned int *>(&f)>>16;
i = i + 2;
}
}
//then for the last row
data[height-1][j] = (unsigned short)0;
}
for (int i = 0; i < faces.rows; i++)
for (int j = 0; j < height; j++)
pFile.write ((char*)&data[j][i], sizeof(unsigned short) );
pFile.close();
//fclose (pFile);
//delete table
for(int i = 0; i < height; i++)
{
delete[] data[i];
}
delete[] data;
}else{
cout<<"stlwrite:cannotWriteFile"<<" "<<"Unable to write to"<<" "<<path.pathtoSTL<<endl;
}
for(int i = 0; i < faces.rows; i++)
{
(*facets[i]).release();
}
delete[] facets;
return 1;
}

Related

My code is realy slow and i need optimization problem

#include <iostream>
#include <chrono>
using namespace std;
int main()
{
const unsigned int m = 200;
const unsigned int n = 200;
srand(static_cast<unsigned int>(static_cast<std::chrono::duration<double>
>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()));
double** matrixa;
double** matrixb;
double** matrixc;
matrixa = new double* [m];
matrixb = new double* [m];
matrixc = new double* [m];
unsigned int max = static_cast<unsigned int>(1u << 31);
for (unsigned int i = 0; i < m; i++)
matrixa[i] = new double[n];
for (unsigned int i = 0; i < m; i++)
matrixb[i] = new double[n];
for (unsigned int i = 0; i < m; i++)
matrixc[i] = new double[n];
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = 0; j < n; j++)
matrixa[i]
[j] = static_cast<double>(static_cast<double>(rand()) / max * 10);
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = 0; j < n; j++)
matrixb[i]
[j] = static_cast<double>(static_cast<double>(rand()) / max * 10);
auto start = std::chrono::high_resolution_clock::now();
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = 0; j < n; j++)
for (unsigned int k = 0; k < m; k++)
for (unsigned int l = 0; l < m; l++)
matrixc[i][j] += matrixa[k][l] * matrixb[l][k];
auto stop = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> time_diff = stop - start;
cout << "Czas wykonania programu " << time_diff.count() << " sekund." <<
endl;
for (unsigned int i = 0; i < m; i++)
delete[] matrixa[i];
for (unsigned int i = 0; i < m; i++)
delete[] matrixb[i];
for (unsigned int i = 0; i < m; i++)
delete[] matrixc[i];
delete[] matrixa;
delete[] matrixb;
delete[] matrixc;
return 0;
}
I have this code and I would like to optimize it, unfortunately I have absolutely no idea how to go about it. Maybe someone has an idea and would like to help me? I got to the point where the program for 400 arrays executes 105 seconds but it is still too much, I would like to optimize this code to run faster. I found OpenMP library and thread class but I don't know how to use it in my program.
Firstly, your matrix multiply algorithm is over complex than a normal one(Or it's just wrong), you may reference the wiki for a typical algorithm:
Input: matrices A and B
Let C be a new matrix of the appropriate size
For i from 1 to n:
For j from 1 to p:
Let sum = 0
For k from 1 to m:
Set sum ← sum + Aik × Bkj
Set Cij ← sum
Return C
There is a critical bug in your code, you haven't initialized the result matrix.
So the fixed code may like this:
#include <chrono>
#include <iostream>
using namespace std;
int main() {
const unsigned int m = 200;
const unsigned int n = 201;
const unsigned int p = 202;
srand(static_cast<unsigned int>(
static_cast<std::chrono::duration<double> >(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count()));
double** matrixa;
double** matrixb;
double** matrixc;
matrixa = new double*[m];
matrixb = new double*[n];
matrixc = new double*[m];
unsigned int max = static_cast<unsigned int>(1u << 31);
for (unsigned int i = 0; i < m; i++) matrixa[i] = new double[n];
for (unsigned int i = 0; i < n; i++) matrixb[i] = new double[p];
for (unsigned int i = 0; i < m; i++) {
matrixc[i] = new double[p];
std::fill(matrixc[i], matrixc[i] + p, 0.0);
}
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = 0; j < n; j++)
matrixa[i][j] =
static_cast<double>(static_cast<double>(rand()) / max * 10);
for (unsigned int i = 0; i < n; i++)
for (unsigned int j = 0; j < p; j++)
matrixb[i][j] =
static_cast<double>(static_cast<double>(rand()) / max * 10);
auto start = std::chrono::high_resolution_clock::now();
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = 0; j < p; j++)
for (unsigned int k = 0; k < n; k++)
matrixc[i][j] += matrixa[i][k] * matrixb[k][j];
auto stop = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> time_diff = stop - start;
cout << "Czas wykonania programu " << time_diff.count() << " sekund." << endl;
for (unsigned int i = 0; i < m; i++) delete[] matrixa[i];
for (unsigned int i = 0; i < n; i++) delete[] matrixb[i];
for (unsigned int i = 0; i < m; i++) delete[] matrixc[i];
delete[] matrixa;
delete[] matrixb;
delete[] matrixc;
return 0;
}
Now it's much faster than the one in question.
It still can be faster with slightly modification:
#include <chrono>
#include <iostream>
using namespace std;
int main() {
const unsigned int m = 200;
const unsigned int n = 201;
const unsigned int p = 202;
srand(static_cast<unsigned int>(
static_cast<std::chrono::duration<double> >(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count()));
double** matrixa;
double** matrixb;
double** matrixc;
matrixa = new double*[m];
matrixb = new double*[n];
matrixc = new double*[m];
unsigned int max = static_cast<unsigned int>(1u << 31);
for (unsigned int i = 0; i < m; i++) matrixa[i] = new double[n];
for (unsigned int i = 0; i < n; i++) matrixb[i] = new double[p];
for (unsigned int i = 0; i < m; i++) {
matrixc[i] = new double[p];
std::fill(matrixc[i], matrixc[i] + p, 0.0);
}
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = 0; j < n; j++)
matrixa[i][j] =
static_cast<double>(static_cast<double>(rand()) / max * 10);
for (unsigned int i = 0; i < n; i++)
for (unsigned int j = 0; j < p; j++)
matrixb[i][j] =
static_cast<double>(static_cast<double>(rand()) / max * 10);
auto start = std::chrono::high_resolution_clock::now();
for (unsigned int i = 0; i < m; i++)
for (unsigned int k = 0; k < n; k++)
for (unsigned int j = 0; j < p; j++)
matrixc[i][j] += matrixa[i][k] * matrixb[k][j];
auto stop = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> time_diff = stop - start;
cout << "Czas wykonania programu " << time_diff.count() << " sekund." << endl;
for (unsigned int i = 0; i < m; i++) delete[] matrixa[i];
for (unsigned int i = 0; i < n; i++) delete[] matrixb[i];
for (unsigned int i = 0; i < m; i++) delete[] matrixc[i];
delete[] matrixa;
delete[] matrixb;
delete[] matrixc;
return 0;
}
This code is more cache-friendly, the explanation can be found here.
The code can still be improved by a parallel algorithm, to speed up the previous code with OpenMP, with only one line change:
Add we need to add the build option -fopenmp to compile it.
#include <chrono>
#include <iostream>
using namespace std;
int main() {
const unsigned int m = 200;
const unsigned int n = 201;
const unsigned int p = 202;
srand(static_cast<unsigned int>(
static_cast<std::chrono::duration<double> >(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count()));
double** matrixa;
double** matrixb;
double** matrixc;
matrixa = new double*[m];
matrixb = new double*[n];
matrixc = new double*[m];
unsigned int max = static_cast<unsigned int>(1u << 31);
for (unsigned int i = 0; i < m; i++) matrixa[i] = new double[n];
for (unsigned int i = 0; i < n; i++) matrixb[i] = new double[p];
for (unsigned int i = 0; i < m; i++) {
matrixc[i] = new double[p];
std::fill(matrixc[i], matrixc[i] + p, 0.0);
}
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = 0; j < n; j++)
matrixa[i][j] =
static_cast<double>(static_cast<double>(rand()) / max * 10);
for (unsigned int i = 0; i < n; i++)
for (unsigned int j = 0; j < p; j++)
matrixb[i][j] =
static_cast<double>(static_cast<double>(rand()) / max * 10);
auto start = std::chrono::high_resolution_clock::now();
#pragma omp parallel for
for (unsigned int i = 0; i < m; i++)
for (unsigned int k = 0; k < n; k++)
for (unsigned int j = 0; j < p; j++)
matrixc[i][j] += matrixa[i][k] * matrixb[k][j];
auto stop = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> time_diff = stop - start;
cout << "Czas wykonania programu " << time_diff.count() << " sekund." << endl;
for (unsigned int i = 0; i < m; i++) delete[] matrixa[i];
for (unsigned int i = 0; i < n; i++) delete[] matrixb[i];
for (unsigned int i = 0; i < m; i++) delete[] matrixc[i];
delete[] matrixa;
delete[] matrixb;
delete[] matrixc;
return 0;
}
It would be better to use std::vector rather than dynamically allocated arrays, the work is left for you.

How to read a 100x24 matrix from file and keep it in memory as a float matrix?

Here is my code, i can save data in char matrix, but i want to save it in float matrix
const unsigned int HEIGHT = 100;
const unsigned int WIDTH = 24 ;
char arr[HEIGHT][WIDTH];
ifstream fin;
fin.open("PW.txt");
string line;
//let's assume here the proper size of input Map
for (unsigned int i = 0; i < HEIGHT; i++)
{
getline(fin, line);
for (unsigned int j = 0; j < WIDTH; j++)
{
arr[i][j] = line[j];
}
}
//let's assume here the proper size of input Map
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
cout << arr[i][j] ;
}
cout << endl;
}
If you search the internet for "c++ read file matrix" you may see code like this:
static const int MAX_ROWS = 100;
static const int MAX_COLUMNS = 24;
//...
double matrix[MAX_ROWS][MAX_COLUMNS];
double value = 0.0;
for (int row = 0; row < MAX_ROWS; ++row)
{
for (int column = 0; column < MAX_COLUMNS; ++column)
{
text_file >> value;
matrix[row][column] = value;
}
}
You can read a matrix of float by changing the data type from double to float.

window operation by Pointer of image

If we access pixel by a pointer using step and data of Mat Image. see example below
int step = srcimg.step;
for (int j = 0; j < srcimg.rows; j++) {
for (int i = 0; i < srcimg.cols; i++) {
//this is pointer to the pixel value.
uchar* ptr = srcimg.data + step* j + i;
}
}
Question:
How can we perform 3x3 weighted avg operations with image step by a pointer?
thanks
You mustn't use data field in opencv because memory is not allways continuous. you can check this using isContinuous() method.
Now you can do like this (image type is CV_8UC1)
for (int i = 1; i < srcimg.rows-1; i++)
{
for (int j = 1; j < srcimg.cols-1; j++)
{
int x=0;
for (int k=-1;k<=1;k++)
{
uchar* ptr=srcimg.ptr(k+i)+j-1;
for (int l=-1;l<=1;l++,ptr++)
x +=*ptr;
}
}
}
image border are not processed. Now if you want to blur an image use blur method
You can use this post too
I am doing something like this .
int sr = 3;
for (int j = 0; j < srcimg.rows; j++) {
for (int i = 0; i < srcimg.cols; i++) {
uchar* cp_imptr = im.data;
uchar* tptr = im.data + imstep *(sr + j) + (sr + i);
int val_tptr = cp_imptr [imstep *(sr + j) + (sr + i)]; //pointer of image data amd step at 3x3
int val_cp_imptr = cp_imptr[imstep *j + i];
double s = 0;
for (int n = templeteWindowSize; n--;)
{
for (int m = templeteWindowSize; m--;)
{
uchar* t = tptr; //pointer of template
// sum
s += *t;
t++;
}
t += cstep;
}
}
cout << endl;
}

How to find unique labels for segments in SuperpixelSLIC

I am using cv::ximgproc::SuperpixelSLIC opencv c++ to generate segments of image. I want each segment label to be unique. Here is my code.
Mat segmentImage() {
int num_iterations = 4;
int prior = 2;
bool double_step = false;
int num_levels = 10;
int num_histogram_bins = 5;
int width, height;
width = h1.size().width;
height = h1.size().height;
seeds = createSuperpixelSLIC(h1);
Mat mask;
seeds->iterate(num_iterations);
Mat labels;
seeds->getLabels(labels);
for (int i = 0; i < labels.rows; i++) {
for (int j = 0; j < labels.cols; j++) {
if (labels.at<int>(i, j) == 0)
cout << i << " " << j << " " << labels.at<int>(i, j) << endl;
}
}
ofstream myfile;
myfile.open("label.txt");
myfile << labels;
myfile.close();
seeds->getLabelContourMask(mask, false);
h1.setTo(Scalar(0, 0, 255), mask);
imshow("result", h1);
imwrite("result.png", h1);
return labels;
}
In label.txt file I observe that label 0 has been given to two segments (i.e. segment include pixel(0,0) and pixel(692,442). These two segments are pretty far away.
Is this normal thing or my code is incorrect. Please help me to find unique label for each segment.
What you essentially need is a connected components algorithm. Without knowing the exact SLIC implementation you use, SLIC usually tends to produce disconnected superpixels, i.e. disconnected segments with the same label. A simple solution I used is the connected components algorithm form here: https://github.com/davidstutz/matlab-multi-label-connected-components (originally from here: http://xenia.media.mit.edu/~rahimi/connected/). Note that this repository contains a MatLab wrapper. In your case you only need connected_components.h together with the following code:
#include "connected_components.h"
// ...
void relabelSuperpixels(cv::Mat &labels) {
int max_label = 0;
for (int i = 0; i < labels.rows; i++) {
for (int j = 0; j < labels.cols; j++) {
if (labels.at<int>(i, j) > max_label) {
max_label = labels.at<int>(i, j);
}
}
}
int current_label = 0;
std::vector<int> label_correspondence(max_label + 1, -1);
for (int i = 0; i < labels.rows; i++) {
for (int j = 0; j < labels.cols; j++) {
int label = labels.at<int>(i, j);
if (label_correspondence[label] < 0) {
label_correspondence[label] = current_label++;
}
labels.at<int>(i, j) = label_correspondence[label];
}
}
}
int relabelConnectedSuperpixels(cv::Mat &labels) {
relabelSuperpixels(labels);
int max = 0;
for (int i = 0; i < labels.rows; ++i) {
for (int j = 0; j < labels.cols; ++j) {
if (labels.at<int>(i, j) > max) {
max = labels.at<int>(i, j);
}
}
}
ConnectedComponents cc(2*max);
cv::Mat components(labels.rows, labels.cols, CV_32SC1, cv::Scalar(0));
int component_count = cc.connected<int, int, std::equal_to<int>, bool>((int*) labels.data, (int*) components.data, labels.cols,
labels.rows, std::equal_to<int>(), false);
for (int i = 0; i < labels.rows; i++) {
for (int j = 0; j < labels.cols; j++) {
labels.at<int>(i, j) = components.at<int>(i, j);
}
}
// component_count would be the NEXT label index, max is the current highest!
return component_count - max - 1;
}
On the obtained labels, run relabelConnectedSuperpixels.

How to add chars to 2D array?

My code:
FILE * file;
file = fopen("c://catalog//file.txt", "r");
int m,n; //size of 2d array (m x n)
fscanf(file, "%d", &m);
fscanf(file, "%d", &n);
fclose(file);
printf("Size: %d x %d\n", m, n);
// create 2d array
char **TAB2 = new char*[m];
for (int i = 0; i < m; i++)
char *TAB2 = new char[n];
// display 2d array
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++)
{
printf("%c ", &TAB2[i][j]);
}
printf("\n");
}
How fill this array with chars or string? for example text = "someting", and for array 3x5 will be:
S o m e t
h i n g ?
? ? ? ? ?
I tried: TAB2[0][0] = 's'; *&TAB2[0][0] = 's'; for one char, and this does'nt work...
Probably I badly use pointers(?). Anyone help me?
The dynamic allocation array is wrong.
char **TAB2 = new char*[m];
for (int i = 0; i < m; ++i)
TAB2[i] = new char[n];
Check this link for help.
You could try this:
#include<iostream>
using namespace std;
int main() {
const int m = 3, n = 5;
char **TAB2 = new char*[m];
for (int i = 0; i < m; ++i)
TAB2[i] = new char[n];
char c;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
std::cin >> c;
TAB2[i][j] = c;
}
}
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
std::cout << TAB2[i][j];
}
std::cout << "\n";
}
// NEVER FORGET TO FREE YOUR DYNAMIC MEMORY
for(int i = 0; i < m; ++i)
delete [] TAB2[i];
delete [] TAB2;
return 0;
}
Output:
jorje
georg
klouv
jorje
georg
klouv
Important links:
How do I declare a 2d array in C++ using new?
How do I use arrays in C++?
The allocation of the array seems incorrect; it should be as follows.
char **TAB2 = new char*[m];
for (int i = 0; i < m; i++)
TAB2[i] = new char[n];