private static JTNode XMLElement2Node(XmlNode referenceElement, Dictionary <string, ZipArchiveEntry> partEntries) { var referenceElementAttributes = referenceElement.Attributes; var node = new JTNode() { ID = int.Parse(referenceElementAttributes["id"].Value), Number = referenceElementAttributes["name"].Value, Attributes = ExtractAttributes(referenceElement.ChildNodes) }; if (node.Attributes.ContainsKey("V_Name")) { node.Name = node.Attributes["V_Name"].ToString(); } if (referenceElement.Name == "ReferenceRep") { var partFileName = referenceElement.Attributes["associatedFile"].Value.Replace("urn:3DXML:", ""); if (partEntries.ContainsKey(partFileName)) { using (var partFileStream = partEntries[partFileName].Open()) { node.GeometricSets = GetGeometricSets(partFileStream); } } } return(node); }
private SegmentHeader GetMetaDataSegmentHeader(JTNode node) { if (uniqueMetaDataSegmentHeaders.ContainsKey(node)) { return(uniqueMetaDataSegmentHeaders[node]); } var attributes = node.Attributes; if (attributes.Count == 0) { return(null); } var keys = new List <string>(attributes.Keys); var values = new List <object>(attributes.Values); var metaDataSegment = new MetaDataSegment(new PropertyProxyMetaDataElement(keys, values)); var compressedMetaDataSegment = CompressionUtils.Compress(metaDataSegment.Bytes); var metaDataSegmentHeaderZLIB = new LogicElementHeaderZLIB(2, compressedMetaDataSegment.Length + 1, 2); // CompressionAlgorithm field (of type Byte) is included in CompressedDataLength var metaDataSegmentHeader = new SegmentHeader(GUID.NewGUID(), 4, SegmentHeader.Size + metaDataSegmentHeaderZLIB.ByteCount + compressedMetaDataSegment.Length); uniqueMetaDataSegmentHeaders[node] = metaDataSegmentHeader; compressedMetaDataSegments.Add(compressedMetaDataSegment); metaDataSegmentHeadersZLIB.Add(metaDataSegmentHeaderZLIB); metaDataSegmentHeaders.Add(metaDataSegmentHeader); return(metaDataSegmentHeader); }
public JTNode(JTNode node) { ID = node.ID; Attributes = node.Attributes; Children = node.Children; GeometricSets = node.GeometricSets; MeasurementUnit = node.MeasurementUnit; Number = node.Number; Name = node.Name; TransformationMatrix = node.TransformationMatrix; ReferencedFile = node.ReferencedFile; ReferencedFileIsPart = node.ReferencedFileIsPart; }
public static JTNode Read(string path) { JTNode rootNode = null; using (var archive = ZipFile.OpenRead(path)) { var archiveEntriesCount = archive.Entries.Count; ZipArchiveEntry threeDXMLEntry = null; var partEntries = new Dictionary <string, ZipArchiveEntry>(archiveEntriesCount); for (int i = 0; i < archiveEntriesCount; ++i) { var entry = archive.Entries[i]; var entryName = entry.FullName; var entryNameExt = Path.GetExtension(entryName).ToLower(); if (entryName.ToLower() == "manifest.xml") { var xmlDoc = new XmlDocument(); xmlDoc.Load(entry.Open()); var rootElementText = xmlDoc.SelectSingleNode("//*[local-name()='Root']/text()"); if (rootElementText != null) { threeDXMLEntry = archive.GetEntry(rootElementText.Value); } } else if (entryNameExt == ".xml" || entryNameExt == ".3drep") { partEntries[entryName] = entry; } } if (threeDXMLEntry == null) { throw new Exception(String.Format("{0} does not contain PRODUCT.3dxml file.", path)); } rootNode = BuildStructure(threeDXMLEntry.Open(), partEntries); } return(rootNode); }
private void ProcessAttributes(JTNode node, int nodeElementId) { var attributes = new Dictionary <string, object>(node.Attributes.Count); foreach (var attribute in node.Attributes) { var key = attribute.Key.Trim(); var value = attribute.Value; while (key.EndsWith(":")) { key = key.Substring(0, key.Length - 1); } while (key.Contains("::")) { key = key.Replace("::", ":"); } if (key.Length == 0) { continue; } attributes[key + "::"] = value; } if (separateAttributeSegments) { var metaDataSegmentHeader = GetMetaDataSegmentHeader(new JTNode() { Attributes = attributes }); attributes.Clear(); if (metaDataSegmentHeader != null) { attributes["JT_LLPROP_METADATA"] = metaDataSegmentHeader; } } attributes["JT_PROP_MEASUREMENT_UNITS"] = node.MeasurementUnitAsString; //if (node.Number != null || node.Name != null) attributes["JT_PROP_NAME"] = string.Join(" - ", new[] { node.Number, node.Name }.Where(v => v != null).ToArray()) + "." + (node.Children.Count > 0 ? "asm" : "part") + ";0;0:"; if (node.Number != null || node.Name != null) { attributes["JT_PROP_NAME"] = string.Join(" - ", new[] { node.Number, node.Name }.Where(v => v != null)) + "." + (node.Children.Count > 0 || (((node.ReferencedFile ?? "").Length > 0) && !node.ReferencedFileIsPart) ? "asm" : "part") + ";0;0:"; } //if (node == this && node.Children.Count > 0) attributes["PartitionType"] = "Assembly"; if (node.GeometricSets.Length > 0) { attributes["JT_LLPROP_SHAPEIMPL"] = node.GeometricSets; } var attributesCount = attributes.Count; var keys = new List <int>(attributesCount); var values = new List <int>(attributesCount); foreach (var attribute in attributes) { var key = attribute.Key; var value = attribute.Value; var valueTypeName = value.GetType().Name; if (valueTypeName != "String" && valueTypeName != "Int32" && valueTypeName != "Single" && valueTypeName != "DateTime" && valueTypeName != "GeometricSet[]" && valueTypeName != "SegmentHeader") { throw new Exception(String.Format("Only String, Int32, Single, DateTime, GeometricSet[] and SegmentHeader value types are allowed. Current value is {0}.", valueTypeName)); } var keyLookupKey = String.Format("{0}-{1}", key.GetType().Name, key); int keyId; if (uniquePropertyIds.ContainsKey(keyLookupKey)) { keyId = uniquePropertyIds[keyLookupKey]; } else { keyId = IdGenUtils.NextId; propertyAtomElements.Add(new StringPropertyAtomElement(key, keyId)); uniquePropertyIds[keyLookupKey] = keyId; } keys.Add(keyId); var valueAsString = valueTypeName != "GeometricSet[]" ? value.ToString() : ((GeometricSet[])(value))[0].ToString(); var valueLookupKey = valueTypeName + "-" + valueAsString; int valueId; if (uniquePropertyIds.ContainsKey(valueLookupKey)) { valueId = uniquePropertyIds[valueLookupKey]; } else { valueId = IdGenUtils.NextId; uniquePropertyIds[valueLookupKey] = valueId; switch (valueTypeName) { case "String": propertyAtomElements.Add(new StringPropertyAtomElement((string)value, valueId)); break; case "Int32": propertyAtomElements.Add(new IntegerPropertyAtomElement((int)value, valueId)); break; case "Single": propertyAtomElements.Add(new FloatingPointPropertyAtomElement((float)value, valueId)); break; case "DateTime": propertyAtomElements.Add(new DatePropertyAtomElement((DateTime)value, valueId)); break; case "GeometricSet[]": var geometricSet = ((GeometricSet[])value)[0]; var shapeLODSegment = new ShapeLODSegment(new TriStripSetShapeLODElement(geometricSet.TriStrips, geometricSet.Positions, geometricSet.Normals)); var shapeLODSegmentHeader = new SegmentHeader(GUID.NewGUID(), 6, SegmentHeader.Size + shapeLODSegment.ByteCount); shapeLODSegments.Add(shapeLODSegment); shapeLODSegmentHeaders.Add(shapeLODSegmentHeader); propertyAtomElements.Add(new LateLoadedPropertyAtomElement(shapeLODSegmentHeader.SegmentID, shapeLODSegmentHeader.SegmentType, valueId)); break; case "SegmentHeader": var segmentHeader = (SegmentHeader)value; propertyAtomElements.Add(new LateLoadedPropertyAtomElement(segmentHeader.SegmentID, segmentHeader.SegmentType, valueId)); break; } } values.Add(valueId); } propertyTableContents.Add(nodeElementId, new NodePropertyTable(keys, values)); }
private BaseNodeElement CreateElement(JTNode node) { //if (!monolithic && node.GeometricSets.Length > 0) if (node.ReferencedFile != null) { PartitionNodeElement partitionElement; if (savedFileIds.ContainsKey(node.ID)) { partitionElement = savedFileIds[node.ID]; } else { //var partFileName = String.Join("_", node.Number.Split(Path.GetInvalidFileNameChars())) + "_" + node.ID + ".jt"; //var partFileDirectory = Path.Combine(Path.GetDirectoryName(savePath), Path.GetFileNameWithoutExtension(savePath)); //var partFilePath = Path.Combine(partFileDirectory, partFileName); //if (!Directory.Exists(partFileDirectory)) Directory.CreateDirectory(partFileDirectory); //partitionElement = new PartitionNodeElement(IdGenUtils.NextId, new JTNode(node) { TransformationMatrix = null }.Save(partFilePath, true, this.separateAttributeSegments)) partitionElement = new PartitionNodeElement(IdGenUtils.NextId) { //FileName = new MbString(@".\" + Path.GetFileNameWithoutExtension(savePath) + @"\" + partFileName) FileName = new MbString(node.ReferencedFile) }; elements.Add(partitionElement); savedFileIds[node.ID] = partitionElement; } var instanceElement = new InstanceNodeElement(partitionElement.ObjectId, IdGenUtils.NextId); elements.Add(instanceElement); ProcessAttributes(new JTNode(node) { GeometricSets = null }, instanceElement.ObjectId); // Process transformatio matrix if (node.TransformationMatrix != null) { var transformationMatrixAsString = String.Join("|", node.TransformationMatrix); int geometricTransformAttributeElementId; if (uniqueAttributeIds.ContainsKey(transformationMatrixAsString)) { geometricTransformAttributeElementId = uniqueAttributeIds[transformationMatrixAsString]; } else { geometricTransformAttributeElementId = IdGenUtils.NextId; uniqueAttributeIds[transformationMatrixAsString] = geometricTransformAttributeElementId; elements.Add(new GeometricTransformAttributeElement(node.TransformationMatrix, geometricTransformAttributeElementId)); } instanceElement.AttributeObjectIds.Add(geometricTransformAttributeElementId); } // END Process transformatio matrix return(instanceElement); } // Process children and store their IDs var childNodes = node.Children; var childNodesCount = childNodes.Count; var childNodeObjectIds = new List <int>(childNodesCount); for (int i = 0; i < childNodesCount; ++i) { childNodeObjectIds.Add(CreateElement(childNodes[i]).ObjectId); } // END Process children and store their IDs // Create node MetaDataNodeElement nodeElement = node.GeometricSets.Length > 0 ? new PartNodeElement(IdGenUtils.NextId) : new MetaDataNodeElement(IdGenUtils.NextId); nodeElement.ChildNodeObjectIds = childNodeObjectIds; // END Create node // Process transformatio matrix if (node.TransformationMatrix != null) { var transformationMatrixAsString = String.Join("|", node.TransformationMatrix); int geometricTransformAttributeElementId; if (uniqueAttributeIds.ContainsKey(transformationMatrixAsString)) { geometricTransformAttributeElementId = uniqueAttributeIds[transformationMatrixAsString]; } else { geometricTransformAttributeElementId = IdGenUtils.NextId; uniqueAttributeIds[transformationMatrixAsString] = geometricTransformAttributeElementId; elements.Add(new GeometricTransformAttributeElement(node.TransformationMatrix, geometricTransformAttributeElementId)); } nodeElement.AttributeObjectIds.Add(geometricTransformAttributeElementId); } // END Process transformatio matrix // Process Geometric Sets var geometricSetsCount = node.geometricSets.Length; if (geometricSetsCount > 0) { float x = 0, y = 0, z = 0; int count = 0; var groupNodeElement = new GroupNodeElement(IdGenUtils.NextId); elements.Add(groupNodeElement); for (int i = 0; i < geometricSetsCount; ++i) { var geometricSet = node.GeometricSets[i]; var colour = geometricSet.Colour; var colourAsString = colour.ToString(); int materialAttributeElementId; if (uniqueAttributeIds.ContainsKey(colourAsString)) { materialAttributeElementId = uniqueAttributeIds[colourAsString]; } else { materialAttributeElementId = IdGenUtils.NextId; uniqueAttributeIds[colourAsString] = materialAttributeElementId; elements.Add(new MaterialAttributeElement(colour, materialAttributeElementId)); } var triStripSetShapeNodeElement = new TriStripSetShapeNodeElement(geometricSet, IdGenUtils.NextId) { AttributeObjectIds = new List <int>() { materialAttributeElementId } }; elements.Add(triStripSetShapeNodeElement); groupNodeElement.ChildNodeObjectIds.Add(triStripSetShapeNodeElement.ObjectId); x += geometricSet.Center.X; y += geometricSet.Center.Y; z += geometricSet.Center.Z; count++; ProcessAttributes(new JTNode() { GeometricSets = new GeometricSet[] { geometricSet } }, triStripSetShapeNodeElement.ObjectId); } var rangeLODNodeElement = new RangeLODNodeElement(IdGenUtils.NextId) { ChildNodeObjectIds = new List <int>() { groupNodeElement.ObjectId }, Center = new CoordF32(x / count, y / count, z / count) }; elements.Add(rangeLODNodeElement); nodeElement.ChildNodeObjectIds.Add(rangeLODNodeElement.ObjectId); } // END Process Geometric Sets // Process root element if (node == this) { float area = 0; int vertexCountMin = 0, vertexCountMax = 0, nodeCountMin = 0, nodeCountMax = 0, polygonCountMin = 0, polygonCountMax = 0; float minX = 0, minY = 0, minZ = 0, maxX = 0, maxY = 0, maxZ = 0; bool firstTriStripSetShapeNodeElementVisited = false; var triStripSetShapeNodeElementType = typeof(TriStripSetShapeNodeElement); var partitionNodeElementType = typeof(PartitionNodeElement); for (int elementIndex = 0, elementCount = elements.Count; elementIndex < elementCount; ++elementIndex) { var element = elements[elementIndex]; var elementType = element.GetType(); if ((monolithic && elementType != triStripSetShapeNodeElementType) || (!monolithic && elementType != partitionNodeElementType)) { continue; } CountRange vertexCountRange, nodeCountRange, polygonCountRange; BBoxF32 untransformedBBox; if (monolithic) { var triStripSetShapeNodeElement = (TriStripSetShapeNodeElement)element; area += triStripSetShapeNodeElement.Area; vertexCountRange = triStripSetShapeNodeElement.VertexCountRange; nodeCountRange = triStripSetShapeNodeElement.NodeCountRange; polygonCountRange = triStripSetShapeNodeElement.PolygonCountRange; untransformedBBox = triStripSetShapeNodeElement.UntransformedBBox; } else { var childPartitionNodeElement = (PartitionNodeElement)element; area += childPartitionNodeElement.Area; vertexCountRange = childPartitionNodeElement.VertexCountRange; nodeCountRange = childPartitionNodeElement.NodeCountRange; polygonCountRange = childPartitionNodeElement.PolygonCountRange; untransformedBBox = childPartitionNodeElement.UntransformedBBox; } vertexCountMin += vertexCountRange.Min; vertexCountMax += vertexCountRange.Max; nodeCountMin += nodeCountRange.Min; nodeCountMax += nodeCountRange.Max; polygonCountMin += polygonCountRange.Min; polygonCountMax += polygonCountRange.Max; var minCorner = untransformedBBox.MinCorner; var maxCorner = untransformedBBox.MaxCorner; if (!firstTriStripSetShapeNodeElementVisited) { minX = minCorner.X; minY = minCorner.Y; minZ = minCorner.Z; maxX = maxCorner.X; maxY = maxCorner.Y; maxZ = maxCorner.Z; firstTriStripSetShapeNodeElementVisited = true; } else { if (minCorner.X < minX) { minX = minCorner.X; } if (minCorner.Y < minY) { minY = minCorner.Y; } if (minCorner.Z < minZ) { minZ = minCorner.Z; } if (maxCorner.X > maxX) { maxX = maxCorner.X; } if (maxCorner.Y > maxY) { maxY = maxCorner.Y; } if (maxCorner.Z > maxZ) { maxZ = maxCorner.Z; } } } var partitionNodeElement = new PartitionNodeElement(IdGenUtils.NextId) { ChildNodeObjectIds = new List <int>() { nodeElement.ObjectId }, Area = area, VertexCountRange = new CountRange(vertexCountMin, vertexCountMax), NodeCountRange = new CountRange(nodeCountMin, nodeCountMax), PolygonCountRange = new CountRange(polygonCountMin, polygonCountMax), UntransformedBBox = new BBoxF32(minX, minY, minZ, maxX, maxY, maxZ) }; elements.Insert(0, partitionNodeElement); // ProcessAttributes(node, partitionNodeElement.ObjectId); // !!!!!!! Causes double top node !!!!! } // END Process root element elements.Add(nodeElement); ProcessAttributes(node, nodeElement.ObjectId); return(nodeElement); }
private static JTNode BuildStructure(Stream threeDXMLFileStream, Dictionary <string, ZipArchiveEntry> partEntries) { var threeDXMLDocument = new XmlDocument(); threeDXMLDocument.Load(threeDXMLFileStream); var xmlNamespaceManager = new XmlNamespaceManager(threeDXMLDocument.NameTable); xmlNamespaceManager.AddNamespace("ns", "http://www.3ds.com/xsd/3DXML"); var referenceElements = threeDXMLDocument.SelectNodes("//*[local-name()='Reference3D' or local-name()='ReferenceRep']", xmlNamespaceManager); var referenceElementCount = referenceElements.Count; var nodes = new Dictionary <string, JTNode>(referenceElementCount); for (int i = 0; i < referenceElementCount; ++i) { var reference3DElement = referenceElements[i]; nodes[reference3DElement.Attributes["id"].Value] = XMLElement2Node(reference3DElement, partEntries); } var instanceElements = threeDXMLDocument.SelectNodes("//*[local-name()='Instance3D' or local-name()='InstanceRep']", xmlNamespaceManager); for (int i = 0, c = instanceElements.Count; i < c; ++i) { var instanceElement = instanceElements[i]; var childNodes = instanceElement.ChildNodes; string aggregatedBy = null; string instanceOf = null; string relativeMatrix = null; for (int childNodeIndex = 0, childNodeCount = childNodes.Count; childNodeIndex < childNodeCount; ++childNodeIndex) { var childNode = childNodes[childNodeIndex]; switch (childNode.Name) { case "IsAggregatedBy": aggregatedBy = childNode.InnerText; break; case "IsInstanceOf": instanceOf = childNode.InnerText; break; case "RelativeMatrix": relativeMatrix = childNode.InnerText; break; } } if (aggregatedBy == null || instanceOf == null || !nodes.ContainsKey(aggregatedBy) || !nodes.ContainsKey(instanceOf)) { continue; } float[] transformationMatrix = null; if (relativeMatrix != null && relativeMatrix != "1 0 0 0 1 0 0 0 1 0 0 0") { transformationMatrix = ConstUtils.IndentityMatrix; var relativeMatrixValues = relativeMatrix.Trim().Split(new char[] { ' ' }); var offset = 0; for (int matrixValueIndex = 0, matrixValueCount = relativeMatrixValues.Length; matrixValueIndex < matrixValueCount; matrixValueIndex += 3) { transformationMatrix[matrixValueIndex + offset] = float.Parse(relativeMatrixValues[matrixValueIndex]); transformationMatrix[matrixValueIndex + 1 + offset] = float.Parse(relativeMatrixValues[matrixValueIndex + 1]); transformationMatrix[matrixValueIndex + 2 + offset] = float.Parse(relativeMatrixValues[matrixValueIndex + 2]); ++offset; } } var tempNode = XMLElement2Node(instanceElement, partEntries); var nodeInstance = new JTNode(nodes[instanceOf]) { //Number = tempNode.Number, TransformationMatrix = transformationMatrix }; foreach (var attribute in tempNode.Attributes) { nodeInstance.Attributes[$"I: {attribute.Key}"] = attribute.Value; } nodes[aggregatedBy].Children.Add(nodeInstance); } var productStructureElement = threeDXMLDocument.SelectSingleNode("//ns:ProductStructure", xmlNamespaceManager); var rootId = productStructureElement.Attributes["root"].Value; return(nodes[rootId]); }