OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::AMFParserContext Struct Reference
Collaboration diagram for Slic3r::AMFParserContext:

Classes

struct  Instance
struct  Object

Public Types

enum  AMFNodeType {
  NODE_TYPE_INVALID = 0 , NODE_TYPE_UNKNOWN , NODE_TYPE_AMF , NODE_TYPE_MATERIAL ,
  NODE_TYPE_OBJECT , NODE_TYPE_MESH , NODE_TYPE_VERTICES , NODE_TYPE_VERTEX ,
  NODE_TYPE_COORDINATES , NODE_TYPE_COORDINATE_X , NODE_TYPE_COORDINATE_Y , NODE_TYPE_COORDINATE_Z ,
  NODE_TYPE_VOLUME , NODE_TYPE_TRIANGLE , NODE_TYPE_VERTEX1 , NODE_TYPE_VERTEX2 ,
  NODE_TYPE_VERTEX3 , NODE_TYPE_CONSTELLATION , NODE_TYPE_INSTANCE , NODE_TYPE_DELTAX ,
  NODE_TYPE_DELTAY , NODE_TYPE_DELTAZ , NODE_TYPE_RX , NODE_TYPE_RY ,
  NODE_TYPE_RZ , NODE_TYPE_SCALE , NODE_TYPE_SCALEX , NODE_TYPE_SCALEY ,
  NODE_TYPE_SCALEZ , NODE_TYPE_MIRRORX , NODE_TYPE_MIRRORY , NODE_TYPE_MIRRORZ ,
  NODE_TYPE_PRINTABLE , NODE_TYPE_METADATA
}

Public Member Functions

 AMFParserContext (XML_Parser parser, DynamicPrintConfig *config, ConfigSubstitutionContext *config_substitutions, Model *model)
void stop (const std::string &msg=std::string())
bool error () const
const char * error_message () const
void startElement (const char *name, const char **atts)
void endElement (const char *name)
void endDocument ()
void characters (const XML_Char *s, int len)

Static Public Member Functions

static void XMLCALL startElement (void *userData, const char *name, const char **atts)
static void XMLCALL endElement (void *userData, const char *name)
static void XMLCALL characters (void *userData, const XML_Char *s, int len)
static const char * get_attribute (const char **atts, const char *id)

Public Attributes

XML_Parser m_parser
bool m_error { false }
std::string m_error_message
Model & m_model
std::vector< AMFNodeType > m_path
ModelObject * m_object { nullptr }
std::map< std::string, Object > m_object_instances_map
std::vector< Vec3f > m_object_vertices
ModelVolume * m_volume { nullptr }
std::vector< Vec3i32 > m_volume_facets
Transform3d m_volume_transform
ModelMaterial * m_material { nullptr }
Instance * m_instance { nullptr }
std::string m_value [5]
DynamicPrintConfig * m_config { nullptr }
ConfigSubstitutionContext * m_config_substitutions { nullptr }
bool m_use_inches { false }

Private Member Functions

AMFParserContext & operator= (AMFParserContext &)

Detailed Description

Member Enumeration Documentation

◆ AMFNodeType

Enumerator
NODE_TYPE_INVALID 
NODE_TYPE_UNKNOWN 
NODE_TYPE_AMF 
NODE_TYPE_MATERIAL 
NODE_TYPE_OBJECT 
NODE_TYPE_MESH 
NODE_TYPE_VERTICES 
NODE_TYPE_VERTEX 
NODE_TYPE_COORDINATES 
NODE_TYPE_COORDINATE_X 
NODE_TYPE_COORDINATE_Y 
NODE_TYPE_COORDINATE_Z 
NODE_TYPE_VOLUME 
NODE_TYPE_TRIANGLE 
NODE_TYPE_VERTEX1 
NODE_TYPE_VERTEX2 
NODE_TYPE_VERTEX3 
NODE_TYPE_CONSTELLATION 
NODE_TYPE_INSTANCE 
NODE_TYPE_DELTAX 
NODE_TYPE_DELTAY 
NODE_TYPE_DELTAZ 
NODE_TYPE_RX 
NODE_TYPE_RY 
NODE_TYPE_RZ 
NODE_TYPE_SCALE 
NODE_TYPE_SCALEX 
NODE_TYPE_SCALEY 
NODE_TYPE_SCALEZ 
NODE_TYPE_MIRRORX 
NODE_TYPE_MIRRORY 
NODE_TYPE_MIRRORZ 
NODE_TYPE_PRINTABLE 
NODE_TYPE_METADATA 
132 {
135 NODE_TYPE_AMF, // amf
136 // amf/metadata
137 NODE_TYPE_MATERIAL, // amf/material
138 // amf/material/metadata
139 NODE_TYPE_OBJECT, // amf/object
140 // amf/object/metadata
141 // NODE_TYPE_LAYER_CONFIG, // amf/object/layer_config_ranges
142 //NODE_TYPE_RANGE, // amf/object/layer_config_ranges/range
143 // amf/object/layer_config_ranges/range/metadata
144 NODE_TYPE_MESH, // amf/object/mesh
145 NODE_TYPE_VERTICES, // amf/object/mesh/vertices
146 NODE_TYPE_VERTEX, // amf/object/mesh/vertices/vertex
147 NODE_TYPE_COORDINATES, // amf/object/mesh/vertices/vertex/coordinates
148 NODE_TYPE_COORDINATE_X, // amf/object/mesh/vertices/vertex/coordinates/x
149 NODE_TYPE_COORDINATE_Y, // amf/object/mesh/vertices/vertex/coordinates/y
150 NODE_TYPE_COORDINATE_Z, // amf/object/mesh/vertices/vertex/coordinates/z
151 NODE_TYPE_VOLUME, // amf/object/mesh/volume
152 // amf/object/mesh/volume/metadata
153 NODE_TYPE_TRIANGLE, // amf/object/mesh/volume/triangle
154 NODE_TYPE_VERTEX1, // amf/object/mesh/volume/triangle/v1
155 NODE_TYPE_VERTEX2, // amf/object/mesh/volume/triangle/v2
156 NODE_TYPE_VERTEX3, // amf/object/mesh/volume/triangle/v3
157 NODE_TYPE_CONSTELLATION, // amf/constellation
158 NODE_TYPE_INSTANCE, // amf/constellation/instance
159 NODE_TYPE_DELTAX, // amf/constellation/instance/deltax
160 NODE_TYPE_DELTAY, // amf/constellation/instance/deltay
161 NODE_TYPE_DELTAZ, // amf/constellation/instance/deltaz
162 NODE_TYPE_RX, // amf/constellation/instance/rx
163 NODE_TYPE_RY, // amf/constellation/instance/ry
164 NODE_TYPE_RZ, // amf/constellation/instance/rz
165 NODE_TYPE_SCALE, // amf/constellation/instance/scale
166 NODE_TYPE_SCALEX, // amf/constellation/instance/scalex
167 NODE_TYPE_SCALEY, // amf/constellation/instance/scaley
168 NODE_TYPE_SCALEZ, // amf/constellation/instance/scalez
169 NODE_TYPE_MIRRORX, // amf/constellation/instance/mirrorx
170 NODE_TYPE_MIRRORY, // amf/constellation/instance/mirrory
171 NODE_TYPE_MIRRORZ, // amf/constellation/instance/mirrorz
172 NODE_TYPE_PRINTABLE, // amf/constellation/instance/mirrorz
173 //NODE_TYPE_CUSTOM_GCODE, // amf/custom_code_per_height
174 //NODE_TYPE_GCODE_PER_HEIGHT, // amf/custom_code_per_height/code
175 //NODE_TYPE_CUSTOM_GCODE_MODE, // amf/custom_code_per_height/mode
176 NODE_TYPE_METADATA, // anywhere under amf/*/metadata
177 };
@ NODE_TYPE_VERTEX
Definition AMF.cpp:146
@ NODE_TYPE_RY
Definition AMF.cpp:163
@ NODE_TYPE_INVALID
Definition AMF.cpp:133
@ NODE_TYPE_VOLUME
Definition AMF.cpp:151
@ NODE_TYPE_MIRRORZ
Definition AMF.cpp:171
@ NODE_TYPE_MIRRORY
Definition AMF.cpp:170
@ NODE_TYPE_CONSTELLATION
Definition AMF.cpp:157
@ NODE_TYPE_COORDINATE_X
Definition AMF.cpp:148
@ NODE_TYPE_PRINTABLE
Definition AMF.cpp:172
@ NODE_TYPE_SCALEY
Definition AMF.cpp:167
@ NODE_TYPE_DELTAX
Definition AMF.cpp:159
@ NODE_TYPE_METADATA
Definition AMF.cpp:176
@ NODE_TYPE_SCALEX
Definition AMF.cpp:166
@ NODE_TYPE_RX
Definition AMF.cpp:162
@ NODE_TYPE_COORDINATE_Y
Definition AMF.cpp:149
@ NODE_TYPE_VERTEX2
Definition AMF.cpp:155
@ NODE_TYPE_OBJECT
Definition AMF.cpp:139
@ NODE_TYPE_COORDINATE_Z
Definition AMF.cpp:150
@ NODE_TYPE_TRIANGLE
Definition AMF.cpp:153
@ NODE_TYPE_MIRRORX
Definition AMF.cpp:169
@ NODE_TYPE_MATERIAL
Definition AMF.cpp:137
@ NODE_TYPE_MESH
Definition AMF.cpp:144
@ NODE_TYPE_DELTAZ
Definition AMF.cpp:161
@ NODE_TYPE_AMF
Definition AMF.cpp:135
@ NODE_TYPE_DELTAY
Definition AMF.cpp:160
@ NODE_TYPE_SCALE
Definition AMF.cpp:165
@ NODE_TYPE_VERTICES
Definition AMF.cpp:145
@ NODE_TYPE_VERTEX3
Definition AMF.cpp:156
@ NODE_TYPE_INSTANCE
Definition AMF.cpp:158
@ NODE_TYPE_RZ
Definition AMF.cpp:164
@ NODE_TYPE_COORDINATES
Definition AMF.cpp:147
@ NODE_TYPE_SCALEZ
Definition AMF.cpp:168
@ NODE_TYPE_VERTEX1
Definition AMF.cpp:154
@ NODE_TYPE_UNKNOWN
Definition AMF.cpp:134

Constructor & Destructor Documentation

◆ AMFParserContext()

Slic3r::AMFParserContext::AMFParserContext ( XML_Parser parser,
DynamicPrintConfig * config,
ConfigSubstitutionContext * config_substitutions,
Model * model )
inline
70 :
71 m_parser(parser),
72 m_model(*model),
73 m_config(config),
74 m_config_substitutions(config_substitutions)
75 {
76 m_path.reserve(12);
77 }
std::vector< AMFNodeType > m_path
Definition AMF.cpp:244
Model & m_model
Definition AMF.cpp:242
DynamicPrintConfig * m_config
Definition AMF.cpp:264
ConfigSubstitutionContext * m_config_substitutions
Definition AMF.cpp:266
XML_Parser m_parser
Definition AMF.cpp:236

References m_config, m_config_substitutions, m_model, m_parser, and m_path.

Referenced by characters(), endElement(), operator=(), and startElement().

Here is the caller graph for this function:

Member Function Documentation

◆ characters() [1/2]

void Slic3r::AMFParserContext::characters ( const XML_Char * s,
int len )
473{
474 if (m_path.back() == NODE_TYPE_METADATA) {
475 m_value[1].append(s, len);
476 }
477 else
478 {
479 switch (m_path.size()) {
480 case 4:
481 if (m_path.back() == NODE_TYPE_DELTAX ||
482 m_path.back() == NODE_TYPE_DELTAY ||
483 m_path.back() == NODE_TYPE_DELTAZ ||
484 m_path.back() == NODE_TYPE_RX ||
485 m_path.back() == NODE_TYPE_RY ||
486 m_path.back() == NODE_TYPE_RZ ||
487 m_path.back() == NODE_TYPE_SCALEX ||
488 m_path.back() == NODE_TYPE_SCALEY ||
489 m_path.back() == NODE_TYPE_SCALEZ ||
490 m_path.back() == NODE_TYPE_SCALE ||
491 m_path.back() == NODE_TYPE_MIRRORX ||
492 m_path.back() == NODE_TYPE_MIRRORY ||
493 m_path.back() == NODE_TYPE_MIRRORZ ||
494 m_path.back() == NODE_TYPE_PRINTABLE)
495 m_value[0].append(s, len);
496 break;
497 case 6:
498 switch (m_path.back()) {
499 case NODE_TYPE_VERTEX1: m_value[0].append(s, len); break;
500 case NODE_TYPE_VERTEX2: m_value[1].append(s, len); break;
501 case NODE_TYPE_VERTEX3: m_value[2].append(s, len); break;
502 default: break;
503 }
504 case 7:
505 switch (m_path.back()) {
506 case NODE_TYPE_COORDINATE_X: m_value[0].append(s, len); break;
507 case NODE_TYPE_COORDINATE_Y: m_value[1].append(s, len); break;
508 case NODE_TYPE_COORDINATE_Z: m_value[2].append(s, len); break;
509 default: break;
510 }
511 default:
512 break;
513 }
514 }
515}
std::string m_value[5]
Definition AMF.cpp:262

References m_path, m_value, NODE_TYPE_COORDINATE_X, NODE_TYPE_COORDINATE_Y, NODE_TYPE_COORDINATE_Z, NODE_TYPE_DELTAX, NODE_TYPE_DELTAY, NODE_TYPE_DELTAZ, NODE_TYPE_METADATA, NODE_TYPE_MIRRORX, NODE_TYPE_MIRRORY, NODE_TYPE_MIRRORZ, NODE_TYPE_PRINTABLE, NODE_TYPE_RX, NODE_TYPE_RY, NODE_TYPE_RZ, NODE_TYPE_SCALE, NODE_TYPE_SCALEX, NODE_TYPE_SCALEY, NODE_TYPE_SCALEZ, NODE_TYPE_VERTEX1, NODE_TYPE_VERTEX2, and NODE_TYPE_VERTEX3.

Referenced by characters(), Slic3r::extract_model_from_archive(), and Slic3r::load_amf_file().

Here is the caller graph for this function:

◆ characters() [2/2]

void XMLCALL Slic3r::AMFParserContext::characters ( void * userData,
const XML_Char * s,
int len )
inlinestatic
116 {
117 AMFParserContext *ctx = (AMFParserContext*)userData;
118 ctx->characters(s, len);
119 }
AMFParserContext(XML_Parser parser, DynamicPrintConfig *config, ConfigSubstitutionContext *config_substitutions, Model *model)
Definition AMF.cpp:70

References AMFParserContext(), and characters().

Here is the call graph for this function:

◆ endDocument()

void Slic3r::AMFParserContext::endDocument ( )
862{
863 for (const auto &object : m_object_instances_map) {
864 if (object.second.idx == -1) {
865 BOOST_LOG_TRIVIAL(error) << "Undefined object " << object.first.c_str() << " referenced in constellation";
866 continue;
867 }
868 int index = 0;
869 for (const Instance &instance : object.second.instances) {
870 ModelObject *model_object = m_model.objects[object.second.idx];
871 index++;
872 if (index > 1) {
873 ModelObject *new_model_object = m_model.add_object(*model_object);
874 new_model_object->clear_instances();
875 model_object = new_model_object;
876 }
877
878 if (instance.anything_set()) {
879 ModelInstance *mi = model_object->add_instance();
880 mi->set_offset(Vec3d(instance.deltax_set ? (double) instance.deltax : 0.0, instance.deltay_set ? (double) instance.deltay : 0.0,
881 instance.deltaz_set ? (double) instance.deltaz : 0.0));
882 mi->set_rotation(Vec3d(instance.rx_set ? (double) instance.rx : 0.0, instance.ry_set ? (double) instance.ry : 0.0, instance.rz_set ? (double) instance.rz : 0.0));
883 mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double) instance.scalex : 1.0, instance.scaley_set ? (double) instance.scaley : 1.0,
884 instance.scalez_set ? (double) instance.scalez : 1.0));
885 mi->set_mirror(Vec3d(instance.mirrorx_set ? (double) instance.mirrorx : 1.0, instance.mirrory_set ? (double) instance.mirrory : 1.0,
886 instance.mirrorz_set ? (double) instance.mirrorz : 1.0));
887 mi->printable = instance.printable;
888 }
889 }
890 }
891}
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
std::map< std::string, Object > m_object_instances_map
Definition AMF.cpp:248
bool error() const
Definition AMF.cpp:88

References Slic3r::ModelObject::add_instance(), Slic3r::ModelObject::clear_instances(), error(), m_model, m_object_instances_map, Slic3r::ModelInstance::printable, Slic3r::ModelInstance::set_mirror(), Slic3r::ModelInstance::set_offset(), Slic3r::ModelInstance::set_rotation(), and Slic3r::ModelInstance::set_scaling_factor().

Referenced by Slic3r::load_amf_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ endElement() [1/2]

void Slic3r::AMFParserContext::endElement ( const char * name)
518{
520 switch (m_path.back()) {
521
522 // Constellation transformation:
523 case NODE_TYPE_DELTAX:
524 assert(m_instance);
525 m_instance->deltax = float(atof(m_value[0].c_str()));
526 m_instance->deltax_set = true;
527 m_value[0].clear();
528 break;
529 case NODE_TYPE_DELTAY:
530 assert(m_instance);
531 m_instance->deltay = float(atof(m_value[0].c_str()));
532 m_instance->deltay_set = true;
533 m_value[0].clear();
534 break;
535 case NODE_TYPE_DELTAZ:
536 assert(m_instance);
537 m_instance->deltaz = float(atof(m_value[0].c_str()));
538 m_instance->deltaz_set = true;
539 m_value[0].clear();
540 break;
541 case NODE_TYPE_RX:
542 assert(m_instance);
543 m_instance->rx = float(atof(m_value[0].c_str()));
544 m_instance->rx_set = true;
545 m_value[0].clear();
546 break;
547 case NODE_TYPE_RY:
548 assert(m_instance);
549 m_instance->ry = float(atof(m_value[0].c_str()));
550 m_instance->ry_set = true;
551 m_value[0].clear();
552 break;
553 case NODE_TYPE_RZ:
554 assert(m_instance);
555 m_instance->rz = float(atof(m_value[0].c_str()));
556 m_instance->rz_set = true;
557 m_value[0].clear();
558 break;
559 case NODE_TYPE_SCALE:
560 assert(m_instance);
561 m_instance->scalex = float(atof(m_value[0].c_str()));
562 m_instance->scalex_set = true;
563 m_instance->scaley = float(atof(m_value[0].c_str()));
564 m_instance->scaley_set = true;
565 m_instance->scalez = float(atof(m_value[0].c_str()));
566 m_instance->scalez_set = true;
567 m_value[0].clear();
568 break;
569 case NODE_TYPE_SCALEX:
570 assert(m_instance);
571 m_instance->scalex = float(atof(m_value[0].c_str()));
572 m_instance->scalex_set = true;
573 m_value[0].clear();
574 break;
575 case NODE_TYPE_SCALEY:
576 assert(m_instance);
577 m_instance->scaley = float(atof(m_value[0].c_str()));
578 m_instance->scaley_set = true;
579 m_value[0].clear();
580 break;
581 case NODE_TYPE_SCALEZ:
582 assert(m_instance);
583 m_instance->scalez = float(atof(m_value[0].c_str()));
584 m_instance->scalez_set = true;
585 m_value[0].clear();
586 break;
588 assert(m_instance);
589 m_instance->mirrorx = float(atof(m_value[0].c_str()));
590 m_instance->mirrorx_set = true;
591 m_value[0].clear();
592 break;
594 assert(m_instance);
595 m_instance->mirrory = float(atof(m_value[0].c_str()));
596 m_instance->mirrory_set = true;
597 m_value[0].clear();
598 break;
600 assert(m_instance);
601 m_instance->mirrorz = float(atof(m_value[0].c_str()));
602 m_instance->mirrorz_set = true;
603 m_value[0].clear();
604 break;
606 assert(m_instance);
607 m_instance->printable = bool(atoi(m_value[0].c_str()));
608 m_value[0].clear();
609 break;
610
611 // Object vertices:
612 case NODE_TYPE_VERTEX:
613 assert(m_object);
614 // Parse the vertex data
615 m_object_vertices.emplace_back(float(atof(m_value[0].c_str())), float(atof(m_value[1].c_str())), float(atof(m_value[2].c_str())));
616 m_value[0].clear();
617 m_value[1].clear();
618 m_value[2].clear();
619 break;
620
621 // Faces of the current volume:
623 assert(m_object && m_volume);
624 m_volume_facets.emplace_back(atoi(m_value[0].c_str()), atoi(m_value[1].c_str()), atoi(m_value[2].c_str()));
625 m_value[0].clear();
626 m_value[1].clear();
627 m_value[2].clear();
628 break;
629
630 // Closing the current volume. Create an STL from m_volume_facets pointing to m_object_vertices.
631 case NODE_TYPE_VOLUME:
632 {
633 assert(m_object && m_volume);
634 if (m_volume_facets.empty()) {
635 this->stop("Found an empty triangle mesh");
636 return;
637 }
638
639 {
640 // Verify validity of face indices, find the vertex span.
641 int min_id = m_volume_facets.front()[0];
642 int max_id = min_id;
643 for (const Vec3i32& face : m_volume_facets) {
644 for (const int tri_id : face) {
645 if (tri_id < 0 || tri_id >= int(m_object_vertices.size())) {
646 this->stop("Found a malformed triangle mesh");
647 return;
648 }
649 min_id = std::min(min_id, tri_id);
650 max_id = std::max(max_id, tri_id);
651 }
652 }
653
654 // rebase indices to the current vertices list
655 for (Vec3i32 &face : m_volume_facets)
656 face -= Vec3i32(min_id, min_id, min_id);
657
658 indexed_triangle_set its { std::move(m_volume_facets), { m_object_vertices.begin() + min_id, m_object_vertices.begin() + max_id + 1 } };
660 if (its_volume(its) < 0)
662 m_volume->set_mesh(std::move(its));
663 }
664
665 // stores the volume matrix taken from the metadata, if present
666 if (bool has_transform = !m_volume_transform.isApprox(Transform3d::Identity(), 1e-10); has_transform)
667 m_volume->source.transform = Slic3r::Geometry::Transformation(m_volume_transform);
668
669 if (m_volume->source.input_file.empty() && (m_volume->type() == ModelVolumeType::MODEL_PART)) {
670 m_volume->source.object_idx = (int)m_model.objects.size() - 1;
671 m_volume->source.volume_idx = (int)m_model.objects.back()->volumes.size() - 1;
672 m_volume->center_geometry_after_creation();
673 } else
674 // pass false if the mesh offset has been already taken from the data
675 m_volume->center_geometry_after_creation(m_volume->source.input_file.empty());
676
677 m_volume->calculate_convex_hull();
678 m_volume_facets.clear();
679 m_volume = nullptr;
680 break;
681 }
682
683 case NODE_TYPE_OBJECT:
684 assert(m_object);
685 m_object_vertices.clear();
686 m_object = nullptr;
687 break;
688
690 assert(m_material);
691 m_material = nullptr;
692 break;
693
695 assert(m_instance);
696 m_instance = nullptr;
697 break;
698
699 /*case NODE_TYPE_GCODE_PER_HEIGHT: {
700 double print_z = double(atof(m_value[0].c_str()));
701 int extruder = atoi(m_value[1].c_str());
702 const std::string& color= m_value[2];
703 CustomGCode::Type type = static_cast<CustomGCode::Type>(atoi(m_value[3].c_str()));
704 const std::string& extra= m_value[4];
705
706 m_model.custom_gcode_per_print_z.gcodes.push_back(CustomGCode::Item{print_z, type, extruder, color, extra});
707
708 for (std::string& val: m_value)
709 val.clear();
710 break;
711 }
712
713 case NODE_TYPE_CUSTOM_GCODE_MODE: {
714 const std::string& mode = m_value[0];
715
716 m_model.custom_gcode_per_print_z.mode = mode == CustomGCode::SingleExtruderMode ? CustomGCode::Mode::SingleExtruder :
717 mode == CustomGCode::MultiAsSingleMode ? CustomGCode::Mode::MultiAsSingle :
718 CustomGCode::Mode::MultiExtruder;
719 for (std::string& val: m_value)
720 val.clear();
721 break;
722 }
723 */
725 /*if ((m_config != nullptr) && strncmp(m_value[0].c_str(), SLIC3R_CONFIG_TYPE, strlen(SLIC3R_CONFIG_TYPE)) == 0) {
726 //FIXME Loading a "will be one day a legacy format" of configuration in a form of a G-code comment.
727 // Each config line is prefixed with a semicolon (G-code comment), that is ugly.
728
729 // Replacing the legacy function with load_from_ini_string_commented leads to issues when
730 // parsing 3MFs from before PrusaSlicer 2.0.0 (which can have duplicated entries in the INI.
731 // See https://github.com/prusa3d/PrusaSlicer/issues/7155. We'll revert it for now.
732 //m_config_substitutions->substitutions = m_config->load_from_ini_string_commented(std::move(m_value[1].c_str()), m_config_substitutions->rule);
733 ConfigBase::load_from_gcode_string_legacy(*m_config, std::move(m_value[1].c_str()), *m_config_substitutions);
734 }
735 else if (strncmp(m_value[0].c_str(), "slic3r.", 7) == 0) {
736 const char *opt_key = m_value[0].c_str() + 7;
737 if (print_config_def.options.find(opt_key) != print_config_def.options.end()) {
738 ModelConfig *config = nullptr;
739 if (m_path.size() == 3) {
740 if (m_path[1] == NODE_TYPE_MATERIAL && m_material)
741 config = &m_material->config;
742 else if (m_path[1] == NODE_TYPE_OBJECT && m_object)
743 config = &m_object->config;
744 }
745 else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
746 config = &m_volume->config;
747 else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_RANGE && m_object && !m_object->layer_config_ranges.empty()) {
748 auto it = --m_object->layer_config_ranges.end();
749 config = &it->second;
750 }
751 if (config)
752 config->set_deserialize(opt_key, m_value[1], *m_config_substitutions);
753 } else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) {
754 // Parse object's layer height profile, a semicolon separated list of floats.
755 char *p = m_value[1].data();
756 std::vector<coordf_t> data;
757 for (;;) {
758 char *end = strchr(p, ';');
759 if (end != nullptr)
760 *end = 0;
761 data.emplace_back(float(atof(p)));
762 if (end == nullptr)
763 break;
764 p = end + 1;
765 }
766 m_object->layer_height_profile.set(std::move(data));
767 }
768 else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "sla_support_points") == 0) {
769 // Parse object's layer height profile, a semicolon separated list of floats.
770 unsigned char coord_idx = 0;
771 Eigen::Matrix<float, 5, 1, Eigen::DontAlign> point(Eigen::Matrix<float, 5, 1, Eigen::DontAlign>::Zero());
772 char *p = m_value[1].data();
773 for (;;) {
774 char *end = strchr(p, ';');
775 if (end != nullptr)
776 *end = 0;
777
778 point(coord_idx) = float(atof(p));
779 if (++coord_idx == 5) {
780 m_object->sla_support_points.push_back(sla::SupportPoint(point));
781 coord_idx = 0;
782 }
783 if (end == nullptr)
784 break;
785 p = end + 1;
786 }
787 m_object->sla_points_status = sla::PointsStatus::UserModified;
788 }
789 else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE &&
790 m_object && strcmp(opt_key, "layer_height_range") == 0) {
791 // Parse object's layer_height_range, a semicolon separated doubles.
792 char* p = m_value[1].data();
793 char* end = strchr(p, ';');
794 *end = 0;
795
796 const t_layer_height_range range = {double(atof(p)), double(atof(end + 1))};
797 m_object->layer_config_ranges[range];
798 }
799 else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume) {
800 if (strcmp(opt_key, "modifier") == 0) {
801 // Is this volume a modifier volume?
802 // "modifier" flag comes first in the XML file, so it may be later overwritten by the "type" flag.
803 m_volume->set_type((atoi(m_value[1].c_str()) == 1) ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART);
804 } else if (strcmp(opt_key, "volume_type") == 0) {
805 m_volume->set_type(ModelVolume::type_from_string(m_value[1]));
806 }
807 else if (strcmp(opt_key, "matrix") == 0) {
808 m_volume_transform = Slic3r::Geometry::transform3d_from_string(m_value[1]);
809 }
810 else if (strcmp(opt_key, "source_file") == 0) {
811 m_volume->source.input_file = m_value[1];
812 }
813 else if (strcmp(opt_key, "source_object_id") == 0) {
814 m_volume->source.object_idx = ::atoi(m_value[1].c_str());
815 }
816 else if (strcmp(opt_key, "source_volume_id") == 0) {
817 m_volume->source.volume_idx = ::atoi(m_value[1].c_str());
818 }
819 else if (strcmp(opt_key, "source_offset_x") == 0) {
820 m_volume->source.mesh_offset(0) = ::atof(m_value[1].c_str());
821 }
822 else if (strcmp(opt_key, "source_offset_y") == 0) {
823 m_volume->source.mesh_offset(1) = ::atof(m_value[1].c_str());
824 }
825 else if (strcmp(opt_key, "source_offset_z") == 0) {
826 m_volume->source.mesh_offset(2) = ::atof(m_value[1].c_str());
827 }
828 else if (strcmp(opt_key, "source_in_inches") == 0) {
829 m_volume->source.is_converted_from_inches = m_value[1] == "1";
830 }
831 else if (strcmp(opt_key, "source_in_meters") == 0) {
832 m_volume->source.is_converted_from_meters = m_value[1] == "1";
833 }
834 }
835 }
836 else */if (m_path.size() == 3) {
837 if (m_path[1] == NODE_TYPE_MATERIAL) {
838 if (m_material)
839 m_material->attributes[m_value[0]] = m_value[1];
840 } else if (m_path[1] == NODE_TYPE_OBJECT) {
841 if (m_object && m_value[0] == "name")
842 m_object->name = std::move(m_value[1]);
843 }
844 } else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME) {
845 if (m_volume && m_value[0] == "name")
846 m_volume->name = std::move(m_value[1]);
847 }
848 /*else if (strncmp(m_value[0].c_str(), SLIC3RPE_AMF_VERSION, strlen(SLIC3RPE_AMF_VERSION)) == 0) {
849 m_version = (unsigned int)atoi(m_value[1].c_str());
850 }*/
851
852 m_value[0].clear();
853 m_value[1].clear();
854 break;
855 default:
856 break;
857 }
858 m_path.pop_back();
859}
@ MODEL_PART
Definition Model.hpp:357
float its_volume(const indexed_triangle_set &its)
Definition TriangleMesh.cpp:1479
bool is_decimal_separator_point()
Definition LocalesUtils.cpp:78
Eigen::Matrix< int32_t, 3, 1, Eigen::DontAlign > Vec3i32
Definition Point.hpp:59
void its_flip_triangles(indexed_triangle_set &its)
Definition TriangleMesh.cpp:752
int its_compactify_vertices(indexed_triangle_set &its, bool shrink_to_fit)
Definition TriangleMesh.cpp:773
void stop(const std::string &msg=std::string())
Definition AMF.cpp:79
ModelObject * m_object
Definition AMF.cpp:246
Transform3d m_volume_transform
Definition AMF.cpp:256
ModelMaterial * m_material
Definition AMF.cpp:258
std::vector< Vec3i32 > m_volume_facets
Definition AMF.cpp:254
Instance * m_instance
Definition AMF.cpp:260
std::vector< Vec3f > m_object_vertices
Definition AMF.cpp:250
ModelVolume * m_volume
Definition AMF.cpp:252

References Slic3r::is_decimal_separator_point(), Slic3r::its_compactify_vertices(), Slic3r::its_flip_triangles(), Slic3r::its_volume(), m_instance, m_material, m_model, m_object, m_object_vertices, m_path, m_value, m_volume, m_volume_facets, m_volume_transform, Slic3r::MODEL_PART, NODE_TYPE_DELTAX, NODE_TYPE_DELTAY, NODE_TYPE_DELTAZ, NODE_TYPE_INSTANCE, NODE_TYPE_MATERIAL, NODE_TYPE_METADATA, NODE_TYPE_MIRRORX, NODE_TYPE_MIRRORY, NODE_TYPE_MIRRORZ, NODE_TYPE_OBJECT, NODE_TYPE_PRINTABLE, NODE_TYPE_RX, NODE_TYPE_RY, NODE_TYPE_RZ, NODE_TYPE_SCALE, NODE_TYPE_SCALEX, NODE_TYPE_SCALEY, NODE_TYPE_SCALEZ, NODE_TYPE_TRIANGLE, NODE_TYPE_VERTEX, NODE_TYPE_VOLUME, and stop().

Referenced by endElement(), Slic3r::extract_model_from_archive(), and Slic3r::load_amf_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ endElement() [2/2]

void XMLCALL Slic3r::AMFParserContext::endElement ( void * userData,
const char * name )
inlinestatic
109 {
110 AMFParserContext *ctx = (AMFParserContext*)userData;
111 ctx->endElement(name);
112 }

References AMFParserContext(), and endElement().

Here is the call graph for this function:

◆ error()

bool Slic3r::AMFParserContext::error ( ) const
inline
88{ return m_error; }
bool m_error
Definition AMF.cpp:239

References m_error.

Referenced by endDocument(), and Slic3r::load_amf_file().

Here is the caller graph for this function:

◆ error_message()

const char * Slic3r::AMFParserContext::error_message ( ) const
inline
89 {
90 return m_error ?
91 // The error was signalled by the user code, not the expat parser.
92 (m_error_message.empty() ? "Parse AMF file failed" : m_error_message.c_str()) :
93 // The error was signalled by the expat parser.
94 XML_ErrorString(XML_GetErrorCode(m_parser));
95 }
std::string m_error_message
Definition AMF.cpp:240

References m_error, m_error_message, and m_parser.

Referenced by Slic3r::load_amf_file().

Here is the caller graph for this function:

◆ get_attribute()

const char * Slic3r::AMFParserContext::get_attribute ( const char ** atts,
const char * id )
inlinestatic
121 {
122 if (atts == nullptr)
123 return nullptr;
124 while (*atts != nullptr) {
125 if (strcmp(*(atts ++), id) == 0)
126 return *atts;
127 ++ atts;
128 }
129 return nullptr;
130 }

Referenced by startElement().

Here is the caller graph for this function:

◆ operator=()

AMFParserContext & Slic3r::AMFParserContext::operator= ( AMFParserContext & )
private

References AMFParserContext().

Here is the call graph for this function:

◆ startElement() [1/2]

void Slic3r::AMFParserContext::startElement ( const char * name,
const char ** atts )
275{
276 AMFNodeType node_type_new = NODE_TYPE_UNKNOWN;
277 switch (m_path.size()) {
278 case 0: {
279 // An AMF file must start with an <amf> tag.
280 node_type_new = NODE_TYPE_AMF;
281 if (strcmp(name, "amf") != 0) this->stop();
282 // BBS: add units logic
283 const char *units = get_attribute(atts, "unit");
284 if (units && (strcmp(units, "inch") == 0)) { m_use_inches = true; }
285 break;
286 }
287 case 1:
288 if (strcmp(name, "metadata") == 0) {
289 const char *type = get_attribute(atts, "type");
290 if (type != nullptr) {
291 m_value[0] = type;
292 node_type_new = NODE_TYPE_METADATA;
293 }
294 } else if (strcmp(name, "material") == 0) {
295 const char *material_id = get_attribute(atts, "id");
296 m_material = m_model.add_material((material_id == nullptr) ? "_" : material_id);
297 node_type_new = NODE_TYPE_MATERIAL;
298 } else if (strcmp(name, "object") == 0) {
299 const char *object_id = get_attribute(atts, "id");
300 if (object_id == nullptr)
301 this->stop();
302 else {
303 assert(m_object_vertices.empty());
304 m_object = m_model.add_object();
305 m_object_instances_map[object_id].idx = int(m_model.objects.size())-1;
306 node_type_new = NODE_TYPE_OBJECT;
307 }
308 } else if (strcmp(name, "constellation") == 0) {
309 node_type_new = NODE_TYPE_CONSTELLATION;
310 }/*else if (strcmp(name, "custom_gcodes_per_height") == 0) {
311 node_type_new = NODE_TYPE_CUSTOM_GCODE;
312 }*/
313 break;
314 case 2:
315 if (strcmp(name, "metadata") == 0) {
317 const char *type = get_attribute(atts, "type");
318 if (type == nullptr)
319 this->stop();
320 else {
321 m_value[0] = type;
322 node_type_new = NODE_TYPE_METADATA;
323 }
324 }
325 }/* else if (strcmp(name, "layer_config_ranges") == 0 && m_path[1] == NODE_TYPE_OBJECT)
326 node_type_new = NODE_TYPE_LAYER_CONFIG;*/
327 else if (strcmp(name, "mesh") == 0) {
328 if (m_path[1] == NODE_TYPE_OBJECT)
329 node_type_new = NODE_TYPE_MESH;
330 } else if (strcmp(name, "instance") == 0) {
332 const char *object_id = get_attribute(atts, "objectid");
333 if (object_id == nullptr)
334 this->stop();
335 else {
336 m_object_instances_map[object_id].instances.push_back(AMFParserContext::Instance());
337 m_instance = &m_object_instances_map[object_id].instances.back();
338 node_type_new = NODE_TYPE_INSTANCE;
339 }
340 }
341 else
342 this->stop();
343 }
344 /*else if (m_path[1] == NODE_TYPE_CUSTOM_GCODE) {
345 if (strcmp(name, "code") == 0) {
346 node_type_new = NODE_TYPE_GCODE_PER_HEIGHT;
347 m_value[0] = get_attribute(atts, "print_z");
348 m_value[1] = get_attribute(atts, "extruder");
349 m_value[2] = get_attribute(atts, "color");
350 if (get_attribute(atts, "type"))
351 {
352 m_value[3] = get_attribute(atts, "type");
353 m_value[4] = get_attribute(atts, "extra");
354 }
355 else
356 {
357 // It means that data was saved in old version (2.2.0 and older) of PrusaSlicer
358 // read old data ...
359 std::string gcode = get_attribute(atts, "gcode");
360 // ... and interpret them to the new data
361 CustomGCode::Type type= gcode == "M600" ? CustomGCode::ColorChange :
362 gcode == "M601" ? CustomGCode::PausePrint :
363 gcode == "tool_change" ? CustomGCode::ToolChange : CustomGCode::Custom;
364 m_value[3] = std::to_string(static_cast<int>(type));
365 m_value[4] = type == CustomGCode::PausePrint ? m_value[2] :
366 type == CustomGCode::Custom ? gcode : "";
367 }
368 }
369 else if (strcmp(name, "mode") == 0) {
370 node_type_new = NODE_TYPE_CUSTOM_GCODE_MODE;
371 m_value[0] = get_attribute(atts, "value");
372 }
373 }*/
374 break;
375 case 3:
376 if (m_path[2] == NODE_TYPE_MESH) {
377 assert(m_object);
378 if (strcmp(name, "vertices") == 0)
379 node_type_new = NODE_TYPE_VERTICES;
380 else if (strcmp(name, "volume") == 0) {
381 assert(! m_volume);
382 m_volume = m_object->add_volume(TriangleMesh());
383 m_volume_transform = Transform3d::Identity();
384 node_type_new = NODE_TYPE_VOLUME;
385 }
386 }
387 else if (m_path[2] == NODE_TYPE_INSTANCE) {
388 assert(m_instance);
389 if (strcmp(name, "deltax") == 0)
390 node_type_new = NODE_TYPE_DELTAX;
391 else if (strcmp(name, "deltay") == 0)
392 node_type_new = NODE_TYPE_DELTAY;
393 else if (strcmp(name, "deltaz") == 0)
394 node_type_new = NODE_TYPE_DELTAZ;
395 else if (strcmp(name, "rx") == 0)
396 node_type_new = NODE_TYPE_RX;
397 else if (strcmp(name, "ry") == 0)
398 node_type_new = NODE_TYPE_RY;
399 else if (strcmp(name, "rz") == 0)
400 node_type_new = NODE_TYPE_RZ;
401 else if (strcmp(name, "scalex") == 0)
402 node_type_new = NODE_TYPE_SCALEX;
403 else if (strcmp(name, "scaley") == 0)
404 node_type_new = NODE_TYPE_SCALEY;
405 else if (strcmp(name, "scalez") == 0)
406 node_type_new = NODE_TYPE_SCALEZ;
407 else if (strcmp(name, "scale") == 0)
408 node_type_new = NODE_TYPE_SCALE;
409 else if (strcmp(name, "mirrorx") == 0)
410 node_type_new = NODE_TYPE_MIRRORX;
411 else if (strcmp(name, "mirrory") == 0)
412 node_type_new = NODE_TYPE_MIRRORY;
413 else if (strcmp(name, "mirrorz") == 0)
414 node_type_new = NODE_TYPE_MIRRORZ;
415 else if (strcmp(name, "printable") == 0)
416 node_type_new = NODE_TYPE_PRINTABLE;
417 }
418 /*else if (m_path[2] == NODE_TYPE_LAYER_CONFIG && strcmp(name, "range") == 0) {
419 assert(m_object);
420 node_type_new = NODE_TYPE_RANGE;
421 }*/
422 break;
423 case 4:
424 if (m_path[3] == NODE_TYPE_VERTICES) {
425 if (strcmp(name, "vertex") == 0)
426 node_type_new = NODE_TYPE_VERTEX;
427 } else if (m_path[3] == NODE_TYPE_VOLUME) {
428 if (strcmp(name, "metadata") == 0) {
429 const char *type = get_attribute(atts, "type");
430 if (type == nullptr)
431 this->stop();
432 else {
433 m_value[0] = type;
434 node_type_new = NODE_TYPE_METADATA;
435 }
436 } else if (strcmp(name, "triangle") == 0)
437 node_type_new = NODE_TYPE_TRIANGLE;
438 }
439 /*else if (m_path[3] == NODE_TYPE_RANGE && strcmp(name, "metadata") == 0) {
440 m_value[0] = get_attribute(atts, "type");
441 node_type_new = NODE_TYPE_METADATA;
442 }*/
443 break;
444 case 5:
445 if (strcmp(name, "coordinates") == 0) {
446 if (m_path[4] == NODE_TYPE_VERTEX) {
447 node_type_new = NODE_TYPE_COORDINATES;
448 } else
449 this->stop();
450 } else if (name[0] == 'v' && name[1] >= '1' && name[1] <= '3' && name[2] == 0) {
451 if (m_path[4] == NODE_TYPE_TRIANGLE) {
452 node_type_new = AMFNodeType(NODE_TYPE_VERTEX1 + name[1] - '1');
453 } else
454 this->stop();
455 }
456 break;
457 case 6:
458 if ((name[0] == 'x' || name[0] == 'y' || name[0] == 'z') && name[1] == 0) {
460 node_type_new = AMFNodeType(NODE_TYPE_COORDINATE_X + name[0] - 'x');
461 else
462 this->stop();
463 }
464 break;
465 default:
466 break;
467 }
468
469 m_path.push_back(node_type_new);
470}
bool m_use_inches
Definition AMF.cpp:268
static const char * get_attribute(const char **atts, const char *id)
Definition AMF.cpp:121
AMFNodeType
Definition AMF.cpp:132

References get_attribute(), m_instance, m_material, m_model, m_object, m_object_instances_map, m_object_vertices, m_path, m_use_inches, m_value, m_volume, m_volume_transform, NODE_TYPE_AMF, NODE_TYPE_CONSTELLATION, NODE_TYPE_COORDINATE_X, NODE_TYPE_COORDINATES, NODE_TYPE_DELTAX, NODE_TYPE_DELTAY, NODE_TYPE_DELTAZ, NODE_TYPE_INSTANCE, NODE_TYPE_MATERIAL, NODE_TYPE_MESH, NODE_TYPE_METADATA, NODE_TYPE_MIRRORX, NODE_TYPE_MIRRORY, NODE_TYPE_MIRRORZ, NODE_TYPE_OBJECT, NODE_TYPE_PRINTABLE, NODE_TYPE_RX, NODE_TYPE_RY, NODE_TYPE_RZ, NODE_TYPE_SCALE, NODE_TYPE_SCALEX, NODE_TYPE_SCALEY, NODE_TYPE_SCALEZ, NODE_TYPE_TRIANGLE, NODE_TYPE_UNKNOWN, NODE_TYPE_VERTEX, NODE_TYPE_VERTEX1, NODE_TYPE_VERTICES, NODE_TYPE_VOLUME, and stop().

Referenced by Slic3r::extract_model_from_archive(), Slic3r::load_amf_file(), and startElement().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ startElement() [2/2]

void XMLCALL Slic3r::AMFParserContext::startElement ( void * userData,
const char * name,
const char ** atts )
inlinestatic
103 {
104 AMFParserContext *ctx = (AMFParserContext*)userData;
105 ctx->startElement(name, atts);
106 }

References AMFParserContext(), and startElement().

Here is the call graph for this function:

◆ stop()

void Slic3r::AMFParserContext::stop ( const std::string & msg = std::string())
inline
80 {
81 assert(! m_error);
82 assert(m_error_message.empty());
83 m_error = true;
84 m_error_message = msg;
85 XML_StopParser(m_parser, 0);
86 }

References m_error, m_error_message, and m_parser.

Referenced by endElement(), and startElement().

Here is the caller graph for this function:

Member Data Documentation

◆ m_config

DynamicPrintConfig* Slic3r::AMFParserContext::m_config { nullptr }
264{ nullptr };

Referenced by AMFParserContext().

◆ m_config_substitutions

ConfigSubstitutionContext* Slic3r::AMFParserContext::m_config_substitutions { nullptr }
266{ nullptr };

Referenced by AMFParserContext().

◆ m_error

bool Slic3r::AMFParserContext::m_error { false }
239{ false };

Referenced by error(), error_message(), and stop().

◆ m_error_message

std::string Slic3r::AMFParserContext::m_error_message

Referenced by error_message(), and stop().

◆ m_instance

Instance* Slic3r::AMFParserContext::m_instance { nullptr }
260{ nullptr };

Referenced by endElement(), and startElement().

◆ m_material

ModelMaterial* Slic3r::AMFParserContext::m_material { nullptr }
258{ nullptr };

Referenced by endElement(), and startElement().

◆ m_model

Model& Slic3r::AMFParserContext::m_model

◆ m_object

ModelObject* Slic3r::AMFParserContext::m_object { nullptr }
246{ nullptr };

Referenced by endElement(), and startElement().

◆ m_object_instances_map

std::map<std::string, Object> Slic3r::AMFParserContext::m_object_instances_map

Referenced by endDocument(), and startElement().

◆ m_object_vertices

std::vector<Vec3f> Slic3r::AMFParserContext::m_object_vertices

Referenced by endElement(), and startElement().

◆ m_parser

XML_Parser Slic3r::AMFParserContext::m_parser

◆ m_path

std::vector<AMFNodeType> Slic3r::AMFParserContext::m_path

◆ m_use_inches

bool Slic3r::AMFParserContext::m_use_inches { false }
268{ false };

Referenced by Slic3r::load_amf_file(), and startElement().

◆ m_value

std::string Slic3r::AMFParserContext::m_value[5]

◆ m_volume

ModelVolume* Slic3r::AMFParserContext::m_volume { nullptr }
252{ nullptr };

Referenced by endElement(), and startElement().

◆ m_volume_facets

std::vector<Vec3i32> Slic3r::AMFParserContext::m_volume_facets

Referenced by endElement().

◆ m_volume_transform

Transform3d Slic3r::AMFParserContext::m_volume_transform

Referenced by endElement(), and startElement().


The documentation for this struct was generated from the following file:
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Format/AMF.cpp