From 044356876d317508c608d8f1723d3cb8393e3696 Mon Sep 17 00:00:00 2001 From: Bozo The Builder Date: Sun, 3 May 2020 10:07:05 -0700 Subject: [PATCH] Sync changes from upstream repository Co-authored-by: Andrew Le Bihan Co-authored-by: Dale Lear Co-authored-by: Greg Arden Co-authored-by: Jussi Aaltonen Co-authored-by: Lowell Co-authored-by: Tim Hemmelman Co-authored-by: piac --- opennurbs_archive.cpp | 94 +++++- opennurbs_archive.h | 14 +- opennurbs_brep.cpp | 153 +++++++++- opennurbs_brep.h | 198 +++++++++---- opennurbs_brep_io.cpp | 43 ++- opennurbs_color.cpp | 90 ++++++ opennurbs_color.h | 109 +++++++ opennurbs_compstat.cpp | 124 +++++++- opennurbs_compstat.h | 136 +++++++++ opennurbs_dimensionformat.cpp | 2 +- opennurbs_font.cpp | 11 +- opennurbs_font.h | 100 ++++++- opennurbs_instance.h | 4 +- opennurbs_material.cpp | 23 ++ opennurbs_material.h | 4 + opennurbs_model_component.h | 2 +- opennurbs_object.h | 6 +- opennurbs_object_history.cpp | 303 ++++++++++++++++++- opennurbs_object_history.h | 21 +- opennurbs_objref.h | 4 +- opennurbs_public_version.h | 16 +- opennurbs_statics.cpp | 133 +++++++-- opennurbs_subd.cpp | 535 +++++++++++++++++++++++++--------- opennurbs_subd.h | 432 ++++++++++++++++++++++++--- opennurbs_subd_archive.cpp | 73 +++-- opennurbs_subd_copy.cpp | 10 + opennurbs_subd_data.cpp | 10 +- opennurbs_subd_data.h | 15 +- opennurbs_subd_frommesh.cpp | 24 +- opennurbs_subd_heap.cpp | 14 +- opennurbs_subd_limit.cpp | 18 +- opennurbs_subd_mesh.cpp | 22 +- opennurbs_subd_ring.cpp | 2 +- opennurbs_subd_texture.cpp | 88 +++++- opennurbs_textlog.cpp | 96 +++++- opennurbs_textlog.h | 131 ++++++++- opennurbs_textrun.cpp | 19 +- opennurbs_win_dwrite.cpp | 390 ++++++++++++++++++++----- 38 files changed, 2987 insertions(+), 482 deletions(-) diff --git a/opennurbs_archive.cpp b/opennurbs_archive.cpp index 4c1cf582..a5f8f3ac 100644 --- a/opennurbs_archive.cpp +++ b/opennurbs_archive.cpp @@ -2188,6 +2188,51 @@ ON_BinaryArchive::ReadArray( ON_SimpleArray& a ) return rc; } +bool +ON_BinaryArchive::ReadArray(ON_SimpleArray& a) +{ + a.Empty(); + int count = 0; + bool rc = ReadInt(&count); + if (rc && count > 0) { + a.SetCapacity(count); + rc = ReadChar(count, a.Array()); + if (rc) + a.SetCount(count); + } + return rc; +} + +bool +ON_BinaryArchive::ReadArray(ON_SimpleArray& a) +{ + a.Empty(); + int count = 0; + bool rc = ReadInt(&count); + if (rc && count > 0) { + a.SetCapacity(count); + rc = ReadShort(count, a.Array()); + if (rc) + a.SetCount(count); + } + return rc; +} + +bool +ON_BinaryArchive::ReadArray(ON_SimpleArray& a) +{ + a.Empty(); + int count = 0; + bool rc = ReadInt(&count); + if (rc && count > 0) { + a.SetCapacity(count); + rc = ReadInt(count, a.Array()); + if (rc) + a.SetCount(count); + } + return rc; +} + bool ON_BinaryArchive::ReadArray( ON_SimpleArray& a ) { @@ -3842,6 +3887,47 @@ ON_BinaryArchive::WriteArray( const ON_SimpleArray& a ) return rc; } + +bool +ON_BinaryArchive::WriteArray(const ON_SimpleArray& a) +{ + int count = a.Count(); + if (count < 0) + count = 0; + bool rc = WriteInt(count); + if (rc && count > 0) { + rc = WriteChar(count, a.Array()); + } + return rc; +} + +bool +ON_BinaryArchive::WriteArray(const ON_SimpleArray& a) +{ + int count = a.Count(); + if (count < 0) + count = 0; + bool rc = WriteInt(count); + if (rc && count > 0) { + rc = WriteShort(count, a.Array()); + } + return rc; +} + +bool +ON_BinaryArchive::WriteArray(const ON_SimpleArray& a) +{ + int count = a.Count(); + if (count < 0) + count = 0; + bool rc = WriteInt(count); + if (rc && count > 0) { + rc = WriteInt(count, a.Array()); + } + return rc; +} + + bool ON_BinaryArchive::WriteArray( const ON_SimpleArray& a ) { @@ -18422,7 +18508,13 @@ bool ON_BinaryArchiveBuffer::Flush() ON_3dmAnnotationContext::~ON_3dmAnnotationContext() { - Internal_Destroy(); + // NOTE WELL: + // https://mcneel.myjetbrains.com/youtrack/issue/RH-57616 + // ON_3dmAnnotationContext::Default is a global const instance. + // Compilers like VS 2019 16.5.0 set the memory for that instance to read-only. + // This destructor must not write to memory used by const instances. + if ( this != &ON_3dmAnnotationContext::Default) + Internal_Destroy(); } ON_3dmAnnotationContext::ON_3dmAnnotationContext(const ON_3dmAnnotationContext& src) diff --git a/opennurbs_archive.h b/opennurbs_archive.h index 59a386e9..5b2f4d27 100644 --- a/opennurbs_archive.h +++ b/opennurbs_archive.h @@ -2367,9 +2367,12 @@ public: bool ReadComponentIndex( ON_COMPONENT_INDEX& ); bool ReadArray( ON_SimpleArray& ); - bool ReadArray( ON_SimpleArray& ); - bool ReadArray( ON_SimpleArray& ); - bool ReadArray( ON_SimpleArray& ); + bool ReadArray(ON_SimpleArray&); + bool ReadArray(ON_SimpleArray&); + bool ReadArray(ON_SimpleArray&); + bool ReadArray(ON_SimpleArray&); + bool ReadArray(ON_SimpleArray&); + bool ReadArray(ON_SimpleArray&); bool ReadArray( ON_SimpleArray& ); bool ReadArray( ON_SimpleArray& ); bool ReadArray( ON_SimpleArray& ); @@ -2663,6 +2666,11 @@ public: bool WriteArray( const ON_SimpleArray& ); bool WriteArray( const ON_SimpleArray& ); bool WriteArray( const ON_SimpleArray& ); + + bool WriteArray(const ON_SimpleArray&); + bool WriteArray(const ON_SimpleArray&); + bool WriteArray(const ON_SimpleArray&); + bool WriteArray( const ON_SimpleArray& ); bool WriteArray( const ON_SimpleArray& ); diff --git a/opennurbs_brep.cpp b/opennurbs_brep.cpp index b15a8dad..83080f21 100644 --- a/opennurbs_brep.cpp +++ b/opennurbs_brep.cpp @@ -825,6 +825,7 @@ ON_BrepFace& ON_BrepFace::operator=(const ON_BrepFace& src) m_bRev = src.m_bRev; m_face_material_channel = src.m_face_material_channel; m_face_uuid = src.m_face_uuid; + m_per_face_color = src.m_per_face_color; if ( m_render_mesh ) { delete m_render_mesh; m_render_mesh = 0; @@ -846,7 +847,6 @@ ON_BrepFace& ON_BrepFace::operator=(const ON_BrepFace& src) if ( src.m_preview_mesh ) { m_preview_mesh = new ON_Mesh(*src.m_preview_mesh); } - //m_material_index = src.m_material_index; } return *this; } @@ -927,45 +927,137 @@ bool ON_BrepFace::IsValid( ON_TextLog* text_log ) const void ON_BrepFace::Dump( ON_TextLog& dump ) const { dump.Print("ON_BrepFace[%d]:",m_face_index); + bool bNeedComma = false; if ( ON_UuidCompare(m_face_uuid,ON_nil_uuid) ) { - dump.Print(" ("); + if (bNeedComma) + dump.Print(","); + dump.Print(" FaceId="); dump.Print(m_face_uuid); - dump.Print(" )"); + bNeedComma = true; + } + if (ON_Color::UnsetColor != m_per_face_color) + { + if (bNeedComma) + dump.Print(","); + dump.Print(" PerFaceColor=("); + dump.PrintColor(m_per_face_color); + dump.Print(")"); + } + if (0 != m_face_material_channel) + { + if (bNeedComma) + dump.Print(","); + dump.Print(" PerFaceMaterialChannel="); + dump.Print("%d", m_face_material_channel); } dump.Print("\n"); } - void ON_BrepFace::SetMaterialChannelIndex(int material_channel_index) const { - if (material_channel_index >= 0 && material_channel_index <= ON_Material::MaximumMaterialChannelIndex) + if (material_channel_index > 0 && material_channel_index <= ON_Material::MaximumMaterialChannelIndex) { const_cast(this)->m_face_material_channel = material_channel_index; } else { - ON_ERROR("Invalid material_channel_index value."); - const_cast(this)->m_face_material_channel = 0; + if (0 != material_channel_index) + { + ON_ERROR("Invalid material_channel_index value."); + } + ClearMaterialChannelIndex(); // makes it easier to detect when the per face setting is cleared. } } +void ON_BrepFace::ClearMaterialChannelIndex() const +{ + const_cast(this)->m_face_material_channel = 0; +} + int ON_BrepFace::MaterialChannelIndex() const { return m_face_material_channel; } -/* -int ON_BrepFace::MaterialIndex() const +void ON_BrepFace::SetPerFaceColor( + ON_Color color + ) const { - return m_material_index; + if (ON_Color::UnsetColor == color) + ClearPerFaceColor(); // makes it easier to detect when the per face setting is cleared. + else + m_per_face_color = color; } -void ON_BrepFace::SetMaterialIndex(int mi) +void ON_BrepFace::ClearPerFaceColor() const { - m_material_index = (mi>0) ? mi : -1; + m_per_face_color = ON_Color::UnsetColor; } -*/ + + +const ON_Color ON_BrepFace::PerFaceColor() const +{ + return m_per_face_color; +} + + +unsigned int ON_Brep::ClearPerFaceMaterialChannelIndices() +{ + unsigned change_count = 0; + const unsigned face_count = m_F.UnsignedCount(); + const ON_BrepFace* f = m_F.Array(); + for (unsigned fi = 0; fi < face_count; ++fi) + { + if (0 != f[fi].m_face_material_channel) + { + f[fi].ClearMaterialChannelIndex(); + ++change_count; + } + } + return change_count; +} + +bool ON_Brep::HasPerFaceMaterialChannelIndices() const +{ + const unsigned face_count = m_F.UnsignedCount(); + const ON_BrepFace* f = m_F.Array(); + for (unsigned fi = 0; fi < face_count; ++fi) + { + if (0 != f[fi].m_face_material_channel) + return true; + } + return false; +} + +unsigned int ON_Brep::ClearPerFaceColors() const +{ + unsigned change_count = 0; + const unsigned face_count = m_F.UnsignedCount(); + const ON_BrepFace* f = m_F.Array(); + for (unsigned fi = 0; fi < face_count; ++fi) + { + if (ON_Color::UnsetColor != f[fi].m_per_face_color) + { + f[fi].ClearPerFaceColor(); + ++change_count; + } + } + return change_count; +} + +bool ON_Brep::HasPerFaceColors() const +{ + const unsigned face_count = m_F.UnsignedCount(); + const ON_BrepFace* f = m_F.Array(); + for (unsigned fi = 0; fi < face_count; ++fi) + { + if (ON_Color::UnsetColor != f[fi].m_per_face_color) + return true; + } + return false; +} + const ON_Mesh* ON_BrepFace::Mesh( ON::mesh_type mt ) const { @@ -1157,6 +1249,37 @@ ON_Brep::ON_Brep() { ON__SET__THIS__PTR(m_s_ON_Brep_ptr); Initialize(); + + /* + const size_t sz = sizeof(*this); + const char* p0 = (char*)(this); + const char* p1 = (char*)(&m_bbox); + const char* p2 = (char*)(&m_region_topology); + const char* p3 = (char*)(&m_aggregate_status); + const char* p4 = (char*)(&m_is_solid); + const char* p5 = (char*)(&m_sleep_lock); + const char* p100 = (char*)(this+1); + + const size_t offset1 = (p1 - p0); + const size_t offset2 = (p2 - p0); + const size_t offset3 = (p3 - p0); + const size_t offset4 = (p4 - p0); + const size_t offset5 = (p5 - p0); + const size_t offset100 = (p100 - p0); + ON_TextLog::Null.Print(L"", sz, offset1, offset2, offset3, offset4, offset5, offset100); + + //BEFORE: + // offset1 216 + // offset2 264 + // offset3 272 + // offset4 304 + // offset5 308 + // offset100 312 + // sz 312 + + // AFTER + // ... + */ } ON_Brep::ON_Brep(const ON_Brep& src) : ON_Geometry(src) @@ -9008,7 +9131,7 @@ ON_Brep* ON_Brep::DuplicateFaces( int face_count, const int* face_index, bool bD face_copy.m_bbox = face.m_bbox; face_copy.m_domain[0] = face.m_domain[0]; face_copy.m_domain[1] = face.m_domain[1]; - //face_copy.m_material_index = face.m_material_index; + face_copy.m_per_face_color = face.m_per_face_color; // do NOT duplicate meshes here // duplicate loops and trims @@ -11137,7 +11260,7 @@ ON_BrepVertex& ON_Brep::NewPointOnFace( ON_BrepVertex& vertex = NewVertex( point ); ON_BrepLoop& loop = NewLoop( ON_BrepLoop::ptonsrf, face ); - ON_BrepTrim& trim = NewTrim(false,loop,-1); + ON_BrepTrim& trim = NewTrim(false, loop, -1); vertex.m_tolerance = 0.0; trim.m_type = ON_BrepTrim::ptonsrf; diff --git a/opennurbs_brep.h b/opennurbs_brep.h index 8cabe47a..17317554 100644 --- a/opennurbs_brep.h +++ b/opennurbs_brep.h @@ -131,9 +131,9 @@ public: // // For closed edges, edge.m_vi[0] = edge.m_vi[1] and // edge.m_edge_index appears twice in the m_ei[] array. - // The first occurance of edge.m_edge_index in m_ei[] + // The first occurrence of edge.m_edge_index in m_ei[] // is for the closed edge starting the vertex. - // The second occurance of edge,m_edge_index in m_ei[] + // The second occurrence of edge,m_edge_index in m_ei[] // is for the closed edge ending at the vertex. // C.f. ON_Brep::Next/PrevEdge(). ON_SimpleArray m_ei; @@ -244,7 +244,7 @@ public: The trim brep.m_T[edge.m_ti[eti]]; Remarks: This version of "Trim" hides the virtual function ON_CurveProxy::Trim(const ON_Interval&), - which is a good thing. Special care must be takend when changing the geometry + which is a good thing. Special care must be taken when changing the geometry of a brep edge to insure vertex, trim, and edge information remains valid. */ ON_BrepTrim* Trim( int eti ) const; @@ -352,9 +352,9 @@ public: // // For closed edges, m_vi[0] = m_vi[1] and m_edge_index // appears twice in the m_V[m_vi[0]].m_ei[] array. - // The first occurance of m_edge_index in m_V[m_vi[0]].m_ei[] + // The first occurrence of m_edge_index in m_V[m_vi[0]].m_ei[] // is for the closed edge starting the vertex. The second - // occurance of m_edge_index in m_V[m_vi[0]].m_ei[] + // occurrence of m_edge_index in m_V[m_vi[0]].m_ei[] // is for the closed edge edge ending at the vertex. // C.f. ON_Brep::Next/PrevEdge(). int m_vi[2]; @@ -403,7 +403,7 @@ Description: the ON_Curve virtual member functions. Note well that the domains and orientations of the curve - m_C2[trim.m_c2i] and the trin as a curve may not + m_C2[trim.m_c2i] and the trim as a curve may not agree. */ class ON_CLASS ON_BrepTrim : public ON_CurveProxy @@ -446,9 +446,9 @@ public: // inner or slit loop, and one other trim from the // same loop is connected to the edge. // (There can be other mated trims that are also - // connected to the edge. For example, the non-mainfold + // connected to the edge. For example, the non-manifold // edge that results when a surface edge lies in the - // middle of another surface.) Non-mainfold "cuts" + // middle of another surface.) Non-manifold "cuts" // have seam trims too. singular = 4, // trim is part of an outer loop, the trim's 2d curve // runs along the singular side of a surface, and the @@ -512,7 +512,7 @@ public: ///////////////////////////////////////////////////////////////// // ON_Object overrides // - // (Trims are purely topologicial - geometry queries should be + // (Trims are purely topological - geometry queries should be // directed at the trim's 2d curve or the trim's edge's 3d curve.) bool IsValid( class ON_TextLog* text_log = nullptr ) const override; @@ -530,10 +530,10 @@ public: // Reverses curve - caller must make sure trim's m_bRev3d // flags are properly updated. Use // ON_Brep::FlipTrim to reverse and trim and update all - // m_bRev3d informtion. + // m_bRev3d information. bool Reverse() override; - /* Not necessary Base clasee does the same. + /* Not necessary Base class does the same. // virtual ON_Curve::SetStartPoint override bool SetStartPoint( ON_3dPoint start_point @@ -696,7 +696,7 @@ public: /* Description: - Expert user tool that tranforms all the parameter space (2d) + Expert user tool that transforms all the parameter space (2d) trimming curves in this loop. Only 2d curve geometry is changed. The caller is responsible for reversing loops, toggle m_bRev, flags, etc. @@ -744,7 +744,7 @@ public: // A value of ON_UNSET_VALUE indicates that the // tolerance should be computed. If the value >= 0.0, // then the tolerance is set. If the value is - // ON_UNSET_VALUE, then the tolrance needs to be + // ON_UNSET_VALUE, then the tolerance needs to be // computed. // // If the trim is not singular, then the trim must @@ -889,7 +889,7 @@ public: ///////////////////////////////////////////////////////////////// // ON_Object overrides // - // (Loops and trims are purely topologicial - geometry queries should be + // (Loops and trims are purely topological - geometry queries should be // directed at the trim's 2d curve or the trim's edge's 3d curve.) // virtual ON_Object::SizeOf override @@ -929,7 +929,7 @@ public: /* Description: - Expert user tool that tranforms all the parameter space (2d) + Expert user tool that transforms all the parameter space (2d) trimming curves in this loop. Only 2d curve geometry is changed. The caller is responsible for reversing loops, toggle m_bRev, flags, etc. @@ -1027,7 +1027,7 @@ public: ///////////////////////////////////////////////////////////////// // ON_Object overrides // - // (Faces are purely topologicial - geometry queries should be + // (Faces are purely topological - geometry queries should be // directed at the face's 3d surface.) // virtual ON_Object::SizeOf override @@ -1119,15 +1119,14 @@ public: //int MaterialIndex() const; // if -1, use parent's material definition //void SetMaterialIndex(int); - // If true is returne, then ~ON_BrepFace will delete mesh. + // If true is returned, then ~ON_BrepFace will delete mesh. bool SetMesh( ON::mesh_type, ON_Mesh* mesh ); const ON_Mesh* Mesh( ON::mesh_type mesh_type ) const; /* Description: - Destroy meshes used to render and analyze surface and polysrf - objects. + Destroy meshes used to render and analyze surface and polysurface objects. Parameters: mesh_type - [in] type of mesh to destroy bDeleteMesh - [in] if true, cached mesh is deleted. @@ -1144,7 +1143,7 @@ public: /* Description: - Expert user tool that tranforms all the parameter space (2d) + Expert user tool that transforms all the parameter space (2d) trimming curves on this face. Only 2d curve geometry is changed. The caller is responsible for reversing loops, toggle m_bRev, flags, etc. @@ -1177,10 +1176,15 @@ public: bool m_bRev = false; // true if face orientation is opposite // of natural surface orientation +private: + ON__UINT8 m_reserved2 = 0; + ON__UINT16 m_reserved3 = 0; + +public: // The application specifies a base ON_Material used to render the brep this face belongs to. // If m_material_channel_index > 0 AND face_material_id = base.MaterialChannelIdFromIndex(m_material_channel_index) // is not nil, then face_material_id identifies an override rendering material for this face. - // Othewise base will be used to render this face. + // Otherwise base will be used to render this face. int m_face_material_channel = 0; public: @@ -1197,10 +1201,16 @@ public: If base_material is the ON_Material assigned to render this brep and ON_UUID face_material_id = base_material.MaterialChannelIdFromIndex( material_channel_index ) is not nil, then face_material_id identifies an override rendering material for this face. - Otherwise base_material is used to reneder this face. + Otherwise base_material is used to render this face. */ void SetMaterialChannelIndex(int material_channel_index) const; + /* + Description: + Remove per face rendering material channel index setting. The face will use the material assigned to the brep object. + */ + void ClearMaterialChannelIndex() const; + /* Returns: This face's rendering material channel index. @@ -1209,14 +1219,43 @@ public: If base_material is the ON_Material assigned to render this subd, MaterialChannelIndex() > 0, and ON_UUID face_material_id = base_material.MaterialChannelIdFromIndex( face.MaterialChannelIndex() ) is not nil, then face_material_id identifies an override rendering material for this face. - Otherwise base_material is used to reneder this face. + Otherwise base_material is used to render this face. */ int MaterialChannelIndex() const; + /* + Description: + Set per face color. + + Parameters: + color - [in] + */ + void SetPerFaceColor( + ON_Color color + ) const; + + /* + Description: + Remove per face color setting. The face will use the color assigned to the brep object. + */ + void ClearPerFaceColor() const; + + /* + Returns: + Per face color. A value of ON_Color::UnsetColor indicates the face uses the color assigned to the brep object. + */ + const ON_Color PerFaceColor() const; + public: // Persistent id for this face. Default is ON_nil_uuid. ON_UUID m_face_uuid = ON_nil_uuid; + +private: + // RH-37306 + // 30 Mar 2020: Space reserved for future implementation. + mutable ON_Color m_per_face_color = ON_Color::UnsetColor; + private: ON_BoundingBox m_bbox; // 3d bounding box ON_Interval m_domain[2]; // rectangular bounds of 2d curves @@ -1289,8 +1328,8 @@ public: public: int m_ri; // region index - // m_ri = -1 indicates this faceside overlaps - // another faceside. Generally this is a flaw + // m_ri = -1 indicates this face side overlaps + // another face side. Generally this is a flaw // in an ON_Brep. int m_fi; // face index int m_srf_dir; // 1 ON_BrepFace's surface normal points into region @@ -1360,7 +1399,7 @@ public: const ON_BoundingBox& BoundingBox() const; ON_SimpleArray m_fsi; // indices of face sides - int m_type; // 0 = infinte, 1 = bounded + int m_type; // 0 = infinite, 1 = bounded ON_BoundingBox m_bbox; /* @@ -1779,7 +1818,7 @@ public: valid. Parameters: text_log - [in] if the brep topology is not valid and - text_log is not nullptr, then a brief english + text_log is not nullptr, then a brief English description of the problem is appended to the log. The information appended to text_log is suitable for low-level debugging purposes by programmers and is @@ -1807,7 +1846,7 @@ public: brep.IsValidGeometry() can be safely called. Parameters: text_log - [in] if the brep geometry is not valid and - text_log is not nullptr, then a brief english + text_log is not nullptr, then a brief English description of the problem is appended to the log. The information appended to text_log is suitable for low-level debugging purposes by programmers and is @@ -1836,7 +1875,7 @@ public: be safely called. Parameters: text_log - [in] if the brep tolerance or flags are not - valid and text_log is not nullptr, then a brief english + valid and text_log is not nullptr, then a brief English description of the problem is appended to the log. The information appended to text_log is suitable for low-level debugging purposes by programmers and is @@ -1901,7 +1940,7 @@ public: // virtual ON_Geometry::SwapCoordinates() override bool SwapCoordinates( - int, int // indices of coords to swap + int, int // indices of coordinates to swap ) override; @@ -2022,7 +2061,7 @@ public: Pointer to new face. Remarks: Adding a new face may grow the dynamic arrays used to store - vertices, edges, faces, loops, and trims. When these dyamic + vertices, edges, faces, loops, and trims. When these dynamic arrays are grown, any pointers and references to memory in the previous arrays may become invalid. Use indices if this is an issue. @@ -2192,7 +2231,7 @@ public: Add a planar trimming loop to a planar face. Parameters: face_index - [in] index of planar face. The underlying - suface must be an ON_PlaneSurface. + surface must be an ON_PlaneSurface. loop_type - [in] type of loop to add. If loop_type is ON_BrepLoop::unknown, then the loop direction is tested and the the new loops type will be set to @@ -2471,7 +2510,7 @@ public: bLazy - [in] if true and trim.m_type is set to something other than ON_BrepTrim::unknown, then no calculation is performed and the value of trim.m_type is returned. - If false, the value of trim.m_type is ignored and is caluculated. + If false, the value of trim.m_type is ignored and is calculated. Returns: Type of trim. Remarks: @@ -2811,9 +2850,7 @@ public: Test brep to see if it is a solid. (A "solid" is a closed oriented manifold.) Returns: - @untitled table - true brep is a solid - fals brep is not a solid + If the brep is a solid, true is returned. Otherwise false is returned. See Also: ON_Brep::SolidOrientation ON_Brep::IsManifold @@ -2831,8 +2868,7 @@ public: to true if b-rep has a boundary edge and false if brep does not have a boundary edge. Returns: - true brep is a manifold - fals brep is not a manifold + If the brep is a manifold, true is returned. Otherwise false is returned. See Also: ON_Brep::IsSolid */ @@ -3025,7 +3061,7 @@ public: // rearrange the arrays that hold the brep objects. The // deleted objects have their indices set to -1. Deleting // an object that is connected to other objects will - // modify thos objects. + // modify those objects. void DeleteVertex(ON_BrepVertex& vertex); void DeleteEdge(ON_BrepEdge& edge, bool bDeleteEdgeVertices); // pass true to delete vertices used only by edge void DeleteTrim(ON_BrepTrim& trim, bool bDeleteTrimEdges); // pass true to delete edges and vertices used only by trim @@ -3059,7 +3095,7 @@ public: Returns: number of connected components Remarks: - For each face in the ith component, sets m_face_user.i to i>0. + For each face in the i-th component, sets m_face_user.i to i>0. Chases through trim lists of face edges to find adjacent faces. Numbering starts at 1. Does NOT check for vertex-vertex connections. See Also: @@ -3098,13 +3134,13 @@ public: are out of range or if sub_fi[] contains duplicates, this function will return null.) sub_brep - [in] if this pointer is not null, - then the subbrep will be created in this + then the sub-brep will be created in this class. Returns: If the input is valid, a pointer to the - subbrep is returned. If the input is not + sub-brep is returned. If the input is not valid, null is returned. The faces in - in the subbrep's m_F array are in the same + in the sub-brep's m_F array are in the same order as they were specified in sub_fi[]. */ ON_Brep* SubBrep( @@ -3312,10 +3348,10 @@ public: on all four sides. @table value meaning - 0x0001 Dont shrink on the west side of domain. - 0x0002 Dont shrink on the south side of domain. - 0x0004 Dont shrink on the east side of domain. - 0x0008 Dont shrink on the north side of domain. + 0x0001 Don't shrink on the west side of domain. + 0x0002 Don't shrink on the south side of domain. + 0x0004 Don't shrink on the east side of domain. + 0x0008 Don't shrink on the north side of domain. Returns: @untitled table true successful @@ -3380,7 +3416,7 @@ public: ///////////////////////////////////////////////////////////////// // Navigation Interface - // for moving around loops - returns trim index of prev/next trim in loop + // for moving around loops - returns trim index of previous/next trim in loop int PrevTrim( int // index of current trim (m_trim_index) ) const; @@ -3547,7 +3583,7 @@ public: ON_BrepFace* Face( ON_COMPONENT_INDEX face_index ) const; //Match endpoints of adjacent trims. If a trim needs to be adjusted, copy the 2d curve if necessary, - //convert to nurb form, yank cvs. Compact() should be called afterwards. Returns false if error in + //convert to NURBS form, yank cvs. Compact() should be called afterwards. Returns false if error in //computation, Trims must be from same face and meet at a common vertex. //These are expert user functions. When in doubt use MatchTrimEnds() on the entire Brep. @@ -3600,7 +3636,7 @@ public: T - [in] brep trim Returns: Pointer to m_C2[T.m_c2i] - NOTE: After calling this, m_C2[T.m_c2i] will be a nurbs curve only referenced by + NOTE: After calling this, m_C2[T.m_c2i] will be a NURBS curve only referenced by T, with domain = T.m_t. Caller should not delete the returned curve since its memory is owned by the brep (this). */ @@ -3744,7 +3780,7 @@ public: old_vi - [in] index of old vertex new_vi - [in] index of new vertex bClearTolerances - [in] if true, then tolerances of - edges and trims that are connected ot the old + edges and trims that are connected to the old vertex are set to ON_UNSET_VALUE. vertex_index - [in] if >= 0, this the edge is collapsed to this vertex. Otherwise a vertex is automatically @@ -3797,7 +3833,6 @@ public: trim, and vertex information from the brep's m_E[], m_V[], m_T[], m_C2[], and m_C3[] arrays. - If you want to remove wire edges and wiere After you finish cleaning up the brep, you need to call ON_Brep::Compact() to remove deleted vertices from the m_V[] array. @@ -3820,6 +3855,44 @@ public: */ int RemoveWireVertices(); + +public: + /* + Description: + Removes all per face material channel index overrides. + Returns: + Number of changed faces. + Remarks: + Per face material channel indices are a mutable property on ON_BrepFace and are set with ON_BrepFace.SetMaterialChannelIndex(). + */ + unsigned int ClearPerFaceMaterialChannelIndices(); + + /* + Returns: + True if one or more faces have per face material channel index overrides. + Remarks: + Per face material channel indices are a mutable property on ON_BrepFace and are set with ON_BrepFace.SetMaterialChannelIndex(). + */ + bool HasPerFaceMaterialChannelIndices() const; + + /* + Description: + Removes all per face color overrides. + Returns: + Number of changed faces. + Remarks: + Per face colors are a mutable property on ON_BrepFace and are set with ON_BrepFace.SetPerFaceColor(). + */ + unsigned int ClearPerFaceColors() const; + + /* + Returns: + True if one or more faces have per face color overrides. + Remarks: + Per face colors are a mutable property on ON_BrepFace and are set with ON_BrepFace.SetPerFaceColor(). + */ + bool HasPerFaceColors() const; + ///////////////////////////////////////////////////////////////// // "Expert" Interface @@ -3870,6 +3943,9 @@ protected: ON_BinaryArchive& archive ) const; + + // m_aggregate_status "should" be an ON_AggregateComponentStatusEx, + // but that change requires breaking the C++ SDK. mutable ON_AggregateComponentStatus m_aggregate_status; // Never directly set m_is_solid, use calls to IsSolid() and/or @@ -3882,7 +3958,7 @@ protected: int m_is_solid = 0; public: - // Not ideal - used in debug/dev testing + // Not ideal - used in debugging and testing //bool GetLock(); //bool GetLockOrReturnFalse(); //bool ReturnLock(); @@ -4006,7 +4082,7 @@ Description: Get an ON_Brep definition of a box. Parameters: box_corners - [in] 8 points defining the box corners - arranged as the vN lables indicate. + arranged as the vN labels indicate. v7_______e6_____v6 |\ |\ @@ -4056,7 +4132,7 @@ Description: Get an ON_Brep definition of a wedge. Parameters: corners - [in] 6 points defining the box corners - arranged as the vN lables indicate. + arranged as the vN labels indicate. /v5 /|\ @@ -4121,7 +4197,7 @@ Description: Get an ON_Brep definition of a sphere. Parameters: Center - [in] Center of sphere - radius - [int] Radius of shphere + radius - [int] Radius of sphere pBrep - [in] if not nullptr, this brep will be used and returned. Returns: @@ -4179,7 +4255,7 @@ Returns: An ON_Brep representation of the cone with a single face for the cone, an edge along the cone seam, and vertices at the base and apex ends of this seam edge. - The optional cap is asingle face with one circular edge + The optional cap is a single face with one circular edge starting and ending at the base vertex. */ ON_DECL @@ -4277,7 +4353,7 @@ Description: Parameters: brep - [in/out] path_curve - [in] path to extrude along. - bCap - [in] if true, the extusion is capped with a translation + bCap - [in] if true, the extrusion is capped with a translation of the input brep. Returns: True if successful. @@ -4307,7 +4383,7 @@ Parameters: brep - [in/out] face_index - [in] index of face to extrude. path_curve - [in] path to extrude along. - bCap - [in] if true, the extusion is capped with a translation + bCap - [in] if true, the extrusion is capped with a translation of the face being extruded. Example: Extrude a face along a vector. @@ -4350,7 +4426,7 @@ Parameters: brep - [in/out] loop_index - [in] index of face to extrude. path_curve - [in] path to extrude along. - bCap - [in] if true and the loop is closed, the extusion + bCap - [in] if true and the loop is closed, the extrusion is capped. Returns: @untitled table @@ -4593,7 +4669,7 @@ Must have at least as many ON2dex as the vertex has edges. bClosed - [out] If true, then all edges at the vertex have exactly two trims Returns: True if the order can be found. If any edge at the vertex is non-manifold, or if more than two are naked, then false. -NOTE: If you don't know how many edges are at the vertex, caall the version that takes an ON_SimpleArray. +NOTE: If you don't know how many edges are at the vertex, call the version that takes an ON_SimpleArray. */ ON_DECL bool ON_OrderEdgesAroundVertex(const ON_Brep& B, int vid, diff --git a/opennurbs_brep_io.cpp b/opennurbs_brep_io.cpp index 3d35b4e9..212b9ac9 100644 --- a/opennurbs_brep_io.cpp +++ b/opennurbs_brep_io.cpp @@ -598,6 +598,23 @@ bool ON_BrepFaceArray::Read( ON_BinaryArchive& file ) { rc = file.ReadUuid( m_a[i].m_face_uuid ); } + + if (rc && minor_version >= 2) + { + // chunk version 1.2 and later has per face colors + bool bHavePerFaceColors = false; + rc = file.ReadBool(&bHavePerFaceColors); + if (rc && bHavePerFaceColors) + { + for (i = 0; rc && i < count; i++) + { + ON_Color per_face_color = ON_Color::UnsetColor; + rc = file.ReadColor(per_face_color); + if (rc && ON_Color::UnsetColor != per_face_color) + m_a[i].SetPerFaceColor(per_face_color); + } + } + } } } else @@ -617,7 +634,10 @@ bool ON_BrepFaceArray::Write( ON_BinaryArchive& file ) const bool rc = file.BeginWrite3dmChunk( TCODE_ANONYMOUS_CHUNK, 0 ); if (rc) { - rc = file.Write3dmChunkVersion(1,1); // 1.1 added m_face_uuid + // 1.1 added m_face_uuid + // 1.2 added m_per_face_color + const int minor_version = file.Archive3dmVersion() >= 70 ? 2 : 1; + rc = file.Write3dmChunkVersion(1, minor_version); // chunk version 1.0 and later const int count = Count(); @@ -633,6 +653,27 @@ bool ON_BrepFaceArray::Write( ON_BinaryArchive& file ) const rc = file.WriteUuid( m_a[i].m_face_uuid ); } + if (rc && minor_version >= 2) + { + // 1.2 added optional per face colors + bool bHavePerFaceColors = false; + for (i = 0; rc && i < count; i++) + { + if (ON_Color::UnsetColor != m_a[i].PerFaceColor()) + { + bHavePerFaceColors = true; + break; + } + } + + rc = file.WriteBool(bHavePerFaceColors); + if (rc && bHavePerFaceColors) + { + for (i = 0; rc && i < count; i++) + rc = file.WriteColor(m_a[i].PerFaceColor()); + } + } + if ( !file.EndWrite3dmChunk() ) rc = false; } diff --git a/opennurbs_color.cpp b/opennurbs_color.cpp index 62d8de8b..93cd9ba0 100644 --- a/opennurbs_color.cpp +++ b/opennurbs_color.cpp @@ -276,6 +276,96 @@ void ON_Color::SetHSV( SetFractionalRGB(r,g,b); } + +const ON_wString ON_Color::ToString( + ON_Color::TextFormat format, + wchar_t separator, + bool bFormatUnsetColor, + class ON_TextLog& text_log +) const +{ + ON_wString s; + if (ON_Color::UnsetColor == *this) + { + if (bFormatUnsetColor) + s = L"ON_Color::UnsetColor"; + } + else + { + if (0 != Alpha()) + { + // handle conditional alpha case + switch (format) + { + case ON_Color::TextFormat::FractionalRGBa: + format = ON_Color::TextFormat::FractionalRGBA; + break; + case ON_Color::TextFormat::DecimalRGBa: + format = ON_Color::TextFormat::DecimalRGBA; + break; + case ON_Color::TextFormat::HexadecimalRGBa: + format = ON_Color::TextFormat::HexadecimalRGBA; + break; + case ON_Color::TextFormat::HSVa: + format = ON_Color::TextFormat::HSVA; + break; + } + } + + if (0 == separator) + separator = ','; + + switch (format) + { + case ON_Color::TextFormat::Unset: + // intentionally returns empty string. + break; + case ON_Color::TextFormat::FractionalRGB: + case ON_Color::TextFormat::FractionalRGBa: // nonzero alpha handled above + s = ON_wString::FormatToString(L"%g%lc%g%lc%g", FractionRed(), separator, FractionGreen(), separator, FractionBlue()); + break; + case ON_Color::TextFormat::FractionalRGBA: + s = ON_wString::FormatToString(L"%g%lc%g%lc%g%lc%g", FractionRed(), separator, FractionGreen(), separator, FractionBlue(), separator, FractionAlpha()); + break; + case ON_Color::TextFormat::DecimalRGB: + case ON_Color::TextFormat::DecimalRGBa: // nonzero alpha handled above + s = ON_wString::FormatToString(L"%d%lc%d%lc%d", Red(), separator, Green(), separator, Blue()); + break; + case ON_Color::TextFormat::DecimalRGBA: + s = ON_wString::FormatToString(L"%d%lc%d%lc%d%lc%d", Red(), separator, Green(), separator, Blue(), separator, Alpha()); + break; + case ON_Color::TextFormat::HexadecimalRGB: + case ON_Color::TextFormat::HexadecimalRGBa: // nonzero alpha handled above + s = ON_wString::FormatToString(L"%02x%lc%02x%lc%02x", Red(), separator, Green(), separator, Blue()); + break; + case ON_Color::TextFormat::HexadecimalRGBA: + s = ON_wString::FormatToString(L"%02x%lc%02x%lc%02x%lc%02x", Red(), separator, Green(), separator, Blue(), separator, Alpha()); + break; + case ON_Color::TextFormat::HSV: + case ON_Color::TextFormat::HSVa: // nonzero alpha handled above + s = ON_wString::FormatToString(L"%g%lc%g%lc%g", Hue(), separator, Saturation(), separator, Value()); + break; + case ON_Color::TextFormat::HSVA: + s = ON_wString::FormatToString(L"%g%lc%g%lc%g%lc%g", Hue(), separator, Saturation(), separator, Value(), separator, FractionAlpha()); + break; + } + } + return s; +} + + +void ON_Color::ToText( + ON_Color::TextFormat format, + wchar_t separator, + bool bFormatUnsetColor, + class ON_TextLog& text_log +) const +{ + const ON_wString s = ToString(format, separator, bFormatUnsetColor, text_log); + if (s.IsNotEmpty()) + text_log.Print(L"%ls", static_cast(s)); +} + ON_ColorStop::ON_ColorStop(const ON_Color& color, double position) : m_color(color) , m_position(position) diff --git a/opennurbs_color.h b/opennurbs_color.h index 6f76a3c5..d69e700c 100644 --- a/opennurbs_color.h +++ b/opennurbs_color.h @@ -193,6 +193,115 @@ public: double v // value ); + /// + /// Formats used by ON_Color::ToText() and ON_Color::ToString(). + /// + enum class TextFormat: unsigned char + { + /// + /// Indicates no format has been selected. Empty text is created. + /// + Unset = 0, + + /// + /// red,green,blue as floating point values from 0.0 to 1.0. + /// + FractionalRGB = 1, + + /// + /// red,green,blue as floating point values from 0.0 to 1.0. alpha is appended if it is not zero. + /// + FractionalRGBa = 2, + + /// + /// red,green,blue,alpha as floating point values from 0.0 to 1.0. + /// + FractionalRGBA = 3, + + /// + /// red,green,blue as decimal integers from 0 to 255. + /// + DecimalRGB = 4, + + /// + /// red,green,blue as decimal integers from 0 to 255. alpha is appended if it is not zero. + /// + DecimalRGBa = 5, + + /// + /// red,green,blue,alpha as decimal integers from 0 to 255. + /// + DecimalRGBA = 6, + + /// + /// red,green,blue as hexadecimal integers from 0 to 255. + /// + HexadecimalRGB = 7, + + /// + /// red,green,blue as hexadecimal integers from 0 to 255. alpha is appended if it is not zero. + /// + HexadecimalRGBa = 8, + + /// + /// red,green,blue,alpha as hexadecimal integers from 0 to 255. + /// + HexadecimalRGBA = 9, + + /// + /// hue (0 to 2pi), saturation (0 to 1), value (0 to 1) as floating point values. + /// + HSV = 10, + + /// + /// hue (0 to 2pi), saturation (0 to 1), value (0 to 1) as floating point values. alpha (0 to 1) is appended if it is not zero. + /// + HSVa = 11, + + /// + /// hue (0 to 2pi), saturation (0 to 1), value (0 to 1), alpha (0 to 1) as floating point values. + /// + HSVA = 12, + }; + + /* + Parameters: + format - [in] + separator - [in] + character to sepearate numbers (unicode code point - UTF-16 surrogate pairs not supported) + pass 0 for default. + bFormatUnsetColor - [in] + If true, ON_Color::UnsetColor will return "UnsetColor". Otherwise ON_Color::UnsetColor will return the empty string. + text_log - [in] + destination of the text. + */ + const ON_wString ToString( + ON_Color::TextFormat format, + wchar_t separator, + bool bFormatUnsetColor, + class ON_TextLog& text_log + ) const; + + /* + Parameters: + format - [in] + If format is ON_Color::TextFormat::Unset, then text_log.ColorFormat is used. + separator - [in] + character to sepearate numbers (unicode code point - UTF-16 surrogate pairs not supported) + pass 0 for default. + bFormatUnsetColor - [in] + If true, ON_Color::UnsetColor will return "UnsetColor". Otherwise ON_Color::UnsetColor will return the empty string. + text_log - [in] + destination of the text. + */ + void ToText( + ON_Color::TextFormat format, + wchar_t separator, + bool bFormatUnsetColor, + class ON_TextLog& text_log + ) const; + + private: union { // On little endian (Intel) computers, m_color has the same byte order diff --git a/opennurbs_compstat.cpp b/opennurbs_compstat.cpp index 28e717a5..1819c6ff 100644 --- a/opennurbs_compstat.cpp +++ b/opennurbs_compstat.cpp @@ -559,6 +559,40 @@ bool ON_ComponentStatus::NoEqualStates( return (mask == (s1 ^ s2)); } +ON_AggregateComponentStatus::ON_AggregateComponentStatus(const ON_AggregateComponentStatusEx& src) +{ + memcpy(this, &src, sizeof(*this)); +} + +ON_AggregateComponentStatus& ON_AggregateComponentStatus::operator=(const ON_AggregateComponentStatusEx& src) +{ + memcpy(this, &src, sizeof(*this)); + return *this; +} + +ON_AggregateComponentStatusEx::ON_AggregateComponentStatusEx(const ON_AggregateComponentStatus& src) + : ON_AggregateComponentStatus(src) +{ + Internal_ChangeStatusSerialNumber(); +} + +ON_AggregateComponentStatusEx& ON_AggregateComponentStatusEx::operator=(const ON_AggregateComponentStatus& src) +{ + ON_AggregateComponentStatus::operator=(src); + Internal_ChangeStatusSerialNumber(); + return *this; +} + +ON__UINT64 ON_AggregateComponentStatusEx::ComponentStatusSerialNumber() const +{ + return m_component_status_serial_number; +} + +void ON_AggregateComponentStatusEx::Internal_ChangeStatusSerialNumber() +{ + m_component_status_serial_number = ON_NextContentSerialNumber(); +} + bool ON_AggregateComponentStatus::ClearAllStates() { if (m_current <= 1) @@ -573,6 +607,12 @@ bool ON_AggregateComponentStatus::ClearAllStates() return false; } +bool ON_AggregateComponentStatusEx::ClearAllStates() +{ + Internal_ChangeStatusSerialNumber(); + return ON_AggregateComponentStatus::ClearAllStates(); +} + bool ON_AggregateComponentStatus::ClearAggregateStatus( ON_ComponentStatus states_to_clear ) @@ -608,15 +648,34 @@ bool ON_AggregateComponentStatus::ClearAggregateStatus( return false; } +bool ON_AggregateComponentStatusEx::ClearAggregateStatus( + ON_ComponentStatus states_to_clear +) +{ + Internal_ChangeStatusSerialNumber(); + return ON_AggregateComponentStatus::ClearAggregateStatus(states_to_clear); +} + bool ON_AggregateComponentStatus::IsEmpty() const { return (0 == m_current); } + +bool ON_AggregateComponentStatusEx::IsEmpty() const +{ + return ON_AggregateComponentStatus::IsEmpty(); +} + bool ON_AggregateComponentStatus::IsCurrent() const { return (1 == m_current); } +bool ON_AggregateComponentStatusEx::IsCurrent() const +{ + return ON_AggregateComponentStatus::IsCurrent(); +} + void ON_AggregateComponentStatus::MarkAsNotCurrent() { if (2 != m_current) @@ -626,43 +685,90 @@ void ON_AggregateComponentStatus::MarkAsNotCurrent() } } +void ON_AggregateComponentStatusEx::MarkAsNotCurrent() +{ + Internal_ChangeStatusSerialNumber(); + return ON_AggregateComponentStatus::MarkAsNotCurrent(); +} + ON_ComponentStatus ON_AggregateComponentStatus::AggregateStatus() const { return m_aggregate_status; } +ON_ComponentStatus ON_AggregateComponentStatusEx::AggregateStatus() const +{ + return ON_AggregateComponentStatus::AggregateStatus(); +} + unsigned int ON_AggregateComponentStatus::ComponentCount() const { return m_component_count; } +unsigned int ON_AggregateComponentStatusEx::ComponentCount() const +{ + return ON_AggregateComponentStatus::ComponentCount(); +} + unsigned int ON_AggregateComponentStatus::SelectedCount() const { return m_selected_count; } +unsigned int ON_AggregateComponentStatusEx::SelectedCount() const +{ + return ON_AggregateComponentStatus::SelectedCount(); +} + unsigned int ON_AggregateComponentStatus::SelectedPersistentCount() const { return m_selected_persistent_count; } +unsigned int ON_AggregateComponentStatusEx::SelectedPersistentCount() const +{ + return ON_AggregateComponentStatus::SelectedPersistentCount(); +} + unsigned int ON_AggregateComponentStatus::HighlightedCount() const { return m_highlighted_count; } +unsigned int ON_AggregateComponentStatusEx::HighlightedCount() const +{ + return ON_AggregateComponentStatus::HighlightedCount(); +} + unsigned int ON_AggregateComponentStatus::HiddenCount() const { return m_hidden_count; } +unsigned int ON_AggregateComponentStatusEx::HiddenCount() const +{ + return ON_AggregateComponentStatus::HiddenCount(); +} + unsigned int ON_AggregateComponentStatus::LockedCount() const { return m_locked_count; } + +unsigned int ON_AggregateComponentStatusEx::LockedCount() const +{ + return ON_AggregateComponentStatus::LockedCount(); +} + unsigned int ON_AggregateComponentStatus::DamagedCount() const { - return m_locked_count; + return m_damaged_count; +} + +unsigned int ON_AggregateComponentStatusEx::DamagedCount() const +{ + return ON_AggregateComponentStatus::DamagedCount(); } bool ON_AggregateComponentStatus::Add( @@ -712,6 +818,14 @@ bool ON_AggregateComponentStatus::Add( return true; } +bool ON_AggregateComponentStatusEx::Add( + const ON_AggregateComponentStatus& aggregate_status +) +{ + Internal_ChangeStatusSerialNumber(); + return ON_AggregateComponentStatus::Add(aggregate_status); +} + bool ON_AggregateComponentStatus::Add( ON_ComponentStatus component_status ) @@ -748,6 +862,14 @@ bool ON_AggregateComponentStatus::Add( } +bool ON_AggregateComponentStatusEx::Add( + ON_ComponentStatus component_status +) +{ + Internal_ChangeStatusSerialNumber(); + return ON_AggregateComponentStatus::Add(component_status); +} + ///////////////////////////////////////////////////////////////// // // ON_Object component status virtual interface diff --git a/opennurbs_compstat.h b/opennurbs_compstat.h index 5b274f6b..af714052 100644 --- a/opennurbs_compstat.h +++ b/opennurbs_compstat.h @@ -524,6 +524,14 @@ private: // ON_AggregateComponentStatus // // + + +/* +ON_AggregateComponentStatus is obsolte. +It exists because the virtual interface on ON_Object and the member on ON_Brep +cannot be changed without breakky the pubic C++ SDK. +Whenever possible, use ON_AggregateComponentStatusEx. +*/ class ON_CLASS ON_AggregateComponentStatus { public: @@ -535,6 +543,9 @@ public: ON_AggregateComponentStatus(const ON_AggregateComponentStatus&) = default; ON_AggregateComponentStatus& operator=(const ON_AggregateComponentStatus&) = default; + ON_AggregateComponentStatus(const class ON_AggregateComponentStatusEx&); + ON_AggregateComponentStatus& operator=(const class ON_AggregateComponentStatusEx&); + /* Description: Sets all states to clear. @@ -665,6 +676,131 @@ private: unsigned int m_damaged_count = 0; }; +class ON_CLASS ON_AggregateComponentStatusEx : private ON_AggregateComponentStatus +{ +public: + static const ON_AggregateComponentStatusEx Empty; + static const ON_AggregateComponentStatusEx NotCurrent; + + ON_AggregateComponentStatusEx() = default; + ~ON_AggregateComponentStatusEx() = default; + ON_AggregateComponentStatusEx(const ON_AggregateComponentStatusEx&) = default; + ON_AggregateComponentStatusEx& operator=(const ON_AggregateComponentStatusEx&) = default; + + ON_AggregateComponentStatusEx(const ON_AggregateComponentStatus&); + ON_AggregateComponentStatusEx& operator=(const ON_AggregateComponentStatus&); + + /* + Returns: + A runtime serial number that is incremented every time a component status setting + changes, even when the actual counts may be unknown. + If the returned value is 0, status information is unknown. + */ + ON__UINT64 ComponentStatusSerialNumber() const; + + /* + Description: + Sets all states to clear. + Marks status as current. + Does not change compoent count + Returns + true if successful. + false if information is not current and ClearAllStates() failed. + */ + bool ClearAllStates(); + + /* + Description: + Sets all states specified by states_to_clear to clear. + Does not change current mark. + Does not change compoent count. + Returns + true if successful. + false if information is not current and ClearAggregateStatus() failed. + */ + bool ClearAggregateStatus( + ON_ComponentStatus states_to_clear + ); + + /* + Description: + Add the status information in component_status to this aggregate status. + Parameters: + component_status - [in] + Returns: + true if successful. + false if information is not current and Add failed. + */ + bool Add( + ON_ComponentStatus component_status + ); + + /* + Description: + Add the status information in aggregate_status to this aggregate status. + Parameters: + aggregate_status - [in] + Returns: + true if successful. + false if information is not current and Add failed. + */ + bool Add( + const ON_AggregateComponentStatus& aggregate_status + ); + + /* + Returns: + true if this is empty + false if not empty. + */ + bool IsEmpty() const; + + /* + Returns: + true if the information is current (valid, up to date, ...). + false if the information is not current. + Remarks: + If the information is not current, all counts are zero and states are clear. + */ + bool IsCurrent() const; + + /* + Description: + Mark the information as not current. + Erases all information. + */ + void MarkAsNotCurrent(); + + ON_ComponentStatus AggregateStatus() const; + + unsigned int ComponentCount() const; + + /* + Returns: + Number of compoents that are selected or persistently selected. + */ + unsigned int SelectedCount() const; + + /* + Returns: + Number of compoents that are persistently selected. + */ + unsigned int SelectedPersistentCount() const; + + unsigned int HighlightedCount() const; + + unsigned int HiddenCount() const; + + unsigned int LockedCount() const; + + unsigned int DamagedCount() const; + +private: + // Whenever component status changes, m_runtime_serial_number is changed by calling Internal_ChangeStatusSerialNumber(). + void Internal_ChangeStatusSerialNumber(); + ON__UINT64 m_component_status_serial_number = 0; +}; + ////////////////////////////////////////////////////////////////////////// // // ON_UniqueTester diff --git a/opennurbs_dimensionformat.cpp b/opennurbs_dimensionformat.cpp index cd1b93c8..0d8e9a0a 100644 --- a/opennurbs_dimensionformat.cpp +++ b/opennurbs_dimensionformat.cpp @@ -404,7 +404,7 @@ bool ON_NumberFormatter::FormatAngleStringDMS(double angle_radians, ON_wString& minutes = minutes % 60; degrees *= sign; - formatted_string.Format(L"%d%c %d\' %d\"", degrees, ON_wString::DegreeSymbol, minutes, seconds); + formatted_string.Format(L"%d%lc %d\' %d\"", degrees, ON_wString::DegreeSymbol, minutes, seconds); rc = true; } return rc; diff --git a/opennurbs_font.cpp b/opennurbs_font.cpp index 17efefc9..071709a8 100644 --- a/opennurbs_font.cpp +++ b/opennurbs_font.cpp @@ -7330,6 +7330,7 @@ ON_OutlineFigure::Type ON_OutlineFigure::FigureTypeFromField10Description( if (description_len > 0) { + description.MakeLowerOrdinal(); const ON_wString s[2] = { ON_wString(L"singlestroke"), ON_wString(L"doublestroke") @@ -7341,14 +7342,8 @@ ON_OutlineFigure::Type ON_OutlineFigure::FigureTypeFromField10Description( size_t count = sizeof(t) / sizeof(t[0]); for (size_t i = 0; i < count; ++i) { - const int s_len = s[i].Length(); - if (description_len > s_len) - continue; - for (int j = 0; j < description_len - s_len; ++j) - { - if ( ON_wString::EqualOrdinal(s[i], s_len, field_10_description, s_len, true) ) - return t[i]; - } + if (description.Find(s[i]) >= 0) + return t[i]; } } diff --git a/opennurbs_font.h b/opennurbs_font.h index 35a901a2..b323ac4d 100644 --- a/opennurbs_font.h +++ b/opennurbs_font.h @@ -2148,6 +2148,30 @@ public: ON_wString m_loc_gdi_subfamily_name; ON_wString m_en_gdi_subfamily_name; + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME, ... ) + ON_wString m_loc_weight_stretch_style_model_name; + ON_wString m_en_weight_stretch_style_model_name; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, ... ) + ON_wString m_loc_field_0_copyright; + ON_wString m_en_field_0_copyright; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, ... ) + ON_wString m_loc_field_5_version; + ON_wString m_en_field_5_version; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_TRADEMARK, ... ) + ON_wString m_loc_field_7_trademark; + ON_wString m_en_field_7_trademark; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_MANUFACTURER, ... ) + ON_wString m_loc_field_8_manufacturer; + ON_wString m_en_field_8_manufacturer; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_DESIGNER, ... ) + ON_wString m_loc_field_9_designer; + ON_wString m_en_field_9_designer; + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_DESCRIPTION, ... ) // Opennurbs searches the description saved in field 10 of the name table // for the strings "Engraving - single stroke" / "Engraving - double stroke" / "Engraving" @@ -2157,6 +2181,25 @@ public: ON_wString m_loc_field_10_description; ON_wString m_en_field_10_description; + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL, ... ) + ON_wString m_loc_field_11_vendor_URL; + ON_wString m_en_field_11_vendor_URL; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_DESIGNER_URL, ... ) + ON_wString m_loc_field_12_designer_URL; + ON_wString m_en_field_12_designer_URL; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION, ... ) + ON_wString m_loc_field_13_license; + ON_wString m_en_field_13_license; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL, ... ) + ON_wString m_loc_field_14_license_URL; + ON_wString m_en_field_14_license_URL; + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME, ... ) + ON_wString m_loc_field_20_postscript_cid; // NOT the same as PostScriptName + ON_wString m_en_field_20_postscript_cid; // from IDWriteGdiInterop.ConvertFontToLOGFONT LOGFONT m_gdi_interop_logfont; @@ -4643,6 +4686,36 @@ public: const wchar_t* preferedLocale ); + // DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME + static const ON_wString WeightStretchStyleModelFamilyNameFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_0_CopyrightFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_5_VersionFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_7_TrademarkFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_8_ManufacturerFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_9_DesignerFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); // Returns the desription saved in field 10. // Opennurbs searches the description saved in field 10 of the name table @@ -4650,7 +4723,32 @@ public: // to identify fonts that are desgned for engraving (and which tend to render poorly when // used to dispaly text devices like screens, monitors, and printers). // The SLF (single line fonts) are examples of fonts that have Engraving in field 10. - static const ON_wString Field10DescriptionFromWindowsDWriteFont( + static const ON_wString Field_10_DescriptionFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_11_VendorURLFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_12_DesignerURLFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_13_LicenseFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_14_LicenseURLFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale + ); + + static const ON_wString Field_20_PostScriptCIDNameFromWindowsDWriteFont( struct IDWriteFont* dwrite_font, const wchar_t* preferedLocale ); diff --git a/opennurbs_instance.h b/opennurbs_instance.h index eec4af2d..02d57226 100644 --- a/opennurbs_instance.h +++ b/opennurbs_instance.h @@ -724,7 +724,7 @@ public: /* Parameters: parent_idef_uuid - [in] - The peristent id of the parent idef that contains the (possibly deeply nested) + The persistent id of the parent idef that contains the (possibly deeply nested) instance definion this reference refers to. parent_reference_file - [in] the file for the parent idef. @@ -771,7 +771,7 @@ private: // iref.m_parent_reference_file = idefA.FileReference(). // iref.m_nested_reference_file = idefX.FileReference(). // - // is used to identify idefX in a peristent way. + // is used to identify idefX in a persistent way. // bool m_bReferenceToNestedLinkedIdef = false; ON_UUID m_parent_idef_uuid = ON_nil_uuid; // persistent id diff --git a/opennurbs_material.cpp b/opennurbs_material.cpp index 6334b5dd..3b729769 100644 --- a/opennurbs_material.cpp +++ b/opennurbs_material.cpp @@ -5496,6 +5496,8 @@ int ON_MappingChannel::Compare( const ON_MappingChannel& other ) const int rc = m_mapping_channel_id - other.m_mapping_channel_id; if (!rc) rc = ON_UuidCompare(m_mapping_id,other.m_mapping_id); + if (!rc) + rc = m_object_xform.Compare(other.m_object_xform); return rc; } @@ -7112,6 +7114,27 @@ const ON_PhysicallyBasedMaterial ON_Material::PhysicallyBased(void) const return ON_PhysicallyBasedMaterial(*this); } +ON_Material ON_Material::ConvertToPhysicallyBased(void) const +{ + if (PhysicallyBased().Supported()) + return *this; + + //Copy all of the textures and the old-school parameters first. + ON_Material material(*this); + auto pbr = material.PhysicallyBased(); + + const bool bMetal = m_transparency < 0.01 && !m_bFresnelReflections && m_reflectivity > 0.99; + const bool bGlass = m_transparency > 0.99; + + pbr.SetBaseColor(bMetal ? m_reflection : bGlass ? m_transparent : m_diffuse); + pbr.SetMetallic(bMetal ? 1.0 : 0.0); + pbr.SetRoughness(bMetal ? m_reflection_glossiness : 1.0 - m_reflectivity); + pbr.SetOpacity(1.0 - m_transparency); + pbr.SetOpacityIOR(m_index_of_refraction); + + return material; +} + const ON_PhysicallyBasedMaterial::Impl& ON_PhysicallyBasedMaterial::Implementation(void) const { diff --git a/opennurbs_material.h b/opennurbs_material.h index 622df8ef..cc57f1c4 100644 --- a/opennurbs_material.h +++ b/opennurbs_material.h @@ -281,6 +281,10 @@ public: const ON_PhysicallyBasedMaterial PhysicallyBased(void) const; ON_PhysicallyBasedMaterial PhysicallyBased(void); + //Returns a material that is the best approximation of the original, but as a physically based material. + //the returned material is guaranteed to return true to material.PhysicallyBased().IsSupported() + ON_Material ConvertToPhysicallyBased(void) const; + //Internal use only static ON_UUID PhysicallyBasedUserdataId(void); diff --git a/opennurbs_model_component.h b/opennurbs_model_component.h index a70891b6..284dd9a4 100644 --- a/opennurbs_model_component.h +++ b/opennurbs_model_component.h @@ -1096,7 +1096,7 @@ public: could be called. Remarks: About the only good use for this function is when a model compoenent is - peristent and the name is needed for a formatted string. For any + persistent and the name is needed for a formatted string. For any other use, call the Name() function and store the result in an ON_wString. This function is dangerous because the returned pointer will be invalid if SetName() is called. diff --git a/opennurbs_object.h b/opennurbs_object.h index da27728f..7f89a5ed 100644 --- a/opennurbs_object.h +++ b/opennurbs_object.h @@ -685,7 +685,7 @@ public: /* Description: Attach a user string to the object. This information will - perisist through copy construction, operator=, and file IO. + persist through copy construction, operator=, and file IO. Parameters: key - [in] id used to retrieve this string. string_value - [in] @@ -1113,6 +1113,10 @@ public: Returns: Aggregate information about the object's component states. + + Remarks: + This function "should" return a const ON_AggregateComponentStatusEx, + but that requires breaking the C++ SDK. */ virtual ON_AggregateComponentStatus AggregateComponentStatus() const; diff --git a/opennurbs_object_history.cpp b/opennurbs_object_history.cpp index b9678f12..b10dc802 100644 --- a/opennurbs_object_history.cpp +++ b/opennurbs_object_history.cpp @@ -48,6 +48,7 @@ public: uuid_value = 11, point_on_object_value = 12, polyedge_value = 13, + subd_edge_chain_value = 14, // each value type must have a case in ON_Value::CreateValue(). @@ -64,11 +65,12 @@ public: // The valid id is a nonzero integer the developer // assigns to this value. Developers are responsible // for ensuring the - int m_value_id; + int m_value_id = -1; const VALUE_TYPE m_value_type; - ON_Value( VALUE_TYPE ); + ON_Value(VALUE_TYPE); + ON_Value(const ON_Value& src); virtual ~ON_Value(); virtual ON_Value* Duplicate() const=0; @@ -87,20 +89,24 @@ public: virtual int GetUuids( const ON_UUID*& ) const; virtual int GetObjRefs( ON_ClassArray& ) const; virtual int GetGeometryPointers( const ON_Geometry* const*& ) const; + virtual int GetSubDEdgeChainPointers(const ON_SubDEdgeChain* const*&) const; virtual int GetStrings( ON_ClassArray& ) const; - virtual int GetPolyEdgePointers( ON_ClassArray& ) const; + virtual int GetPolyEdgePointers(ON_ClassArray&) const; private: // no implementation - ON_Value(); - ON_Value& operator=(const ON_Value&); + ON_Value() = delete; + ON_Value& operator=(const ON_Value&) = delete; }; ON_Value::ON_Value( ON_Value::VALUE_TYPE value_type ) : m_value_type(value_type) -{ - m_value_id = -1; -} +{} + +ON_Value::ON_Value(const ON_Value& src) + : m_value_id(src.m_value_id) + , m_value_type(src.m_value_type) +{} ON_Value::~ON_Value() {} @@ -116,8 +122,9 @@ int ON_Value::GetXforms( const ON_Xform*& ) const {return 0;} int ON_Value::GetUuids( const ON_UUID*& ) const {return 0;} int ON_Value::GetObjRefs( ON_ClassArray& ) const {return 0;} int ON_Value::GetGeometryPointers( const ON_Geometry* const*& ) const {return 0;} +int ON_Value::GetSubDEdgeChainPointers(const ON_SubDEdgeChain* const*&) const { return 0; } int ON_Value::GetStrings( ON_ClassArray& ) const {return 0;} -int ON_Value::GetPolyEdgePointers( ON_ClassArray& ) const {return 0;} +int ON_Value::GetPolyEdgePointers(ON_ClassArray&) const { return 0; } class ON_DummyValue : public ON_Value { @@ -1395,6 +1402,191 @@ int ON_PolyEdgeHistoryValue::GetPolyEdgePointers( ON_ClassArray m_value; + + class ON_Value* Duplicate() const override; + int Count() const override; + bool ReadHelper(ON_BinaryArchive& archive) override; + bool WriteHelper(ON_BinaryArchive& archive) const override; + bool ReportHelper(ON_TextLog& text_log) const override; + int GetSubDEdgeChainPointers(const ON_SubDEdgeChain* const*&) const override; +}; + +ON_SubDEdgeChainHistoryValue::ON_SubDEdgeChainHistoryValue() + : ON_Value(ON_Value::subd_edge_chain_value) +{ +} + +ON_SubDEdgeChainHistoryValue::~ON_SubDEdgeChainHistoryValue() +{ + int i, count = m_value.Count(); + for (i = 0; i < count; i++) + { + ON_SubDEdgeChain* p = m_value[i]; + if (nullptr != p) + { + m_value[i] = nullptr; + delete p; + } + } +} + +ON_SubDEdgeChainHistoryValue::ON_SubDEdgeChainHistoryValue(const ON_SubDEdgeChainHistoryValue& src) : ON_Value(src) +{ + *this = src; +} + +ON_SubDEdgeChainHistoryValue& ON_SubDEdgeChainHistoryValue::operator=(const ON_SubDEdgeChainHistoryValue& src) +{ + if (this != &src) + { + int i, count = m_value.Count(); + for (i = 0; i < count; i++) + { + ON_SubDEdgeChain* p = m_value[i]; + if (nullptr != p) + { + m_value[i] = nullptr; + delete p; + } + } + m_value.Destroy(); + + m_value_id = src.m_value_id; + + count = src.m_value.Count(); + m_value.Reserve(count); + for (i = 0; i < count; i++) + { + const ON_SubDEdgeChain* src_ptr = src.m_value[i]; + if (!src_ptr) + continue; + ON_SubDEdgeChain* ptr = new ON_SubDEdgeChain(*src_ptr); + if (ptr) + m_value.Append(ptr); + } + } + return *this; +} + +// virtual +class ON_Value* ON_SubDEdgeChainHistoryValue::Duplicate() const +{ + return new ON_SubDEdgeChainHistoryValue(*this); +} + +// virtual +int ON_SubDEdgeChainHistoryValue::Count() const +{ + return m_value.Count(); +} + +// virtual +bool ON_SubDEdgeChainHistoryValue::ReadHelper(ON_BinaryArchive& archive) +{ + m_value.Destroy(); + + int chunk_version = 0; + if (false == archive.BeginRead3dmAnonymousChunk(&chunk_version)) + return false; + + bool rc = false; + for (;;) + { + if (chunk_version < 1) + break; + int count = 0; + if (false == archive.ReadInt(&count)) + break; + + m_value.Reserve(count); + for (int i = 0; i < count; i++) + { + ON_SubDEdgeChain* c = new ON_SubDEdgeChain(); + if (false == c->Read(archive)) + break; + m_value.Append(c); + } + if (count == m_value.Count()) + rc = true; + else + m_value.Destroy(); + + break; + } + + if (!archive.EndRead3dmChunk()) + rc = false; + return rc; +} + +// virtual +bool ON_SubDEdgeChainHistoryValue::WriteHelper(ON_BinaryArchive& archive) const +{ + if (false == archive.BeginWrite3dmAnonymousChunk(1)) + return false; + + bool rc = false; + for (;;) + { + int count = m_value.Count(); + for (int i = 0; i < count; ++i) + { + if (nullptr == m_value[i]) + count = 0; + } + if (false == archive.WriteInt(count)) + break; + + rc = true; + for (int i = 0; i < count && rc; i++) + rc = m_value[i]->Write(archive); + + break; + } + + if (!archive.EndWrite3dmChunk()) + rc = false; + return rc; +} + +// virtual +bool ON_SubDEdgeChainHistoryValue::ReportHelper(ON_TextLog& text_log) const +{ + text_log.Print("subd edge chain value\n"); + text_log.PushIndent(); + int i, count = m_value.Count(); + for (i = 0; i < count; i++) + { + if( nullptr != m_value[i]) + m_value[i]->Dump(text_log); + } + text_log.PopIndent(); + return true; +} + +// virtual +int ON_SubDEdgeChainHistoryValue::GetSubDEdgeChainPointers(const ON_SubDEdgeChain* const*& a) const +{ + a = m_value.Array(); + return m_value.Count(); +} + + /////////////////////////////////////////////////////////////////////// // @@ -1445,6 +1637,9 @@ ON_Value* ON_Value::CreateValue( int value_type ) case polyedge_value: value = new ON_PolyEdgeHistoryValue(); break; + case subd_edge_chain_value: + value = new ON_SubDEdgeChainHistoryValue(); + break; case force_32bit_enum: break; default: @@ -1609,9 +1804,10 @@ bool ON_HistoryRecord::SetGeometryValue( int value_id, ON_Geometry* g) { ON_SimpleArray a(1); a.Append(g); - return ( 1 == SetGeometryValues(value_id, a) ); + return SetGeometryValues(value_id, a); } + bool ON_HistoryRecord::SetPolyEdgeValue( int value_id, const ON_PolyEdgeHistory& polyedge ) { return ( 1 == SetPolyEdgeValues(value_id, 1, &polyedge) ); @@ -1907,16 +2103,70 @@ bool ON_HistoryRecord::SetObjRefValues( int value_id, int count, const ON_ObjRef } -bool ON_HistoryRecord::SetGeometryValues( int value_id, const ON_SimpleArray a) +bool ON_HistoryRecord::SetGeometryValues(int value_id, const ON_SimpleArray a) { - ON_GeometryValue* v = static_cast(FindValueHelper(value_id,ON_Value::geometry_value,true)); - if ( v ) + ON_GeometryValue* v = static_cast(FindValueHelper(value_id, ON_Value::geometry_value, true)); + if (v) { v->m_value = a; } return (0 != v); } +bool ON_HistoryRecord::SetSubDEdgeChainValue(int value_id, const ON_SubDEdgeChain& edge_chain) +{ + ON_SimpleArray a; + a.Append(&edge_chain); + return ON_HistoryRecord::SetSubDEdgeChainValues(value_id, a); +} + +bool ON_HistoryRecord::SetSubDEdgeChainValues(int value_id, const ON_ClassArray& edge_chains) +{ + const unsigned count = edge_chains.UnsignedCount(); + ON_SimpleArray a(count); + for (unsigned i = 0; i < count; ++i) + a.Append(&edge_chains[i]); + return ON_HistoryRecord::SetSubDEdgeChainValues(value_id, a); +} + +bool ON_HistoryRecord::SetSubDEdgeChainValues(int value_id, const ON_SimpleArray& edge_chains) +{ + // validate + const unsigned count = edge_chains.UnsignedCount(); + if (count <= 0) + return false; + + for (unsigned i = 0; i < count; ++i) + { + const ON_SubDEdgeChain* c = edge_chains[i]; + if (nullptr == c) + return false; + const ON_UUID parent_subd_id = c->PersistentSubDId(); + if (ON_nil_uuid == parent_subd_id) + return false; // a persistent id is reqiured so that update history can find the new subd and update the runtime ON_SubDEdgePtr values. + if (c->EdgeCount() <= 0) + return false; + if (false == c->HasPersistentEdgeIds()) + { + c->SetPersistentEdgeIdsFromRuntimeEdgePtrs(); + if (false == c->HasPersistentEdgeIds()) + return false; + } + m_antecedents.AddUuid(parent_subd_id, true); + } + + // copy edge chains and add + ON_SubDEdgeChainHistoryValue* v = static_cast(FindValueHelper(value_id, ON_Value::subd_edge_chain_value, true)); + if ( nullptr != v ) + { + v->m_value.Reserve(count); + for (unsigned i = 0; i < count; ++i) + v->m_value.Append(new ON_SubDEdgeChain(*edge_chains[i])); + } + + return (nullptr != v); +} + bool ON_HistoryRecord::SetPolyEdgeValues( int value_id, int count, const ON_PolyEdgeHistory* a ) { ON_PolyEdgeHistoryValue* v = static_cast(FindValueHelper(value_id,ON_Value::polyedge_value,true)); @@ -2059,6 +2309,19 @@ bool ON_HistoryRecord::GetGeometryValue( int value_id, const ON_Geometry*& g ) c return rc; } +bool ON_HistoryRecord::GetSubDEdgeChainValue(int value_id, const ON_SubDEdgeChain*& edge_chain) const +{ + bool rc = false; + edge_chain = 0; + const ON_SubDEdgeChainHistoryValue* v = static_cast(FindValueHelper(value_id, ON_Value::subd_edge_chain_value, 0)); + if (v && 1 == v->m_value.Count()) + { + edge_chain = v->m_value[0]; + rc = true; + } + return rc; +} + bool ON_HistoryRecord::GetPolyEdgeValue( int value_id, const ON_PolyEdgeHistory*& polyedge ) const { bool rc = false; @@ -2243,6 +2506,20 @@ int ON_HistoryRecord::GetGeometryValues( int value_id, ON_SimpleArray& a) const +{ + a.SetCount(0); + const ON_SubDEdgeChainHistoryValue* v = static_cast(FindValueHelper(value_id, ON_Value::subd_edge_chain_value, 0)); + if (v) + { + int i, count = v->m_value.Count(); + a.Reserve(count); + for (i = 0; i < count; i++) + a.Append(v->m_value[i]); + } + return a.Count(); +} + int ON_HistoryRecord::GetPolyEdgeValues( int value_id, ON_SimpleArray& a) const { a.SetCount(0); diff --git a/opennurbs_object_history.h b/opennurbs_object_history.h index 9815ea05..7a07a468 100644 --- a/opennurbs_object_history.h +++ b/opennurbs_object_history.h @@ -149,6 +149,14 @@ public: bool SetPointOnObjectValue( int value_id, const ON_ObjRef& oref, ON_3dPoint point ); bool SetUuidValue( int value_id, ON_UUID uuid ); bool SetStringValue( int value_id, const wchar_t* s ); + /* + Parameters: + edge_chain - [in] + edge_chain.PersistentSubDId() must be non-nil and identify the parent subd in the model. + If the model is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If the model is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + */ + bool SetSubDEdgeChainValue(int value_id, const ON_SubDEdgeChain& edge_chain); bool SetGeometryValue( int value_id, ON_Geometry* g); bool SetPolyEdgeValue( int value_id, const ON_PolyEdgeHistory& polyedge ); @@ -196,7 +204,16 @@ public: bool SetStringValues( int value_id, int count, const wchar_t* const* s ); bool SetStringValues( int value_id, const ON_ClassArray& s ); bool SetGeometryValues( int value_id, const ON_SimpleArray a); - bool SetPolyEdgeValues( int value_id, int count, const ON_PolyEdgeHistory* a ); + /* + Parameters: + edge_chain - [in] + edge_chain.PersistentSubDId() must be non-nil and identify the parent subd in the model. + If the model is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If the model is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + */ + bool SetSubDEdgeChainValues(int value_id, const ON_ClassArray& edge_chains); + bool SetSubDEdgeChainValues(int value_id, const ON_SimpleArray& edge_chains); + bool SetPolyEdgeValues(int value_id, int count, const ON_PolyEdgeHistory* a); /* Description: @@ -217,6 +234,7 @@ public: bool GetBrepValue( int value_id, const ON_Brep*& ) const; bool GetMeshValue( int value_id, const ON_Mesh*& ) const; bool GetGeometryValue( int value_id, const ON_Geometry*& ) const; + bool GetSubDEdgeChainValue(int value_id, const ON_SubDEdgeChain*& edge_chain) const; bool GetUuidValue( int value_id, ON_UUID* uuid ) const; bool GetPolyEdgeValue( int value_id, const ON_PolyEdgeHistory*& polyedge ) const; @@ -230,6 +248,7 @@ public: int GetColorValues( int value_id, ON_SimpleArray& ) const; int GetObjRefValues( int value_id, ON_ClassArray& objects ) const; int GetGeometryValues( int value_id, ON_SimpleArray& ) const; + int GetSubDEdgeChainValues(int value_id, ON_SimpleArray& edge_chains) const; int GetUuidValues( int value_id, ON_SimpleArray& ) const; int GetPolyEdgeValues( int value_id, ON_SimpleArray& ) const; diff --git a/opennurbs_objref.h b/opennurbs_objref.h index c9e23872..7a027250 100644 --- a/opennurbs_objref.h +++ b/opennurbs_objref.h @@ -93,7 +93,7 @@ private: public: double m_t[4]; ON_Interval m_s[3]; // curve/surface/cage domains - ON_COMPONENT_INDEX m_t_ci; // Not necesarily the same as m_component_index + ON_COMPONENT_INDEX m_t_ci; // Not necessarily the same as m_component_index // See comment above for details. }; @@ -122,7 +122,7 @@ public: // ON_InstanceDefinition.m_uuid. ON_UUID m_idef_uuid = ON_nil_uuid; - // m_geometry_index is the index of the uuid of the pertinant + // m_geometry_index is the index of the uuid of the pertinent // piece of geometry in the ON_InstanceRef.m_object_uuid[] // array. This index is identical to the index of the // geometry's CRhinoObject in the diff --git a/opennurbs_public_version.h b/opennurbs_public_version.h index f18f9816..c7ea5eeb 100644 --- a/opennurbs_public_version.h +++ b/opennurbs_public_version.h @@ -14,10 +14,10 @@ // first step in each build. // #define RMA_VERSION_YEAR 2020 -#define RMA_VERSION_MONTH 3 -#define RMA_VERSION_DATE 11 -#define RMA_VERSION_HOUR 14 -#define RMA_VERSION_MINUTE 39 +#define RMA_VERSION_MONTH 4 +#define RMA_VERSION_DATE 28 +#define RMA_VERSION_HOUR 13 +#define RMA_VERSION_MINUTE 30 //////////////////////////////////////////////////////////////// // @@ -35,8 +35,8 @@ // 3 = build system release build #define RMA_VERSION_BRANCH 0 -#define VERSION_WITH_COMMAS 7,0,20071,14390 -#define VERSION_WITH_PERIODS 7.0.20071.14390 +#define VERSION_WITH_COMMAS 7,0,20119,13300 +#define VERSION_WITH_PERIODS 7.0.20119.13300 #define COPYRIGHT "Copyright (C) 1993-2020, Robert McNeel & Associates. All Rights Reserved." #define SPECIAL_BUILD_DESCRIPTION "Public OpenNURBS C++ 3dm file IO library." @@ -47,8 +47,8 @@ #define RMA_VERSION_NUMBER_SR_STRING "SR0" #define RMA_VERSION_NUMBER_SR_WSTRING L"SR0" -#define RMA_VERSION_WITH_PERIODS_STRING "7.0.20071.14390" -#define RMA_VERSION_WITH_PERIODS_WSTRING L"7.0.20071.14390" +#define RMA_VERSION_WITH_PERIODS_STRING "7.0.20119.13300" +#define RMA_VERSION_WITH_PERIODS_WSTRING L"7.0.20119.13300" diff --git a/opennurbs_statics.cpp b/opennurbs_statics.cpp index 45d251b8..9c7d8785 100644 --- a/opennurbs_statics.cpp +++ b/opennurbs_statics.cpp @@ -114,6 +114,7 @@ ON_SubDComponentLocation ON_SubD::DefaultSubDAppearance = ON_SubDComponentLocati const double ON_SubDSectorType::MinimumCornerAngleRadians = (2.0*ON_PI)/((double)(ON_SubDSectorType::MaximumCornerAngleIndex)); const double ON_SubDSectorType::MaximumCornerAngleRadians = 2.0*ON_PI - ON_SubDSectorType::MinimumCornerAngleRadians; + ON_ClassId* ON_ClassId::m_p0 = 0; // static pointer to first id in list ON_ClassId* ON_ClassId::m_p1 = 0; // static pointer to last id in list int ON_ClassId::m_mark0 = 0; @@ -2343,6 +2344,80 @@ const ON_MeshRef ON_MeshRef::Empty ON_CLANG_CONSTRUCTOR_BUG_INIT(ON_MeshRef); unsigned int ON_SubD::ErrorCount = 0; +const bool ON_SubD::AutomaticRhino5BoxModeTSplineToSubDDefault = true; +const bool ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubDDefault = false; + +bool ON_SubD::AutomaticRhino5BoxModeTSplineToSubD = ON_SubD::AutomaticRhino5BoxModeTSplineToSubDDefault; +bool ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubD = ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubDDefault; + + +void ON_SubD::AutomaticMeshToSubDRestoreDefaults( + ON_SubD::AutomaticMeshToSubDContext context + ) +{ + switch (context) + { + case ON_SubD::AutomaticMeshToSubDContext::Unset: + default: + ON_SubD::AutomaticRhino5BoxModeTSplineToSubD = ON_SubD::AutomaticRhino5BoxModeTSplineToSubDDefault; + ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubD = ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubDDefault; + break; + case ON_SubD::AutomaticMeshToSubDContext::Rhino5BoxModeTSpline: + ON_SubD::AutomaticRhino5BoxModeTSplineToSubD = ON_SubD::AutomaticRhino5BoxModeTSplineToSubDDefault; + break; + case ON_SubD::AutomaticMeshToSubDContext::FBXMeshWithDivisionLevels: + ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubD = ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubDDefault; + break; + } +} + +bool ON_SubD::AutomaticMeshToSubD( + ON_SubD::AutomaticMeshToSubDContext context +) +{ + bool bAutomaticallyCreateSubD; + switch (context) + { + case ON_SubD::AutomaticMeshToSubDContext::Unset: + bAutomaticallyCreateSubD = false; + break; + case ON_SubD::AutomaticMeshToSubDContext::Rhino5BoxModeTSpline: + bAutomaticallyCreateSubD = ON_SubD::AutomaticRhino5BoxModeTSplineToSubD; + break; + case ON_SubD::AutomaticMeshToSubDContext::FBXMeshWithDivisionLevels: + bAutomaticallyCreateSubD = ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubD; + break; + default: + bAutomaticallyCreateSubD = false; + break; + } + return bAutomaticallyCreateSubD; +} + +void ON_SubD::SetAutomaticMeshToSubD( + ON_SubD::AutomaticMeshToSubDContext context, + bool bAutomaticallyCreateSubD +) +{ + // remove possiblity of hacks to use this as a char value + bAutomaticallyCreateSubD = bAutomaticallyCreateSubD ? true : false; + + switch (context) + { + case ON_SubD::AutomaticMeshToSubDContext::Unset: + break; + case ON_SubD::AutomaticMeshToSubDContext::Rhino5BoxModeTSpline: + ON_SubD::AutomaticRhino5BoxModeTSplineToSubD = bAutomaticallyCreateSubD; + break; + case ON_SubD::AutomaticMeshToSubDContext::FBXMeshWithDivisionLevels: + ON_SubD::AutomaticFBXMeshWithDivisionLevelsToSubD = bAutomaticallyCreateSubD; + break; + default: + break; + } +} + + const ON_SubDVertexEdgeProperties ON_SubDVertexEdgeProperties::Zero ON_CLANG_CONSTRUCTOR_BUG_INIT(ON_SubDVertexEdgeProperties); const ON_SubDVertexPtr ON_SubDVertexPtr::Null = { 0 }; @@ -2434,22 +2509,27 @@ static ON_ComponentStatus ON_ComponentStatus_AllSet() } const ON_ComponentStatus ON_ComponentStatus::AllSet = ON_ComponentStatus_AllSet(); -static ON_AggregateComponentStatus ON_AggregateComponentStatus_Empty() +static ON_AggregateComponentStatus ON_Internal_AggregateComponentStatus_Init(int k) { ON_AggregateComponentStatus s; memset(&s, 0, sizeof(s)); + if (1 == k) + s.MarkAsNotCurrent(); return s; } -const ON_AggregateComponentStatus ON_AggregateComponentStatus::Empty = ON_AggregateComponentStatus_Empty(); +const ON_AggregateComponentStatus ON_AggregateComponentStatus::Empty = ON_Internal_AggregateComponentStatus_Init(0); +const ON_AggregateComponentStatus ON_AggregateComponentStatus::NotCurrent = ON_Internal_AggregateComponentStatus_Init(1); -static ON_AggregateComponentStatus ON_AggregateComponentStatus_NotCurrent() + +static ON_AggregateComponentStatusEx ON_Internal_AggregateComponentStatusEx_Init(int k) { - ON_AggregateComponentStatus s; - memset(&s, 0, sizeof(s)); - s.MarkAsNotCurrent(); + ON_AggregateComponentStatusEx s(ON_Internal_AggregateComponentStatus_Init(k)); + *((ON__UINT64*)(((char*)(&s)) + sizeof(ON_AggregateComponentStatus))) = 0; // m_component_status_serial_number = 0 return s; } -const ON_AggregateComponentStatus ON_AggregateComponentStatus::NotCurrent = ON_AggregateComponentStatus_NotCurrent(); +const ON_AggregateComponentStatusEx ON_AggregateComponentStatusEx::Empty = ON_Internal_AggregateComponentStatusEx_Init(0); +const ON_AggregateComponentStatusEx ON_AggregateComponentStatusEx::NotCurrent = ON_Internal_AggregateComponentStatusEx_Init(1); + const ON_SubDComponentPoint ON_SubDComponentPoint::Unset = ON_SubDComponentPoint(); @@ -2527,26 +2607,45 @@ const ON_SubDSectorType ON_SubDSectorType::Empty ON_CLANG_CONSTRUCTOR_BUG_INIT(O const ON_SubDMatrix ON_SubDMatrix::Empty ON_CLANG_CONSTRUCTOR_BUG_INIT(ON_SubDMatrix); const ON_SubDComponentRef ON_SubDComponentRef::Empty ON_CLANG_CONSTRUCTOR_BUG_INIT(ON_SubDComponentRef); -static ON_ToSubDParameters ON_SubDCreaseParameters_CreaseAt( - ON_ToSubDParameters::InteriorCreaseOption crease_type +static ON_SubDFromMeshParameters ON_SubDCreaseParameters_CreaseAt( + ON_SubDFromMeshParameters::InteriorCreaseOption crease_type ) { - ON_ToSubDParameters cp; + ON_SubDFromMeshParameters cp; cp.SetInteriorCreaseOption(crease_type); return cp; } -static ON_ToSubDParameters ON_SubDCreaseParameters_ConvexCorners() +static ON_SubDFromMeshParameters ON_SubDCreaseParameters_ConvexCorners() { - ON_ToSubDParameters cp; - cp.SetConvexCornerOption(ON_ToSubDParameters::ConvexCornerOption::AtMeshCorner); + ON_SubDFromMeshParameters cp; + cp.SetConvexCornerOption(ON_SubDFromMeshParameters::ConvexCornerOption::AtMeshCorner); return cp; } -const ON_ToSubDParameters ON_ToSubDParameters::Smooth ON_CLANG_CONSTRUCTOR_BUG_INIT(ON_ToSubDParameters); -const ON_ToSubDParameters ON_ToSubDParameters::InteriorCreaseAtMeshCrease = ON_SubDCreaseParameters_CreaseAt(ON_ToSubDParameters::InteriorCreaseOption::AtMeshCrease); -const ON_ToSubDParameters ON_ToSubDParameters::InteriorCreaseAtMeshEdge = ON_SubDCreaseParameters_CreaseAt(ON_ToSubDParameters::InteriorCreaseOption::AtMeshEdge); -const ON_ToSubDParameters ON_ToSubDParameters::ConvexCornerAtMeshCorner = ON_SubDCreaseParameters_ConvexCorners(); +const ON_SubDFromMeshParameters ON_SubDFromMeshParameters::Smooth ON_CLANG_CONSTRUCTOR_BUG_INIT(ON_SubDFromMeshParameters); +const ON_SubDFromMeshParameters ON_SubDFromMeshParameters::InteriorCreaseAtMeshCrease = ON_SubDCreaseParameters_CreaseAt(ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshCrease); +const ON_SubDFromMeshParameters ON_SubDFromMeshParameters::InteriorCreaseAtMeshEdge = ON_SubDCreaseParameters_CreaseAt(ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshEdge); +const ON_SubDFromMeshParameters ON_SubDFromMeshParameters::ConvexCornerAtMeshCorner = ON_SubDCreaseParameters_ConvexCorners(); + +const ON_SubDFromSurfaceParameters ON_SubDFromSurfaceParameters::Default ON_CLANG_CONSTRUCTOR_BUG_INIT(ON_SubDFromSurfaceParameters); + +static const ON_SubDFromSurfaceParameters Internal_InitSubDFromSurfaceParameters( + ON_SubDFromSurfaceParameters::Methods method, + bool bCorners + ) +{ + ON_SubDFromSurfaceParameters p; + if (ON_SubDFromSurfaceParameters::Methods::Unset != method) + p.SetMethod(method); + p.SetCorners(bCorners); + return p; +} + +const ON_SubDFromSurfaceParameters ON_SubDFromSurfaceParameters::DefaultWithCorners = Internal_InitSubDFromSurfaceParameters(ON_SubDFromSurfaceParameters::Methods::Unset, true); +const ON_SubDFromSurfaceParameters ON_SubDFromSurfaceParameters::ControlNet = Internal_InitSubDFromSurfaceParameters(ON_SubDFromSurfaceParameters::Methods::FromNurbsControlNet, false); +const ON_SubDFromSurfaceParameters ON_SubDFromSurfaceParameters::ControlNetWithCorners = Internal_InitSubDFromSurfaceParameters(ON_SubDFromSurfaceParameters::Methods::FromNurbsControlNet, true); + const ON_SubDComponentFilter ON_SubDComponentFilter::Unset = ON_SubDComponentFilter::Create(true, true, true); const ON_SubDComponentFilter ON_SubDComponentFilter::OnlyVertices = ON_SubDComponentFilter::Create(true, false, false); diff --git a/opennurbs_subd.cpp b/opennurbs_subd.cpp index 5c8c5be7..6097498f 100644 --- a/opennurbs_subd.cpp +++ b/opennurbs_subd.cpp @@ -1513,43 +1513,43 @@ bool ON_SubDComponentPtrPair::BothAreNotNull() const ////////////////////////////////////////////////////////////////////////// // -// ON_ToSubDParameters +// ON_SubDFromMeshParameters // -ON_ToSubDParameters::ConvexCornerOption ON_ToSubDParameters::ConvexCornerOptionFromUnsigned( +ON_SubDFromMeshParameters::ConvexCornerOption ON_SubDFromMeshParameters::ConvexCornerOptionFromUnsigned( unsigned int convex_corner_option_as_unsigned ) { switch (convex_corner_option_as_unsigned) { - case (unsigned int)ON_ToSubDParameters::ConvexCornerOption::Unset: - return ON_ToSubDParameters::ConvexCornerOption::Unset; - case (unsigned int)ON_ToSubDParameters::ConvexCornerOption::None: - return ON_ToSubDParameters::ConvexCornerOption::None; - case (unsigned int)ON_ToSubDParameters::ConvexCornerOption::AtMeshCorner: - return ON_ToSubDParameters::ConvexCornerOption::AtMeshCorner; + case (unsigned int)ON_SubDFromMeshParameters::ConvexCornerOption::Unset: + return ON_SubDFromMeshParameters::ConvexCornerOption::Unset; + case (unsigned int)ON_SubDFromMeshParameters::ConvexCornerOption::None: + return ON_SubDFromMeshParameters::ConvexCornerOption::None; + case (unsigned int)ON_SubDFromMeshParameters::ConvexCornerOption::AtMeshCorner: + return ON_SubDFromMeshParameters::ConvexCornerOption::AtMeshCorner; default: break; } - return ON_ToSubDParameters::ConvexCornerOption::Unset; + return ON_SubDFromMeshParameters::ConvexCornerOption::Unset; } -void ON_ToSubDParameters::SetConvexCornerOption( - ON_ToSubDParameters::ConvexCornerOption convex_corner_option +void ON_SubDFromMeshParameters::SetConvexCornerOption( + ON_SubDFromMeshParameters::ConvexCornerOption convex_corner_option ) { - m_convex_corner_option = ON_ToSubDParameters::ConvexCornerOptionFromUnsigned((unsigned int)convex_corner_option); + m_convex_corner_option = ON_SubDFromMeshParameters::ConvexCornerOptionFromUnsigned((unsigned int)convex_corner_option); } -ON_ToSubDParameters::ConvexCornerOption ON_ToSubDParameters::ConvexCornerTest() const +ON_SubDFromMeshParameters::ConvexCornerOption ON_SubDFromMeshParameters::ConvexCornerTest() const { switch (m_convex_corner_option) { - case ON_ToSubDParameters::ConvexCornerOption::Unset: - case ON_ToSubDParameters::ConvexCornerOption::None: + case ON_SubDFromMeshParameters::ConvexCornerOption::Unset: + case ON_SubDFromMeshParameters::ConvexCornerOption::None: return m_convex_corner_option; - case ON_ToSubDParameters::ConvexCornerOption::AtMeshCorner: + case ON_SubDFromMeshParameters::ConvexCornerOption::AtMeshCorner: if ( m_maximum_convex_corner_edge_count >= 2 && m_maximum_convex_corner_edge_count <= ON_SubDVertex::MaximumEdgeCount && m_maximum_convex_corner_angle_radians >= 0.0 @@ -1559,10 +1559,10 @@ ON_ToSubDParameters::ConvexCornerOption ON_ToSubDParameters::ConvexCornerTest() break; } - return ON_ToSubDParameters::ConvexCornerOption::Unset; + return ON_SubDFromMeshParameters::ConvexCornerOption::Unset; } -void ON_ToSubDParameters::SetMaximumConvexCornerEdgeCount( +void ON_SubDFromMeshParameters::SetMaximumConvexCornerEdgeCount( unsigned int maximum_convex_corner_edge_count ) { @@ -1570,12 +1570,12 @@ void ON_ToSubDParameters::SetMaximumConvexCornerEdgeCount( m_maximum_convex_corner_edge_count = (unsigned short)maximum_convex_corner_edge_count; } -unsigned int ON_ToSubDParameters::MaximumConvexCornerEdgeCount() const +unsigned int ON_SubDFromMeshParameters::MaximumConvexCornerEdgeCount() const { return m_maximum_convex_corner_edge_count; } -void ON_ToSubDParameters::SetMaximumConvexCornerAngleRadians( +void ON_SubDFromMeshParameters::SetMaximumConvexCornerAngleRadians( double maximum_convex_corner_angle_radians ) { @@ -1583,13 +1583,13 @@ void ON_ToSubDParameters::SetMaximumConvexCornerAngleRadians( m_maximum_convex_corner_angle_radians = maximum_convex_corner_angle_radians; } -double ON_ToSubDParameters::MaximumConvexCornerAngleRadians() const +double ON_SubDFromMeshParameters::MaximumConvexCornerAngleRadians() const { return m_maximum_convex_corner_angle_radians; } -ON_ToSubDParameters::ConvexCornerOption ON_ToSubDParameters::CopyConvexCornerTest( - ON_ToSubDParameters source_parameters +ON_SubDFromMeshParameters::ConvexCornerOption ON_SubDFromMeshParameters::CopyConvexCornerTest( + ON_SubDFromMeshParameters source_parameters ) { SetConvexCornerOption(source_parameters.ConvexCornerTest()); @@ -1598,12 +1598,12 @@ ON_ToSubDParameters::ConvexCornerOption ON_ToSubDParameters::CopyConvexCornerTes return ConvexCornerTest(); } -bool ON_ToSubDParameters::InterpolateMeshVertices() const +bool ON_SubDFromMeshParameters::InterpolateMeshVertices() const { return m_bInterpolateMeshVertices; } -void ON_ToSubDParameters::SetInterpolateMeshVertices( +void ON_SubDFromMeshParameters::SetInterpolateMeshVertices( bool bInterpolateMeshVertices ) { @@ -1611,34 +1611,34 @@ void ON_ToSubDParameters::SetInterpolateMeshVertices( m_bInterpolateMeshVertices = false; } -bool ON_ToSubDParameters::MergeColinearBoundaryEdges() const +bool ON_SubDFromMeshParameters::MergeColinearBoundaryEdges() const { // clear bit means true, set bit means false - return (0 == (ON_ToSubDParameters::MergeColinearBoundaryEdgesMask & m_merge_edges_bits)); + return (0 == (ON_SubDFromMeshParameters::MergeColinearBoundaryEdgesMask & m_merge_edges_bits)); } -void ON_ToSubDParameters::SetMergeColinearBoundaryEdges( +void ON_SubDFromMeshParameters::SetMergeColinearBoundaryEdges( bool bAllowColinearBoundaryEdges ) { - const unsigned char mask = ON_ToSubDParameters::MergeColinearBoundaryEdgesMask; + const unsigned char mask = ON_SubDFromMeshParameters::MergeColinearBoundaryEdgesMask; if (false == bAllowColinearBoundaryEdges) m_merge_edges_bits |= mask; // set bit else m_merge_edges_bits &= ~mask; // clear bit } -bool ON_ToSubDParameters::MergeColinearInteriorEdges() const +bool ON_SubDFromMeshParameters::MergeColinearInteriorEdges() const { // clear bit means true, set bit means false - return (0 == (ON_ToSubDParameters::MergeColinearInteriorEdgesMask & m_merge_edges_bits)); + return (0 == (ON_SubDFromMeshParameters::MergeColinearInteriorEdgesMask & m_merge_edges_bits)); } -void ON_ToSubDParameters::SetMergeColinearInteriorEdges( +void ON_SubDFromMeshParameters::SetMergeColinearInteriorEdges( bool bAllowColinearInteriorEdges ) { - const unsigned char mask = ON_ToSubDParameters::MergeColinearInteriorEdgesMask; + const unsigned char mask = ON_SubDFromMeshParameters::MergeColinearInteriorEdgesMask; if (false == bAllowColinearInteriorEdges) m_merge_edges_bits |= mask; // set bit else @@ -1646,19 +1646,19 @@ void ON_ToSubDParameters::SetMergeColinearInteriorEdges( } -void ON_ToSubDParameters::SetInteriorCreaseOption( - ON_ToSubDParameters::InteriorCreaseOption interior_crease_option +void ON_SubDFromMeshParameters::SetInteriorCreaseOption( + ON_SubDFromMeshParameters::InteriorCreaseOption interior_crease_option ) { - m_interior_crease_option = ON_ToSubDParameters::InteriorCreaseOptionFromUnsigned((unsigned int)interior_crease_option); + m_interior_crease_option = ON_SubDFromMeshParameters::InteriorCreaseOptionFromUnsigned((unsigned int)interior_crease_option); } -ON_ToSubDParameters::InteriorCreaseOption ON_ToSubDParameters::InteriorCreaseTest() const +ON_SubDFromMeshParameters::InteriorCreaseOption ON_SubDFromMeshParameters::InteriorCreaseTest() const { return m_interior_crease_option; } -void ON_ToSubDParameters::SetMinimumCreaseAngleRadians( +void ON_SubDFromMeshParameters::SetMinimumCreaseAngleRadians( double minimum_crease_angle_radians ) { @@ -1667,13 +1667,13 @@ void ON_ToSubDParameters::SetMinimumCreaseAngleRadians( } -double ON_ToSubDParameters::MinimumCreaseAngleRadians() const +double ON_SubDFromMeshParameters::MinimumCreaseAngleRadians() const { return m_minimum_crease_angle_radians; } -ON_ToSubDParameters::InteriorCreaseOption ON_ToSubDParameters::CopyInteriorCreaseTest( - ON_ToSubDParameters source_parameters +ON_SubDFromMeshParameters::InteriorCreaseOption ON_SubDFromMeshParameters::CopyInteriorCreaseTest( + ON_SubDFromMeshParameters source_parameters ) { SetInteriorCreaseOption(source_parameters.InteriorCreaseTest()); @@ -1681,29 +1681,54 @@ ON_ToSubDParameters::InteriorCreaseOption ON_ToSubDParameters::CopyInteriorCreas return InteriorCreaseTest(); } -ON_ToSubDParameters::InteriorCreaseOption ON_ToSubDParameters::InteriorCreaseOptionFromUnsigned( +ON_SubDFromMeshParameters::InteriorCreaseOption ON_SubDFromMeshParameters::InteriorCreaseOptionFromUnsigned( unsigned int interior_crease_option_as_unsigned ) { switch (interior_crease_option_as_unsigned) { - case (unsigned int)ON_ToSubDParameters::InteriorCreaseOption::Unset: - return ON_ToSubDParameters::InteriorCreaseOption::Unset; + case (unsigned int)ON_SubDFromMeshParameters::InteriorCreaseOption::Unset: + return ON_SubDFromMeshParameters::InteriorCreaseOption::Unset; break; - case (unsigned int)ON_ToSubDParameters::InteriorCreaseOption::None: - return ON_ToSubDParameters::InteriorCreaseOption::None; + case (unsigned int)ON_SubDFromMeshParameters::InteriorCreaseOption::None: + return ON_SubDFromMeshParameters::InteriorCreaseOption::None; break; - case (unsigned int)ON_ToSubDParameters::InteriorCreaseOption::AtMeshCrease: - return ON_ToSubDParameters::InteriorCreaseOption::AtMeshCrease; + case (unsigned int)ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshCrease: + return ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshCrease; break; - case (unsigned int)ON_ToSubDParameters::InteriorCreaseOption::AtMeshEdge: - return ON_ToSubDParameters::InteriorCreaseOption::AtMeshEdge; + case (unsigned int)ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshEdge: + return ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshEdge; break; default: break; } - return ON_ToSubDParameters::InteriorCreaseOption::Unset; + return ON_SubDFromMeshParameters::InteriorCreaseOption::Unset; +} + + +ON_SubDFromSurfaceParameters::Methods ON_SubDFromSurfaceParameters::Method() const +{ + return m_method; +} + +void ON_SubDFromSurfaceParameters::SetMethod( + ON_SubDFromSurfaceParameters::Methods method + ) +{ + m_method = method; +} + +bool ON_SubDFromSurfaceParameters::Corners() const +{ + return m_bCorners; +} + +void ON_SubDFromSurfaceParameters::SetCorners( + bool bCorners + ) +{ + m_bCorners = bCorners ? true : false; } ////////////////////////////////////////////////////////////////////////// @@ -3267,8 +3292,10 @@ void ON_SubDFace::CopyFrom( m_next_face = nullptr; - m_zero_face_id = src->m_zero_face_id; - m_parent_face_id = src->m_parent_face_id; + m_material_channel_index = src->m_material_channel_index; + m_per_face_color = src->m_per_face_color; + + m_level_zero_face_id = src->m_level_zero_face_id; if (bCopyEdgeArray) { @@ -4129,6 +4156,12 @@ ON__UINT64 ON_SubD::ContentSerialNumber() const return (nullptr != subdimple) ? subdimple->ContentSerialNumber() : 0; } +ON__UINT64 ON_SubD::ComponentStatusSerialNumber() const +{ + ON_SubDimple* subdimple = m_subdimple_sp.get(); + return (nullptr != subdimple) ? subdimple->ComponentStatusSerialNumber() : 0; +} + ON__UINT64 ON_SubD::ChangeContentSerialNumberForExperts( bool bChangePreservesSymmetry ) @@ -6111,8 +6144,39 @@ unsigned int ON_SubDLevel::DumpTopology( } text_log.Print(" }\n"); + + + bool bNeedComma = false; + + const ON_Color per_face_color = f->PerFaceColor(); + if (ON_Color::UnsetColor != per_face_color) + { + if (bNeedComma) + text_log.Print(", "); + else + text_log.Print("Per face"); + bNeedComma = true; + text_log.Print("face color=("); + text_log.PrintColor(per_face_color); + text_log.Print(")"); + } + + const int per_face_material_channel_index = f->MaterialChannelIndex(); + if (0 != per_face_material_channel_index) + { + if (bNeedComma) + text_log.Print(", "); + else + text_log.Print("Per face"); + bNeedComma = true; + text_log.Print(" material channel index=%d", per_face_material_channel_index); + } + if (bNeedComma) + text_log.PrintNewLine(); + if (f->TextureDomainIsSet()) { + bNeedComma = true; const ON_wString s = ON_SubD::TextureDomainTypeToString(f->TextureDomainType()); const bool bGridOrder = true; const bool bNormalized = false; @@ -6122,84 +6186,14 @@ unsigned int ON_SubDLevel::DumpTopology( f->TextureDomainCorner(bGridOrder,bNormalized,2), f->TextureDomainCorner(bGridOrder,bNormalized,3) }; - text_log.Print("%ls texture domain. Grid corners: (%g,%g), (%g,%g), (%g,%g), (%g,%g)\n", + text_log.Print("%ls texture domain. Grid corners: (%g,%g), (%g,%g), (%g,%g), (%g,%g)", static_cast(s), corners[0].x, corners[0].y, corners[1].x, corners[1].y, corners[2].x, corners[2].y, corners[3].x, corners[3].y ); - ////const ON_SubDMeshFragment *fragments = f->MeshFragments(); - ////if (nullptr != fragments) - ////{ - ////ON_TextLogIndent indent1(text_log); - //// unsigned short fragment_count = 0; - //// const unsigned short expected_fragment_count = (unsigned short)((4 == face_edge_count) ? 1 : face_edge_count); - //// ON_3dPoint fragmentT[4]; - //// bool bDamagedOrIncompleteFragments = false; - //// for (unsigned short fragdex = 0; fragdex <= expected_fragment_count && nullptr != fragments; fragdex++, fragments = fragments->m_next_fragment) - //// { - //// ++fragment_count; - //// if (expected_fragment_count != fragments->m_face_fragment_count) - //// { - //// bDamagedOrIncompleteFragments = true; - //// break; - //// } - //// if (fragdex != fragments->m_face_fragment_index) - //// { - //// bDamagedOrIncompleteFragments = true; - //// break; - //// } - //// } - //// if (expected_fragment_count == fragment_count) - //// { - //// fragments = f->MeshFragments(); - //// if (1 == fragment_count) - //// { - //// if (fragments->GetTextureCoordinteCorners(bGridOrder, fragmentT)) - //// { - //// text_log.Print("Quad face fragment texture corners = (%g,%g,%g), (%g,%g,%g), (%g,%g,%g), (%g,%g,%g)\n", - //// fragmentT[0].x, fragmentT[0].y, fragmentT[0].z, - //// fragmentT[1].x, fragmentT[1].y, fragmentT[1].z, - //// fragmentT[2].x, fragmentT[2].y, fragmentT[2].z, - //// fragmentT[3].x, fragmentT[3].y, fragmentT[3].z - //// ); - //// } - //// else - //// { - //// text_log.Print("Quad face fragment texture corners not available.\n"); - //// } - //// } - //// else - //// { - //// text_log.Print("%u face fragments.\n", (unsigned)expected_fragment_count); - //// ON_TextLogIndent indent2(text_log); - //// for (unsigned short fragdex = 0; fragdex <= expected_fragment_count && nullptr != fragments; fragdex++, fragments = fragments->m_next_fragment) - //// { - //// if (fragments->GetTextureCoordinteCorners(bGridOrder, fragmentT)) - //// { - //// text_log.Print("fragment[%u] texture corners = (%g,%g,%g), (%g,%g,%g), (%g,%g,%g), (%g,%g,%g)\n", - //// (unsigned)fragdex, - //// fragmentT[0].x, fragmentT[0].y, fragmentT[0].z, - //// fragmentT[1].x, fragmentT[1].y, fragmentT[1].z, - //// fragmentT[2].x, fragmentT[2].y, fragmentT[2].z, - //// fragmentT[3].x, fragmentT[3].y, fragmentT[3].z - //// ); - //// } - //// else - //// { - //// text_log.Print("fragment[%u] texture corners not available.\n", (unsigned)fragdex); - //// } - //// } - //// } - //// } - //// else if (nullptr == fragments) - //// { - //// bDamagedOrIncompleteFragments = true; - //// } - //// if (bDamagedOrIncompleteFragments ) - //// text_log.Print("Damaged or incomplete mesh fragments.\n"); - ////} + text_log.PrintNewLine(); } text_log.PopIndent(); @@ -6285,7 +6279,7 @@ void ON_SubD::DestroyRuntimeCache( bool bDelete ) if (level) { level->ClearEvaluationCache(); - level->AggregateComponentStatus().MarkAsNotCurrent(); + level->MarkAggregateComponentStatusAsNotCurrent(); } } dimple->ChangeContentSerialNumber(false); @@ -7618,7 +7612,7 @@ const ON_ComponentStatus ON_SubDComponentBase::Status() const bool ON_SubDComponentBase::IsActive() const { - return (m_id >= 0 && m_archive_id != ON_UNSET_UINT_INDEX); + return (m_id > 0 && m_archive_id != ON_UNSET_UINT_INDEX); } @@ -9639,8 +9633,9 @@ unsigned int ON_SubDimple::Internal_GlobalQuadSubdivideFace( if (f0_edge_count < 3) return 0; - const unsigned int parent_face_id = f0->m_id; - const unsigned int zero_face_id = (0 == f0->SubdivisionLevel()) ? parent_face_id : f0->m_zero_face_id; + const int material_channel_index = f0->MaterialChannelIndex(); + const ON_Color per_face_color = f0->PerFaceColor(); + const unsigned int level_zero_face_id = (0 == f0->SubdivisionLevel()) ? f0->m_id : f0->m_level_zero_face_id; if (nullptr == f0->m_subd_point1) { @@ -9735,8 +9730,9 @@ unsigned int ON_SubDimple::Internal_GlobalQuadSubdivideFace( ON_SubDFace* f1 = AddFace(4, f1edges); if (nullptr != f1) { - f1->m_zero_face_id = zero_face_id; - f1->m_parent_face_id = parent_face_id; + f1->SetMaterialChannelIndex(material_channel_index); + f1->SetPerFaceColor(per_face_color); + f1->m_level_zero_face_id = level_zero_face_id; f1_count++; } } @@ -11328,7 +11324,7 @@ unsigned int ON_SubDLevel::GetComponentsWithSetStates( if (states_filter.IsClear()) return 0; - ON_AggregateComponentStatus acs = AggregateComponentStatus(); + const ON_AggregateComponentStatusEx acs = AggregateComponentStatus(); ON_ComponentStatus as = acs.AggregateStatus(); if (bAllEqualStates) @@ -12389,7 +12385,7 @@ unsigned int ON_SubDimple::DeleteComponents( for (unsigned short efi = 0; efi < edge_face_count; efi++, fptr0++) { if (2 == efi) - fptr0 = edge->m_face2; + fptr0 = edge->m_facex; const ON_SubDFace* face = fptr0->Face(); if (nullptr == face || ON_UNSET_UINT_INDEX == face->ArchiveId()) continue; @@ -15803,22 +15799,25 @@ bool ON_SubDEdgeChain::IsConvexLoop(bool bStrictlyConvex) const unsigned int ON_SubDEdgeChain::BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SubDEdge* initial_edge ) { - return ON_SubDEdgeChain::BeginEdgeChain(subd_ref, ON_SubDEdgePtr::Create(initial_edge, 0)); + return ON_SubDEdgeChain::BeginEdgeChain(persistent_subd_id, subd_ref, ON_SubDEdgePtr::Create(initial_edge, 0)); } unsigned int ON_SubDEdgeChain::BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SimpleArray& initial_edge_chain ) { - return BeginEdgeChain(subd_ref, initial_edge_chain.Array(), initial_edge_chain.UnsignedCount()); + return BeginEdgeChain(persistent_subd_id, subd_ref, initial_edge_chain.Array(), initial_edge_chain.UnsignedCount()); } unsigned int ON_SubDEdgeChain::BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SubDEdge*const* initial_edge_chain, size_t edge_count @@ -15834,7 +15833,7 @@ unsigned int ON_SubDEdgeChain::BeginEdgeChain( return 0; if ( 1 == edge_count) - return ON_SubDEdgeChain::BeginEdgeChain(subd_ref, ON_SubDEdgePtr::Create(initial_edge_chain[0], 0)); + return ON_SubDEdgeChain::BeginEdgeChain(persistent_subd_id, subd_ref, ON_SubDEdgePtr::Create(initial_edge_chain[0], 0)); const ON_SubDEdge* e0 = initial_edge_chain[0]; if (nullptr == e0 || nullptr == e0->m_vertex[0] || nullptr == e0->m_vertex[1] ) @@ -15860,26 +15859,29 @@ unsigned int ON_SubDEdgeChain::BeginEdgeChain( eptr_chain.Append(eptr); } - return ON_SubDEdgeChain::BeginEdgeChain(subd_ref,eptr_chain); + return ON_SubDEdgeChain::BeginEdgeChain(persistent_subd_id, subd_ref,eptr_chain); } unsigned int ON_SubDEdgeChain::BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, ON_SubDEdgePtr eptr ) { - return ON_SubDEdgeChain::BeginEdgeChain(subd_ref, &eptr, 1); + return ON_SubDEdgeChain::BeginEdgeChain(persistent_subd_id, subd_ref, &eptr, 1); } unsigned int ON_SubDEdgeChain::BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SimpleArray& initial_edge_chain ) { - return ON_SubDEdgeChain::BeginEdgeChain(subd_ref, initial_edge_chain.Array(), initial_edge_chain.UnsignedCount() ); + return ON_SubDEdgeChain::BeginEdgeChain(persistent_subd_id, subd_ref, initial_edge_chain.Array(), initial_edge_chain.UnsignedCount() ); } unsigned int ON_SubDEdgeChain::BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SubDEdgePtr* initial_edge_chain, size_t edge_count @@ -15887,6 +15889,7 @@ unsigned int ON_SubDEdgeChain::BeginEdgeChain( { ClearEdgeChain(); + m_persistent_subd_id = persistent_subd_id; m_subd_ref = subd_ref; if (edge_count <= 0 || m_subd_ref.SubD().IsEmpty()) @@ -15937,6 +15940,252 @@ unsigned int ON_SubDEdgeChain::BeginEdgeChain( return m_edge_chain.UnsignedCount(); } +const ON_UUID ON_SubDEdgeChain::PersistentSubDId() const +{ + return m_persistent_subd_id; +} + +bool ON_SubDEdgeChain::HasPersistentEdgeIds() const +{ + const unsigned count = this->EdgeCount(); + return + count > 0 + && count == m_persistent_edge_id.UnsignedCount() + && count == m_persistent_edge_orientation.UnsignedCount() + ; +} + +bool ON_SubDEdgeChain::HasRuntimeEdgePtrs() const +{ + const unsigned count = this->EdgeCount(); + return + count > 0 + && count == this->m_edge_chain.UnsignedCount() + && m_subd_ref.SubD().EdgeCount() > 0 + ; +} + +bool ON_SubDEdgeChain::SetPersistentEdgeIdsFromRuntimeEdgePtrs() const +{ + m_persistent_edge_id.SetCount(0); + m_persistent_edge_orientation.SetCount(0); + const unsigned count = (m_subd_ref.SubD().EdgeCount() > 0) ? m_edge_chain.UnsignedCount() : 0; + bool rc = count > 0; + if (rc) + { + m_persistent_edge_id.Reserve(count); + m_persistent_edge_orientation.Reserve(count); + for (unsigned i = 0; i < count; ++i) + { + const ON_SubDEdgePtr eptr = m_edge_chain[i]; + const unsigned edge_id = eptr.EdgeId(); + if (edge_id <= 0) + break; + if (false == eptr.IsActive()) + break; + m_persistent_edge_id.Append(edge_id); + m_persistent_edge_orientation.Append(0 == eptr.EdgeDirection() ? 0 : 1); + } + if (count != m_persistent_edge_id.UnsignedCount() || count != m_persistent_edge_orientation.UnsignedCount()) + { + rc = false; + m_persistent_edge_id.SetCount(0); + m_persistent_edge_orientation.SetCount(0); + } + } + return rc; +} + +bool ON_SubDEdgeChain::SetRuntimeEdgePtrsFromPersistentSubD( + ON_UUID persistent_subd_id, + ON_SubDRef persistent_subd_ref +) +{ + bool rc = true; + m_edge_chain.SetCount(0); + const unsigned count = m_persistent_edge_id.UnsignedCount(); + const ON_SubD& subd = persistent_subd_ref.SubD(); + if (count > 0 && count == m_persistent_edge_orientation.UnsignedCount() && subd.EdgeCount() > 0) + { + rc = false; + ON_SimpleArray local_edge_chain(count); + for (unsigned i = 0; i < count; ++i) + { + const ON_SubDEdge* e = subd.EdgeFromId(m_persistent_edge_id[i]); + if (nullptr == e) + break; + const ON_SubDEdgePtr eptr = ON_SubDEdgePtr::Create(e, (1 == m_persistent_edge_orientation[i]) ? 1 : 0); + local_edge_chain.Append(eptr); + } + if (count == local_edge_chain.UnsignedCount()) + { + if (ON_SubDEdgeChain::IsValidEdgeChain(local_edge_chain, false)) + { + m_edge_chain = local_edge_chain; + rc = true; + } + } + } + if (persistent_subd_ref.SubD().RuntimeSerialNumber() != m_subd_ref.SubD().RuntimeSerialNumber()) + m_subd_ref = persistent_subd_ref; + if (ON_UuidIsNotNil(persistent_subd_id) && 0 != ON_UuidCompare(m_persistent_subd_id, persistent_subd_id)) + m_persistent_subd_id = persistent_subd_id; + return rc; +} + +bool ON_SubDEdgeChain::Write(class ON_BinaryArchive& archive) const +{ + // This write has to work if a read happened but the m_edge_chain[] was never set. + if (m_edge_chain.UnsignedCount() > 0) + SetPersistentEdgeIdsFromRuntimeEdgePtrs(); + const unsigned count = m_persistent_edge_id.UnsignedCount(); + + if (false == archive.BeginWrite3dmAnonymousChunk(1)) + return false; + + bool rc = false; + for (;;) + { + if (false == archive.WriteUuid(m_persistent_subd_id)) + break; + if (false == archive.WriteInt(count)) + break; + if (count > 0) + { + if (false == archive.WriteArray(m_persistent_edge_id)) + break; + if (false == archive.WriteArray(m_persistent_edge_orientation)) + break; + } + + rc = true; + break; + } + + if (false == archive.EndWrite3dmChunk()) + rc = false; + + return rc; +} + +bool ON_SubDEdgeChain::Read(class ON_BinaryArchive& archive) +{ + *this = ON_SubDEdgeChain::Empty; + + int chunk_version = 0; + if (false == archive.BeginRead3dmAnonymousChunk(&chunk_version)) + return false; + + bool rc = false; + for (;;) + { + if (chunk_version < 1) + break; + if (false == archive.ReadUuid(m_persistent_subd_id)) + break; + unsigned int count = 0; + if (false == archive.ReadInt(&count)) + break; + if (count > 0) + { + if (false == archive.ReadArray(m_persistent_edge_id)) + break; + if (false == archive.ReadArray(m_persistent_edge_orientation)) + break; + } + + if (count != m_persistent_edge_id.UnsignedCount() || count != m_persistent_edge_orientation.UnsignedCount()) + { + m_persistent_edge_id.SetCount(0); + m_persistent_edge_orientation.SetCount(0); + } + + rc = true; + break; + } + + if (false == archive.EndRead3dmChunk()) + rc = false; + + // At some point, the caller will need to find the subd for this edge chain and call SetRuntimeEdgePtrsFromPersistentSubD(). + + return rc; +} + +void ON_SubDEdgeChain::Dump(class ON_TextLog& text_log) const +{ + const unsigned edge_count = EdgeCount(); + const ON__UINT64 subd_sn = m_subd_ref.SubD().EdgeCount() > 0 ? m_subd_ref.SubD().RuntimeSerialNumber() : 0; + const bool bSubDIdIsNotNil = ON_UuidIsNotNil(m_persistent_subd_id); + if (edge_count > 0 && (0 != subd_sn || bSubDIdIsNotNil)) + { + if (0 != subd_sn) + { + text_log.Print(L"SubD[%" PRIu64 "]", subd_sn); + if (bSubDIdIsNotNil) + { + text_log.Print(L" persistent subd id = "); + text_log.Print(m_persistent_subd_id); + } + } + else + { + text_log.Print(L"Persistent subd id = "); + text_log.Print(m_persistent_subd_id); + } + text_log.Print("%u edges.\n", edge_count); + + const bool bPrintEdgePtr = (subd_sn != 0 && edge_count == m_edge_chain.UnsignedCount()); + const bool bPrintPersistentEdgeId = + false == bPrintEdgePtr + && edge_count == m_persistent_edge_id.UnsignedCount() + && edge_count == m_persistent_edge_orientation.UnsignedCount(); + ON_TextLogIndent indent1(text_log); + if (bPrintEdgePtr || bPrintPersistentEdgeId) + { + const wchar_t plus_minus[3] = { '+', '-', '?' }; + for (unsigned i = 0; i < edge_count; ++i) + { + if (0 != i) + text_log.Print(L", "); + unsigned sign_dex = 2; + unsigned edge_id = 0; + if (bPrintEdgePtr) + { + const ON_SubDEdgePtr eptr = m_edge_chain[i]; + sign_dex = 0 != eptr.EdgeDirection() ? 1 : 0; + edge_id = eptr.EdgeId(); + } + else if (bPrintPersistentEdgeId) + { + sign_dex = 0 != m_persistent_edge_orientation[i] ? 1 : 0; + edge_id = m_persistent_edge_id[i]; + } + text_log.Print(L"%lce%u", plus_minus[sign_dex], edge_id); + if (i == 5 && edge_count > 15) + { + text_log.Print(L", ..."); + i = edge_count - 5; + } + } + } + else + { + text_log.Print("Corrupt edge list."); + } + } + else if( 0 == edge_count) + { + text_log.Print("Empty subd edge chain."); + } + else + { + text_log.Print("Corrupt subd edge chain."); + } + text_log.PrintNewLine(); + +} + void ON_SubDEdgeChain::ClearEdgeChain() { m_edge_chain.SetCount(0); @@ -15945,7 +16194,13 @@ void ON_SubDEdgeChain::ClearEdgeChain() unsigned int ON_SubDEdgeChain::EdgeCount() const { - return m_edge_chain.UnsignedCount(); + const unsigned edge_count = m_edge_chain.UnsignedCount(); + if (edge_count > 0) + return edge_count; + const unsigned id_count = (ON_UuidIsNotNil(this->m_persistent_subd_id)) ? m_persistent_edge_id.UnsignedCount() : 0; + if (id_count > 0 && id_count == m_persistent_edge_orientation.UnsignedCount()) + return id_count; + return 0; } void ON_SubDEdgeChain::SetStatusCheck( diff --git a/opennurbs_subd.h b/opennurbs_subd.h index ec78a4bd..197d13cc 100644 --- a/opennurbs_subd.h +++ b/opennurbs_subd.h @@ -1683,6 +1683,75 @@ public: class ON_NurbsSurface* m_nurbs_surface = nullptr; }; + +////////////////////////////////////////////////////////////////////////// +// +// ON_SubDFromMeshParameters +// +class ON_CLASS ON_SubDFromSurfaceParameters +{ +public: + + // Default construction is identical to ON_SubDFromMeshParameters::Smooth. + ON_SubDFromSurfaceParameters() = default; + ~ON_SubDFromSurfaceParameters() = default; + ON_SubDFromSurfaceParameters(const ON_SubDFromSurfaceParameters&) = default; + ON_SubDFromSurfaceParameters& operator=(const ON_SubDFromSurfaceParameters&) = default; + + static const ON_SubDFromSurfaceParameters Default; + static const ON_SubDFromSurfaceParameters DefaultWithCorners; + static const ON_SubDFromSurfaceParameters ControlNet; + static const ON_SubDFromSurfaceParameters ControlNetWithCorners; + +#pragma region RH_C_SHARED_ENUM [ON_SubDFromSurfaceParameters::Methods] [Rhino.Geometry.SubDFromSurfaceMethods] [byte] + /// + /// ON_SubDFromSurfaceParameters::Method are ways to create a SubD from a surface. + /// + enum class Methods : unsigned char + { + /// + /// Used to indicate the method is not set. + /// + Unset = 0, + + /// + /// The surface is approximated with a SubD friendly NURBS surface and the SubD is created + /// to match the subd friendly nurbs surface. + /// If the input surface is a subd friendly NURBS surface, the subd and surface have the same geometry. + /// + SubDFriendlyFit = 1, + + /// + /// The surface is converted to a NURBS surface and then a subd with one face per NURBS bispan + /// is created by using an appropriate subset of the NURBS surface control net. + /// If the input surface is a subd friendly NURBS surface, the subd and surface have the same geometry. + /// + FromNurbsControlNet = 2 + }; +#pragma endregion + + ON_SubDFromSurfaceParameters::Methods Method() const; + + void SetMethod( + ON_SubDFromSurfaceParameters::Methods method + ); + + bool Corners() const; + + void SetCorners( + bool bCorners + ); + +private: + ON_SubDFromSurfaceParameters::Methods m_method = ON_SubDFromSurfaceParameters::Methods::SubDFriendlyFit; + bool m_bCorners = false; + unsigned short m_reserved1 = 0; + unsigned int m_reserved2 = 0; + double m_reserved3 = 0.0; + double m_reserved4 = 0.0; +}; + + ////////////////////////////////////////////////////////////////////////// // // ON_SubD @@ -1723,6 +1792,13 @@ public: */ ON__UINT64 ContentSerialNumber() const; + /* + Returns: + A runtime serial number that is incremented every time a component status + (locked, hidden, selected, highlighted, ...) is changed. + */ + ON__UINT64 ComponentStatusSerialNumber() const; + /* Description: Change the content serial number. @@ -1952,8 +2028,9 @@ public: // ); #pragma region RH_C_SHARED_ENUM [ON_SubD::VertexFacetType] [Rhino.Geometry.SubDVertexFacetType] [byte] - - ///Summarizes the number of edges in faces in the whole object. + /// + /// Summarizes the number of edges in faces in the whole object. + /// enum class VertexFacetType : unsigned char { ///Not a valid vertex face type. @@ -2503,20 +2580,86 @@ public: level_zero_mesh - [in] from_mesh_parameters - [in] To get the smoothest possible result, pass nullptr - or ON_ToSubDParameters::Smooth. To get a sub-D with interior - creases use other static ON_ToSubDParameters values or + or ON_SubDFromMeshParameters::Smooth. To get a sub-D with interior + creases use other static ON_SubDFromMeshParameters values or create one with custom settings. */ static ON_SubD* CreateFromMesh( const class ON_Mesh* level_zero_mesh, - const class ON_ToSubDParameters* from_mesh_parameters, + const class ON_SubDFromMeshParameters* from_mesh_parameters, ON_SubD* subd ); +public: +#pragma region RH_C_SHARED_ENUM [ON_SubD::AutomaticMeshToSubDContext] [Rhino.Geometry.SubDAutomaticMeshToSubDContext] [byte] + /// + /// ON_SubD::AutomaticMeshToSubDContext indentifies a context where meshes can automatically + /// be converted to subds. + /// + enum class AutomaticMeshToSubDContext : unsigned char + { + /// + /// Indicates the context has not been initialized. + /// + Unset = 0, + + /// + /// A mesh in a Rhino 5 3dm file that is a representation of a box mode T-spline. + /// By default, these meshes are automatically converted to subds. + /// + Rhino5BoxModeTSpline = 1, + + /// + /// A mesh in an FBX file that has nonzero values for either preview division levels or render division levels. + /// Some FBX files created by Maya save subdivision objects as meshes with nonzero division level values. + /// By default, FBX division levels are ignored. + /// + FBXMeshWithDivisionLevels = 2 + }; +#pragma endregion + + /* + Returns: + true if SubDs are automatically created when an ON_Mesh is found in the specified context. + false otherwise. + */ + static bool AutomaticMeshToSubD( + ON_SubD::AutomaticMeshToSubDContext context + ); + + /* + Parameters: + context - [in] + Situation where an ON_Mesh can automatically be converted into a subd. + bAutomaticallyCreateSubD - [in] + true if SubDs are automatically created when an ON_Mesh is found in the specified context. + false otherwise. + */ + static void SetAutomaticMeshToSubD( + ON_SubD::AutomaticMeshToSubDContext context, + bool bAutomaticallyCreateSubD + ); + + /* + Parameters: + context - [in] + If context is ON_SubD::AutomaticMeshToSubDContext::Unset, all defaults will be restored. + Otherwise, the default for the specific context will be restored. + */ + static void AutomaticMeshToSubDRestoreDefaults( + ON_SubD::AutomaticMeshToSubDContext context + ); + +private: + static const bool AutomaticRhino5BoxModeTSplineToSubDDefault; // = true + static const bool AutomaticFBXMeshWithDivisionLevelsToSubDDefault; // = false + static bool AutomaticRhino5BoxModeTSplineToSubD; // current setting + static bool AutomaticFBXMeshWithDivisionLevelsToSubD; // current setting + private: static ON_SubD* Internal_CreateFromMeshWithValidNgons( const class ON_Mesh* level_zero_mesh_with_valid_ngons, - const class ON_ToSubDParameters* from_mesh_parameters, + const class ON_SubDFromMeshParameters* from_mesh_parameters, ON_SubD* subd ); @@ -3046,6 +3189,43 @@ public: bool bMarkDeletedFaceEdges ); +public: + /* + Description: + Removes all per face material channel index overrides on the active level. + Returns: + Number of changed faces. + Remarks: + Per face material channel indices are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetMaterialChannelIndex(). + */ + unsigned int ClearPerFaceMaterialChannelIndices(); + + /* + Returns: + True if one or more faces on the active level have per face material channel index overrides. + Remarks: + Per face material channel indices are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetMaterialChannelIndex(). + */ + bool HasPerFaceMaterialChannelIndices() const; + + /* + Description: + Removes all per face color overrides on the active level. + Returns: + Number of changed faces. + Remarks: + Per face colors are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetPerFaceColor(). + */ + unsigned int ClearPerFaceColors() const; + + /* + Returns: + True if one or more faces on the active level have per face color overrides. + Remarks: + Per face colors are a mutable property on ON_SubDFace and are set with ON_SubDFace.SetPerFaceColor(). + */ + bool HasPerFaceColors() const; + ///////////////////////////////////////////////////////// // @@ -9450,7 +9630,7 @@ private: public: /* Description: - Set this face's rendering material channel index. + Set the per face rendering material channel index. Parameters: material_channel_index - [in] @@ -9465,6 +9645,13 @@ public: */ void SetMaterialChannelIndex(int material_channel_index) const; + /* + Description: + Remove the per face rendering material channel index. + The face will use the material assigned to the subd object. + */ + void ClearMaterialChannelIndex() const; + /* Returns: This face's rendering material channel index. @@ -9477,6 +9664,41 @@ public: */ int MaterialChannelIndex() const; +private: + // The application specifies a base ON_Material used to render the subd this face belongs to. + // If m_material_channel_index > 0 AND face_material_id = base.MaterialChannelIdFromIndex(m_material_channel_index) + // is not nil, then face_material_id identifies an override rendering material for this face. + // Othewise base will be used to render this face. + mutable ON_Color m_per_face_color = ON_Color::UnsetColor; + +public: + + /* + Description: + Set per face color. + + Parameters: + color - [in] + */ + void SetPerFaceColor( + ON_Color color + ) const; + + /* + Description: + Remove per face color setting. The face will use the color assigned to the subd object. + */ + void ClearPerFaceColor() const; + + /* + Returns: + Per face color. A value of ON_Color::UnsetColor indicates the face uses the color assigned to the subd object. + */ + const ON_Color PerFaceColor() const; + + + + public: const bool TextureDomainIsSet() const; @@ -9534,8 +9756,7 @@ public: ) const; public: - unsigned int m_zero_face_id = 0; // id of level zero face - unsigned int m_parent_face_id = 0; // id of previous level face + unsigned int m_level_zero_face_id = 0; // id of level zero face public: // Array of m_edge_count edges that form the boundary of the face. @@ -11570,17 +11791,17 @@ private: ////////////////////////////////////////////////////////////////////////// // -// ON_ToSubDParameters +// ON_SubDFromMeshParameters // -class ON_CLASS ON_ToSubDParameters +class ON_CLASS ON_SubDFromMeshParameters { public: - // Default construction is identical to ON_ToSubDParameters::Smooth. - ON_ToSubDParameters() = default; - ~ON_ToSubDParameters() = default; - ON_ToSubDParameters(const ON_ToSubDParameters&) = default; - ON_ToSubDParameters& operator=(const ON_ToSubDParameters&) = default; + // Default construction is identical to ON_SubDFromMeshParameters::Smooth. + ON_SubDFromMeshParameters() = default; + ~ON_SubDFromMeshParameters() = default; + ON_SubDFromMeshParameters(const ON_SubDFromMeshParameters&) = default; + ON_SubDFromMeshParameters& operator=(const ON_SubDFromMeshParameters&) = default; /////////////////////////////////////////////////////////////////////////////////////// // @@ -11588,24 +11809,24 @@ public: // // No interior creases and no corners. - static const ON_ToSubDParameters Smooth; + static const ON_SubDFromMeshParameters Smooth; // Create an interior sub-D crease along coincident input mesh edges // where the vertex normal directions at one end differ by at // least 30 degrees. - static const ON_ToSubDParameters InteriorCreaseAtMeshCrease; + static const ON_SubDFromMeshParameters InteriorCreaseAtMeshCrease; // Create an interior sub-D crease along all coincident input mesh edges. - static const ON_ToSubDParameters InteriorCreaseAtMeshEdge; + static const ON_SubDFromMeshParameters InteriorCreaseAtMeshEdge; /////////////////////////////////////////////////////////////////////////////////////// // // Custom interior crease options // #pragma region RH_C_SHARED_ENUM [SubD::InteriorCreaseOption] [Rhino.Geometry.SubDCreationOptions.InteriorCreaseOption] [nested:byte] - /// - ///Defines how interior creases are treated. - /// + /// + /// Defines how interior creases are treated. + /// enum class InteriorCreaseOption : unsigned char { ///The interior creases option is not defined. @@ -11625,7 +11846,7 @@ public: }; #pragma endregion - static ON_ToSubDParameters::InteriorCreaseOption InteriorCreaseOptionFromUnsigned( + static ON_SubDFromMeshParameters::InteriorCreaseOption InteriorCreaseOptionFromUnsigned( unsigned int interior_crease_option_as_unsigned ); @@ -11634,20 +11855,20 @@ public: interior_crease_option - [in] */ void SetInteriorCreaseOption( - ON_ToSubDParameters::InteriorCreaseOption interior_crease_option + ON_SubDFromMeshParameters::InteriorCreaseOption interior_crease_option ); /* Returns: The interior crease option. */ - ON_ToSubDParameters::InteriorCreaseOption InteriorCreaseTest() const; + ON_SubDFromMeshParameters::InteriorCreaseOption InteriorCreaseTest() const; /* Description: When the interior crease option is - ON_ToSubDParameters::InteriorCreaseOption::AtMeshCreases, + ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshCreases, the value of MinimumCreaseAngleRadians() determines which coincident input mesh edges generate sub-D creases. @@ -11667,7 +11888,7 @@ public: /* Description: When the interior crease option is - ON_ToSubDParameters::InteriorCreaseOption::AtMeshCreases, + ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshCreases, the value of MinimumCreaseAngleRadians() determines which coincident input mesh edges generate sub-D creases. @@ -11688,8 +11909,8 @@ public: Returns: The currently selected interior crease option. */ - ON_ToSubDParameters::InteriorCreaseOption CopyInteriorCreaseTest( - ON_ToSubDParameters source_options + ON_SubDFromMeshParameters::InteriorCreaseOption CopyInteriorCreaseTest( + ON_SubDFromMeshParameters source_options ); @@ -11700,16 +11921,16 @@ public: // Look for convex corners at sub-D vertices with 2 edges // that have an included angle <= 90 degrees. - static const ON_ToSubDParameters ConvexCornerAtMeshCorner; + static const ON_SubDFromMeshParameters ConvexCornerAtMeshCorner; /////////////////////////////////////////////////////////////////////////////////////// // // Custom convex corner options // #pragma region RH_C_SHARED_ENUM [SubD::ConvexCornerOption] [Rhino.Geometry.SubDCreationOptions.ConvexCornerOption] [nested:byte] - /// - ///Defines how convex corners are treated. - /// + /// + /// Defines how convex corners are treated. + /// enum class ConvexCornerOption : unsigned char { ///The option is not set. @@ -11726,7 +11947,7 @@ public: }; #pragma endregion - static ON_ToSubDParameters::ConvexCornerOption ConvexCornerOptionFromUnsigned( + static ON_SubDFromMeshParameters::ConvexCornerOption ConvexCornerOptionFromUnsigned( unsigned int convex_corner_option_as_unsigned ); @@ -11735,14 +11956,14 @@ public: convex_corner_option - [in] */ void SetConvexCornerOption( - ON_ToSubDParameters::ConvexCornerOption convex_corner_option + ON_SubDFromMeshParameters::ConvexCornerOption convex_corner_option ); /* Returns: The currently selected convex corner option. */ - ON_ToSubDParameters::ConvexCornerOption ConvexCornerTest() const; + ON_SubDFromMeshParameters::ConvexCornerOption ConvexCornerTest() const; /* Description: @@ -11801,8 +12022,8 @@ public: Returns: The currently selected convex corner option. */ - ON_ToSubDParameters::ConvexCornerOption CopyConvexCornerTest( - ON_ToSubDParameters source_parameters + ON_SubDFromMeshParameters::ConvexCornerOption CopyConvexCornerTest( + ON_SubDFromMeshParameters source_parameters ); /* @@ -11884,8 +12105,8 @@ private: bool m_bInterpolateMeshVertices = false; - ON_ToSubDParameters::InteriorCreaseOption m_interior_crease_option = ON_ToSubDParameters::InteriorCreaseOption::None; - ON_ToSubDParameters::ConvexCornerOption m_convex_corner_option = ON_ToSubDParameters::ConvexCornerOption::None; + ON_SubDFromMeshParameters::InteriorCreaseOption m_interior_crease_option = ON_SubDFromMeshParameters::InteriorCreaseOption::None; + ON_SubDFromMeshParameters::ConvexCornerOption m_convex_corner_option = ON_SubDFromMeshParameters::ConvexCornerOption::None; unsigned short m_maximum_convex_corner_edge_count = 2U; @@ -13056,33 +13277,105 @@ public: ) const; + /* + Parameters: + persistent_subd_id - [in] + If this edge chain needs to persist in a 3dm archive, then persistent_subd_id + should identify the subd in its current context. + If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + If the edge chain is being used in a runtime context and will not be saved in a 3dm archive + or otherwise serialized, then persistent_subd_id can be ON_nil_uuid. + + */ unsigned int BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SubDEdge* initial_edge ); + /* + Parameters: + persistent_subd_id - [in] + If this edge chain needs to persist in a 3dm archive, then persistent_subd_id + should identify the subd in its current context. + If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + If the edge chain is being used in a runtime context and will not be saved in a 3dm archive + or otherwise serialized, then persistent_subd_id can be ON_nil_uuid. + + */ unsigned int BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SimpleArray& initial_edge_chain ); + /* + Parameters: + persistent_subd_id - [in] + If this edge chain needs to persist in a 3dm archive, then persistent_subd_id + should identify the subd in its current context. + If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + If the edge chain is being used in a runtime context and will not be saved in a 3dm archive + or otherwise serialized, then persistent_subd_id can be ON_nil_uuid. + + */ unsigned int BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SubDEdge*const* initial_edge_chain, size_t edge_count ); + /* + Parameters: + persistent_subd_id - [in] + If this edge chain needs to persist in a 3dm archive, then persistent_subd_id + should identify the subd in its current context. + If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + If the edge chain is being used in a runtime context and will not be saved in a 3dm archive + or otherwise serialized, then persistent_subd_id can be ON_nil_uuid. + + */ unsigned int BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, ON_SubDEdgePtr initial_edge ); + /* + Parameters: + persistent_subd_id - [in] + If this edge chain needs to persist in a 3dm archive, then persistent_subd_id + should identify the subd in its current context. + If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + If the edge chain is being used in a runtime context and will not be saved in a 3dm archive + or otherwise serialized, then persistent_subd_id can be ON_nil_uuid. + + */ unsigned int BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SimpleArray& initial_edge_chain ); + /* + Parameters: + persistent_subd_id - [in] + If this edge chain needs to persist in a 3dm archive, then persistent_subd_id + should identify the subd in its current context. + If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + If the edge chain is being used in a runtime context and will not be saved in a 3dm archive + or otherwise serialized, then persistent_subd_id can be ON_nil_uuid. + + */ unsigned int BeginEdgeChain( + ON_UUID persistent_subd_id, ON_SubDRef subd_ref, const ON_SubDEdgePtr* initial_edge_chain, size_t edge_count @@ -13141,9 +13434,66 @@ public: void ClearEdgeChain(); + /* + Returns: + The persistent id of the parent subd object. + If the context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If the context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + */ + const ON_UUID PersistentSubDId() const; + + bool HasPersistentEdgeIds() const; + + bool HasRuntimeEdgePtrs() const; + + bool SetPersistentEdgeIdsFromRuntimeEdgePtrs() const; + + /* + Description: + In situations where this edge chain is being read from a 3dm archive, + or a similar serialization context, this function uses the saved edge + id information to initialize the runtime ON_SubDEdgePtr information. + Parameters: + persistent_subd_id - [in] + This id is passed to insure it matches the saved persistent_subd_id. + The source of the id depends on the context of the model managing the subd. + If that context is an ONX_Model, then the persistent id is the ON_ModelGeometryComponent.Id(). + If that context is a CRhinoDoc, then the persistent id is CRhinoObject.ModelObjectId(). + Returns: + True if successful. + False if not successful. + */ + bool SetRuntimeEdgePtrsFromPersistentSubD( + ON_UUID persistent_subd_id, + ON_SubDRef persistent_subd_ref + ); + + bool Write(class ON_BinaryArchive& archive) const; + bool Read(class ON_BinaryArchive& archive); + void Dump(class ON_TextLog& text_log) const; + private: ON_SubDRef m_subd_ref; ON_SimpleArray m_edge_chain; + + + // If m_persistent_subd_id, then the id identifies the parent subd in the model. + // In an ONX_Model, this is the ON_ModelGeometryComponent.Id() value + // of the corresponding ON_SubD in the ONX_Model. + // In Rhino, this is the CRhinoObject.ModelObjectId() value + // of the corresponding CRhinoSubDObject in the CRhinoDoc. + ON_UUID m_persistent_subd_id = ON_nil_uuid; + + // If m_persistent_subd_id is set and m_persistent_edge_id[] is not empty, + // m_persistent_edge_id[] is a list of edge ids and orientations. + // unsigned id = m_persistent_edge_id[] & 0xFFFFFFFF. + // reversed orientation = (0 != (m_persistent_edge_id[] & 0x8000000000000000)). + // The persistent id information is saved in 3dm archives. When that archive is read, + // the SetRuntimeEdgePtrsFromPersistentSubD() can be used to set the runtime edge chain values. + // These mutable fields are set by Write and used by Read. + mutable ON_SimpleArray m_persistent_edge_id; + mutable ON_SimpleArray m_persistent_edge_orientation; // 0 = not reversed, 1 = reversed. + ON_UniqueTester m_unique_tester; ON_ComponentStatus m_status_check_pass = ON_ComponentStatus::NoneSet; ON_ComponentStatus m_status_check_fail = ON_ComponentStatus::Selected; @@ -13370,7 +13720,7 @@ private: #if defined(ON_COMPILING_OPENNURBS) /* The ON_SubDAsUserData class is used to attach a subd to it proxy mesh -when writing V6 files in commerical rhino. +when writing V6 files in commercial rhino. */ class ON_SubDMeshProxyUserData : public ON_UserData { diff --git a/opennurbs_subd_archive.cpp b/opennurbs_subd_archive.cpp index 5cb26581..fc29dade 100644 --- a/opennurbs_subd_archive.cpp +++ b/opennurbs_subd_archive.cpp @@ -942,10 +942,14 @@ bool ON_SubDFace::Write( { if (!WriteBase(this,archive)) break; - if (!archive.WriteInt(m_zero_face_id)) + if (!archive.WriteInt(m_level_zero_face_id)) break; - if (!archive.WriteInt(m_parent_face_id)) + + // OBSOLETE parent face id + const int obsolete_parent_face_id = 0; + if (!archive.WriteInt(obsolete_parent_face_id)) break; + if (!archive.WriteShort(m_edge_count)) break; if (!WriteEdgePtrList(m_edge_count,sizeof(m_edge4)/sizeof(m_edge4[0]),m_edge4,m_edgex_capacity,m_edgex, archive)) @@ -981,30 +985,26 @@ bool ON_SubDFace::Write( break; } - //////if ( ON::Version() >= ON_VersionNumberConstruct(7, 0, 2020, 2, 18, 0) ) + // 4 byte render material channel index + const int material_channel_index = MaterialChannelIndex(); + const bool bWriteMaterialChannelIndex = (material_channel_index > 0 && material_channel_index <= ON_Material::MaximumMaterialChannelIndex); + if (false == Internal_WriteComponentAdditionSize(bWriteMaterialChannelIndex, archive, 4)) + break; + if (bWriteMaterialChannelIndex) { - ////// https://mcneel.myjetbrains.com/youtrack/issue/RH-56820 - ////// Today is Feb 3, 2020. - ////// We need to give Rhino 7 WIP users until Feb 18, 2020 to get automatically - ////// updated before we can save the material index in 3dm archives. - ////// This is because there was a bug in Internal_FinishReadingComponentAdditions() - ////// that failed to keep the chunk CRCs up to date when older versions of Rhino - ////// skipped over newer information. - ////// This CRC bug was fixed Feb 3, 2020 and made available to customers Feb 4, 2020. - ////// On or after Feb 18, 2020, this comment and the if ( ON::Version() >= ON_VersionNumberConstruct(7, 0, 2020, 2, 18, 0) ).... - ////// check can be removed. - // - // Done Feb 20, 2020. The comment can be deleted in March 2020 or later because by then this code will have been well tested. - - const int material_channel_index = MaterialChannelIndex(); - const bool bWriteMaterialChannelIndex = (material_channel_index > 0 && material_channel_index <= ON_Material::MaximumMaterialChannelIndex); - if (false == Internal_WriteComponentAdditionSize(bWriteMaterialChannelIndex, archive, 4)) + if (!archive.WriteInt(material_channel_index)) + break; + } + + // 4 byte per face color + const ON_Color per_face_color = PerFaceColor(); + const bool bWritePerFaceColor = (ON_Color::UnsetColor != per_face_color); + if (false == Internal_WriteComponentAdditionSize(bWritePerFaceColor, archive, 4)) + break; + if (bWritePerFaceColor) + { + if (!archive.WriteColor(per_face_color)) break; - if (bWriteMaterialChannelIndex) - { - if (!archive.WriteInt(material_channel_index)) - break; - } } return Internal_FinishWritingComponentAdditions(archive); @@ -1027,15 +1027,15 @@ bool ON_SubDFace::Read( break; ON_SubDComponentBase base = ON_SubDComponentBase::Unset; - unsigned int zero_face_id = 0; - unsigned int parent_face_id = 0; + unsigned int level_zero_face_id = 0; + unsigned int obsolete_parent_face_id = 0; unsigned short edge_count = 0; if (!ReadBase(archive,base)) break; - if (!archive.ReadInt(&zero_face_id)) + if (!archive.ReadInt(&level_zero_face_id)) break; - if (!archive.ReadInt(&parent_face_id)) + if (!archive.ReadInt(&obsolete_parent_face_id)) break; if (!archive.ReadShort(&edge_count)) break; @@ -1051,8 +1051,7 @@ bool ON_SubDFace::Read( f->ON_SubDComponentBase::operator=(base); - f->m_zero_face_id = zero_face_id; - f->m_parent_face_id = parent_face_id; + f->m_level_zero_face_id = level_zero_face_id; if (!ReadEdgePtrList(archive,edge_count,sizeof(f->m_edge4)/sizeof(f->m_edge4[0]),f->m_edge4,f->m_edgex_capacity,f->m_edgex)) break; @@ -1109,6 +1108,20 @@ bool ON_SubDFace::Read( f->SetMaterialChannelIndex(material_channel_index); } + sz = 0; + if (false == Internal_ReadComponentAdditionSize(archive, 4, &sz)) + break; + if (ON_SubDComponentArchiveAdditionEndMark == sz) + return true; // end of additions + if (0 != sz) + { + // 4 bytes of per face color + ON_Color per_face_color = ON_Color::UnsetColor; + if (false == archive.ReadColor(per_face_color)) + break; + f->SetPerFaceColor(per_face_color); + } + return Internal_FinishReadingComponentAdditions(archive); } return ON_SUBD_RETURN_ERROR(false); diff --git a/opennurbs_subd_copy.cpp b/opennurbs_subd_copy.cpp index 60b4770e..41e43b27 100644 --- a/opennurbs_subd_copy.cpp +++ b/opennurbs_subd_copy.cpp @@ -645,6 +645,16 @@ ON__UINT64 ON_SubDimple::ContentSerialNumber() const return m_subd_content_serial_number; } +ON__UINT64 ON_SubDimple::ComponentStatusSerialNumber() const +{ + return ActiveLevel().ComponentStatusSerialNumber(); +} + +const ON_AggregateComponentStatusEx ON_SubDimple::AggregateComponentStatus() const +{ + return ActiveLevel().AggregateComponentStatus(); +} + ON__UINT64 ON_SubDimple::ChangeContentSerialNumber( bool bChangePreservesSymmetry ) const diff --git a/opennurbs_subd_data.cpp b/opennurbs_subd_data.cpp index a50d3f23..1febaec1 100644 --- a/opennurbs_subd_data.cpp +++ b/opennurbs_subd_data.cpp @@ -191,8 +191,7 @@ unsigned int ON_SubDimple::ClearLowerSubdivisionLevels( for (ON_SubDFace* face = level->m_face[0]; nullptr != face; face = const_cast(face->m_next_face)) { face->SetSubdivisionLevel(new_level_index); - face->m_parent_face_id = 0; - face->m_zero_face_id = face->m_id; + face->m_level_zero_face_id = face->m_id; } m_levels[new_level_index] = level; @@ -445,13 +444,18 @@ bool ON_SubDAggregates::GetTopologicalAttributes(const ON_SubDLevel * level, boo return GetTopologicalAttributes(bIsManifold, bIsOriented, bHasBoundary, solid_orientation); } -ON_AggregateComponentStatus ON_SubDLevel::AggregateComponentStatus() const +const ON_AggregateComponentStatusEx ON_SubDLevel::AggregateComponentStatus() const { if (false == m_aggregates.m_aggregate_status.IsCurrent()) m_aggregates.UpdateAggregateComponentStatus(this); return m_aggregates.m_aggregate_status; } +ON__UINT64 ON_SubDLevel::ComponentStatusSerialNumber() const +{ + return m_aggregates.m_aggregate_status.ComponentStatusSerialNumber(); +} + void ON_SubDAggregates::UpdateAggregateEdgeAttributes( const ON_SubDLevel* level ) diff --git a/opennurbs_subd_data.h b/opennurbs_subd_data.h index 82f7acd7..783001b4 100644 --- a/opennurbs_subd_data.h +++ b/opennurbs_subd_data.h @@ -553,7 +553,7 @@ public: bool m_bDirtyEdgeAttributes = false; bool m_bDirtyBoundingBox = false; - ON_AggregateComponentStatus m_aggregate_status = ON_AggregateComponentStatus::Empty; + ON_AggregateComponentStatusEx m_aggregate_status = ON_AggregateComponentStatusEx::Empty; unsigned int m_aggregate_edge_attributes = 0; private: @@ -1147,7 +1147,9 @@ public: ON_ComponentStatus status_to_copy ) const; - ON_AggregateComponentStatus AggregateComponentStatus() const; + const ON_AggregateComponentStatusEx AggregateComponentStatus() const; + + ON__UINT64 ComponentStatusSerialNumber() const; void MarkAggregateComponentStatusAsNotCurrent() const { @@ -1647,6 +1649,15 @@ public: */ ON__UINT64 ContentSerialNumber() const; + /* + Returns: + A runtime serial number that is incremented every time a component status + (locked, hidden, selected, highlighted, ...) is changed. + */ + ON__UINT64 ComponentStatusSerialNumber() const; + + const ON_AggregateComponentStatusEx AggregateComponentStatus() const; + /* Description: Change the content serial number. diff --git a/opennurbs_subd_frommesh.cpp b/opennurbs_subd_frommesh.cpp index b0c21e62..3a8371ae 100644 --- a/opennurbs_subd_frommesh.cpp +++ b/opennurbs_subd_frommesh.cpp @@ -300,7 +300,7 @@ private: ON_SubD* ON_SubD::CreateFromMesh( const class ON_Mesh* level_zero_mesh, - const class ON_ToSubDParameters* from_mesh_options, + const class ON_SubDFromMeshParameters* from_mesh_options, ON_SubD* subd ) { @@ -349,7 +349,7 @@ ON_SubD* ON_SubD::CreateFromMesh( ON_SubD* ON_SubD::Internal_CreateFromMeshWithValidNgons( const class ON_Mesh* level_zero_mesh, - const class ON_ToSubDParameters* from_mesh_options, + const class ON_SubDFromMeshParameters* from_mesh_options, ON_SubD* subd ) { @@ -366,7 +366,7 @@ ON_SubD* ON_SubD::Internal_CreateFromMeshWithValidNgons( ON_Workspace ws; if (nullptr == from_mesh_options) - from_mesh_options = &ON_ToSubDParameters::Smooth; + from_mesh_options = &ON_SubDFromMeshParameters::Smooth; ON_3dPointListRef mesh_points(level_zero_mesh); const unsigned int mesh_point_count = mesh_points.PointCount(); @@ -416,12 +416,12 @@ ON_SubD* ON_SubD::Internal_CreateFromMeshWithValidNgons( double max_cos_crease_angle = ON_UNSET_VALUE; double min_crease_angle_radians = -ON_UNSET_VALUE; - ON_ToSubDParameters::InteriorCreaseOption crease_test + ON_SubDFromMeshParameters::InteriorCreaseOption crease_test = (nullptr != from_mesh_options) ? from_mesh_options->InteriorCreaseTest() - : ON_ToSubDParameters::InteriorCreaseOption::None; + : ON_SubDFromMeshParameters::InteriorCreaseOption::None; - if (ON_ToSubDParameters::InteriorCreaseOption::AtMeshCrease == crease_test && nullptr != pointNormal ) + if (ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshCrease == crease_test && nullptr != pointNormal ) { double min_angle = from_mesh_options->MinimumCreaseAngleRadians(); if (min_angle >= 0.0 && min_angle < ON_PI) @@ -438,12 +438,12 @@ ON_SubD* ON_SubD::Internal_CreateFromMeshWithValidNgons( } else { - crease_test = ON_ToSubDParameters::InteriorCreaseOption::None; + crease_test = ON_SubDFromMeshParameters::InteriorCreaseOption::None; } } - else if (ON_ToSubDParameters::InteriorCreaseOption::AtMeshEdge != crease_test) + else if (ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshEdge != crease_test) { - crease_test = ON_ToSubDParameters::InteriorCreaseOption::None; + crease_test = ON_SubDFromMeshParameters::InteriorCreaseOption::None; } // Get sub-D edge list @@ -604,7 +604,7 @@ ON_SubD* ON_SubD::Internal_CreateFromMeshWithValidNgons( unsigned int* Nid = nullptr; unsigned int nextNid = 0; - if (ON_ToSubDParameters::InteriorCreaseOption::AtMeshCrease == crease_test) + if (ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshCrease == crease_test) { Nid = (unsigned int*)ws.GetIntMemory(mesh_point_count); memset(Nid, 0, mesh_point_count*sizeof(Nid[0])); @@ -705,7 +705,7 @@ ON_SubD* ON_SubD::Internal_CreateFromMeshWithValidNgons( { // set the normal ids from the ON_Mesh m_V[] indices struct ON_MeshNGonEdge& mesh_edge_ref = mesh_edges[i]; - if (ON_ToSubDParameters::InteriorCreaseOption::AtMeshEdge == crease_test) + if (ON_SubDFromMeshParameters::InteriorCreaseOption::AtMeshEdge == crease_test) { // All coincident mesh vertices generate interior creases mesh_edge_ref.Ni = mesh_edge_ref.i; @@ -966,7 +966,7 @@ ON_SubD* ON_SubD::Internal_CreateFromMeshWithValidNgons( if ( false == new_subd->IsOriented() ) new_subd->Orient(); - if (ON_ToSubDParameters::ConvexCornerOption::AtMeshCorner == from_mesh_options->ConvexCornerTest()) + if (ON_SubDFromMeshParameters::ConvexCornerOption::AtMeshCorner == from_mesh_options->ConvexCornerTest()) { // Add corners ON_SubDVertexIterator vit(*new_subd); diff --git a/opennurbs_subd_heap.cpp b/opennurbs_subd_heap.cpp index d0f5a24a..30a153ce 100644 --- a/opennurbs_subd_heap.cpp +++ b/opennurbs_subd_heap.cpp @@ -725,7 +725,7 @@ const ON_SubDEdgePtr ON_SubD_FixedSizeHeap::AllocateEdge( } ON_SubDFace* ON_SubD_FixedSizeHeap::Internal_AllocateFace( - unsigned int zero_face_id, + unsigned int level_zero_face_id, unsigned int parent_face_id ) { @@ -742,8 +742,8 @@ ON_SubDFace* ON_SubD_FixedSizeHeap::Internal_AllocateFace( } f->m_id = ++m_f_index; - f->m_zero_face_id = (0 == zero_face_id) ? parent_face_id : zero_face_id; - f->m_parent_face_id = parent_face_id; + f->ClearPerFaceColor(); + f->m_level_zero_face_id = (0 == level_zero_face_id) ? parent_face_id : level_zero_face_id; return f; } @@ -1072,14 +1072,16 @@ class ON_SubDFace* ON_SubDHeap::AllocateFaceAndSetId( ) { ON_SubDComponentBase* unused_list = m_unused_face; - ON_SubDComponentBase* c = ON_SubDHeap::Internal_AllocateComponentAndSetId( + ON_SubDFace* f = static_cast( ON_SubDHeap::Internal_AllocateComponentAndSetId( m_fspf, unused_list, m_max_face_id, candidate_face_id - ); + ) ); m_unused_face = static_cast(unused_list); - return static_cast(c); + if (nullptr != f) + f->ClearPerFaceColor(); + return f; } void ON_SubDHeap::ReturnFace(class ON_SubDFace* f) diff --git a/opennurbs_subd_limit.cpp b/opennurbs_subd_limit.cpp index 0cc85b23..b2907b15 100644 --- a/opennurbs_subd_limit.cpp +++ b/opennurbs_subd_limit.cpp @@ -1811,7 +1811,7 @@ static ON_SubDFace* ON_SubDQuadFaceTopology_SubdivideFace( ON_SubDEdgePtr f1_epts[4] = { e1[0], e12, e23, e1[1].Reversed() }; - ON_SubDFace* f1 = fsh.AllocateQuad(f0->m_zero_face_id, f0->m_id, f1_epts); + ON_SubDFace* f1 = fsh.AllocateQuad(f0->m_level_zero_face_id, f0->m_id, f1_epts); if ( nullptr == f1) return ON_SUBD_RETURN_ERROR(nullptr); @@ -1851,7 +1851,7 @@ bool ON_SubDQuadNeighborhood::Subdivide( if ( nullptr == qf0 || 4 != qf0->m_edge_count) return ON_SUBD_RETURN_ERROR(false); - const unsigned int zero_face_id = qf0->m_zero_face_id; + const unsigned int zero_face_id = qf0->m_level_zero_face_id; const unsigned int parent_face_id = qf0->m_id; const ON_SubDEdge* qf0_edges[4] = { @@ -2651,8 +2651,8 @@ bool ON_SubDFaceNeighborhood::QuadSubdivideHelper( const unsigned int N = face->m_edge_count; - const unsigned int zero_face_id = face->m_zero_face_id; - const unsigned int parent_face_id = face->m_parent_face_id; + const unsigned int level_zero_face_id = face->m_level_zero_face_id; + const unsigned int parent_face_idX = face->m_id; ON_SubDSectorSurfacePoint limit_point; @@ -2803,7 +2803,7 @@ bool ON_SubDFaceNeighborhood::QuadSubdivideHelper( return ON_SUBD_RETURN_ERROR(false); face1_eptrs[2] = edge1; - face1 = m_fsh.AllocateQuad(zero_face_id, parent_face_id, face1_eptrs); + face1 = m_fsh.AllocateQuad(level_zero_face_id, parent_face_idX, face1_eptrs); if ( nullptr == face1) return ON_SUBD_RETURN_ERROR(false); } @@ -3014,7 +3014,7 @@ bool ON_SubDFaceNeighborhood::QuadSubdivideHelper( face1_eptrs[1] = ON_SubDEdgePtr::Create(edge1_quartet[0],0); face1_eptrs[2] = ON_SubDEdgePtr::Create(edge1_quartet[3],1); face1_eptrs[3] = ON_SubDEdgePtr::Create(edge1_quartet[2],1); - face1 = m_fsh.AllocateQuad(zero_face_id, parent_face_id, face1_eptrs); + face1 = m_fsh.AllocateQuad(level_zero_face_id, parent_face_idX, face1_eptrs); if ( nullptr == face1) return ON_SUBD_RETURN_ERROR(false); continue; @@ -3087,7 +3087,7 @@ bool ON_SubDFaceNeighborhood::QuadSubdivideHelper( face1_eptrs[2] = ON_SubDEdgePtr::Create(edge1_quartet[3],1); face1_eptrs[3] = ON_SubDEdgePtr::Create(edge1_quartet[2],1); - face1 = m_fsh.AllocateQuad(zero_face_id, parent_face_id, face1_eptrs); + face1 = m_fsh.AllocateQuad(level_zero_face_id, parent_face_idX, face1_eptrs); if ( nullptr == face1 ) return ON_SUBD_RETURN_ERROR(false); @@ -3133,7 +3133,7 @@ bool ON_SubDFaceNeighborhood::QuadSubdivideHelper( return ON_SUBD_RETURN_ERROR(false); face1_eptrs[2] = edge1; - face1 = m_fsh.AllocateQuad(zero_face_id, parent_face_id, face1_eptrs); + face1 = m_fsh.AllocateQuad(level_zero_face_id, parent_face_idX, face1_eptrs); if ( nullptr == face1 ) return ON_SUBD_RETURN_ERROR(false); @@ -3370,7 +3370,7 @@ bool ON_SubDFaceNeighborhood::QuadSubdivideHelper( face1_eptrs[j] = edge1; } - face1 = m_fsh.AllocateQuad(zero_face_id, parent_face_id, face1_eptrs); + face1 = m_fsh.AllocateQuad(level_zero_face_id, parent_face_idX, face1_eptrs); if ( nullptr == face1 ) return ON_SUBD_RETURN_ERROR(false); } diff --git a/opennurbs_subd_mesh.cpp b/opennurbs_subd_mesh.cpp index eba44f74..0f2b2adf 100644 --- a/opennurbs_subd_mesh.cpp +++ b/opennurbs_subd_mesh.cpp @@ -501,8 +501,8 @@ bool ON_SubDFaceRegion::IsValid( const unsigned short face_region_subdivision_count = m_face_region.SubdivisionCount(); - bool bPeristentVertex[4] = { bIsQuad, bIsQuad, true, bIsQuad }; - bool bPeristentEdge[4] = { bIsQuad, true, true, bIsQuad }; + bool bPersistentVertex[4] = { bIsQuad, bIsQuad, true, bIsQuad }; + bool bPersistentEdge[4] = { bIsQuad, true, true, bIsQuad }; for (unsigned short i = bIsQuad?0:1; i < face_region_subdivision_count && i < ON_SubDComponentRegionIndex::IndexCapacity; i++) { const unsigned short r = m_face_region.m_region_index.m_index[i]; @@ -512,12 +512,12 @@ bool ON_SubDFaceRegion::IsValid( ON_SUBD_ERROR("Unexpected value in face_region.m_region_index[]."); return false; } - bPeristentVertex[(r+1)%4] = false; - bPeristentVertex[(r+2)%4] = false; - bPeristentVertex[(r+3)%4] = false; - bPeristentEdge[(r+1)%4] = false; - bPeristentEdge[(r+2)%4] = false; - if (false == bPeristentVertex[r] && false == bPeristentEdge[r] && false == bPeristentEdge[(r + 3) % 4] ) + bPersistentVertex[(r+1)%4] = false; + bPersistentVertex[(r+2)%4] = false; + bPersistentVertex[(r+3)%4] = false; + bPersistentEdge[(r+1)%4] = false; + bPersistentEdge[(r+2)%4] = false; + if (false == bPersistentVertex[r] && false == bPersistentEdge[r] && false == bPersistentEdge[(r + 3) % 4] ) break; } @@ -529,7 +529,7 @@ bool ON_SubDFaceRegion::IsValid( const bool bEmptyEdge = m_edge_region[ei].IsEmptyRegion(); if (bEmptyEdge) { - if ( bPeristentEdge[ei]) + if ( bPersistentEdge[ei]) { if (false == bSilentError) ON_SUBD_ERROR("Unexpected empty edge in m_edge_region[]."); @@ -552,7 +552,7 @@ bool ON_SubDFaceRegion::IsValid( return false; } - if (bPeristentEdge[ei]) + if (bPersistentEdge[ei]) { if (false == m_edge_region[ei].IsPersistentId()) { @@ -601,7 +601,7 @@ bool ON_SubDFaceRegion::IsValid( for (unsigned int vi = 0; vi < 4; vi++) { - if (bPeristentVertex[vi]) + if (bPersistentVertex[vi]) { if (false == ON_SubDComponentRegion::IsPersistentId(m_vertex_id[vi])) { diff --git a/opennurbs_subd_ring.cpp b/opennurbs_subd_ring.cpp index 6b1af75a..92093250 100644 --- a/opennurbs_subd_ring.cpp +++ b/opennurbs_subd_ring.cpp @@ -621,7 +621,7 @@ const ON_SubDVertex* ON_SubD::SubdivideSector( e1[2] = fsh.AllocateEdge(v1[2], ON_SubDSectorType::IgnoredSectorCoefficient, v1[3], at_crease_weight); f1epts[1] = e1[1]; f1epts[2] = e1[2]; - if (nullptr == fsh.AllocateQuad(face0->m_zero_face_id, face0->m_id, f1epts) ) + if (nullptr == fsh.AllocateQuad(face0->m_level_zero_face_id, face0->m_id, f1epts) ) return ON_SUBD_RETURN_ERROR(nullptr); if (i + 1 == N) diff --git a/opennurbs_subd_texture.cpp b/opennurbs_subd_texture.cpp index dcbb111e..9c936fc6 100644 --- a/opennurbs_subd_texture.cpp +++ b/opennurbs_subd_texture.cpp @@ -619,22 +619,104 @@ void ON_SubDFace::SetTextureDomain( void ON_SubDFace::SetMaterialChannelIndex(int material_channel_index) const { - if ( material_channel_index >= 0 && material_channel_index <= ON_Material::MaximumMaterialChannelIndex ) + if ( material_channel_index > 0 && material_channel_index <= ON_Material::MaximumMaterialChannelIndex ) { m_material_channel_index = (unsigned short)material_channel_index; } else { - ON_ERROR("Invalid material_channel_index value."); - m_material_channel_index = 0; + if (0 != material_channel_index) + { + ON_ERROR("Invalid material_channel_index value."); + } + ClearMaterialChannelIndex(); // makes it easier to detect when per face setting is cleared. } } +void ON_SubDFace::ClearMaterialChannelIndex() const +{ + m_material_channel_index = 0; +} + int ON_SubDFace::MaterialChannelIndex() const { return (int)m_material_channel_index; } +void ON_SubDFace::SetPerFaceColor( + ON_Color color + ) const +{ + if (ON_Color::UnsetColor == color) + ClearPerFaceColor(); // makes it easier to detect when the per face setting is cleared. + else + m_per_face_color = color; +} + +void ON_SubDFace::ClearPerFaceColor() const +{ + m_per_face_color = ON_Color::UnsetColor; +} + + +const ON_Color ON_SubDFace::PerFaceColor() const +{ + return m_per_face_color; +} + + +unsigned int ON_SubD::ClearPerFaceMaterialChannelIndices() +{ + unsigned change_count = 0; + ON_SubDFaceIterator fit(*this); + for (const ON_SubDFace* f = fit.FirstFace(); nullptr != f; f = fit.NextFace()) + { + if (0 != f->MaterialChannelIndex()) + { + f->ClearMaterialChannelIndex(); + ++change_count; + } + } + return change_count; +} + +bool ON_SubD::HasPerFaceMaterialChannelIndices() const +{ + ON_SubDFaceIterator fit(*this); + for (const ON_SubDFace* f = fit.FirstFace(); nullptr != f; f = fit.NextFace()) + { + if (0 != f->MaterialChannelIndex()) + return true; + } + return false; +} + +unsigned int ON_SubD::ClearPerFaceColors() const +{ + unsigned change_count = 0; + ON_SubDFaceIterator fit(*this); + for (const ON_SubDFace* f = fit.FirstFace(); nullptr != f; f = fit.NextFace()) + { + if (ON_Color::UnsetColor != f->PerFaceColor()) + { + f->ClearPerFaceColor(); + ++change_count; + } + } + return change_count; +} + +bool ON_SubD::HasPerFaceColors() const +{ + ON_SubDFaceIterator fit(*this); + for (const ON_SubDFace* f = fit.FirstFace(); nullptr != f; f = fit.NextFace()) + { + if (ON_Color::UnsetColor != f->PerFaceColor()) + return true; + } + return false; +} + const bool ON_SubDFace::TextureDomainIsSet() const { return (ON_SubDTextureDomainType::Unset != TextureDomainType()); diff --git a/opennurbs_textlog.cpp b/opennurbs_textlog.cpp index d2d33cf3..3b2e31c1 100644 --- a/opennurbs_textlog.cpp +++ b/opennurbs_textlog.cpp @@ -47,6 +47,27 @@ ON_TextLogIndent::~ON_TextLogIndent() m_text_log.PopIndent(); } +ON_TextLogLevelOfDetail::ON_TextLogLevelOfDetail( + class ON_TextLog& text_log, + ON_TextLog::LevelOfDetail level_of_detail +) + : m_text_log(text_log) + , m_saved_level_of_detail(text_log.GetLevelOfDetail()) +{ + m_text_log.SetLevelOfDetail(level_of_detail); +} + +ON_TextLogLevelOfDetail::~ON_TextLogLevelOfDetail() +{ + m_text_log.SetLevelOfDetail(m_saved_level_of_detail); +} + +ON_TextLog::LevelOfDetail ON_TextLogLevelOfDetail::SavedLevelOfDetail() const +{ + return m_saved_level_of_detail; +} + + ////////////////////////////////////////////////////////////////////////////// ON_TextLog::ON_TextLog() @@ -83,6 +104,58 @@ ON_TextLog::~ON_TextLog() { } + +ON_TextLog::LevelOfDetail ON_TextLog::LevelOfDetailFromUnsigned( + unsigned int level_of_detail +) +{ + switch (level_of_detail) + { + ON_ENUM_FROM_UNSIGNED_CASE(ON_TextLog::LevelOfDetail::Minimum); + ON_ENUM_FROM_UNSIGNED_CASE(ON_TextLog::LevelOfDetail::Medium); + ON_ENUM_FROM_UNSIGNED_CASE(ON_TextLog::LevelOfDetail::Maximum); + } + ON_ERROR("Invalid level_of_detail parameter value"); + return (ON_TextLog::LevelOfDetail::Medium); +} + +void ON_TextLog::SetLevelOfDetail(ON_TextLog::LevelOfDetail level_of_detail) +{ + if (false == IsNull() && false == IsTextHash()) + { + if (level_of_detail == ON_TextLog::LevelOfDetailFromUnsigned(static_cast(level_of_detail))) + m_level_of_detail = level_of_detail; + } +} + +ON_TextLog::LevelOfDetail ON_TextLog::GetLevelOfDetail() const +{ + return m_level_of_detail; +} + +bool ON_TextLog::LevelOfDetailIsAtLeast(ON_TextLog::LevelOfDetail level_of_detail) +{ + return static_cast(m_level_of_detail) >= static_cast(level_of_detail); +} + +void ON_TextLog::SetColorFormat(ON_Color::TextFormat color_format) +{ + if (ON_Color::TextFormat::Unset == color_format) + ClearColorFormat(); + else + m_color_format = (color_format); +} + +ON_Color::TextFormat ON_TextLog::GetColorFormat() +{ + return m_color_format; +} + +void ON_TextLog::ClearColorFormat() +{ + m_color_format = ON_Color::TextFormat::DecimalRGBa; +} + void ON_TextLog::SetDoubleFormat(const char* sFormat) { m_double_format = sFormat; @@ -569,6 +642,17 @@ void ON_TextLog::PrintNewLine() Print("\n"); } +void ON_TextLog::PrintSpace() +{ + Print("\n"); +} + +void ON_TextLog::PrintTab() +{ + Print("\t"); +} + + void ON_TextLog::PrintString( const wchar_t* s ) { if (s && *s) @@ -579,12 +663,14 @@ void ON_TextLog::PrintString( const wchar_t* s ) } } -void ON_TextLog::PrintRGB( const ON_Color& color ) +void ON_TextLog::PrintRGB(const ON_Color& color) { - if ( color == ON_UNSET_COLOR ) - Print("ON_UNSET_COLOR"); - else - Print("%d %d %d",color.Red(),color.Green(),color.Blue()); + color.ToText(ON_Color::TextFormat::DecimalRGB, 0, true, *this); +} + +void ON_TextLog::PrintColor(const ON_Color& color) +{ + color.ToText(this->GetColorFormat(), 0, true, *this); } void ON_TextLog::PrintCurrentTime() diff --git a/opennurbs_textlog.h b/opennurbs_textlog.h index ea04ecc3..592977c2 100644 --- a/opennurbs_textlog.h +++ b/opennurbs_textlog.h @@ -45,6 +45,65 @@ public: */ ON_TextLog( ON_wString& s ); + + ////////////////////////////////////////////////////////////// + // + // Level of detail interface + // + + /// + /// ON_TextLog::LevelOfDetail determines ow much detail is printed. Functions that have an ON_TextLog + /// parameter, like the Dump() functions, may use the level of detail to tailor their output. + /// may use the level of detail to tailor their output. + /// + enum class LevelOfDetail : unsigned char + { + /// + /// A brief summary or synopsis. + /// + Minimum = 0, + + /// + /// The default level of detail. + /// + Medium = 1, + + /// + /// A verbose description that may be so long it obscures the important points. + /// + Maximum = 2 + }; + + static ON_TextLog::LevelOfDetail LevelOfDetailFromUnsigned( + unsigned int level_of_detail + ); + + /* + Description: + Set the level of detail to print. + Parameters: + level_of_detail - [in] + (default = ON_TextLog::LevelOfDetail::Medium) + */ + void SetLevelOfDetail(ON_TextLog::LevelOfDetail level_of_detail); + + /* + Returns: + Level of detail to print + 0 = minimum level of detail + 4 = maximum level of detail + */ + ON_TextLog::LevelOfDetail GetLevelOfDetail() const; + + /* + Parameter: + level_of_detail - [in] + Returns: + True if this text log's level of detail the same or more detailed than + the amount specified by level_of_detail. + */ + bool LevelOfDetailIsAtLeast(ON_TextLog::LevelOfDetail level_of_detail); + /* Description: ON_TextLog::Null is a silent text log and can be used when no output @@ -75,6 +134,15 @@ public: void SetFloatFormat( const char* ); // default is %g void GetFloatFormat( ON_String& ) const; + void SetColorFormat(ON_Color::TextFormat color_format); + ON_Color::TextFormat GetColorFormat(); + + /* + Description: + Returns color format to the default ON_Color::TextFormat::DecimalRGBa + */ + void ClearColorFormat(); + void PushIndent(); void PopIndent(); int IndentSize() const; // 0: one tab per indent @@ -164,6 +232,18 @@ public: */ void PrintNewLine(); + /* + Description: + Same as calling Print(" "); + */ + void PrintSpace(); + + /* + Description: + Same as calling Print("\t"); + */ + void PrintTab(); + /* Description: Print an unformatted ASCII string of any length. @@ -180,7 +260,17 @@ public: */ void PrintString( const wchar_t* s ); - void PrintRGB( const ON_Color& ); + /* + Description: + Print color using the format ON_Color::TextFormat::DecimalRGB. + */ + void PrintRGB( const ON_Color& color); + + /* + Description: + Print color using ON_Color::ToText(this->GetColorFormat(),0,true,*this); + */ + void PrintColor(const ON_Color& color); /* Description: @@ -293,8 +383,9 @@ private: int m_indent_count = 0; const bool m_bNullTextLog = false; - ON__UINT8 m_reserved0 = 0; - ON__UINT16 m_reserved1 = 0; + ON_TextLog::LevelOfDetail m_level_of_detail = ON_TextLog::LevelOfDetail::Medium; + ON_Color::TextFormat m_color_format = ON_Color::TextFormat::DecimalRGBa; + ON__UINT8 m_reserved1 = 0; private: ON_TextLog( const ON_TextLog& ) = delete; @@ -334,6 +425,40 @@ private: ON_TextLogIndent& operator=(const ON_TextLogIndent&); }; + +/* +Description: + ON_TextLogLevelOfDetail is a class used with ON_TextLog to push and pop level of detail. +*/ +class ON_CLASS ON_TextLogLevelOfDetail +{ +public: + + // The constructor saves the current level of detail and then sets the level of detail to level_of_detail. + ON_TextLogLevelOfDetail( + class ON_TextLog& text_log, + ON_TextLog::LevelOfDetail level_of_detail + ); + + // The destructor restores the level ot detail the saved value. + ~ON_TextLogLevelOfDetail(); + + /* + Returns: + Level of detail the text log had when the constructor was called. + */ + ON_TextLog::LevelOfDetail SavedLevelOfDetail() const; + +private: + ON_TextLogLevelOfDetail() = delete; + ON_TextLogLevelOfDetail(const ON_TextLogLevelOfDetail&) = delete; + ON_TextLogLevelOfDetail& operator=(const ON_TextLogLevelOfDetail&) = delete; + +private: + class ON_TextLog& m_text_log; + const ON_TextLog::LevelOfDetail m_saved_level_of_detail; +}; + class ON_CLASS ON_TextHash : public ON_TextLog { public: diff --git a/opennurbs_textrun.cpp b/opennurbs_textrun.cpp index 2c1820d6..dbc2905d 100644 --- a/opennurbs_textrun.cpp +++ b/opennurbs_textrun.cpp @@ -257,17 +257,30 @@ ON_TextRunArray::ON_TextRunArray(const ON_TextRunArray& src) ON_StackedText::~ON_StackedText() { + // NOTE WELL: + // https://mcneel.myjetbrains.com/youtrack/issue/RH-57616 + // ON_StackedText::Empty is a global const instance. + // Compilers like VS 2019 16.5.0 set the memory for that instance to read-only. + // This destructor must not write to memory used by const instances. + // + // m_top_run, m_bottom_run, and m_parent_run are set to nullptr to prevent crashes + // if in-place classes are referenced after destruction. + // This is done because bugs are better than crashes in the released product. + if (nullptr != m_top_run) { ON_TextRun::ReturnManagedTextRun(m_top_run); + m_top_run = nullptr; } if (nullptr != m_bottom_run) { ON_TextRun::ReturnManagedTextRun(m_bottom_run); + m_bottom_run = nullptr; + } + if (nullptr != m_parent_run) + { + m_parent_run = nullptr; } - m_top_run = nullptr; - m_bottom_run = nullptr; - m_parent_run = nullptr; } ON_StackedText::ON_StackedText(const ON_StackedText& src) diff --git a/opennurbs_win_dwrite.cpp b/opennurbs_win_dwrite.cpp index 05873d8b..24e8ea11 100644 --- a/opennurbs_win_dwrite.cpp +++ b/opennurbs_win_dwrite.cpp @@ -457,6 +457,23 @@ void ON_Font::DumpWindowsDWriteFont( // Other names: Internal_DWriteFontInformation info_strings[] = { + // field 4 + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_FULL_NAME,L"DWrite full name"), + + // field 6 + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,L"DWrite PostScript name"), + + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES,L"GDI family name"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES,L"GDI sub-family name"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME,L"DWrite weight-stretch-style model family name"), + + // other fields - useful when trying to compare fonts / bugs from different computers + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE,L"DWrite field 0 copyright"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS,L"DWrite field 5 version"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_TRADEMARK,L"DWrite field 7 trademark"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_MANUFACTURER,L"DWrite field 8 manufacturer"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_DESIGNER,L"DWrite field 9 designer/foundary"), + // DWRITE_INFORMATIONAL_STRING_DESCRIPTION gets field 10 from the ttf file. // Opennurbs searches the description saved in field 10 of the name table // for the strings "Engraving - single stroke" / "Engraving - double stroke" / "Engraving" @@ -465,13 +482,14 @@ void ON_Font::DumpWindowsDWriteFont( // The SLF (single line fonts) are examples of fonts that have Engraving in field 10. Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_DESCRIPTION,L"DWrite field 10 description"), - Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_FULL_NAME,L"DWrite full name"), - Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME,L"DWrite PostScript name"), - Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES,L"GDI family name"), - Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES,L"GDI sub-family name"), - - Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME,L"Dwrite PostScript CID findfont name") + // other fields - useful when trying to compare fonts / bugs from different computers + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL,L"DWrite field 11 vendor URL"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_DESIGNER_URL,L"DWrite field 12 designer URL"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION,L"DWrite field 13 license"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL,L"DWrite field 14 license URL"), + Internal_DWriteFontInformation(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME,L"Dwrite field 20 PostScript CID findfont name") }; + const size_t info_strings_count = sizeof(info_strings) / sizeof(info_strings[0]); for (size_t i = 0; i < info_strings_count; i++) { @@ -490,7 +508,7 @@ void ON_Font::DumpWindowsDWriteFont( // to identify fonts that are desgned for engraving (and which tend to render poorly when // used to dispaly text devices like screens, monitors, and printers). // The SLF (single line fonts) are examples of fonts that have Engraving in field 10. - const ON_wString field_10_description = ON_Font::Field10DescriptionFromWindowsDWriteFont(dwrite_font, preferedLocale); + const ON_wString field_10_description = ON_Font::Field_10_DescriptionFromWindowsDWriteFont(dwrite_font, preferedLocale); text_log.Print(L"ON_Font field 10 description = \"%ls\"\n", static_cast(field_10_description)); bool bGotLogfont = false; @@ -650,15 +668,9 @@ const ON_wString ON_Font::PostScriptNameFromWindowsDWriteFont( return ON_wString::EmptyString; } - -// Returns the desription saved in field 10. -// Opennurbs searches the description saved in field 10 of the name table -// for the strings "Engraving - single stroke" / "Engraving - double stroke" / "Engraving" -// to identify fonts that are desgned for engraving (and which tend to render poorly when -// used to dispaly text devices like screens, monitors, and printers). -// The SLF (single line fonts) are examples of fonts that have Engraving in field 10. -const ON_wString ON_Font::Field10DescriptionFromWindowsDWriteFont( +static const ON_wString Internal_InfoStringFromWindowsDWriteFont( struct IDWriteFont* dwrite_font, + enum DWRITE_INFORMATIONAL_STRING_ID info_string_id, const wchar_t* preferedLocale ) { @@ -667,87 +679,270 @@ const ON_wString ON_Font::Field10DescriptionFromWindowsDWriteFont( if (nullptr == dwrite_font) break; BOOL exists = false; - Microsoft::WRL::ComPtr descriptions = nullptr; - HRESULT hr = dwrite_font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_DESCRIPTION, &descriptions, &exists); + Microsoft::WRL::ComPtr info_string = nullptr; + HRESULT hr = dwrite_font->GetInformationalStrings(info_string_id, &info_string, &exists); if (FAILED(hr)) break; ON_wString loc_description; ON_wString en_description; if (exists) - Internal_GetLocalizeStrings(preferedLocale, descriptions.Get(), loc_description, en_description); + Internal_GetLocalizeStrings(preferedLocale, info_string.Get(), loc_description, en_description); return loc_description.IsNotEmpty() ? loc_description : en_description; } return ON_wString::EmptyString; } +const ON_wString ON_Font::WeightStretchStyleModelFamilyNameFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME, preferedLocale); +} + +const ON_wString ON_Font::Field_0_CopyrightFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, preferedLocale); +} + +const ON_wString ON_Font::Field_5_VersionFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, preferedLocale); +} + +const ON_wString ON_Font::Field_7_TrademarkFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_TRADEMARK, preferedLocale); +} + +const ON_wString ON_Font::Field_8_ManufacturerFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_MANUFACTURER, preferedLocale); +} + +const ON_wString ON_Font::Field_9_DesignerFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_DESIGNER, preferedLocale); +} + +// Returns the desription saved in field 10. +// Opennurbs searches the description saved in field 10 of the name table +// for the strings "Engraving - single stroke" / "Engraving - double stroke" / "Engraving" +// to identify fonts that are desgned for engraving (and which tend to render poorly when +// used to dispaly text devices like screens, monitors, and printers). +// The SLF (single line fonts) are examples of fonts that have Engraving in field 10. +const ON_wString ON_Font::Field_10_DescriptionFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font,DWRITE_INFORMATIONAL_STRING_DESCRIPTION, preferedLocale); +} + + +const ON_wString ON_Font::Field_11_VendorURLFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_FONT_VENDOR_URL, preferedLocale); +} + +const ON_wString ON_Font::Field_12_DesignerURLFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_DESIGNER_URL, preferedLocale); +} + +const ON_wString ON_Font::Field_13_LicenseFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION, preferedLocale); +} + +const ON_wString ON_Font::Field_14_LicenseURLFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL, preferedLocale); +} + +const ON_wString ON_Font::Field_20_PostScriptCIDNameFromWindowsDWriteFont( + struct IDWriteFont* dwrite_font, + const wchar_t* preferedLocale +) +{ + return Internal_InfoStringFromWindowsDWriteFont(dwrite_font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME, preferedLocale); +} + void ON_WindowsDWriteFontInformation::Dump(ON_TextLog& text_log) const { text_log.Print("IDWriteFont:\n"); + + const bool bTerse = text_log.LevelOfDetailIsAtLeast(ON_TextLog::LevelOfDetail::Medium); + const bool bChatty = text_log.LevelOfDetailIsAtLeast(ON_TextLog::LevelOfDetail::Medium); + const bool bVerbose = text_log.LevelOfDetailIsAtLeast(ON_TextLog::LevelOfDetail::Maximum); + ON_TextLogIndent indent1(text_log); - if (m_prefered_locale.IsNotEmpty()) - text_log.Print("Prefered locale = \"%ls\"\n", static_cast(m_prefered_locale)); - if (FamilyName().IsNotEmpty()) + if ( bVerbose ) { - if ( FaceName().IsNotEmpty()) - text_log.Print("Iteration index = family[%d].font[%u]\n", m_family_index, m_family_font_index); - else - text_log.Print("Iteration index = family[%d]\n", m_family_index); + if (m_prefered_locale.IsNotEmpty()) + text_log.Print("Prefered locale = \"%ls\"\n", static_cast(m_prefered_locale)); + if (FamilyName().IsNotEmpty()) + { + if (FaceName().IsNotEmpty()) + text_log.Print("Iteration index = family[%d].font[%u]\n", m_family_index, m_family_font_index); + else + text_log.Print("Iteration index = family[%d]\n", m_family_index); + } } - text_log.Print(L"Localized Names:\n"); - text_log.PushIndent(); - text_log.Print(L"Family name = \"%ls\"\n", static_cast(m_loc_family_name)); - text_log.Print(L"Face name = \"%ls\"\n", static_cast(m_loc_face_name)); - text_log.Print(L"PostScript name = \"%ls\"\n", static_cast(m_loc_postscript_name)); - text_log.Print(L"GDI LOGFONT name = \"%ls\"\n", static_cast(m_loc_gdi_family_name)); - text_log.Print(L"GDI subfamily name = \"%ls\"\n", static_cast(m_loc_gdi_subfamily_name)); - text_log.Print(L"Full name = \"%ls\"\n", static_cast(m_loc_full_name)); - text_log.Print(L"Field 10 Description = \"%ls\"\n", static_cast(m_loc_field_10_description)); - text_log.PopIndent(); - - text_log.Print(L"English Names:\n"); - text_log.PushIndent(); - text_log.Print(L"Family name = \"%ls\"\n", static_cast(m_en_family_name)); - text_log.Print(L"Face name = \"%ls\"\n", static_cast(m_en_face_name)); - text_log.Print(L"PostScript name = \"%ls\"\n", static_cast(m_en_postscript_name)); - text_log.Print(L"GDI LOGFONT name = \"%ls\"\n", static_cast(m_en_gdi_family_name)); - text_log.Print(L"GDI subfamily name = \"%ls\"\n", static_cast(m_en_gdi_subfamily_name)); - text_log.Print(L"Full name = \"%ls\"\n", static_cast(m_en_full_name)); - text_log.Print(L"Field 10 Description = \"%ls\"\n", static_cast(m_en_field_10_description)); - text_log.PopIndent(); - - if (m_bSimulatedBold || m_bSimulatedOblique || m_bSimulatedOther) + ON_wString family_name = m_loc_family_name; + ON_wString face_name = m_loc_face_name; + ON_wString postscript_name = m_loc_postscript_name; + ON_wString logfont_name = m_loc_gdi_family_name; + if (false == bChatty) { - text_log.Print("Simuilations ="); - if (m_bSimulatedBold) - text_log.Print(" BOLD"); - if (m_bSimulatedOblique) - text_log.Print(" OBLIQUE"); - if (m_bSimulatedOther) - text_log.Print(" other"); - text_log.PrintNewLine(); + if (family_name.IsEmpty()) + family_name = m_en_family_name; + if (face_name.IsEmpty()) + face_name = m_en_face_name; + if (postscript_name.IsEmpty()) + postscript_name = m_en_postscript_name; + if (logfont_name.IsEmpty()) + logfont_name = m_en_gdi_family_name; } - const DWRITE_FONT_WEIGHT dwrite_weight = (DWRITE_FONT_WEIGHT)m_weight; - const ON_wString weightString = Internal_DWRITE_FONT_WEIGHT_ToString(dwrite_weight); - text_log.Print(L"Weight = %ls\n", static_cast(weightString)); + if (bChatty) + text_log.Print(L"Localized Names:\n"); + else + text_log.Print(L"Names:\n"); - const DWRITE_FONT_STYLE dwrite_style = (DWRITE_FONT_STYLE)m_style; - const ON_wString styleString = Internal_DWRITE_FONT_STYLE_ToString(dwrite_style); - text_log.Print(L"Style = %ls\n", static_cast(styleString)); - - const DWRITE_FONT_STRETCH dwrite_stretch = (DWRITE_FONT_STRETCH)m_stretch; - const ON_wString stretchString = Internal_DWRITE_FONT_STRETCH_ToString(dwrite_stretch); - text_log.Print(L"Stretch = %ls\n", static_cast(stretchString)); - - text_log.Print("IsSymbolFont = %s.\n",(m_bIsSymbolFont?"true":"false")); + text_log.PushIndent(); - if (0 != m_gdi_interop_logfont.lfFaceName[0]) + text_log.Print(L"Family name = \"%ls\"\n", static_cast(family_name)); + text_log.Print(L"Face name = \"%ls\"\n", static_cast(face_name)); + text_log.Print(L"PostScript name = \"%ls\"\n", static_cast(postscript_name)); + text_log.Print(L"GDI LOGFONT name = \"%ls\"\n", static_cast(logfont_name)); + + if ( bChatty ) { - text_log.Print("GDI interop IsSystemFont = %s\n", (m_gdi_interop_logfont_bIsSystemFont ? "true" : "false")); - text_log.Print("GDI interop "); - ON_Font::DumpLogfont(&m_gdi_interop_logfont, text_log); + text_log.Print(L"GDI subfamily name = \"%ls\"\n", static_cast(m_loc_gdi_subfamily_name)); + text_log.Print(L"Full name = \"%ls\"\n", static_cast(m_loc_full_name)); + if ( bVerbose ) + { + text_log.Print(L"Direct Write Weight-Stretch-Style Model Name = \"%ls\"\n", static_cast(m_loc_weight_stretch_style_model_name)); + + text_log.Print(L"Field 0 Copyright = \"%ls\"\n", static_cast(m_loc_field_0_copyright)); + text_log.Print(L"Field 5 Version = \"%ls\"\n", static_cast(m_loc_field_5_version)); + text_log.Print(L"Field 7 Trademark = \"%ls\"\n", static_cast(m_loc_field_7_trademark)); + text_log.Print(L"Field 8 Manufacturer = \"%ls\"\n", static_cast(m_loc_field_8_manufacturer)); + text_log.Print(L"Field 9 Designer = \"%ls\"\n", static_cast(m_loc_field_9_designer)); + text_log.Print(L"Field 10 Description = \"%ls\"\n", static_cast(m_loc_field_10_description)); + text_log.Print(L"Field 11 Vendor URL = \"%ls\"\n", static_cast(m_loc_field_11_vendor_URL)); + text_log.Print(L"Field 12 Designer_URL = \"%ls\"\n", static_cast(m_loc_field_12_designer_URL)); + text_log.Print(L"Field 13 License = \"%ls\"\n", static_cast(m_loc_field_13_license)); + text_log.Print(L"Field 14 License URL = \"%ls\"\n", static_cast(m_loc_field_14_license_URL)); + text_log.Print(L"Field 20 PostScript CID Name = \"%ls\"\n", static_cast(m_loc_field_20_postscript_cid)); + } + } + + if ( false == bVerbose ) + { + if (ON_OutlineFigure::Type::Unset != ON_OutlineFigure::FigureTypeFromField10Description(m_loc_field_10_description)) + text_log.Print(L"Field 10 Description = \"%ls\"\n", static_cast(m_loc_field_10_description)); + else if (ON_OutlineFigure::Type::Unset != ON_OutlineFigure::FigureTypeFromField10Description(m_en_field_10_description)) + text_log.Print(L"Field 10 Description = \"%ls\"\n", static_cast(m_en_field_10_description)); + } + + text_log.PopIndent(); + + if ( bChatty ) + { + text_log.Print(L"English Names:\n"); + ON_TextLogIndent indent2(text_log); + text_log.Print(L"Family name = \"%ls\"\n", static_cast(m_en_family_name)); + text_log.Print(L"Face name = \"%ls\"\n", static_cast(m_en_face_name)); + text_log.Print(L"PostScript name = \"%ls\"\n", static_cast(m_en_postscript_name)); + text_log.Print(L"GDI LOGFONT name = \"%ls\"\n", static_cast(m_en_gdi_family_name)); + text_log.Print(L"GDI subfamily name = \"%ls\"\n", static_cast(m_en_gdi_subfamily_name)); + text_log.Print(L"Full name = \"%ls\"\n", static_cast(m_en_full_name)); + + if ( bVerbose ) + { + text_log.Print(L"Direct Write Weight-Stretch-Style Model Name = \"%ls\"\n", static_cast(m_en_weight_stretch_style_model_name)); + + text_log.Print(L"Field 0 Copyright = \"%ls\"\n", static_cast(m_en_field_0_copyright)); + text_log.Print(L"Field 5 Version = \"%ls\"\n", static_cast(m_en_field_5_version)); + text_log.Print(L"Field 7 Trademark = \"%ls\"\n", static_cast(m_en_field_7_trademark)); + text_log.Print(L"Field 8 Manufacturer = \"%ls\"\n", static_cast(m_en_field_8_manufacturer)); + text_log.Print(L"Field 9 Designer = \"%ls\"\n", static_cast(m_en_field_9_designer)); + text_log.Print(L"Field 10 Description = \"%ls\"\n", static_cast(m_en_field_10_description)); + text_log.Print(L"Field 11 Vendor URL = \"%ls\"\n", static_cast(m_en_field_11_vendor_URL)); + text_log.Print(L"Field 12 Designer_URL = \"%ls\"\n", static_cast(m_en_field_12_designer_URL)); + text_log.Print(L"Field 13 License = \"%ls\"\n", static_cast(m_en_field_13_license)); + text_log.Print(L"Field 14 License URL = \"%ls\"\n", static_cast(m_en_field_14_license_URL)); + text_log.Print(L"Field 20 PostScript CID Name = \"%ls\"\n", static_cast(m_en_field_20_postscript_cid)); + } + } + + if (bChatty) + { + if (m_bSimulatedBold || m_bSimulatedOblique || m_bSimulatedOther) + { + text_log.Print("Simuilations ="); + if (m_bSimulatedBold) + text_log.Print(" BOLD"); + if (m_bSimulatedOblique) + text_log.Print(" OBLIQUE"); + if (m_bSimulatedOther) + text_log.Print(" other"); + text_log.PrintNewLine(); + } + + const DWRITE_FONT_WEIGHT dwrite_weight = (DWRITE_FONT_WEIGHT)m_weight; + const ON_wString weightString = Internal_DWRITE_FONT_WEIGHT_ToString(dwrite_weight); + text_log.Print(L"Weight = %ls\n", static_cast(weightString)); + + const DWRITE_FONT_STYLE dwrite_style = (DWRITE_FONT_STYLE)m_style; + const ON_wString styleString = Internal_DWRITE_FONT_STYLE_ToString(dwrite_style); + text_log.Print(L"Style = %ls\n", static_cast(styleString)); + + const DWRITE_FONT_STRETCH dwrite_stretch = (DWRITE_FONT_STRETCH)m_stretch; + const ON_wString stretchString = Internal_DWRITE_FONT_STRETCH_ToString(dwrite_stretch); + text_log.Print(L"Stretch = %ls\n", static_cast(stretchString)); + } + + if ( bVerbose ) + { + text_log.Print("IsSymbolFont = %s.\n", (m_bIsSymbolFont ? "true" : "false")); + if (0 != m_gdi_interop_logfont.lfFaceName[0]) + { + text_log.Print("GDI interop IsSystemFont = %s\n", (m_gdi_interop_logfont_bIsSystemFont ? "true" : "false")); + text_log.Print("GDI interop "); + ON_Font::DumpLogfont(&m_gdi_interop_logfont, text_log); + } } } @@ -1066,14 +1261,57 @@ unsigned int ON_Font::GetInstalledWindowsDWriteFonts( Internal_GetLocalizeStrings(preferedLocale, gdiSubfamilyNames.Get(), fi.m_loc_gdi_subfamily_name, fi.m_en_gdi_subfamily_name); } + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_WEIGHT_STRETCH_STYLE_FAMILY_NAME, ... ) + fi.m_en_weight_stretch_style_model_name = ON_Font::WeightStretchStyleModelFamilyNameFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_weight_stretch_style_model_name = ON_Font::WeightStretchStyleModelFamilyNameFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, ... ) + fi.m_loc_field_0_copyright = ON_Font::Field_0_CopyrightFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_0_copyright = ON_Font::Field_0_CopyrightFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_VERSION_STRINGS, ... ) + fi.m_loc_field_5_version = ON_Font::Field_5_VersionFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_5_version = ON_Font::Field_5_VersionFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_TRADEMARK, ... ) + fi.m_loc_field_7_trademark = ON_Font::Field_7_TrademarkFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_7_trademark = ON_Font::Field_7_TrademarkFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_MANUFACTURER, ... ) + fi.m_loc_field_8_manufacturer = ON_Font::Field_8_ManufacturerFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_8_manufacturer = ON_Font::Field_8_ManufacturerFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_DESIGNER, ... ) + fi.m_loc_field_9_designer = ON_Font::Field_9_DesignerFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_9_designer = ON_Font::Field_9_DesignerFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + // Field 10 Description // Opennurbs searches the description saved in field 10 of the name table // for the strings "Engraving - single stroke" / "Engraving - double stroke" / "Engraving" // to identify fonts that are desgned for engraving (and which tend to render poorly when // used to dispaly text devices like screens, monitors, and printers). // The SLF (single line fonts) are examples of fonts that have Engraving in field 10. - fi.m_loc_field_10_description = ON_Font::Field10DescriptionFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); - fi.m_en_field_10_description = ON_Font::Field10DescriptionFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + fi.m_loc_field_10_description = ON_Font::Field_10_DescriptionFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_10_description = ON_Font::Field_10_DescriptionFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + fi.m_loc_field_11_vendor_URL = ON_Font::Field_11_VendorURLFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_11_vendor_URL = ON_Font::Field_11_VendorURLFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_DESIGNER_URL, ... ) + fi.m_loc_field_12_designer_URL = ON_Font::Field_12_DesignerURLFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_12_designer_URL = ON_Font::Field_12_DesignerURLFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_LICENSE_DESCRIPTION, ... ) + fi.m_loc_field_13_license = ON_Font::Field_13_LicenseFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_13_license = ON_Font::Field_13_LicenseFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_LICENSE_INFO_URL, ... ) + fi.m_loc_field_14_license_URL = ON_Font::Field_14_LicenseURLFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_14_license_URL = ON_Font::Field_14_LicenseURLFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); + + // from IDWriteFont.GetInformationalStrings( DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME, ... ) + fi.m_loc_field_20_postscript_cid = ON_Font::Field_20_PostScriptCIDNameFromWindowsDWriteFont(dwriteFont.Get(), preferedLocale); + fi.m_en_field_20_postscript_cid = ON_Font::Field_20_PostScriptCIDNameFromWindowsDWriteFont(dwriteFont.Get(), englishLocale); BOOL isSystemFont = false; LOGFONTW logfont; @@ -1887,8 +2125,8 @@ bool ON_Font::SetFromWindowsDWriteFont( // to identify fonts that are desgned for engraving (and which tend to render poorly when // used to dispaly text devices like screens, monitors, and printers). // The SLF (single line fonts) are examples of fonts that have Engraving in field 10. - ON_wString loc_field_10_description = ON_Font::Field10DescriptionFromWindowsDWriteFont(dwrite_font, preferedLocale); - ON_wString en_field_10_description = ON_Font::Field10DescriptionFromWindowsDWriteFont(dwrite_font, L"en-us"); + ON_wString loc_field_10_description = ON_Font::Field_10_DescriptionFromWindowsDWriteFont(dwrite_font, preferedLocale); + ON_wString en_field_10_description = ON_Font::Field_10_DescriptionFromWindowsDWriteFont(dwrite_font, L"en-us"); if (ON_OutlineFigure::Type::Unset == m_outline_figure_type) m_outline_figure_type = ON_OutlineFigure::FigureTypeFromField10Description(loc_field_10_description); if (ON_OutlineFigure::Type::Unset == m_outline_figure_type)