42 #include <visp3/core/vpXmlParserCamera.h> 44 #ifdef VISP_HAVE_PUGIXML 46 #include <pugixml.hpp> 48 #include <visp3/core/vpDebug.h> 56 #define LABEL_XML_ROOT "root" 57 #define LABEL_XML_CAMERA "camera" 58 #define LABEL_XML_CAMERA_NAME "name" 59 #define LABEL_XML_WIDTH "image_width" 60 #define LABEL_XML_HEIGHT "image_height" 61 #define LABEL_XML_SUBSAMPLING_WIDTH "subsampling_width" 62 #define LABEL_XML_SUBSAMPLING_HEIGHT "subsampling_height" 63 #define LABEL_XML_FULL_WIDTH "full_width" 64 #define LABEL_XML_FULL_HEIGHT "full_height" 65 #define LABEL_XML_MODEL "model" 66 #define LABEL_XML_MODEL_TYPE "type" 67 #define LABEL_XML_U0 "u0" 68 #define LABEL_XML_V0 "v0" 69 #define LABEL_XML_PX "px" 70 #define LABEL_XML_PY "py" 71 #define LABEL_XML_KUD "kud" 72 #define LABEL_XML_KDU "kdu" 74 #define LABEL_XML_MODEL_WITHOUT_DISTORTION "perspectiveProjWithoutDistortion" 75 #define LABEL_XML_MODEL_WITH_DISTORTION "perspectiveProjWithDistortion" 77 #define LABEL_XML_ADDITIONAL_INFO "additional_information" 79 #ifndef DOXYGEN_SHOULD_SKIP_THIS 80 class vpXmlParserCamera::Impl
92 CODE_XML_SUBSAMPLING_WIDTH,
93 CODE_XML_SUBSAMPLING_HEIGHT,
104 CODE_XML_ADDITIONAL_INFO
108 Impl() : camera(), camera_name(), image_width(0), image_height(0), subsampling_width(0),
109 subsampling_height(0), full_width(0), full_height(0)
115 unsigned int im_width,
unsigned int im_height)
117 pugi::xml_document doc;
118 if (!doc.load_file(filename.c_str())) {
122 pugi::xml_node node = doc.document_element();
127 int ret = read(node, cam_name, projModel, im_width, im_height);
149 int read(
const pugi::xml_node &node_,
const std::string &cam_name,
151 unsigned int im_width,
unsigned int im_height,
152 unsigned int subsampl_width=0,
unsigned int subsampl_height=0)
157 unsigned int nbCamera = 0;
159 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
160 if (node.type() != pugi::node_element)
163 if (
SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
164 prop = CODE_XML_OTHER;
167 if (prop == CODE_XML_CAMERA) {
169 read_camera(node, cam_name, projModel, im_width, im_height, subsampl_width, subsampl_height))
177 vpCERROR <<
"No camera parameters is available" << std::endl <<
"with your specifications" << std::endl;
178 }
else if (nbCamera > 1) {
180 vpCERROR << nbCamera <<
" sets of camera parameters are available" << std::endl
181 <<
"with your specifications : " << std::endl
182 <<
"precise your choice..." << std::endl;
203 int read_camera(
const pugi::xml_node &node_,
const std::string &cam_name,
205 unsigned int im_width,
unsigned int im_height,
206 unsigned int subsampl_width,
unsigned int subsampl_height)
210 std::string camera_name_tmp =
"";
211 unsigned int image_height_tmp = 0;
212 unsigned int image_width_tmp = 0;
213 unsigned int subsampling_width_tmp = 0;
214 unsigned int subsampling_height_tmp = 0;
217 bool projModelFound =
false;
220 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
221 if (node.type() != pugi::node_element)
224 if (
SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
225 prop = CODE_XML_OTHER;
230 case CODE_XML_CAMERA_NAME: {
231 camera_name_tmp = node.text().as_string();
232 std::cout <<
"Found camera with name: \"" << camera_name_tmp <<
"\"" << std::endl;
236 image_width_tmp = node.text().as_uint();
239 case CODE_XML_HEIGHT:
240 image_height_tmp = node.text().as_uint();
242 case CODE_XML_SUBSAMPLING_WIDTH:
243 subsampling_width_tmp = node.text().as_uint();
245 case CODE_XML_SUBSAMPLING_HEIGHT:
246 subsampling_height_tmp = node.text().as_uint();
250 back = read_camera_model(node, cam_tmp_model);
252 cam_tmp = cam_tmp_model;
253 projModelFound =
true;
257 case CODE_XML_ADDITIONAL_INFO:
262 case CODE_XML_CAMERA:
263 case CODE_XML_FULL_HEIGHT:
264 case CODE_XML_FULL_WIDTH:
265 case CODE_XML_MODEL_TYPE:
279 bool test_subsampling_width =
true;
280 bool test_subsampling_height =
true;
282 if (subsampling_width) {
283 test_subsampling_width = (abs((
int)subsampl_width - (
int)subsampling_width_tmp) <
284 (allowedPixelDiffOnImageSize * (int)(subsampling_width_tmp / subsampling_width)));
286 if (subsampling_height) {
287 test_subsampling_height = (abs((
int)subsampl_height - (
int)subsampling_height_tmp) <
288 (allowedPixelDiffOnImageSize * (int)(subsampling_height_tmp / subsampling_height)));
290 if (!((projModelFound ==
true) && (cam_name == camera_name_tmp) &&
291 (abs((
int)im_width - (int)image_width_tmp) < allowedPixelDiffOnImageSize || im_width == 0) &&
292 (abs((
int)im_height - (int)image_height_tmp) < allowedPixelDiffOnImageSize || im_height == 0) &&
293 (test_subsampling_width) && (test_subsampling_height))) {
297 camera_name = camera_name_tmp;
298 image_width = image_width_tmp;
299 image_height = image_height_tmp;
300 subsampling_width = subsampling_width_tmp;
301 subsampling_height = subsampling_height_tmp;
302 full_width = subsampling_width_tmp * image_width_tmp;
303 full_height = subsampling_height_tmp * image_height_tmp;
322 std::string model_type =
"";
323 double u0 = cam_tmp.
get_u0();
324 double v0 = cam_tmp.
get_v0();
325 double px = cam_tmp.
get_px();
326 double py = cam_tmp.
get_py();
327 double kud = cam_tmp.
get_kud();
328 double kdu = cam_tmp.
get_kdu();
332 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
334 if (node.type() != pugi::node_element)
337 if (
SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
338 prop = CODE_XML_OTHER;
343 case CODE_XML_MODEL_TYPE: {
344 model_type = node.text().as_string();
346 validation = validation | 0x01;
349 u0 = node.text().as_double();
351 validation = validation | 0x02;
354 v0 = node.text().as_double();
356 validation = validation | 0x04;
359 px = node.text().as_double();
361 validation = validation | 0x08;
364 py = node.text().as_double();
366 validation = validation | 0x10;
369 kud = node.text().as_double();
371 validation = validation | 0x20;
374 kdu = node.text().as_double();
376 validation = validation | 0x40;
380 case CODE_XML_CAMERA:
381 case CODE_XML_CAMERA_NAME:
382 case CODE_XML_HEIGHT:
384 case CODE_XML_SUBSAMPLING_WIDTH:
385 case CODE_XML_SUBSAMPLING_HEIGHT:
386 case CODE_XML_FULL_HEIGHT:
387 case CODE_XML_FULL_WIDTH:
389 case CODE_XML_ADDITIONAL_INFO:
396 if (model_type.empty()) {
397 vpERROR_TRACE(
"projection model type doesn't match with any known model !");
401 if (!strcmp(model_type.c_str(), LABEL_XML_MODEL_WITHOUT_DISTORTION)) {
402 if (nb != 5 || validation != 0x1F) {
403 vpCERROR <<
"ERROR in 'model' field:\n";
404 vpCERROR <<
"it must contain 5 parameters\n";
409 }
else if (!strcmp(model_type.c_str(), LABEL_XML_MODEL_WITH_DISTORTION)) {
410 if (nb != 7 || validation != 0x7F) {
411 vpCERROR <<
"ERROR in 'model' field:\n";
412 vpCERROR <<
"it must contain 7 parameters\n";
418 vpERROR_TRACE(
"projection model type doesn't match with any known model !");
427 unsigned int im_width,
unsigned int im_height,
428 const std::string &additionalInfo)
430 pugi::xml_document doc;
433 if (!doc.load_file(filename.c_str(), pugi::parse_default | pugi::parse_comments)) {
434 node = doc.append_child(pugi::node_declaration);
435 node.append_attribute(
"version") =
"1.0";
436 node = doc.append_child(LABEL_XML_ROOT);
437 pugi::xml_node nodeComment = node.append_child(pugi::node_comment);
438 nodeComment.set_value(
"This file stores intrinsic camera parameters used\n" 439 " in the vpCameraParameters Class of ViSP available\n" 440 " at https://visp.inria.fr/download/ .\n" 441 " It can be read with the parse method of\n" 442 " the vpXmlParserCamera class.");
445 node = doc.document_element();
452 int nbCamera = count(node, cam_name, cam.
get_projModel(), im_width, im_height);
457 pugi::xml_node nodeCamera = find_camera(node, cam_name, im_width, im_height);
459 write(node, cam_name, im_width, im_height);
461 write_camera(nodeCamera);
464 if (!additionalInfo.empty()) {
466 nodeCamera = find_camera(node, cam_name, im_width, im_height);
469 pugi::xml_node nodeAdditionalInfo = find_additional_info(nodeCamera);
471 if (!nodeAdditionalInfo) {
473 pugi::xml_node node_comment = nodeCamera.append_child(pugi::node_comment);
474 node_comment.set_value(
"Additional information");
476 nodeAdditionalInfo = nodeCamera.append_child(LABEL_XML_ADDITIONAL_INFO);
479 if (nodeAdditionalInfo) {
481 pugi::xml_document tmpDoc;
482 if (tmpDoc.load_string(additionalInfo.c_str())) {
483 for (node = tmpDoc.first_child(); node; node = node.next_sibling()) {
484 nodeAdditionalInfo.append_copy(node);
490 doc.save_file(filename.c_str(), PUGIXML_TEXT(
" "));
511 int count(
const pugi::xml_node &node_,
const std::string &cam_name,
513 unsigned int im_width,
unsigned int im_height,
514 unsigned int subsampl_width=0,
unsigned int subsampl_height=0)
519 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
520 if (node.type() != pugi::node_element)
523 if (
SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
524 prop = CODE_XML_OTHER;
527 if (prop == CODE_XML_CAMERA) {
529 read_camera(node, cam_name, projModel, im_width, im_height, subsampl_width, subsampl_height))
553 pugi::xml_node find_camera(
const pugi::xml_node &node_,
const std::string &cam_name,
554 unsigned int im_width,
unsigned int im_height,
555 unsigned int subsampl_width=0,
unsigned int subsampl_height=0)
559 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
560 if (node.type() != pugi::node_element)
563 if (
SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
564 prop = CODE_XML_OTHER;
566 if (prop == CODE_XML_CAMERA) {
567 if (
SEQUENCE_OK == read_camera_header(node, cam_name, im_width, im_height, subsampl_width, subsampl_height)) {
572 return pugi::xml_node();
590 int read_camera_header(
const pugi::xml_node &node_,
const std::string &cam_name,
591 unsigned int im_width,
unsigned int im_height,
592 unsigned int subsampl_width=0,
unsigned int subsampl_height=0)
596 std::string camera_name_tmp =
"";
597 unsigned int image_height_tmp = 0;
598 unsigned int image_width_tmp = 0;
599 unsigned int subsampling_width_tmp = 0;
600 unsigned int subsampling_height_tmp = 0;
603 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
604 if (node.type() != pugi::node_element)
606 if (
SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
607 prop = CODE_XML_OTHER;
612 case CODE_XML_CAMERA_NAME:
613 camera_name_tmp = node.text().as_string();
617 image_width_tmp = node.text().as_uint();
620 case CODE_XML_HEIGHT:
621 image_height_tmp = node.text().as_uint();
624 case CODE_XML_SUBSAMPLING_WIDTH:
625 subsampling_width_tmp = node.text().as_uint();
628 case CODE_XML_SUBSAMPLING_HEIGHT:
629 subsampling_height_tmp = node.text().as_uint();
635 case CODE_XML_ADDITIONAL_INFO:
640 case CODE_XML_CAMERA:
641 case CODE_XML_FULL_HEIGHT:
642 case CODE_XML_FULL_WIDTH:
643 case CODE_XML_MODEL_TYPE:
655 if (!((cam_name == camera_name_tmp) && (im_width == image_width_tmp || im_width == 0) &&
656 (im_height == image_height_tmp || im_height == 0) &&
657 (subsampl_width == subsampling_width_tmp || subsampl_width == 0) &&
658 (subsampl_height == subsampling_height_tmp || subsampl_height == 0))) {
679 int write(pugi::xml_node &node,
const std::string &cam_name,
unsigned int im_width,
680 unsigned int im_height,
unsigned int subsampl_width=0,
681 unsigned int subsampl_height=0)
686 pugi::xml_node node_camera = node.append_child(LABEL_XML_CAMERA);
688 pugi::xml_node node_tmp;
691 if (!cam_name.empty()) {
692 node_tmp = node_camera.append_child(pugi::node_comment);
693 node_tmp.set_value(
"Name of the camera");
694 node_tmp = node_camera.append_child(LABEL_XML_CAMERA_NAME);
695 node_tmp.append_child(pugi::node_pcdata).set_value(cam_name.c_str());
698 if (im_width != 0 || im_height != 0) {
699 node_tmp = node_camera.append_child(pugi::node_comment);
700 node_tmp.set_value(
"Size of the image on which camera " 701 "calibration was performed");
704 node_tmp = node_camera.append_child(LABEL_XML_WIDTH);
705 node_tmp.append_child(pugi::node_pcdata).text() = im_width;
708 node_tmp = node_camera.append_child(LABEL_XML_HEIGHT);
709 node_tmp.append_child(pugi::node_pcdata).text() = im_height;
710 if (subsampling_width != 0 || subsampling_height != 0) {
711 node_tmp = node_camera.append_child(pugi::node_comment);
712 node_tmp.set_value(
"Subsampling used to obtain the " 713 "current size of the image.");
716 node_tmp = node_camera.append_child(LABEL_XML_SUBSAMPLING_WIDTH);
717 node_tmp.append_child(pugi::node_pcdata).text() = subsampl_width;
719 node_tmp = node_camera.append_child(LABEL_XML_SUBSAMPLING_HEIGHT);
720 node_tmp.append_child(pugi::node_pcdata).text() = subsampl_height;
721 node_tmp = node_camera.append_child(pugi::node_comment);
722 node_tmp.set_value(
"The full size is the sensor size actually used to " 723 "grab the image. full_width = subsampling_width * " 727 node_tmp = node_camera.append_child(LABEL_XML_FULL_WIDTH);
728 node_tmp.append_child(pugi::node_pcdata).text() = im_width * subsampl_width;
730 node_tmp = node_camera.append_child(LABEL_XML_FULL_HEIGHT);
731 node_tmp.append_child(pugi::node_pcdata).text() = im_height * subsampl_height;
735 node_tmp = node_camera.append_child(pugi::node_comment);
736 node_tmp.set_value(
"Intrinsic camera parameters " 737 "computed for each projection model");
739 back = write_camera(node_camera);
749 int write_camera(pugi::xml_node &node_camera)
751 pugi::xml_node node_model;
752 pugi::xml_node node_tmp;
755 switch (camera.get_projModel()) {
758 node_model = node_camera.append_child(LABEL_XML_MODEL);
760 node_tmp = node_model.append_child(pugi::node_comment);
761 node_tmp.set_value(
"Projection model type");
764 node_tmp = node_model.append_child(LABEL_XML_MODEL_TYPE);
765 node_tmp.append_child(pugi::node_pcdata).set_value(LABEL_XML_MODEL_WITHOUT_DISTORTION);
767 node_tmp = node_model.append_child(pugi::node_comment);
768 node_tmp.set_value(
"Pixel ratio");
770 node_tmp = node_model.append_child(LABEL_XML_PX);
771 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_px();
773 node_tmp = node_model.append_child(LABEL_XML_PY);
774 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_py();
776 node_tmp = node_model.append_child(pugi::node_comment);
777 node_tmp.set_value(
"Principal point");
780 node_tmp = node_model.append_child(LABEL_XML_U0);
781 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_u0();
783 node_tmp = node_model.append_child(LABEL_XML_V0);
784 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_v0();
790 node_model = node_camera.append_child(LABEL_XML_MODEL);
792 node_tmp = node_model.append_child(pugi::node_comment);
793 node_tmp.set_value(
"Projection model type");
795 node_tmp = node_model.append_child(LABEL_XML_MODEL_TYPE);
796 node_tmp.append_child(pugi::node_pcdata).set_value(LABEL_XML_MODEL_WITH_DISTORTION);
798 node_tmp = node_model.append_child(pugi::node_comment);
799 node_tmp.set_value(
"Pixel ratio");
801 node_tmp = node_model.append_child(LABEL_XML_PX);
802 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_px();
804 node_tmp = node_model.append_child(LABEL_XML_PY);
805 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_py();
807 node_tmp = node_model.append_child(pugi::node_comment);
808 node_tmp.set_value(
"Principal point");
810 node_tmp = node_model.append_child(LABEL_XML_U0);
811 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_u0();
813 node_tmp = node_model.append_child(LABEL_XML_V0);
814 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_v0();
817 node_tmp = node_model.append_child(pugi::node_comment);
818 node_tmp.set_value(
"Undistorted to distorted distortion parameter");
819 node_tmp = node_model.append_child(LABEL_XML_KUD);
820 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_kud();
823 node_tmp = node_model.append_child(pugi::node_comment);
824 node_tmp.set_value(
"Distorted to undistorted distortion parameter");
825 node_tmp = node_model.append_child(LABEL_XML_KDU);
826 node_tmp.append_child(pugi::node_pcdata).text() = camera.get_kdu();
839 pugi::xml_node find_additional_info(
const pugi::xml_node &node_)
843 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
844 if (node.type() != pugi::node_element) {
848 if (
SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
849 prop = CODE_XML_OTHER;
852 if (prop == CODE_XML_ADDITIONAL_INFO) {
858 return pugi::xml_node();
870 vpXmlCodeType val_int = CODE_XML_BAD;
873 if (!strcmp(str, LABEL_XML_CAMERA)) {
874 val_int = CODE_XML_CAMERA;
875 }
else if (!strcmp(str, LABEL_XML_CAMERA_NAME)) {
876 val_int = CODE_XML_CAMERA_NAME;
877 }
else if (!strcmp(str, LABEL_XML_MODEL)) {
878 val_int = CODE_XML_MODEL;
879 }
else if (!strcmp(str, LABEL_XML_MODEL_TYPE)) {
880 val_int = CODE_XML_MODEL_TYPE;
881 }
else if (!strcmp(str, LABEL_XML_WIDTH)) {
882 val_int = CODE_XML_WIDTH;
883 }
else if (!strcmp(str, LABEL_XML_HEIGHT)) {
884 val_int = CODE_XML_HEIGHT;
885 }
else if (!strcmp(str, LABEL_XML_SUBSAMPLING_WIDTH)) {
886 val_int = CODE_XML_SUBSAMPLING_WIDTH;
887 }
else if (!strcmp(str, LABEL_XML_SUBSAMPLING_HEIGHT)) {
888 val_int = CODE_XML_SUBSAMPLING_HEIGHT;
889 }
else if (!strcmp(str, LABEL_XML_FULL_WIDTH)) {
890 val_int = CODE_XML_FULL_WIDTH;
891 }
else if (!strcmp(str, LABEL_XML_FULL_HEIGHT)) {
892 val_int = CODE_XML_FULL_HEIGHT;
893 }
else if (!strcmp(str, LABEL_XML_U0)) {
894 val_int = CODE_XML_U0;
895 }
else if (!strcmp(str, LABEL_XML_V0)) {
896 val_int = CODE_XML_V0;
897 }
else if (!strcmp(str, LABEL_XML_PX)) {
898 val_int = CODE_XML_PX;
899 }
else if (!strcmp(str, LABEL_XML_PY)) {
900 val_int = CODE_XML_PY;
901 }
else if (!strcmp(str, LABEL_XML_KUD)) {
902 val_int = CODE_XML_KUD;
903 }
else if (!strcmp(str, LABEL_XML_KDU)) {
904 val_int = CODE_XML_KDU;
905 }
else if (!strcmp(str, LABEL_XML_ADDITIONAL_INFO)) {
906 val_int = CODE_XML_ADDITIONAL_INFO;
908 val_int = CODE_XML_OTHER;
917 unsigned int getHeight()
const {
return image_height; }
920 unsigned int getWidth()
const {
return image_width; }
922 void setCameraName(
const std::string &name) { camera_name = name; }
923 void setHeight(
unsigned int height) { image_height = height; }
926 void setWidth(
unsigned int width) { image_width = width; }
930 std::string camera_name;
931 unsigned int image_width;
932 unsigned int image_height;
933 unsigned int subsampling_width;
934 unsigned int subsampling_height;
935 unsigned int full_width;
936 unsigned int full_height;
940 static const int allowedPixelDiffOnImageSize = 15;
942 #endif // DOXYGEN_SHOULD_SKIP_THIS 969 unsigned int im_width,
unsigned int im_height)
971 return m_impl->parse(cam, filename, cam_name, projModel, im_width, im_height);
1018 unsigned int im_width,
unsigned int im_height,
1019 const std::string &additionalInfo)
1021 return m_impl->save(cam, filename, cam_name, im_width, im_height, additionalInfo);
1026 return m_impl->getCameraName();
1031 return m_impl->getCameraParameters();
1036 return m_impl->getHeight();
1041 return m_impl->getSubsampling_width();
1046 return m_impl->getSubsampling_height();
1051 return m_impl->getWidth();
1056 m_impl->setCameraName(name);
1061 m_impl->setHeight(height);
1066 m_impl->setSubsampling_width(subsampling);
1071 m_impl->setSubsampling_height(subsampling);
1076 m_impl->setWidth(width);
1079 #elif !defined(VISP_BUILD_SHARED_LIBS) 1082 void dummy_vpXmlParserCamera(){};
1083 #endif // VISP_HAVE_PUGIXML unsigned int getWidth() const
unsigned int getSubsampling_height() const
vpCameraParametersProjType get_projModel() const
void setHeight(unsigned int height)
void setWidth(unsigned int width)
void setCameraName(const std::string &name)
vpCameraParameters getCameraParameters() const
void setSubsampling_height(unsigned int subsampling)
void initPersProjWithDistortion(double px, double py, double u0, double v0, double kud, double kdu)
vpCameraParametersProjType
Generic class defining intrinsic camera parameters.
int parse(vpCameraParameters &cam, const std::string &filename, const std::string &camera_name, const vpCameraParameters::vpCameraParametersProjType &projModel, unsigned int image_width=0, unsigned int image_height=0)
void initPersProjWithoutDistortion(double px, double py, double u0, double v0)
int save(const vpCameraParameters &cam, const std::string &filename, const std::string &camera_name, unsigned int image_width=0, unsigned int image_height=0, const std::string &additionalInfo="")
std::string getCameraName() const
void setSubsampling_width(unsigned int subsampling)
unsigned int getSubsampling_width() const
unsigned int getHeight() const