diff options
Diffstat (limited to 'graphics/asymptote/prc/oPRCFile.cc')
-rw-r--r-- | graphics/asymptote/prc/oPRCFile.cc | 1921 |
1 files changed, 1921 insertions, 0 deletions
diff --git a/graphics/asymptote/prc/oPRCFile.cc b/graphics/asymptote/prc/oPRCFile.cc new file mode 100644 index 0000000000..1f20a681a0 --- /dev/null +++ b/graphics/asymptote/prc/oPRCFile.cc @@ -0,0 +1,1921 @@ +/************ +* +* This file is part of a tool for producing 3D content in the PRC format. +* Copyright (C) 2008 Orest Shardt <shardtor (at) gmail dot com> and +* Michail Vidiassov <master@iaas.msu.ru> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +* +*************/ + +#include "oPRCFile.h" +#include <time.h> +#include <sstream> +#include <iostream> +#include <fstream> +#include <iomanip> +#include <cstring> +#include <zlib.h> + +namespace prc { + +#define WriteUnsignedInteger( value ) out << (uint32_t)(value); +#define WriteInteger( value ) out << (int32_t)(value); +#define WriteDouble( value ) out << (double)(value); +#define WriteString( value ) out << (value); +#define WriteUncompressedUnsignedInteger( value ) writeUncompressedUnsignedInteger(out, (uint32_t)(value)); +#define WriteUncompressedBlock( value, count ) out.write((char *)(value),(count)); +#define SerializeFileStructureUncompressedUniqueId( value ) (value).serializeFileStructureUncompressedUniqueId(out); +#define SerializeCompressedUniqueId( value ) (value).serializeCompressedUniqueId(out); +#define SerializeContentPRCBase write(out); +#define SerializeRgbColor( value ) (value).serializeRgbColor(out); +#define SerializePicture( value ) (value).serializePicture(out); +#define SerializeTextureDefinition( value ) (value)->serializeTextureDefinition(out); +#define SerializeMarkup( value ) (value)->serializeMarkup(out); +#define SerializeAnnotationEntity( value ) (value)->serializeAnnotationEntity(out); +#define SerializeFontKeysSameFont( value ) (value).serializeFontKeysSameFont(out); +#define SerializeMaterial( value ) (value)->serializeMaterial(out); + +#define SerializeUserData UserData(0,0).write(out); +#define SerializeEmptyContentPRCBase ContentPRCBase(PRC_TYPE_ROOT_PRCBase).serializeContentPRCBase(out); +#define SerializeCategory1LineStyle( value ) (value)->serializeCategory1LineStyle(out); +#define SerializeCoordinateSystem( value ) (value)->serializeCoordinateSystem(out); +#define SerializeRepresentationItem( value ) (value)->serializeRepresentationItem(out); +#define SerializePartDefinition( value ) (value)->serializePartDefinition(out); +#define SerializeProductOccurrence( value ) (value)->serializeProductOccurrence(out); +#define SerializeContextAndBodies( value ) (value)->serializeContextAndBodies(out); +#define SerializeGeometrySummary( value ) (value)->serializeGeometrySummary(out); +#define SerializeContextGraphics( value ) (value)->serializeContextGraphics(out); +#define SerializeStartHeader serializeStartHeader(out); +#define SerializeUncompressedFiles \ + { \ + const uint32_t number_of_uncompressed_files = uncompressed_files.size(); \ + WriteUncompressedUnsignedInteger (number_of_uncompressed_files) \ + for(PRCUncompressedFileList::const_iterator it = uncompressed_files.begin(); it != uncompressed_files.end(); it++) \ + { \ + WriteUncompressedUnsignedInteger ((*it)->file_size) \ + WriteUncompressedBlock ((*it)->data, (*it)->file_size) \ + } \ + } +#define SerializeModelFileData serializeModelFileData(modelFile_out); modelFile_out.compress(); +#define SerializeUnit( value ) (value).serializeUnit(out); + +using namespace std; + +void PRCFileStructure::serializeFileStructureGlobals(PRCbitStream &out) +{ + // even though this is technically not part of this section, + // it is handled here for convenience + const uint32_t number_of_schema = 0; + WriteUnsignedInteger (number_of_schema) + + WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureGlobals) + + PRCSingleAttribute sa((int32_t)PRCVersion); + PRCAttribute a("__PRC_RESERVED_ATTRIBUTE_PRCInternalVersion"); + a.addKey(sa); + ContentPRCBase cb(PRC_TYPE_ROOT_PRCBase); + cb.addAttribute(a); + cb.serializeContentPRCBase(out); + WriteUnsignedInteger (number_of_referenced_file_structures) + // SerializeFileStructureInternalGlobalData + WriteDouble (tessellation_chord_height_ratio) + WriteDouble (tessellation_angle_degree) + + // SerializeMarkupSerializationHelper + WriteString (default_font_family_name) + + const uint32_t number_of_fonts = font_keys_of_font.size(); + WriteUnsignedInteger (number_of_fonts) + for (uint32_t i=0;i<number_of_fonts;i++) + { + SerializeFontKeysSameFont (font_keys_of_font[i]) + } + + const uint32_t number_of_colors = colors.size(); + WriteUnsignedInteger (number_of_colors) + for (uint32_t i=0;i<number_of_colors;i++) + SerializeRgbColor (colors[i]) + + const uint32_t number_of_pictures = pictures.size(); + WriteUnsignedInteger (number_of_pictures) + for (uint32_t i=0;i<number_of_pictures;i++) + SerializePicture (pictures[i]) + + const uint32_t number_of_texture_definitions = texture_definitions.size(); + WriteUnsignedInteger (number_of_texture_definitions) + for (uint32_t i=0;i<number_of_texture_definitions;i++) + SerializeTextureDefinition (texture_definitions[i]) + + const uint32_t number_of_materials = materials.size(); + WriteUnsignedInteger (number_of_materials) + for (uint32_t i=0;i<number_of_materials;i++) + SerializeMaterial (materials[i]) + + // number of line patterns hard coded for now + const uint32_t number_of_line_patterns = 1; + WriteUnsignedInteger (number_of_line_patterns) + PRCLinePattern().serializeLinePattern(out); + + const uint32_t number_of_styles = styles.size(); + WriteUnsignedInteger (number_of_styles) + for (uint32_t i=0;i<number_of_styles;i++) + SerializeCategory1LineStyle (styles[i]) + + const uint32_t number_of_fill_patterns = 0; + WriteUnsignedInteger (number_of_fill_patterns) + + const uint32_t number_of_reference_coordinate_systems = reference_coordinate_systems.size(); + WriteUnsignedInteger (number_of_reference_coordinate_systems) + for (uint32_t i=0;i<number_of_reference_coordinate_systems;i++) + SerializeCoordinateSystem (reference_coordinate_systems[i]) + + SerializeUserData +} + +void PRCFileStructure::serializeFileStructureTree(PRCbitStream &out) +{ + WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureTree) + + SerializeEmptyContentPRCBase + + const uint32_t number_of_part_definitions = part_definitions.size(); + WriteUnsignedInteger (number_of_part_definitions) + for (uint32_t i=0;i<number_of_part_definitions;i++) + SerializePartDefinition (part_definitions[i]) + + const uint32_t number_of_product_occurrences = product_occurrences.size(); + WriteUnsignedInteger (number_of_product_occurrences) + for (uint32_t i=0;i<number_of_product_occurrences;i++) + { + product_occurrences[i]->unit_information.unit_from_CAD_file = true; + product_occurrences[i]->unit_information.unit = unit; + SerializeProductOccurrence (product_occurrences[i]) + } + + // SerializeFileStructureInternalData + WriteUnsignedInteger (PRC_TYPE_ASM_FileStructure) + SerializeEmptyContentPRCBase + const uint32_t next_available_index = makePRCID(); + WriteUnsignedInteger (next_available_index) + const uint32_t index_product_occurence = number_of_product_occurrences; // Asymptote (oPRCFile) specific - we write the root product last + WriteUnsignedInteger (index_product_occurence) + + SerializeUserData +} + +void PRCFileStructure::serializeFileStructureTessellation(PRCbitStream &out) +{ + WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureTessellation) + + SerializeEmptyContentPRCBase + const uint32_t number_of_tessellations = tessellations.size(); + WriteUnsignedInteger (number_of_tessellations) + for (uint32_t i=0;i<number_of_tessellations;i++) + tessellations[i]->serializeBaseTessData(out); + + SerializeUserData +} + +void PRCFileStructure::serializeFileStructureGeometry(PRCbitStream &out) +{ + WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureGeometry) + + SerializeEmptyContentPRCBase + const uint32_t number_of_contexts = contexts.size(); + WriteUnsignedInteger (number_of_contexts) + for (uint32_t i=0;i<number_of_contexts;i++) + SerializeContextAndBodies (contexts[i]) + + SerializeUserData +} + +void PRCFileStructure::serializeFileStructureExtraGeometry(PRCbitStream &out) +{ + WriteUnsignedInteger (PRC_TYPE_ASM_FileStructureExtraGeometry) + + SerializeEmptyContentPRCBase + const uint32_t number_of_contexts = contexts.size(); + WriteUnsignedInteger (number_of_contexts) + for (uint32_t i=0;i<number_of_contexts;i++) + { + SerializeGeometrySummary (contexts[i]) + SerializeContextGraphics (contexts[i]) + } + + SerializeUserData +} + +void oPRCFile::serializeModelFileData(PRCbitStream &out) +{ + // even though this is technically not part of this section, + // it is handled here for convenience + const uint32_t number_of_schema = 0; + WriteUnsignedInteger (number_of_schema) + WriteUnsignedInteger (PRC_TYPE_ASM_ModelFile) + + PRCSingleAttribute sa((int32_t)PRCVersion); + PRCAttribute a("__PRC_RESERVED_ATTRIBUTE_PRCInternalVersion"); + a.addKey(sa); + ContentPRCBase cb(PRC_TYPE_ROOT_PRCBase,"PRC file"); + cb.addAttribute(a); + cb.serializeContentPRCBase(out); + + SerializeUnit (unit) + + out << (uint32_t)1; // 1 product occurrence + //UUID + SerializeCompressedUniqueId( fileStructures[0]->file_structure_uuid ) + // index+1 + out << (uint32_t)fileStructures[0]->product_occurrences.size(); + // active + out << true; + out << (uint32_t)0; // index in model file + + SerializeUserData +} + +void makeFileUUID(PRCUniqueId& UUID) +{ + // make a UUID + static uint32_t count = 0; + ++count; + // the minimum requirement on UUIDs is that all must be unique in the file + UUID.id0 = 0x33595341; // some constant + UUID.id1 = (uint32_t)time(NULL); // the time + UUID.id2 = count; + UUID.id3 = 0xa5a55a5a; // Something random, not seeded by the time, would be nice. But for now, a constant + // maybe add something else to make it more unique + // so multiple files can be combined + // a hash of some data perhaps? +} + +void makeAppUUID(PRCUniqueId& UUID) +{ + UUID.id0 = UUID.id1 = UUID.id2 = UUID.id3 = 0; +} + +void PRCUncompressedFile::write(ostream &out) const +{ + if(data!=NULL) + { + WriteUncompressedUnsignedInteger (file_size) + out.write((char*)data,file_size); + } +} + +uint32_t PRCUncompressedFile::getSize() const +{ + return sizeof(file_size)+file_size; +} + + +void PRCStartHeader::serializeStartHeader(ostream &out) const +{ + WriteUncompressedBlock ("PRC",3) + WriteUncompressedUnsignedInteger (minimal_version_for_read) + WriteUncompressedUnsignedInteger (authoring_version) + SerializeFileStructureUncompressedUniqueId( file_structure_uuid ); + SerializeFileStructureUncompressedUniqueId( application_uuid ); +} + +uint32_t PRCStartHeader::getStartHeaderSize() const +{ + return 3+(2+2*4)*sizeof(uint32_t); +} + + +void PRCFileStructure::write(ostream &out) +{ + // SerializeFileStructureHeader + SerializeStartHeader + SerializeUncompressedFiles + globals_out.write(out); + tree_out.write(out); + tessellations_out.write(out); + geometry_out.write(out); + extraGeometry_out.write(out); +} + +#define SerializeFileStructureGlobals serializeFileStructureGlobals(globals_out); globals_out.compress(); sizes[1]=globals_out.getSize(); +#define SerializeFileStructureTree serializeFileStructureTree(tree_out); tree_out.compress(); sizes[2]=tree_out.getSize(); +#define SerializeFileStructureTessellation serializeFileStructureTessellation(tessellations_out); tessellations_out.compress(); sizes[3]=tessellations_out.getSize(); +#define SerializeFileStructureGeometry serializeFileStructureGeometry(geometry_out); geometry_out.compress(); sizes[4]=geometry_out.getSize(); +#define SerializeFileStructureExtraGeometry serializeFileStructureExtraGeometry(extraGeometry_out); extraGeometry_out.compress(); sizes[5]=extraGeometry_out.getSize(); +#define FlushSerialization resetGraphicsAndName(); +void PRCFileStructure::prepare() +{ + uint32_t size = 0; + size += getStartHeaderSize(); + size += sizeof(uint32_t); + for(PRCUncompressedFileList::const_iterator it = uncompressed_files.begin(); it != uncompressed_files.end(); it++) + size += (*it)->getSize(); + sizes[0]=size; + + SerializeFileStructureGlobals + FlushSerialization + + SerializeFileStructureTree + FlushSerialization + + SerializeFileStructureTessellation + FlushSerialization + + SerializeFileStructureGeometry + FlushSerialization + + SerializeFileStructureExtraGeometry + FlushSerialization +} + +uint32_t PRCFileStructure::getSize() +{ + uint32_t size = 0; + for(size_t i=0; i<6; i++) + size += sizes[i]; + return size; +} + + +void PRCFileStructureInformation::write(ostream &out) +{ + SerializeFileStructureUncompressedUniqueId( UUID ); + + WriteUncompressedUnsignedInteger (reserved) + WriteUncompressedUnsignedInteger (number_of_offsets) + for(uint32_t i = 0; i < number_of_offsets; ++i) + { + WriteUncompressedUnsignedInteger (offsets[i]) + } +} + +uint32_t PRCFileStructureInformation::getSize() +{ + return (4+2+number_of_offsets)*sizeof(uint32_t); +} + +void PRCHeader::write(ostream &out) +{ + SerializeStartHeader + WriteUncompressedUnsignedInteger (number_of_file_structures) + for(uint32_t i = 0; i < number_of_file_structures; ++i) + { + fileStructureInformation[i].write(out); + } + WriteUncompressedUnsignedInteger (model_file_offset) + WriteUncompressedUnsignedInteger (file_size) + SerializeUncompressedFiles +} + +uint32_t PRCHeader::getSize() +{ + uint32_t size = getStartHeaderSize() + sizeof(uint32_t); + for(uint32_t i = 0; i < number_of_file_structures; ++i) + size += fileStructureInformation[i].getSize(); + size += 3*sizeof(uint32_t); + for(PRCUncompressedFileList::const_iterator it = uncompressed_files.begin(); it != uncompressed_files.end(); it++) + size += (*it)->getSize(); + return size; +} + +void oPRCFile::doGroup(PRCgroup& group) +{ + const std::string& name = group.name; + + PRCProductOccurrence*& product_occurrence = group.product_occurrence; + PRCProductOccurrence*& parent_product_occurrence = group.parent_product_occurrence; + PRCPartDefinition*& part_definition = group.part_definition; + PRCPartDefinition*& parent_part_definition = group.parent_part_definition; + + if(group.options.tess) + { + if(!group.lines.empty()) + { + for(PRCtesslineMap::const_iterator wit=group.lines.begin(); wit!=group.lines.end(); wit++) + { + bool same_color = true; + const PRCtesslineList& lines = wit->second; + const PRCRgbColor &color = lines.front().color; + for(PRCtesslineList::const_iterator lit=lines.begin(); lit!=lines.end(); lit++) + if(color!=lit->color) + { + same_color = false; + break; + } + map<PRCVector3d,uint32_t> points; + PRC3DWireTess *tess = new PRC3DWireTess(); + if(!same_color) + { + tess->is_segment_color = true; + tess->is_rgba = false; + } + for(PRCtesslineList::const_iterator lit=lines.begin(); lit!=lines.end(); lit++) + { + tess->wire_indexes.push_back(lit->point.size()); + for(uint32_t i=0; i<lit->point.size(); i++) + { + map<PRCVector3d,uint32_t>::iterator pPoint = points.find(lit->point[i]); + if(pPoint!=points.end()) + tess->wire_indexes.push_back(pPoint->second); + else + { + const uint32_t point_index = tess->coordinates.size(); + points.insert(make_pair(lit->point[i],point_index)); + tess->wire_indexes.push_back(point_index); + tess->coordinates.push_back(lit->point[i].x); + tess->coordinates.push_back(lit->point[i].y); + tess->coordinates.push_back(lit->point[i].z); + } + if(!same_color && i>0) + { + tess->rgba_vertices.push_back(byte(lit->color.red)); + tess->rgba_vertices.push_back(byte(lit->color.green)); + tess->rgba_vertices.push_back(byte(lit->color.blue)); + } + } + } + const uint32_t tess_index = add3DWireTess(tess); + PRCPolyWire *polyWire = new PRCPolyWire(); + polyWire->index_tessellation = tess_index; + if(same_color) + polyWire->index_of_line_style = addColourWidth(RGBAColour(color.red,color.green,color.blue),wit->first); + else + polyWire->index_of_line_style = addColourWidth(RGBAColour(1,1,1),wit->first); + part_definition->addPolyWire(polyWire); + } + } +// make rectangles pairs of triangles in a tesselation + if(!group.rectangles.empty()) + { + bool same_color = true; + const uint32_t &style = group.rectangles.front().style; + for(PRCtessrectangleList::const_iterator rit=group.rectangles.begin(); rit!=group.rectangles.end(); rit++) + if(style!=rit->style) + { + same_color = false; + break; + } + map<PRCVector3d,uint32_t> points; + PRC3DTess *tess = new PRC3DTess(); + tess->crease_angle = group.options.crease_angle; + PRCTessFace *tessFace = new PRCTessFace(); + tessFace->used_entities_flag=PRC_FACETESSDATA_Triangle; + uint32_t triangles = 0; + for(PRCtessrectangleList::const_iterator rit=group.rectangles.begin(); rit!=group.rectangles.end(); rit++) + { + const bool degenerate = (rit->vertices[0]==rit->vertices[1]); + uint32_t vertex_indices[4]; + for(size_t i = (degenerate?1:0); i < 4; ++i) + { + map<PRCVector3d,uint32_t>::const_iterator pPoint = points.find(rit->vertices[i]); + if(pPoint!=points.end()) + vertex_indices[i] = pPoint->second; + else + { + points.insert(make_pair(rit->vertices[i],(vertex_indices[i] = tess->coordinates.size()))); + tess->coordinates.push_back(rit->vertices[i].x); + tess->coordinates.push_back(rit->vertices[i].y); + tess->coordinates.push_back(rit->vertices[i].z); + } + } + if(degenerate) + { + tess->triangulated_index.push_back(vertex_indices[1]); + tess->triangulated_index.push_back(vertex_indices[2]); + tess->triangulated_index.push_back(vertex_indices[3]); + triangles++; + if(!same_color) + tessFace->line_attributes.push_back(rit->style); + } + else + { + tess->triangulated_index.push_back(vertex_indices[0]); + tess->triangulated_index.push_back(vertex_indices[2]); + tess->triangulated_index.push_back(vertex_indices[3]); + triangles++; + if(!same_color) + tessFace->line_attributes.push_back(rit->style); + tess->triangulated_index.push_back(vertex_indices[3]); + tess->triangulated_index.push_back(vertex_indices[1]); + tess->triangulated_index.push_back(vertex_indices[0]); + triangles++; + if(!same_color) + tessFace->line_attributes.push_back(rit->style); + } + } + tessFace->sizes_triangulated.push_back(triangles); + tess->addTessFace(tessFace); + const uint32_t tess_index = add3DTess(tess); + PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); + polyBrepModel->index_tessellation = tess_index; + polyBrepModel->is_closed = group.options.closed; + if(same_color) + polyBrepModel->index_of_line_style = style; + part_definition->addPolyBrepModel(polyBrepModel); + } + } + + if(!group.quads.empty()) + { + map<PRCVector3d,uint32_t> points; + PRC3DTess *tess = new PRC3DTess(); + tess->crease_angle = group.options.crease_angle; + PRCTessFace *tessFace = new PRCTessFace(); + tessFace->used_entities_flag=PRC_FACETESSDATA_Triangle; + uint32_t triangles = 0; + + tessFace->is_rgba = false; + for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++) + { + const RGBAColour* C = qit->colours; + if(C[0].A != 1.0 || C[1].A != 1.0 || C[2].A != 1.0 || C[3].A != 1.0) + { + tessFace->is_rgba = true; + break; + } + } + bool same_colour = true; + const RGBAColour& colour = group.quads.front().colours[0]; + for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++) + { + const RGBAColour* C = qit->colours; + if(colour!=C[0] || colour!=C[1] || colour!=C[2] || colour!=C[3]) + { + same_colour = false; + break; + } + } + + for(PRCtessquadList::const_iterator qit=group.quads.begin(); qit!=group.quads.end(); qit++) + { + const RGBAColour* C = qit->colours; + const bool degenerate = (qit->vertices[0]==qit->vertices[1]); + uint32_t vertex_indices[4]; + for(size_t i = (degenerate?1:0); i < 4; ++i) + { + map<PRCVector3d,uint32_t>::const_iterator pPoint = points.find(qit->vertices[i]); + if(pPoint!=points.end()) + vertex_indices[i] = pPoint->second; + else + { + points.insert(make_pair(qit->vertices[i],(vertex_indices[i] = tess->coordinates.size()))); + tess->coordinates.push_back(qit->vertices[i].x); + tess->coordinates.push_back(qit->vertices[i].y); + tess->coordinates.push_back(qit->vertices[i].z); + } + } + if(degenerate) + { + tess->triangulated_index.push_back(vertex_indices[1]); + tess->triangulated_index.push_back(vertex_indices[2]); + tess->triangulated_index.push_back(vertex_indices[3]); + triangles++; + if(!same_colour) + { + tessFace->rgba_vertices.push_back(byte(C[1].R)); + tessFace->rgba_vertices.push_back(byte(C[1].G)); + tessFace->rgba_vertices.push_back(byte(C[1].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[1].A)); + + tessFace->rgba_vertices.push_back(byte(C[2].R)); + tessFace->rgba_vertices.push_back(byte(C[2].G)); + tessFace->rgba_vertices.push_back(byte(C[2].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[2].A)); + + tessFace->rgba_vertices.push_back(byte(C[3].R)); + tessFace->rgba_vertices.push_back(byte(C[3].G)); + tessFace->rgba_vertices.push_back(byte(C[3].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[3].A)); + } + } + else + { + tess->triangulated_index.push_back(vertex_indices[0]); + tess->triangulated_index.push_back(vertex_indices[2]); + tess->triangulated_index.push_back(vertex_indices[3]); + triangles++; + if(!same_colour) + { + tessFace->rgba_vertices.push_back(byte(C[0].R)); + tessFace->rgba_vertices.push_back(byte(C[0].G)); + tessFace->rgba_vertices.push_back(byte(C[0].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[0].A)); + + tessFace->rgba_vertices.push_back(byte(C[2].R)); + tessFace->rgba_vertices.push_back(byte(C[2].G)); + tessFace->rgba_vertices.push_back(byte(C[2].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[2].A)); + + tessFace->rgba_vertices.push_back(byte(C[3].R)); + tessFace->rgba_vertices.push_back(byte(C[3].G)); + tessFace->rgba_vertices.push_back(byte(C[3].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[3].A)); + } + tess->triangulated_index.push_back(vertex_indices[3]); + tess->triangulated_index.push_back(vertex_indices[1]); + tess->triangulated_index.push_back(vertex_indices[0]); + triangles++; + if(!same_colour) + { + tessFace->rgba_vertices.push_back(byte(C[3].R)); + tessFace->rgba_vertices.push_back(byte(C[3].G)); + tessFace->rgba_vertices.push_back(byte(C[3].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[3].A)); + + tessFace->rgba_vertices.push_back(byte(C[1].R)); + tessFace->rgba_vertices.push_back(byte(C[1].G)); + tessFace->rgba_vertices.push_back(byte(C[1].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[1].A)); + + tessFace->rgba_vertices.push_back(byte(C[0].R)); + tessFace->rgba_vertices.push_back(byte(C[0].G)); + tessFace->rgba_vertices.push_back(byte(C[0].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[0].A)); + } + } + } + tessFace->sizes_triangulated.push_back(triangles); + tess->addTessFace(tessFace); + const uint32_t tess_index = add3DTess(tess); + PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); + polyBrepModel->index_tessellation = tess_index; + polyBrepModel->is_closed = group.options.closed; + if(same_colour) + polyBrepModel->index_of_line_style = addColour(colour); + part_definition->addPolyBrepModel(polyBrepModel); + } + + if(!group.points.empty()) + { + for(PRCpointsetMap::const_iterator pit=group.points.begin(); pit!=group.points.end(); pit++) + { + PRCPointSet *pointset = new PRCPointSet(); + pointset->index_of_line_style = pit->first; + pointset->point = pit->second; + part_definition->addPointSet(pointset); + } + } + + if(!group.pointsets.empty()) + { + for(std::vector<PRCPointSet*>::iterator pit=group.pointsets.begin(); pit!=group.pointsets.end(); pit++) + { + part_definition->addPointSet(*pit); + } + } + + if(!group.polymodels.empty()) + { + for(std::vector<PRCPolyBrepModel*>::iterator pit=group.polymodels.begin(); pit!=group.polymodels.end(); pit++) + { + (*pit)->is_closed = group.options.closed; + part_definition->addPolyBrepModel(*pit); + } + } + + if(!group.polywires.empty()) + { + for(std::vector<PRCPolyWire*>::iterator pit=group.polywires.begin(); pit!=group.polywires.end(); pit++) + { + part_definition->addPolyWire(*pit); + } + } + + if(!group.wires.empty()) + { + PRCTopoContext *wireContext = NULL; + const uint32_t context_index = getTopoContext(wireContext); + for(PRCwireList::iterator wit=group.wires.begin(); wit!=group.wires.end(); wit++) + { + PRCWireEdge *wireEdge = new PRCWireEdge; + wireEdge->curve_3d = wit->curve; + PRCSingleWireBody *wireBody = new PRCSingleWireBody; + wireBody->setWireEdge(wireEdge); + const uint32_t wire_body_index = wireContext->addSingleWireBody(wireBody); + PRCWire *wire = new PRCWire(); + wire->index_of_line_style = wit->style; + wire->context_id = context_index; + wire->body_id = wire_body_index; + if(wit->transform) + wire->index_local_coordinate_system = addTransform(wit->transform); + part_definition->addWire(wire); + } + } + + PRCfaceList &faces = group.faces; + if(!faces.empty()) + { + bool same_color = true; + const uint32_t style = faces.front().style; + for(PRCfaceList::const_iterator fit=faces.begin(); fit!=faces.end(); fit++) + if(style!=fit->style) + { + same_color = false; + break; + } + PRCTopoContext *context = NULL; + const uint32_t context_index = getTopoContext(context); + context->granularity = group.options.granularity; + // Acrobat 9 also does the following: + // context->tolerance = group.options.granularity; + // context->have_smallest_face_thickness = true; + // context->smallest_thickness = group.options.granularity; + PRCShell *shell = new PRCShell; + + for(PRCfaceList::iterator fit=faces.begin(); fit!=faces.end(); fit++) + { + if(fit->transform || group.options.do_break || + (fit->transparent && !group.options.no_break)) + { + PRCShell *shell = new PRCShell; + shell->addFace(fit->face); + PRCConnex *connex = new PRCConnex; + connex->addShell(shell); + PRCBrepData *body = new PRCBrepData; + body->addConnex(connex); + const uint32_t body_index = context->addBrepData(body); + + PRCBrepModel *brepmodel = new PRCBrepModel(); + brepmodel->index_of_line_style = fit->style; + brepmodel->context_id = context_index; + brepmodel->body_id = body_index; + brepmodel->is_closed = group.options.closed; + + brepmodel->index_local_coordinate_system = addTransform(fit->transform); + + part_definition->addBrepModel(brepmodel); + } + else + { + if(!same_color) + fit->face->index_of_line_style = fit->style; + shell->addFace(fit->face); + } + } + if(shell->face.empty()) + { + delete shell; + } + else + { + PRCConnex *connex = new PRCConnex; + connex->addShell(shell); + PRCBrepData *body = new PRCBrepData; + body->addConnex(connex); + const uint32_t body_index = context->addBrepData(body); + PRCBrepModel *brepmodel = new PRCBrepModel(); + if(same_color) + brepmodel->index_of_line_style = style; + brepmodel->context_id = context_index; + brepmodel->body_id = body_index; + brepmodel->is_closed = group.options.closed; + part_definition->addBrepModel(brepmodel); + } + } + + PRCcompfaceList &compfaces = group.compfaces; + if(!compfaces.empty()) + { + bool same_color = true; + const uint32_t style = compfaces.front().style; + for(PRCcompfaceList::const_iterator fit=compfaces.begin(); fit!=compfaces.end(); fit++) + if(style!=fit->style) + { + same_color = false; + break; + } + PRCTopoContext *context = NULL; + const uint32_t context_index = getTopoContext(context); + PRCCompressedBrepData *body = new PRCCompressedBrepData; + + body->serial_tolerance=group.options.compression; + body->brep_data_compressed_tolerance=0.1*group.options.compression; + + for(PRCcompfaceList::const_iterator fit=compfaces.begin(); fit!=compfaces.end(); fit++) + { + if(group.options.do_break || + (fit->transparent && !group.options.no_break)) + { + PRCCompressedBrepData *body = new PRCCompressedBrepData; + body->face.push_back(fit->face); + + body->serial_tolerance=group.options.compression; + body->brep_data_compressed_tolerance=2.8346456* + group.options.compression; + const uint32_t body_index = context->addCompressedBrepData(body); + + PRCBrepModel *brepmodel = new PRCBrepModel(); + brepmodel->index_of_line_style = fit->style; + brepmodel->context_id = context_index; + brepmodel->body_id = body_index; + brepmodel->is_closed = group.options.closed; + + part_definition->addBrepModel(brepmodel); + } + else + { + if(!same_color) + fit->face->index_of_line_style = fit->style; + body->face.push_back(fit->face); + } + } + if(body->face.empty()) + { + delete body; + } + else + { + const uint32_t body_index = context->addCompressedBrepData(body); + PRCBrepModel *brepmodel = new PRCBrepModel(); + if(same_color) + brepmodel->index_of_line_style = style; + brepmodel->context_id = context_index; + brepmodel->body_id = body_index; + brepmodel->is_closed = group.options.closed; + part_definition->addBrepModel(brepmodel); + } + } + + // Simplify and reduce to as simple entities as possible + // products with named representation items can not be reduced to sets, since + // outside references are already set + bool nonamedparts = true; + for(PRCRepresentationItemList::const_iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++) + { + if (!(*it)->name.empty()) + { + nonamedparts = false; + break; + } + } + lastgroupname.clear(); + lastgroupnames.clear(); + // First option - reduce to one element in parent + if (parent_part_definition && product_occurrence->index_son_occurrence.empty() && + part_definition->representation_item.size() == 1 && + ( name.empty() || part_definition->representation_item.front()->name.empty() ) && + ( !group.transform || part_definition->representation_item.front()->index_local_coordinate_system==m1) ) + { + if(part_definition->representation_item.front()->name.empty() ) + part_definition->representation_item.front()->name = name; + if(part_definition->representation_item.front()->index_local_coordinate_system==m1) + part_definition->representation_item.front()->index_local_coordinate_system = addTransform(group.transform); + lastgroupname = calculate_unique_name(part_definition->representation_item.front(), parent_product_occurrence); + parent_part_definition->addRepresentationItem(part_definition->representation_item.front()); + part_definition->representation_item.clear(); + delete product_occurrence; product_occurrence = NULL; + delete part_definition; part_definition = NULL; + } + // Second option - reduce to a set + else if (parent_part_definition && product_occurrence->index_son_occurrence.empty() && + !part_definition->representation_item.empty() && + !group.options.do_break && nonamedparts) + { + PRCSet *set = new PRCSet(name); + set->index_local_coordinate_system = addTransform(group.transform); + lastgroupname = calculate_unique_name(set, parent_product_occurrence); + for(PRCRepresentationItemList::iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++) + { + lastgroupnames.push_back(calculate_unique_name(*it, parent_product_occurrence)); + set->addRepresentationItem(*it); + } + part_definition->representation_item.clear(); + parent_part_definition->addSet(set); + delete product_occurrence; product_occurrence = NULL; + delete part_definition; part_definition = NULL; + } + // Third option - create product + else if ( !product_occurrence->index_son_occurrence.empty() || !part_definition->representation_item.empty()) + { + // if everything is enclosed in one group - drop the root group + if (parent_product_occurrence == NULL && group.transform == NULL && + part_definition->representation_item.empty() && product_occurrence->index_son_occurrence.size()==1) { + delete part_definition; part_definition = NULL; + delete product_occurrence; product_occurrence = NULL; + } + else + { + lastgroupname = calculate_unique_name(product_occurrence, NULL); + if (part_definition->representation_item.empty()) { + delete part_definition; part_definition = NULL; + } + else + { + for(PRCRepresentationItemList::const_iterator it=part_definition->representation_item.begin(); it!=part_definition->representation_item.end(); it++) + if ((*it)->name.empty()) + lastgroupnames.push_back(calculate_unique_name(*it, product_occurrence)); + product_occurrence->index_part = addPartDefinition(part_definition); + } + if (group.transform) { + product_occurrence->location = group.transform; + group.transform = NULL; + } + if (parent_product_occurrence) { + parent_product_occurrence->index_son_occurrence.push_back(addProductOccurrence(product_occurrence)); + } + else { + addProductOccurrence(product_occurrence); + } + } + } + // Last case - absolutely nothing to do + else + { + delete product_occurrence; product_occurrence = NULL; + delete part_definition; part_definition = NULL; + } + +} + +std::string oPRCFile::calculate_unique_name(const ContentPRCBase *prc_entity,const ContentPRCBase *prc_occurence) +{ + std::stringstream ss (std::stringstream::in | std::stringstream::out); + uint8_t *serialization_buffer = NULL; + PRCbitStream serialization(serialization_buffer,0u); + const PRCFileStructure *pfile_structure = fileStructures[0]; + const PRCUniqueId& uuid = pfile_structure->file_structure_uuid; +// ConvertUniqueIdentifierToString (prc_entity) +// SerializeCompressedUniqueId (file_structure) + serialization << uuid.id0 << uuid.id1 << uuid.id2 << uuid.id3; +// WriteUnsignedInteger (type) + serialization << prc_entity->getType(); +// WriteUnsignedInteger (unique_identifier) + serialization << prc_entity->getPRCID(); + if (prc_occurence) + { +// serialization_buffer = Flush serialization (serialization) + { + const uint32_t size_serialization = serialization.getSize(); + while(size_serialization == serialization.getSize()) + serialization << false; + } +// ConvertUniqueIdentifierToString (prc_occurrence_unique_id) +// SerializeCompressedUniqueId (file_structure) + serialization << uuid.id0 << uuid.id1 << uuid.id2 << uuid.id3; +// WriteUnsignedInteger (type) + serialization << (uint32_t)PRC_TYPE_ASM_ProductOccurence; +// WriteUnsignedInteger (unique_identifier) + serialization << prc_occurence->getPRCID(); + } + ss << (prc_entity->name.empty()?"node":prc_entity->name) << '.'; + const uint32_t size_serialization = serialization.getSize(); + for(size_t j=0; j<size_serialization; j++) + ss << hex << setfill('0') << setw(2) << (uint32_t)(serialization_buffer[j]); + + return ss.str(); +} + +bool oPRCFile::finish() +{ + if(groups.size()!=1) { + fputs("begingroup without matching endgroup",stderr); + exit(1); + } + doGroup(groups.top()); + + // write each section's bit data + fileStructures[0]->prepare(); + SerializeModelFileData + + // create the header + + // fill out enough info so that sizes can be computed correctly + header.number_of_file_structures = number_of_file_structures; + header.fileStructureInformation = new PRCFileStructureInformation[number_of_file_structures]; + for(uint32_t i = 0; i < number_of_file_structures; ++i) + { + header.fileStructureInformation[i].UUID = fileStructures[i]->file_structure_uuid; + header.fileStructureInformation[i].reserved = 0; + header.fileStructureInformation[i].number_of_offsets = 6; + header.fileStructureInformation[i].offsets = new uint32_t[6]; + } + + header.minimal_version_for_read = PRCVersion; + header.authoring_version = PRCVersion; + makeFileUUID(header.file_structure_uuid); + makeAppUUID(header.application_uuid); + + header.file_size = getSize(); + header.model_file_offset = header.file_size - modelFile_out.getSize(); + + uint32_t currentOffset = header.getSize(); + + for(uint32_t i = 0; i < number_of_file_structures; ++i) + { + for(size_t j=0; j<6; j++) + { + header.fileStructureInformation[i].offsets[j] = currentOffset; + currentOffset += fileStructures[i]->sizes[j]; + } + } + + // write the data + header.write(output); + + for(uint32_t i = 0; i < number_of_file_structures; ++i) + { + fileStructures[i]->write(output); + } + + modelFile_out.write(output); + output.flush(); + + for(uint32_t i = 0; i < number_of_file_structures; ++i) + delete[] header.fileStructureInformation[i].offsets; + delete[] header.fileStructureInformation; + + return true; +} + +uint32_t oPRCFile::getSize() +{ + uint32_t size = header.getSize(); + + for(uint32_t i = 0; i < number_of_file_structures; ++i) + { + size += fileStructures[i]->getSize(); + } + + size += modelFile_out.getSize(); + return size; +} + +uint32_t PRCFileStructure::addPicture(EPRCPictureDataFormat format, uint32_t size, const uint8_t *p, uint32_t width, uint32_t height, std::string name) +{ + uint8_t *data = NULL; + uint32_t components=0; + PRCPicture picture(name); + if(size==0 || p==NULL) + { cerr << "image not set" << endl; return m1; } + PRCUncompressedFile* uncompressed_file = new PRCUncompressedFile; + if(format==KEPRCPicture_PNG || format==KEPRCPicture_JPG) + { + data = new uint8_t[size]; + memcpy(data, p, size); + uncompressed_files.push_back(uncompressed_file); + uncompressed_files.back()->file_size = size; + uncompressed_files.back()->data = data; + picture.format = format; + picture.uncompressed_file_index = uncompressed_files.size()-1; + picture.pixel_width = 0; // width and height are ignored for JPG and PNG pictures - but let us keep things clean + picture.pixel_height = 0; + pictures.push_back(picture); + return pictures.size()-1; + } + + switch(format) + { + case KEPRCPicture_BITMAP_RGB_BYTE: + components = 3; break; + case KEPRCPicture_BITMAP_RGBA_BYTE: + components = 4; break; + case KEPRCPicture_BITMAP_GREY_BYTE: + components = 1; break; + case KEPRCPicture_BITMAP_GREYA_BYTE: + components = 2; break; + default: + { cerr << "unknown picture format" << endl; return m1; } + } + if(width==0 || height==0) + { cerr << "width or height parameter not set" << endl; return m1; } + if (size < width*height*components) + { cerr << "image too small" << endl; return m1; } + + { + uint32_t compressedDataSize = 0; + const int CHUNK= 1024; // is this reasonable? + + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + if(deflateInit(&strm,Z_DEFAULT_COMPRESSION) != Z_OK) + { cerr << "Compression initialization failed" << endl; return m1; } + unsigned int sizeAvailable = deflateBound(&strm,size); + uint8_t *compressedData = (uint8_t*) malloc(sizeAvailable); + strm.avail_in = size; + strm.next_in = (unsigned char*)p; + strm.next_out = (unsigned char*)compressedData; + strm.avail_out = sizeAvailable; + + int code; + unsigned int chunks = 0; + while((code = deflate(&strm,Z_FINISH)) == Z_OK) + { + ++chunks; + // strm.avail_out should be 0 if we got Z_OK + compressedDataSize = sizeAvailable - strm.avail_out; + compressedData = (uint8_t*) realloc(compressedData,CHUNK*chunks); + strm.next_out = (Bytef*)(compressedData + compressedDataSize); + strm.avail_out += CHUNK; + sizeAvailable += CHUNK; + } + compressedDataSize = sizeAvailable-strm.avail_out; + + if(code != Z_STREAM_END) + { + deflateEnd(&strm); + free(compressedData); + { cerr << "Compression error" << endl; return m1; } + } + + deflateEnd(&strm); + size = compressedDataSize; + data = new uint8_t[compressedDataSize]; + memcpy(data, compressedData, compressedDataSize); + free(compressedData); + } + uncompressed_files.push_back(uncompressed_file); + uncompressed_files.back()->file_size = size; + uncompressed_files.back()->data = data; + picture.format = format; + picture.uncompressed_file_index = uncompressed_files.size()-1; + picture.pixel_width = width; + picture.pixel_height = height; + pictures.push_back(picture); + return pictures.size()-1; +} + +uint32_t PRCFileStructure::addTextureDefinition(PRCTextureDefinition*& pTextureDefinition) +{ + texture_definitions.push_back(pTextureDefinition); + pTextureDefinition = NULL; + return texture_definitions.size()-1; +} + +uint32_t PRCFileStructure::addRgbColor(const PRCRgbColor &color) +{ + colors.push_back(color); + return 3*(colors.size()-1); +} + +uint32_t PRCFileStructure::addRgbColorUnique(const PRCRgbColor &color) +{ + for(uint32_t i = 0; i < colors.size(); ++i) + { + if(colors[i] == color) + return 3*i; + } + colors.push_back(color); + return 3*(colors.size()-1); +} + +uint32_t oPRCFile::addColor(const PRCRgbColor &color) +{ + PRCcolorMap::const_iterator pColor = colorMap.find(color); + if(pColor!=colorMap.end()) + return pColor->second; +// color_index = addRgbColorUnique(color); + const uint32_t color_index = fileStructures[0]->addRgbColor(color); + colorMap.insert(make_pair(color,color_index)); + return color_index; +} + +uint32_t oPRCFile::addColour(const RGBAColour &colour) +{ + PRCcolourMap::const_iterator pColour = colourMap.find(colour); + if(pColour!=colourMap.end()) + return pColour->second; + const uint32_t color_index = addColor(PRCRgbColor(colour.R, colour.G, colour.B)); + PRCStyle *style = new PRCStyle(); + style->line_width = 1.0; + style->is_vpicture = false; + style->line_pattern_vpicture_index = 0; + style->is_material = false; + style->color_material_index = color_index; + style->is_transparency_defined = (colour.A < 1.0); + style->transparency = (uint8_t)(colour.A * 256); + style->additional = 0; + const uint32_t style_index = fileStructures[0]->addStyle(style); + colourMap.insert(make_pair(colour,style_index)); + return style_index; +} + +uint32_t oPRCFile::addColourWidth(const RGBAColour &colour, double width) +{ + RGBAColourWidth colourwidth(colour.R, colour.G, colour.B, colour.A, width); + PRCcolourwidthMap::const_iterator pColour = colourwidthMap.find(colourwidth); + if(pColour!=colourwidthMap.end()) + return pColour->second; + const uint32_t color_index = addColor(PRCRgbColor(colour.R, colour.G, colour.B)); + PRCStyle *style = new PRCStyle(); + style->line_width = width; + style->is_vpicture = false; + style->line_pattern_vpicture_index = 0; + style->is_material = false; + style->color_material_index = color_index; + style->is_transparency_defined = (colour.A < 1.0); + style->transparency = (uint8_t)(colour.A * 256); + style->additional = 0; + const uint32_t style_index = fileStructures[0]->addStyle(style); + colourwidthMap.insert(make_pair(colourwidth,style_index)); + return style_index; +} + +uint32_t oPRCFile::addTransform(PRCGeneralTransformation3d*& transform) +{ + if(!transform) + return m1; + PRCtransformMap::const_iterator pTransform = transformMap.find(*transform); + if(pTransform!=transformMap.end()) + return pTransform->second; + PRCCoordinateSystem *coordinateSystem = new PRCCoordinateSystem(); + bool transform_replaced = false; + if( transform->M(0,1)==0 && transform->M(0,2)==0 && + transform->M(1,0)==0 && transform->M(1,2)==0 && + transform->M(2,0)==0 && transform->M(2,1)==0 && + transform->M(3,0)==0 && transform->M(3,1)==0 && transform->M(3,2)==0 && transform->M(3,3)==1 ) + { + transform_replaced = true; + PRCCartesianTransformation3d *carttransform = new PRCCartesianTransformation3d; +// if(transform->M(0,3)==0 && transform->M(1,3)==0 && transform->M(1,3)==0 && +// transform->M(0,0)==1 && transform->M(1,1)==1 && transform->M(2,2)==1 ) +// carttransform->behaviour = PRC_TRANSFORMATION_Identity; + if(transform->M(0,3)!=0 || transform->M(1,3)!=0 || transform->M(2,3)!=0) + { + carttransform->behaviour |= PRC_TRANSFORMATION_Translate; + carttransform->origin.Set(transform->M(0,3),transform->M(1,3),transform->M(2,3)); + } + if(transform->M(0,0)!=transform->M(1,1) || transform->M(0,0)!=transform->M(2,2)) + { + carttransform->behaviour |= PRC_TRANSFORMATION_NonUniformScale; + carttransform->scale.Set(transform->M(0,0),transform->M(1,1),transform->M(2,2)); + } + else + if(transform->M(0,0)!=1) + { + carttransform->behaviour |= PRC_TRANSFORMATION_Scale; + carttransform->uniform_scale=transform->M(0,0); + } + coordinateSystem->axis_set = carttransform; + } + else + coordinateSystem->axis_set = transform; + const uint32_t coordinate_system_index = fileStructures[0]->addCoordinateSystem(coordinateSystem); + transformMap.insert(make_pair(*transform,coordinate_system_index)); + if(transform_replaced) + delete transform; + transform = NULL; + return coordinate_system_index; +} + +uint32_t oPRCFile::addTransform(const double* t) +{ + if(!t) + return m1; + PRCGeneralTransformation3d* transform = new PRCGeneralTransformation3d(t); + return addTransform(transform); +} + +uint32_t oPRCFile::addTransform(const double origin[3], const double x_axis[3], const double y_axis[3], double scale) +{ + PRCCartesianTransformation3d* transform = new PRCCartesianTransformation3d(origin, x_axis, y_axis, scale); + if(transform->behaviour==PRC_TRANSFORMATION_Identity) + return m1; + PRCCoordinateSystem *coordinateSystem = new PRCCoordinateSystem(); + coordinateSystem->axis_set = transform; + const uint32_t coordinate_system_index = fileStructures[0]->addCoordinateSystem(coordinateSystem); + return coordinate_system_index; +} + +uint32_t oPRCFile::addMaterial(const PRCmaterial& m) +{ + uint32_t material_index = m1; + const PRCmaterialgeneric materialgeneric(m); + PRCmaterialgenericMap::const_iterator pMaterialgeneric = materialgenericMap.find(materialgeneric); + if(pMaterialgeneric!=materialgenericMap.end()) + material_index = pMaterialgeneric->second; + else +{ + PRCMaterialGeneric *materialGeneric = new PRCMaterialGeneric(); + const PRCRgbColor ambient(m.ambient.R, m.ambient.G, m.ambient.B); + materialGeneric->ambient = addColor(ambient); + const PRCRgbColor diffuse(m.diffuse.R, m.diffuse.G, m.diffuse.B); + materialGeneric->diffuse = addColor(diffuse); + const PRCRgbColor emissive(m.emissive.R, m.emissive.G, m.emissive.B); + + materialGeneric->emissive = addColor(emissive); + const PRCRgbColor specular(m.specular.R, m.specular.G, m.specular.B); + materialGeneric->specular = addColor(specular); + + materialGeneric->shininess = m.shininess; + materialGeneric->ambient_alpha = m.ambient.A; + materialGeneric->diffuse_alpha = m.diffuse.A; + materialGeneric->emissive_alpha = m.emissive.A; + materialGeneric->specular_alpha = m.specular.A; + material_index = addMaterialGeneric(materialGeneric); + materialgenericMap.insert(make_pair(materialgeneric,material_index)); + } + uint32_t color_material_index = m1; + if(m.picture_data!=NULL) + { + uint32_t picture_index = m1; + PRCpicture picture(m); + PRCpictureMap::const_iterator pPicture = pictureMap.find(picture); + if(pPicture!=pictureMap.end()) + picture_index = pPicture->second; + else + { + picture_index = addPicture(picture); + uint8_t* data = new uint8_t[picture.size]; + memcpy(data,picture.data,picture.size); + picture.data = data; + pictureMap.insert(make_pair(picture,picture_index)); + } + + uint32_t texture_definition_index = m1; + PRCtexturedefinition texturedefinition(picture_index, m); + PRCtexturedefinitionMap::const_iterator pTexturedefinition = texturedefinitionMap.find(texturedefinition); + if(pTexturedefinition!=texturedefinitionMap.end()) + texture_definition_index = pTexturedefinition->second; + else + { + PRCTextureDefinition *TextureDefinition = new PRCTextureDefinition; + if (m.picture_size==216688 && m.picture_format==KEPRCPicture_JPG) + TextureDefinition->texture_mapping_attribute=PRC_TEXTURE_MAPPING_OPACITY; + TextureDefinition->picture_index = picture_index; + TextureDefinition->texture_function = m.picture_replace ? KEPRCTextureFunction_Replace : KEPRCTextureFunction_Modulate; + TextureDefinition->texture_wrapping_mode_S = m.picture_repeat ? KEPRCTextureWrappingMode_Repeat : KEPRCTextureWrappingMode_ClampToEdge; + TextureDefinition->texture_wrapping_mode_T = m.picture_repeat ? KEPRCTextureWrappingMode_Repeat : KEPRCTextureWrappingMode_ClampToEdge; + TextureDefinition->texture_mapping_attribute_components = (m.picture_format==KEPRCPicture_BITMAP_RGB_BYTE || m.picture_format==KEPRCPicture_JPG) ? PRC_TEXTURE_MAPPING_COMPONENTS_RGB : PRC_TEXTURE_MAPPING_COMPONENTS_RGBA; + texture_definition_index = addTextureDefinition(TextureDefinition); + texturedefinitionMap.insert(make_pair(texturedefinition,texture_definition_index)); + } + + uint32_t texture_application_index = m1; + const PRCtextureapplication textureapplication(material_index, texture_definition_index); + PRCtextureapplicationMap::const_iterator pTextureapplication = textureapplicationMap.find(textureapplication); + if(pTextureapplication!=textureapplicationMap.end()) + texture_application_index = pTextureapplication->second; + else + { + PRCTextureApplication *TextureApplication = new PRCTextureApplication; + TextureApplication->material_generic_index = material_index; + TextureApplication->texture_definition_index = texture_definition_index; + texture_application_index = addTextureApplication(TextureApplication); + textureapplicationMap.insert(make_pair(textureapplication,texture_application_index)); + } + + color_material_index = texture_application_index; + } + else + color_material_index = material_index; + + uint32_t style_index = m1; + PRCstyle style(0,m.alpha,true,color_material_index); + PRCstyleMap::const_iterator pStyle = styleMap.find(style); + if(pStyle!=styleMap.end()) + style_index = pStyle->second; + else + { + PRCStyle *Style = new PRCStyle(); + Style->line_width = 0.0; + Style->is_vpicture = false; + Style->line_pattern_vpicture_index = 0; + Style->is_material = true; + Style->is_transparency_defined = (m.alpha < 1.0); + Style->transparency = (uint8_t)(m.alpha * 256); + Style->additional = 0; + Style->color_material_index = color_material_index; + style_index = addStyle(Style); + styleMap.insert(make_pair(style,style_index)); + } +// materialMap.insert(make_pair(material,style_index)); + return style_index; +} + +void oPRCFile::begingroup(const char *name, PRCoptions *options, + const double* t) +{ + const PRCgroup &parent_group = groups.top(); + groups.push(PRCgroup()); + PRCgroup &group = groups.top(); + group.name=name; + if(options) group.options=*options; + if(t&&!isid(t)) + group.transform = new PRCGeneralTransformation3d(t); + group.product_occurrence = new PRCProductOccurrence(name); + group.parent_product_occurrence = parent_group.product_occurrence; + group.part_definition = new PRCPartDefinition; + group.parent_part_definition = parent_group.part_definition; +} + +void oPRCFile::endgroup() +{ + if(groups.size()<2) { + fputs("begingroup without matching endgroup",stderr); + exit(1); + } + doGroup(groups.top()); + groups.pop(); + +// std::cout << lastgroupname << std::endl; +// for(std::vector<std::string>::const_iterator it=lastgroupnames.begin(); it!=lastgroupnames.end(); it++) +// std::cout << " " << *it << std::endl; + +} + +PRCgroup& oPRCFile::findGroup() +{ + return groups.top(); +} + +void oPRCFile::addPoints(uint32_t n, const double P[][3], const RGBAColour &c, double w) +{ + if(n==0 || P==NULL) + return; + PRCgroup &group = findGroup(); + PRCPointSet *pointset = new PRCPointSet(); + group.pointsets.push_back(pointset); + pointset->index_of_line_style = addColourWidth(c,w); + pointset->point.reserve(n); + for(uint32_t i=0; i<n; i++) + pointset->point.push_back(PRCVector3d(P[i][0],P[i][1],P[i][2])); +} + +void oPRCFile::useMesh(uint32_t tess_index, uint32_t style_index, const double origin[3], const double x_axis[3], const double y_axis[3], double scale) +{ + PRCgroup &group = findGroup(); + PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); + polyBrepModel->index_local_coordinate_system = addTransform(origin, x_axis, y_axis, scale); + polyBrepModel->index_tessellation = tess_index; + polyBrepModel->is_closed = group.options.closed; + polyBrepModel->index_of_line_style = style_index; + group.polymodels.push_back(polyBrepModel); +} + +void oPRCFile::useMesh(uint32_t tess_index, uint32_t style_index, const double* t) +{ + PRCgroup &group = findGroup(); + PRCPolyBrepModel *polyBrepModel = new PRCPolyBrepModel(); + polyBrepModel->index_local_coordinate_system = addTransform(t); + polyBrepModel->index_tessellation = tess_index; + polyBrepModel->is_closed = group.options.closed; + polyBrepModel->index_of_line_style = style_index; + group.polymodels.push_back(polyBrepModel); +} + +void oPRCFile::useLines(uint32_t tess_index, uint32_t style_index, const double origin[3], const double x_axis[3], const double y_axis[3], double scale) +{ + PRCgroup &group = findGroup(); + PRCPolyWire *polyWire = new PRCPolyWire(); + polyWire->index_local_coordinate_system = addTransform(origin, x_axis, y_axis, scale); + polyWire->index_tessellation = tess_index; + polyWire->index_of_line_style = style_index; + group.polywires.push_back(polyWire); +} + +void oPRCFile::useLines(uint32_t tess_index, uint32_t style_index, const double* t) +{ + PRCgroup &group = findGroup(); + PRCPolyWire *polyWire = new PRCPolyWire(); + polyWire->index_local_coordinate_system = addTransform(t); + polyWire->index_tessellation = tess_index; + polyWire->index_of_line_style = style_index; + group.polywires.push_back(polyWire); +} + +void oPRCFile::addQuads(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], const PRCmaterial &m, + uint32_t nN, const double N[][3], const uint32_t NI[][4], + uint32_t nT, const double T[][2], const uint32_t TI[][4], + uint32_t nC, const RGBAColour C[], const uint32_t CI[][4], + uint32_t nM, const PRCmaterial M[], const uint32_t MI[], double ca) +{ + if(nP==0 || P==NULL || nI==0 || PI==NULL) + return; + const uint32_t tess_index = createQuadMesh(nP, P, nI, PI, m, nN, N, NI, nT, T, TI, nC, C, CI, nM, M, MI, ca); + useMesh(tess_index,m1); +} + +uint32_t oPRCFile::createQuadMesh(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[][4], uint32_t style_index, + uint32_t nN, const double N[][3], const uint32_t NI[][4], + uint32_t nT, const double T[][2], const uint32_t TI[][4], + uint32_t nC, const RGBAColour C[], const uint32_t CI[][4], + uint32_t nS, const uint32_t S[], const uint32_t SI[], double ca) +{ + if(nP==0 || P==NULL || nI==0 || PI==NULL) + return m1; + + const bool triangle_color = (nS != 0 && S != NULL && SI != NULL); + const bool vertex_color = (nC != 0 && C != NULL && CI != NULL); + const bool has_normals = (nN != 0 && N != NULL && NI != NULL); + const bool textured = (nT != 0 && T != NULL && TI != NULL); + + PRC3DTess *tess = new PRC3DTess(); + PRCTessFace *tessFace = new PRCTessFace(); + tessFace->used_entities_flag = textured ? PRC_FACETESSDATA_TriangleTextured : PRC_FACETESSDATA_Triangle; + tessFace->number_of_texture_coordinate_indexes = textured ? 1 : 0; + tess->coordinates.reserve(3*nP); + for(uint32_t i=0; i<nP; i++) + { + tess->coordinates.push_back(P[i][0]); + tess->coordinates.push_back(P[i][1]); + tess->coordinates.push_back(P[i][2]); + } + if(has_normals) + { + tess->normal_coordinate.reserve(3*nN); + for(uint32_t i=0; i<nN; i++) + { + tess->normal_coordinate.push_back(N[i][0]); + tess->normal_coordinate.push_back(N[i][1]); + tess->normal_coordinate.push_back(N[i][2]); + } + } + else + tess->crease_angle = ca; + if(textured) + { + tess->texture_coordinate.reserve(2*nT); + for(uint32_t i=0; i<nT; i++) + { + tess->texture_coordinate.push_back(T[i][0]); + tess->texture_coordinate.push_back(T[i][1]); + } + } + tess->triangulated_index.reserve(2*(3*nI+(has_normals?3:0)*nI+(textured?3:0)*nI)); + for(uint32_t i=0; i<nI; i++) + { + // first triangle + if(has_normals) + tess->triangulated_index.push_back(3*NI[i][0]); + if(textured) + tess->triangulated_index.push_back(2*TI[i][0]); + tess->triangulated_index.push_back(3*PI[i][0]); + if(has_normals) + tess->triangulated_index.push_back(3*NI[i][1]); + if(textured) + tess->triangulated_index.push_back(2*TI[i][1]); + tess->triangulated_index.push_back(3*PI[i][1]); + if(has_normals) + tess->triangulated_index.push_back(3*NI[i][3]); + if(textured) + tess->triangulated_index.push_back(2*TI[i][3]); + tess->triangulated_index.push_back(3*PI[i][3]); + // second triangle + if(has_normals) + tess->triangulated_index.push_back(3*NI[i][1]); + if(textured) + tess->triangulated_index.push_back(2*TI[i][1]); + tess->triangulated_index.push_back(3*PI[i][1]); + if(has_normals) + tess->triangulated_index.push_back(3*NI[i][2]); + if(textured) + tess->triangulated_index.push_back(2*TI[i][2]); + tess->triangulated_index.push_back(3*PI[i][2]); + if(has_normals) + tess->triangulated_index.push_back(3*NI[i][3]); + if(textured) + tess->triangulated_index.push_back(2*TI[i][3]); + tess->triangulated_index.push_back(3*PI[i][3]); + } + tessFace->sizes_triangulated.push_back(2*nI); + if(triangle_color) + { + tessFace->line_attributes.reserve(2*nI); + for(uint32_t i=0; i<nI; i++) + { + tessFace->line_attributes.push_back(SI[i]); + tessFace->line_attributes.push_back(SI[i]); + } + } + else + { + tessFace->line_attributes.push_back(style_index); + } + if(vertex_color) + { + tessFace->is_rgba=false; + for(uint32_t i=0; i<nI; i++) + if(1.0 != C[CI[i][0]].A || 1.0 != C[CI[i][1]].A || 1.0 != C[CI[i][2]].A) + { + tessFace->is_rgba=true; + break; + } + + tessFace->rgba_vertices.reserve(2*(tessFace->is_rgba?4:3)*3*nI); + for(uint32_t i=0; i<nI; i++) + { + // first triangle + tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].R)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].G)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[CI[i][0]].A)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].R)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].G)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].A)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].R)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].G)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].A)); + // second triangle + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].R)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].G)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[CI[i][1]].A)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].R)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].G)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[CI[i][2]].A)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].R)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].G)); + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].B)); + if(tessFace->is_rgba) + tessFace->rgba_vertices.push_back(byte(C[CI[i][3]].A)); + } + } + tess->addTessFace(tessFace); + const uint32_t tess_index = add3DTess(tess); + return tess_index; +} + +/* +void oPRCFile::addTriangle(const double P[][3], const double T[][2], uint32_t style_index) +{ + PRCgroup &group = findGroup(); + + group.triangles.push_back(PRCtesstriangle()); + PRCtesstriangle &triangle = group.triangles.back(); + for(size_t i = 0; i < 3; i++) + { + triangle.vertices[i].x = P[i][0]; + triangle.vertices[i].y = P[i][1]; + triangle.vertices[i].z = P[i][2]; + triangle.texcoords[i].x = T[i][0]; + triangle.texcoords[i].y = T[i][1]; + } + triangle.style = style_index; +} +*/ + +void oPRCFile::addLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[], + const RGBAColour& c, double w, + bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[]) +{ + if(nP==0 || P==NULL || nI==0 || PI==NULL) + return; + const uint32_t tess_index = createLines(nP, P, nI, PI, segment_color, nC, C, nCI, CI); + useLines(tess_index, c, w); +} + +uint32_t oPRCFile::createLines(uint32_t nP, const double P[][3], uint32_t nI, const uint32_t PI[], + bool segment_color, uint32_t nC, const RGBAColour C[], uint32_t nCI, const uint32_t CI[]) +{ + if(nP==0 || P==NULL || nI==0 || PI==NULL) + return m1; + + const bool vertex_color = (nC != 0 && C != NULL && CI != NULL); + + PRC3DWireTess *tess = new PRC3DWireTess(); + tess->coordinates.reserve(3*nP); + for(uint32_t i=0; i<nP; i++) + { + tess->coordinates.push_back(P[i][0]); + tess->coordinates.push_back(P[i][1]); + tess->coordinates.push_back(P[i][2]); + } + tess->wire_indexes.reserve(nI); + for(uint32_t i=0; i<nI;) + { + tess->wire_indexes.push_back(PI[i]); + const uint32_t ni = i+PI[i]+1; + for(i++; i<ni; i++) + tess->wire_indexes.push_back(3*PI[i]); + } + if(vertex_color) + { + tess->is_segment_color = segment_color; + tess->is_rgba=false; + for(uint32_t i=0; i<nCI; i++) + if(1.0 != C[CI[i]].A) + { + tess->is_rgba=true; + break; + } + tess->rgba_vertices.reserve((tess->is_rgba?4:3)*nCI); + for(uint32_t i=0; i<nCI; i++) + { + tess->rgba_vertices.push_back(byte(C[CI[i]].R)); + tess->rgba_vertices.push_back(byte(C[CI[i]].G)); + tess->rgba_vertices.push_back(byte(C[CI[i]].B)); + if(tess->is_rgba) + tess->rgba_vertices.push_back(byte(C[CI[i]].A)); + } + } + const uint32_t tess_index = add3DWireTess(tess); + return tess_index; +} + +#define PRCFACETRANSFORM const double origin[3], const double x_axis[3], const double y_axis[3], double scale, const double* t + +void oPRCFile::addHemisphere(double radius, const PRCmaterial &m, PRCFACETRANSFORM) +{ + ADDFACE(PRCSphere) + SETTRANSF + surface->uv_domain.min.x = 0; + surface->uv_domain.max.x = 2*pi; + surface->uv_domain.min.y = 0; + surface->uv_domain.max.y = 0.5*pi; + surface->radius = radius; +} + +void oPRCFile::addSphere(double radius, const PRCmaterial &m, PRCFACETRANSFORM) +{ + ADDFACE(PRCSphere) + SETTRANSF + surface->uv_domain.min.x = 0; + surface->uv_domain.max.x = 2*pi; + surface->uv_domain.min.y =-0.5*pi; + surface->uv_domain.max.y = 0.5*pi; + surface->radius = radius; +} + +void oPRCFile::addDisk(double radius, const PRCmaterial &m, PRCFACETRANSFORM) +{ + ADDFACE(PRCRuled) + SETTRANSF + PRCCircle *first_curve = new PRCCircle; + first_curve->radius = radius; + surface->first_curve = first_curve; + PRCCircle *second_curve = new PRCCircle; + second_curve->radius = 0; + surface->second_curve = second_curve; + + surface->uv_domain.min.x = 0; + surface->uv_domain.max.x = 1; + surface->uv_domain.min.y = 0; + surface->uv_domain.max.y = 2*pi; + surface->parameterization_on_v_coeff_a = -1; + surface->parameterization_on_v_coeff_b = 2*pi; +} + +void oPRCFile::addCylinder(double radius, double height, const PRCmaterial &m, PRCFACETRANSFORM) +{ + ADDFACE(PRCCylinder) + SETTRANSF + surface->uv_domain.min.x = 0; + surface->uv_domain.max.x = 2*pi; + surface->uv_domain.min.y = (height>0)?0:height; + surface->uv_domain.max.y = (height>0)?height:0; + surface->radius = radius; +} + +void oPRCFile::addCone(double radius, double height, const PRCmaterial &m, PRCFACETRANSFORM) +{ + ADDFACE(PRCCone) + SETTRANSF + surface->uv_domain.min.x = 0; + surface->uv_domain.max.x = 2*pi; + surface->uv_domain.min.y = (height>0)?0:height; + surface->uv_domain.max.y = (height>0)?height:0; + surface->bottom_radius = radius; + surface->semi_angle = -atan(radius/height);; +} + +void oPRCFile::addTorus(double major_radius, double minor_radius, double angle1, double angle2, const PRCmaterial &m, PRCFACETRANSFORM) +{ + ADDFACE(PRCTorus) + SETTRANSF + surface->uv_domain.min.x = (angle1/180)*pi; + surface->uv_domain.max.x = (angle2/180)*pi; + surface->uv_domain.min.y = 0; + surface->uv_domain.max.y = 2*pi; + surface->major_radius = major_radius; + surface->minor_radius = minor_radius; +} + +#undef ADDWIRE +#undef SETTRANSF + +uint32_t PRCFileStructure::addMaterialGeneric(PRCMaterialGeneric*& pMaterialGeneric) +{ + materials.push_back(pMaterialGeneric); + pMaterialGeneric = NULL; + return materials.size()-1; +} + +uint32_t PRCFileStructure::addTextureApplication(PRCTextureApplication*& pTextureApplication) +{ + materials.push_back(pTextureApplication); + pTextureApplication = NULL; + return materials.size()-1; +} + +uint32_t PRCFileStructure::addStyle(PRCStyle*& pStyle) +{ + styles.push_back(pStyle); + pStyle = NULL; + return styles.size()-1; +} + +uint32_t PRCFileStructure::addPartDefinition(PRCPartDefinition*& pPartDefinition) +{ + part_definitions.push_back(pPartDefinition); + pPartDefinition = NULL; + return part_definitions.size()-1; +} + +uint32_t PRCFileStructure::addProductOccurrence(PRCProductOccurrence*& pProductOccurrence) +{ + product_occurrences.push_back(pProductOccurrence); + pProductOccurrence = NULL; + return product_occurrences.size()-1; +} + +uint32_t PRCFileStructure::addTopoContext(PRCTopoContext*& pTopoContext) +{ + contexts.push_back(pTopoContext); + pTopoContext = NULL; + return contexts.size()-1; +} + +uint32_t PRCFileStructure::getTopoContext(PRCTopoContext*& pTopoContext) +{ + pTopoContext = new PRCTopoContext; + contexts.push_back(pTopoContext); + return contexts.size()-1; +} + +uint32_t PRCFileStructure::add3DTess(PRC3DTess*& p3DTess) +{ + tessellations.push_back(p3DTess); + p3DTess = NULL; + return tessellations.size()-1; +} + +uint32_t PRCFileStructure::add3DWireTess(PRC3DWireTess*& p3DWireTess) +{ + tessellations.push_back(p3DWireTess); + p3DWireTess = NULL; + return tessellations.size()-1; +} +/* +uint32_t PRCFileStructure::addMarkupTess(PRCMarkupTess*& pMarkupTess) +{ + tessellations.push_back(pMarkupTess); + pMarkupTess = NULL; + return tessellations.size()-1; +} + +uint32_t PRCFileStructure::addMarkup(PRCMarkup*& pMarkup) +{ + markups.push_back(pMarkup); + pMarkup = NULL; + return markups.size()-1; +} + +uint32_t PRCFileStructure::addAnnotationItem(PRCAnnotationItem*& pAnnotationItem) +{ + annotation_entities.push_back(pAnnotationItem); + pAnnotationItem = NULL; + return annotation_entities.size()-1; +} +*/ +uint32_t PRCFileStructure::addCoordinateSystem(PRCCoordinateSystem*& pCoordinateSystem) +{ + reference_coordinate_systems.push_back(pCoordinateSystem); + pCoordinateSystem = NULL; + return reference_coordinate_systems.size()-1; +} + +uint32_t PRCFileStructure::addCoordinateSystemUnique(PRCCoordinateSystem*& pCoordinateSystem) +{ + for(uint32_t i = 0; i < reference_coordinate_systems.size(); ++i) + { + if(*(reference_coordinate_systems[i])==*pCoordinateSystem) { + pCoordinateSystem = NULL; + return i; + } + } + reference_coordinate_systems.push_back(pCoordinateSystem); + pCoordinateSystem = NULL; + return reference_coordinate_systems.size()-1; +} + +} |