diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index f76aad0b8e204ddad3a675375bd5be6cc73eed8b..0000000000000000000000000000000000000000 --- a/.editorconfig +++ /dev/null @@ -1,225 +0,0 @@ -# 如果要从更高级别的目录继承 .editorconfig 设置,请删除以下行 -root = true - -# c# 文件 -[*.cs] - -#### Core EditorConfig 选项 #### - -# 缩进和间距 -indent_size = 4 -indent_style = space -tab_width = 4 - -# 新行首选项 -end_of_line = crlf -insert_final_newline = false - -#### .NET 编码约定 #### - -# 组织 Using -dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = false -file_header_template = unset - -# this. 和 Me. 首选项 -dotnet_style_qualification_for_event = false -dotnet_style_qualification_for_field = false -dotnet_style_qualification_for_method = false -dotnet_style_qualification_for_property = false - -# 语言关键字与 bcl 类型首选项 -dotnet_style_predefined_type_for_locals_parameters_members = true -dotnet_style_predefined_type_for_member_access = true - -# 括号首选项 -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity -dotnet_style_parentheses_in_other_operators = never_if_unnecessary -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity - -# 修饰符首选项 -dotnet_style_require_accessibility_modifiers = for_non_interface_members - -# 表达式级首选项 -dotnet_style_coalesce_expression = true -dotnet_style_collection_initializer = true -dotnet_style_explicit_tuple_names = true -dotnet_style_namespace_match_folder = true -dotnet_style_null_propagation = true -dotnet_style_object_initializer = true -dotnet_style_operator_placement_when_wrapping = beginning_of_line -dotnet_style_prefer_auto_properties = true -dotnet_style_prefer_compound_assignment = true -dotnet_style_prefer_conditional_expression_over_assignment = true -dotnet_style_prefer_conditional_expression_over_return = true -dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed -dotnet_style_prefer_inferred_anonymous_type_member_names = true -dotnet_style_prefer_inferred_tuple_names = true -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error -dotnet_style_prefer_simplified_boolean_expressions = true -dotnet_style_prefer_simplified_interpolation = true - -# 字段首选项 -dotnet_style_readonly_field = true - -# 参数首选项 -dotnet_code_quality_unused_parameters = all - -# 禁止显示首选项 -dotnet_remove_unnecessary_suppression_exclusions = 0 - -# 新行首选项 -dotnet_style_allow_multiple_blank_lines_experimental = true -dotnet_style_allow_statement_immediately_after_block_experimental = true - -#### c# 编码约定 #### - -# var 首选项 -csharp_style_var_elsewhere = false -csharp_style_var_for_built_in_types = false -csharp_style_var_when_type_is_apparent = false - -# Expression-bodied 成员 -csharp_style_expression_bodied_accessors = true -csharp_style_expression_bodied_constructors = false -csharp_style_expression_bodied_indexers = true -csharp_style_expression_bodied_lambdas = true -csharp_style_expression_bodied_local_functions = false -csharp_style_expression_bodied_methods = false -csharp_style_expression_bodied_operators = false -csharp_style_expression_bodied_properties = true - -# 模式匹配首选项 -csharp_style_pattern_matching_over_as_with_null_check = true -csharp_style_pattern_matching_over_is_with_cast_check = true -csharp_style_prefer_extended_property_pattern = true -csharp_style_prefer_not_pattern = true -csharp_style_prefer_pattern_matching = true -csharp_style_prefer_switch_expression = true - -# Null 检查首选项 -csharp_style_conditional_delegate_call = true - -# 修饰符首选项 -csharp_prefer_static_local_function = true -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async - -# 代码块首选项 -csharp_prefer_braces = true -csharp_prefer_simple_using_statement = true -csharp_style_namespace_declarations = block_scoped -csharp_style_prefer_method_group_conversion = true -csharp_style_prefer_top_level_statements = true - -# 表达式级首选项 -csharp_prefer_simple_default_expression = true -csharp_style_deconstructed_variable_declaration = true -csharp_style_implicit_object_creation_when_type_is_apparent = true -csharp_style_inlined_variable_declaration = true -csharp_style_prefer_index_operator = true -csharp_style_prefer_local_over_anonymous_function = true -csharp_style_prefer_null_check_over_type_check = true -csharp_style_prefer_range_operator = true -csharp_style_prefer_tuple_swap = true -csharp_style_prefer_utf8_string_literals = true -csharp_style_throw_expression = true -csharp_style_unused_value_assignment_preference = discard_variable -csharp_style_unused_value_expression_statement_preference = discard_variable - -# "using" 指令首选项 -csharp_using_directive_placement = outside_namespace - -# 新行首选项 -csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true -csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true -csharp_style_allow_embedded_statements_on_same_line_experimental = true - -#### C# 格式规则 #### - -# 新行首选项 -csharp_new_line_before_catch = true -csharp_new_line_before_else = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_open_brace = accessors,anonymous_methods,anonymous_types,control_blocks,methods,object_collection_array_initializers,properties,types -csharp_new_line_between_query_expression_clauses = true - -# 缩进首选项 -csharp_indent_block_contents = true -csharp_indent_braces = false -csharp_indent_case_contents = false -csharp_indent_case_contents_when_block = false -csharp_indent_labels = one_less_than_current -csharp_indent_switch_labels = true - -# 空格键首选项 -csharp_space_after_cast = false -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_after_comma = true -csharp_space_after_dot = false -csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = false -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_before_comma = false -csharp_space_before_dot = false -csharp_space_before_open_square_brackets = false -csharp_space_before_semicolon_in_for_statement = false -csharp_space_between_empty_square_brackets = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_declaration_name_and_open_parenthesis = false -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_parentheses = false -csharp_space_between_square_brackets = false - -# 包装首选项 -csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = true - -#### 命名样式 #### - -# 命名规则 - -dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion -dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface -dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i - -dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.types_should_be_pascal_case.symbols = types -dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case - -dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members -dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case - -# 符号规范 - -dotnet_naming_symbols.interface.applicable_kinds = interface -dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.interface.required_modifiers = - -dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum -dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.types.required_modifiers = - -dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method -dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected -dotnet_naming_symbols.non_field_members.required_modifiers = - -# 命名样式 - -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = -dotnet_naming_style.pascal_case.capitalization = pascal_case - -dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = -dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/.gitignore b/.gitignore index e910608fc1ecabe29cb4e88eeab0a35a2b752e7d..75cf7609c93112bc84a2b63eca3f0089dec77a45 100644 --- a/.gitignore +++ b/.gitignore @@ -407,4 +407,4 @@ healthchecksdb .vscode #ifoxcad -#tests/TestConsole/ \ No newline at end of file +**/Properties/launchSettings.json diff --git a/IFoxCAD.sln b/IFoxCAD.sln index 802ff1cc56ccadea875f242dea64a2a32a0c0d69..8b9d772194969843ac6842ac33ccc16608fb0f74 100644 --- a/IFoxCAD.sln +++ b/IFoxCAD.sln @@ -1,137 +1,71 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.1.32113.165 +VisualStudioVersion = 17.8.34309.116 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{786E7347-B116-4F26-9AEF-33EB0AB88D58}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AE09C3B7-58AC-4A68-9884-1F93FDA5D785}" ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - .gitattributes = .gitattributes - .gitignore = .gitignore + src\Directory.Build.props = src\Directory.Build.props EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestConsole", "tests\TestConsole\TestConsole.csproj", "{E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}" +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CADShared", "src\CADShared\CADShared.shproj", "{5178502E-9A78-4588-B849-33ED439976B2}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestShared", "tests\TestShared\TestShared.shproj", "{CED63D2D-0AF6-4831-806D-5E8E9B0D0A07}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestAcad09plus", "tests\TestAcad09plus\TestAcad09plus.csproj", "{5F478F68-19BC-4A3A-AF39-8728F8D396DD}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{C0BEFC15-6DF7-4636-BC76-4A0B88231470}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Basal", "Basal", "{1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A}" - ProjectSection(SolutionItems) = preProject - src\Basal\Directory.Build.props = src\Basal\Directory.Build.props - EndProjectSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IFoxCAD.AutoCad", "src\IFoxCAD.AutoCad\IFoxCAD.AutoCad.csproj", "{9A0A144F-6820-4D15-9D39-43B7298195E3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.Basal", "src\Basal\IFox.Basal\IFox.Basal.csproj", "{FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IFoxCAD.ZwCad", "src\IFoxCAD.ZwCad\IFoxCAD.ZwCad.csproj", "{8546C2AC-815C-47A1-9D8C-A6470DF44AD9}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "IFox.Basal.Shared", "src\Basal\IFox.Basal.Shared\IFox.Basal.Shared.shproj", "{C823514A-2BC2-45C2-ACED-18924A7B80BF}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{46F3EDA8-A6D1-4707-8D03-731CADB41A56}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.Basal.Source", "src\Basal\IFox.Basal.Source\IFox.Basal.Source.csproj", "{D0C6824C-53A3-4C16-AE7B-3227F18C5039}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestAcad2025", "tests\TestAcad2025\TestAcad2025.csproj", "{47C42AB4-C2F4-475B-899C-71FDE57D926E}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "IFox.CAD.Shared", "src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.shproj", "{20F254F7-AEE5-42AE-A9B3-149BBDC7397F}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestZcad2025", "tests\TestZcad2025\TestZcad2025.csproj", "{0B4601B4-CBDA-4FD8-9B31-C1E292D03068}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CAD", "CAD", "{B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{7145708C-A65B-470E-A8DA-ED79AC9A42D7}" ProjectSection(SolutionItems) = preProject - src\CAD\Directory.Build.props = src\CAD\Directory.Build.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.Source", "src\CAD\IFox.CAD.Source\IFox.CAD.Source.csproj", "{88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.ACAD", "src\CAD\IFox.CAD.ACAD\IFox.CAD.ACAD.csproj", "{EF20E632-70A9-40EB-8C9A-539FD85FAFAD}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.GCAD", "src\CAD\IFox.CAD.GCAD\IFox.CAD.GCAD.csproj", "{F388F4B9-F636-414A-9BC9-2B008517B441}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.CAD.ZCAD", "src\CAD\IFox.CAD.ZCAD\IFox.CAD.ZCAD.csproj", "{3D7D095D-EF0A-40B3-9776-5F08C61FD614}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WPF", "WPF", "{1EE1F817-39D3-43E5-B087-E7AD4D0BEC93}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFox.WPF", "src\WPF\IFox.WPF.csproj", "{6ED0A677-6621-4493-AF58-71C2BF31DFCE}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{DA8EA8E7-A98E-4565-A3BF-97855988DB8E}" - ProjectSection(SolutionItems) = preProject - docs\0x01代码规范.md = docs\0x01代码规范.md - docs\DBTrans.md = docs\DBTrans.md - LICENSE = LICENSE - README.md = README.md - docs\SelectionFilter.md = docs\SelectionFilter.md - docs\SymbolTable.md = docs\SymbolTable.md - docs\WPF.md = docs\WPF.md docs\关于IFoxCAD的架构说明.md = docs\关于IFoxCAD的架构说明.md - docs\关于扩展函数的说明.md = docs\关于扩展函数的说明.md EndProjectSection EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestShared", "tests\TestShared\TestShared.shproj", "{CED63D2D-0AF6-4831-806D-5E8E9B0D0A07}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955}.Release|Any CPU.Build.0 = Release|Any CPU - {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F478F68-19BC-4A3A-AF39-8728F8D396DD}.Release|Any CPU.Build.0 = Release|Any CPU - {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7}.Release|Any CPU.Build.0 = Release|Any CPU - {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D0C6824C-53A3-4C16-AE7B-3227F18C5039}.Release|Any CPU.Build.0 = Release|Any CPU - {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4}.Release|Any CPU.Build.0 = Release|Any CPU - {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EF20E632-70A9-40EB-8C9A-539FD85FAFAD}.Release|Any CPU.Build.0 = Release|Any CPU - {F388F4B9-F636-414A-9BC9-2B008517B441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F388F4B9-F636-414A-9BC9-2B008517B441}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F388F4B9-F636-414A-9BC9-2B008517B441}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F388F4B9-F636-414A-9BC9-2B008517B441}.Release|Any CPU.Build.0 = Release|Any CPU - {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3D7D095D-EF0A-40B3-9776-5F08C61FD614}.Release|Any CPU.Build.0 = Release|Any CPU - {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6ED0A677-6621-4493-AF58-71C2BF31DFCE}.Release|Any CPU.Build.0 = Release|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Release|Any CPU.Build.0 = Release|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Release|Any CPU.Build.0 = Release|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Release|Any CPU.Build.0 = Release|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {E2873F0B-CAD2-45E8-8FF0-C05C0C6AD955} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470} - {CED63D2D-0AF6-4831-806D-5E8E9B0D0A07} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470} - {5F478F68-19BC-4A3A-AF39-8728F8D396DD} = {C0BEFC15-6DF7-4636-BC76-4A0B88231470} - {FF4E1CDE-EEB3-4BE8-8C1D-6B5B17A299C7} = {1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A} - {C823514A-2BC2-45C2-ACED-18924A7B80BF} = {1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A} - {D0C6824C-53A3-4C16-AE7B-3227F18C5039} = {1A5C27C1-FEF3-40A0-A1EE-3BC7BF2BD67A} - {20F254F7-AEE5-42AE-A9B3-149BBDC7397F} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E} - {88F3CF78-23F5-494B-9D8F-2C6B4467E0B4} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E} - {EF20E632-70A9-40EB-8C9A-539FD85FAFAD} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E} - {F388F4B9-F636-414A-9BC9-2B008517B441} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E} - {3D7D095D-EF0A-40B3-9776-5F08C61FD614} = {B2AB7DC7-DBF4-4197-808B-0D2A6613AF5E} - {6ED0A677-6621-4493-AF58-71C2BF31DFCE} = {1EE1F817-39D3-43E5-B087-E7AD4D0BEC93} - EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {31D6C754-CF6B-4AB0-9861-6923DD312350} + SolutionGuid = {57CA0128-08DE-436F-B9F1-82C64F49BF67} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution - src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{20f254f7-aee5-42ae-a9b3-149bbdc7397f}*SharedItemsImports = 13 - src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{3d7d095d-ef0a-40b3-9776-5f08c61fd614}*SharedItemsImports = 5 - tests\TestShared\TestShared.projitems*{5f478f68-19bc-4a3a-af39-8728f8d396dd}*SharedItemsImports = 5 - src\Basal\IFox.Basal.Shared\IFox.Basal.Shared.projitems*{c823514a-2bc2-45c2-aced-18924a7b80bf}*SharedItemsImports = 13 - tests\TestShared\TestShared.projitems*{ced63d2d-0af6-4831-806d-5e8e9b0d0a07}*SharedItemsImports = 13 - src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{ef20e632-70a9-40eb-8c9a-539fd85fafad}*SharedItemsImports = 5 - src\CAD\IFox.CAD.Shared\IFox.CAD.Shared.projitems*{f388f4b9-f636-414a-9bc9-2b008517b441}*SharedItemsImports = 5 - src\Basal\IFox.Basal.Shared\IFox.Basal.Shared.projitems*{ff4e1cde-eeb3-4be8-8c1d-6b5b17a299c7}*SharedItemsImports = 5 + CADShared\CADShared.projitems*{5178502e-9a78-4588-b849-33ed439976b2}*SharedItemsImports = 13 + CADShared\CADShared.projitems*{6b29955a-5796-4035-9297-210fa15d3846}*SharedItemsImports = 5 + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9A0A144F-6820-4D15-9D39-43B7298195E3} = {AE09C3B7-58AC-4A68-9884-1F93FDA5D785} + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9} = {AE09C3B7-58AC-4A68-9884-1F93FDA5D785} + {47C42AB4-C2F4-475B-899C-71FDE57D926E} = {46F3EDA8-A6D1-4707-8D03-731CADB41A56} + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068} = {46F3EDA8-A6D1-4707-8D03-731CADB41A56} + {CED63D2D-0AF6-4831-806D-5E8E9B0D0A07} = {46F3EDA8-A6D1-4707-8D03-731CADB41A56} + {5178502E-9A78-4588-B849-33ED439976B2} = {AE09C3B7-58AC-4A68-9884-1F93FDA5D785} EndGlobalSection EndGlobal diff --git a/IFoxCAD.sln.DotSettings b/IFoxCAD.sln.DotSettings new file mode 100644 index 0000000000000000000000000000000000000000..6b05d846b2d8da01c18f95eea13cb8da1ea097f4 --- /dev/null +++ b/IFoxCAD.sln.DotSettings @@ -0,0 +1,32 @@ + + API + DB + OS + SS + WMF + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index c29b07b76f66a8749a9effdd513d4cdc71b69bc3..0000000000000000000000000000000000000000 --- a/README.md +++ /dev/null @@ -1,176 +0,0 @@ -# IFoxCAD 说明 - -基于.NET的Cad二次开发类库。 - -#### 一、项目来源 - -起初 **雪山飞狐(又狐哥)** 在明经论坛发布了[开源库](http://bbs.mjtd.com/thread-75701-1-1.html),后来狐哥自己的项目进行了极大的丰富后形成NFox类库。然后 **落魄山人** 在征得 雪山飞狐的同意后,对NFox类库进行了整理,增加了注释等,重新发布了NFox类库。 - -后来,经过一段时间的更新后,由于莫名其妙的原因NFox类库挂掉了。而这时山人同学已经基本吃透NFox类库,考虑到NFox的封装过于复杂,遂进行了重构。 - -重构的类库命名为IFoxCAD, 寓意为:**I(爱)Fox(狐哥)**,本项目发布于**Inspire Function(中文名:跃动方程)** 组织下,感谢 **小轩轩** 给起的名字。 - -可以加群交流: - -![ifoxcad用户交流群群二维码](./docs/png/ifoxcad用户交流群群二维码.png) - -#### 二、 快速入门 - -- 打开vs,新建一个standard类型的类库项目,**注意,需要选择类型的时候一定要选standard2.0** - -- 双击项目,打开项目文件: - - - 修改项目文件里的`netcore2.0`为`NET45`。其中的net45,可以改为NET45以上的标准TFM(如:net45、net46、net47等等)。同时可以指定多版本。具体的详细的教程见 [VS通过添加不同引用库,建立多条件编译](https://www.yuque.com/vicwjb/zqpcd0/ufbwyl)。 - - - 在 ` xxx ` 中增加 `preview`,主要是为了支持最新的语法,本项目采用了最新的语法编写。项目文件现在的内容类似如下: - -```xml - - - net45 - preview - - -``` - -- 右键项目文件,选择管理nuget程序包。 - -- 在nuget程序里搜索**ifox**,记得将包括预发行版打钩。截止本文最后更新时,nuget上最新的版本为ifox.cad.source 0.5.2.1版本和ifox.Basal.source 0.5.2.3版本。点击安装就可以。 - -- 添加引用,在新建的项目里的cs文件里添加相关的引用 - -```csharp -using Autodesk.AutoCAD.ApplicationServices; -using Autodesk.AutoCAD.EditorInput; -using Autodesk.AutoCAD.Runtime; -using Autodesk.AutoCAD.Geometry; -using Autodesk.AutoCAD.DatabaseServices; -using IFoxCAD.Cad; -``` - -- 添加代码 - -```csharp -[CommandMethod(nameof(Hello))] -public void Hello() -{ - using DBTrans tr = new(); - var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - tr.CurrentSpace.AddEntity(line1); - // 如果您没有添加preview到项目文件里的话:按如下旧语法: - // using(var tr = new DBTrans()) - // { - // var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - // tr.CurrentSpace.AddEntity(line1); - // } -} -``` - -这段代码就是在cad的当前空间内添加了一条直线。 - -- 生成,然后打开cad,netload命令将刚刚生成的dll加载。如果需要调试需要设置启动程序为cad。 - -- 运行hello命令,然后缩放一下视图,现在一条直线和一个圆已经显示在屏幕上了 - -#### 三、屏蔽IFox的元组、索引、范围功能 - -特别提醒: 考虑到早期的框架没有提供System.Range类型(net core 开始提供)、System.Index类型(net core 开始提供)、System.ValueTuple类型(net 47开始提供),本项目IFox.Basal包里包含了他们。 如果引用了包含System.Range等类型的第三方包(如IndexRange等),请在项目文件中定义NOINDEX、NORANGE、NOVALUETUPLE常量,以避免重复定义。上述代码能起作用的前提是用源码包,普通包暂时无解。 - -```xml - - $(Configuration);NOINDEX;NORANGE;NOVALUETUPLE - -``` - -**NOINDEX、NORANGE、NOVALUETUPLE 分别针对三种类型,哪种类型冲突就定义哪种。** - -#### 四、编译 IFox 源码工程 - -由于vs2022抛弃了某几个net版本,所以我们同时安装vs2019和vs2022,然后使用vs2022; -其中的原因是vs2019拥有全部net版本,而vs2022拥有最新的分析器和语法。 - -编译本项目需要你准备好git,具体的安装教程可以去网上搜索一下。当然也可以利用vs的git来完成。 - -首先在gitee上fork本项目到你的账号,然后clone到本地。 - -原生git使用命令行,打开终端/powershell/cmd,cd到你要存放的目录,然后运行下面的命令,把里面的yourname替换为你的名字,这样就在本地创建了一个ifoxcad文件夹,里面就是本项目的所有源码。 - -``` -git clone https://gitee.com/yourname/ifoxcad.git -``` - -当然也可以采用vs的图形化操作,打开vs,选择 克隆存储库-->填入仓库地址和存放路径-->点击克隆。新手小白推荐用此办法。 - -打开ifoxcad文件夹,双击解决方案文件,打开vs,等待项目打开,加载nuget包,然后生成就可以了。 - -**切记,不要用低版本的vs打开本项目,因为本项目采用了某些新的语法,所以老版本的vs是不兼容的。** - -#### 五、IFoxCad 项目模版 - -可以在vs扩展菜单-管理扩展中搜索ifoxcad,即可安装项目模板。使用项目模版可以方便的创建支持多目标多版本的使用ifoxcad类库的项目和类。如果无法在vs的市场里下载,就去上面的QQ群里下载。 - -项目模版里的自动加载选择了简单api,ifox还提供了一套功能更强大的api,具体的可以参考[自动加载和初始化](/docs/autoreg.md)。 - -#### 六、使用IFoxCad的几种方式 - -目前ifox提供了三种使用方式,**建议一般的用户使用第二种源码包的形式。有志于本项目发展并想提交点代码的可以选择第三种。** - -- 第一种是直接使用普通的nuget包。 - - 此种方式使用便捷,只要在项目中引用了IFox.CAD.ACAD的包,就可以直接使用了。缺点一是无法控制ifox提供的元组功能的屏蔽,导致和其他的三方包的冲突;二是生成目录里带有ifox的dll。 - -- 第二种是使用源码包。 - - 此种方式使用便捷,只要在项目中引用了IFox.Basal.Source和IFox.CAD.Source两个nuget包就可以直接使用了。优点就是使用简单,生成的目录里没有ifox的dll,同时还可以通过定义预处理常量的方式屏蔽ifox提供的元组等功能。缺点就是无法修改源码,即便解包修改了,也不会同步到nuget上。 - -- 第三种是使用git子模块。 - - 此种方法使用步骤复杂,需要熟悉git及其子模块的使用,需要引用ifox里的共享项目文件。优点就是可以使用最新的代码,可以修改代码。具体的可以参考如下说明进行: - - **让 IFox 作为您的子模块** - - IFox的develop分支是一个多cad版本分支,您可以利用此作为您的[git项目子模块](https://www.cnblogs.com/JJBox/p/13876501.html#_label13). - - 子模块是以`共享工程`的方式加入到您的工程的,其为`IFox.CAD.Shared`: -1. 千万不要用`IFox.CAD.ACAD`内的工程作为引用,否则您将遭遇cad加载失效. - -2. 一些全局命名空间的缺少,我们也建议您使用全局命名空间来补充, - 您只需要按照`IFox.CAD.ACAD`的`GlobalUsings.cs`文件一样添加就好了. - -3. 若您使用acad是09版本以下的,比如 07 08版本,建议你升级至09 版本以上. - -4. 上面的例子告诉了大家如何使用子模块。 - -#### 七、软件架构及相关说明 - -1. [软件架构说明](/docs/关于IFoxCAD的架构说明.md) - -2. [扩展函数说明](/docs/关于扩展函数的说明.md) - -3. [事务管理器用法](/docs/DBTrans.md) - -4. [选择集过滤器用法](/docs/SelectionFilter.md) - -5. [符号表用法](/docs/SymbolTable.md) - -6. [WPF支持](/docs/WPF.md) - -7. [自动加载与初始化](/docs/autoreg.md) - -8. 天秀的打开模式提权 - - 由于cad的对象是有打开模式,是否可写等等,为了安全起见,在处理对象时,一般是用读模式打开,然后需要写数据的时候在提权为写模式,然后在降级到读模式,但是这个过程中,很容易漏掉某些步骤,然后cad崩溃。为了处理这些情况,内裤提供了提权类来保证读写模式的有序转换。 - - ```csharp - // 第一种方式,采用的是事务管理的模式 - using(line.ForWrite()) // 开启对象写模式提权事务 - { - // 处理代码 - } // 关闭事务自动处理读写模式 - // 第二种方式,采用的是委托的形式 - line.ForWrite(e => { - // 处理代码 - }); - ``` - -9. 未完待续。。。。 diff --git "a/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.assets/2HJE@WH1`PPUBOH2ZFL$BT.png" "b/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.assets/2HJE@WH1`PPUBOH2ZFL$BT.png" deleted file mode 100644 index 459930b8d54d075d94b4d06e960fbbc7edbdd17b..0000000000000000000000000000000000000000 Binary files "a/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.assets/2HJE@WH1`PPUBOH2ZFL$BT.png" and /dev/null differ diff --git "a/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.md" "b/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.md" deleted file mode 100644 index 26f09091f8e0321b4418e199aaa47792282ff1b5..0000000000000000000000000000000000000000 --- "a/docs/0x01\344\273\243\347\240\201\350\247\204\350\214\203.md" +++ /dev/null @@ -1,132 +0,0 @@ -# IFox工程规范 - -## 代码规范 - -### 0x01 分离逻辑代码和业务代码 - -Good: - -```c# -foreach (xx in yyy) - if (xx == "a") - { - 业务(); - break; - } -``` - -Bad: - -```c# -bool flag = false; -foreach (xx in yyy) - if (xx == "a") - { - 业务(); - flag = true; - break; - } -if(!flag) - 其他业务(); -``` - -Good: - -```c# -bool flag = false; -foreach (xx in yyy) - if (xx == "a") - { - flag = true; - break; - } -if(!flag) - 其他业务(); -else - 业务(); -``` - -主要原因是统一业务在判断分支上,能够更清晰分离逻辑代码和业务代码. - -### 0x02 分离逻辑代码和业务代码 - -![img](0x01%E4%BB%A3%E7%A0%81%E8%A7%84%E8%8C%83.assets/2HJE@WH1%60PPUBOH2ZFL$BT.png) - -上述代码中出现了这种情形: for {业务1,业务2,业务1,业务2....} - -如果有这样的逻辑,那么我们看代码的时候总是认为业务2某种条件必须要跟着业务1. - -优化代码的人一看:这代码就不能动了!! 相信我,若干年后的你就是这个优化代码的人. - -所以这样的情况下,我们采用的是用个`List`收集拆离(业务)的id,然后在最后进行循环拆离(业务). - -### 0x03 .editorconfig 配置要求 - -c#的代码风格是两个大括号隔行 - -```c# -if() -{ - ... -} -``` - -但是,由于vs没有制作好的原因,导致`委托箭头`代码格式化总是会出现格式化错误. -所以我们推荐用 .editorconfig 文件约束这个`委托箭头` - -在.edirorconfig文件上面增加此句: - -``` -csharp_style_var_elsewhere = false -``` - -没有这个文件的话,请使用如下步骤: - -```mermaid -graph LR -vs --> 选项 --> 文本编辑器 --> c# -->代码样式,展开它 --> 格式设置 --> 新行 --> 右页,大括号的新行选项 --> 将lambda表达式的左括号置于新行,取消掉勾勾 -``` - -保存为 .editorconfig 文件,并放在.sln旁边,加入git管理: - -```mermaid -graph LR -vs --> 选项 --> 文本编辑器 --> c# -->代码样式 --> 右页,基于设置生成.editorconfig文件 --> 保存到工程中 -``` - -以后每次打开工程vs会自动识别这个 .editorconfig 文件,而不会用你电脑默认设置的. - -### 0x04 所有的注释符号//后面加空格 - -利用此正则替换: - -``` -(? - { - ltt.AsciiDescription = "虚线"; - ltt.PatternLength = 0.95; //线型的总长度 - ltt.NumDashes = 4; //组成线型的笔画数目 - ltt.SetDashLengthAt(0, 0.5); //0.5个单位的划线 - ltt.SetDashLengthAt(1, -0.25); //0.25个单位的空格 - ltt.SetDashLengthAt(2, 0); // 一个点 - ltt.SetDashLengthAt(3, -0.25); //0.25个单位的空格 - }); - // 这段代码同时演示了 ifoxcad 类库关于符号表的public ObjectId Add(string name, Action action)这个函数的用法。 - // 或者直接调用: - tr.LinetypeTable.Add("hah", "虚线",0.95,new double[]{0.5,-0.25,0,-0.25}); - // 获取线型表 - tr.LinetypeTable["hah"]; - ``` - - **其他符号表的操作类同。如果类库没有提供的Add函数的重载,那么Action委托可以完成你想完成的所有事情。** - -## 基础属性操作 - -事务管理器类提供了`Document`、 `Editor` 、`Database`三个属性来在事务内部处理相关事项。 - -同时还提供了关于字典的相关属性。 - -## 对象获取操作 - -提供了1个泛型 `GetObject`函数的重载来根据ObjectId来获取到对象。 - -## 字典操作(未完待续) - -- 扩展字典 - - `SetXRecord` 保存扩展数据到字典 - - `GetXRecord ` 获取扩展数据 - -- 对象字典 - - `SetToDictionary` 保存数据到字典 - - `GetFromDictionary` 从字典获取数据 - - `GetSubDictionary` 获取子对象字典 diff --git a/docs/SelectionFilter.md b/docs/SelectionFilter.md deleted file mode 100644 index bc31b55c3c7d630bd238e99c76ba8e830b4210fe..0000000000000000000000000000000000000000 --- a/docs/SelectionFilter.md +++ /dev/null @@ -1,208 +0,0 @@ -# 选择集过滤器用法 - -## 选择集过滤器简介 - -桌子提供了选择集过滤器是为了更精确的选择对象。可以通过使用选择过滤器来限制哪些对象被选中并添加到选择集,选择过滤器列表通过属性或类型过滤所选对象。 - -在桌子的 .net api 中:选择过滤器由一对 TypedValue 参数构成。TypedValue 的第一个参数表明过滤器的类型(例如对象),第二个参数为要过滤的值(例如圆)。过滤器类型是一个 DXF 组码,用来指定使用哪种过滤器。 - -默认的使用桌子api来创建选择集(带过滤器)分三步: - -1. 创建一个TypedValue数组来定义过滤器条件 - - ```csharp - TypedValue[] acTypValAr = new TypedValue[1]; // 创建数组 - acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "CIRCLE"), 0); - // 添加一个过滤条件,例如选择圆 - - // 如果要创建多个过滤条件怎么办? - TypedValue[] acTypValAr = new TypedValue[3]; - acTypValAr.SetValue(new TypedValue((int)DxfCode.Color, 5), 0); - acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "CIRCLE"), 1); - acTypValAr.SetValue(new TypedValue((int)DxfCode.LayerName, "0"), 2); - // 实际上只要不停的往数组里添加条件就可以了 - ``` - -2. 创建SelectionFilter对象 - - ```csharp - // 将过滤器条件赋值给 SelectionFilter 对象 - SelectionFilter acSelFtr = new SelectionFilter(acTypValAr); - ``` - -3. 创建选择集 - - ```csharp - // 请求用户在图形区域选择对象 - PromptSelectionResult acSSPrompt; - acSSPrompt = acDocEd.GetSelection(acSelFtr); - ``` - -看起来很是简单对不对,单个条件和多个条件的过滤非常简单。当指定多个选择条件时,AutoCAD 假设所选对象必须满足每个条件。我们还可以用另外一种方式定义过滤条件。对于数值项,可以使用关系运算(比如,圆的半径必须大于等于 5.0)。对于所有项,可以使用逻辑运算(比如单行文字或多行文字)。使用 DXF 组码-4 或常量 DxfCode.Operator 表示选择过滤器中的关系预算符类型。运算符本身用字符串表示。 - -比如: - -1. 过滤半径大于等于5.0的圆 - - ```csharp - TypedValue[] acTypValAr = { - new TypedValue((int)DxfCode.Start, "CIRCLE"), - new TypedValue((int)DxfCode.Operator, ">="), - new TypedValue(40, 5) - }; - ``` - -2. 过滤单行文本或者多行文本 - - ```csharp - TypedValue[] acTypValAr = { - new TypedValue((int)DxfCode.Operator, "") - }; - ``` - -3. 更复杂的过滤条件呢?比如选择的对象为不是位于0图层的直线,或者位于2图层的组码10的x坐标>10,y坐标>10的非圆图元。 - - 对应的lisp代码如下: - - ```lisp - '((-4 . "") - (-4 . "not>") - (-4 . "") - (8 . "2") - (-4 . ">,>,*")(10 10 10 0) - (-4 . "and>") - (-4 . "or>")) - ``` - - 对应的c#代码: - - ```csharp - TypedValue[] acTypValAr = { - new TypedValue((int)DxfCode.Operator, ""), - new TypedValue((int)DxfCode.Operator, "not>"), - new TypedValue((int)DxfCode.Operator, ""), - new TypedValue((int)DxfCode.LayerName, "2"), - new TypedValue((int)DxfCode.Operator, ">,>,*"), - new TypedValue(10, new Point3d(10,10,0)), - new TypedValue((int)DxfCode.Operator, "and>"), - new TypedValue((int)DxfCode.Operator, "or>") - }; - ``` - - 这个过滤器是不是看起来很乱,一眼看去根本不知道是要过滤什么,写起来也很麻烦。所以说,虽然桌子提供了api,但是简单的过滤条件很好用,但是复杂的过滤条件就很复杂了。 - - 因此IFox内裤提供了关于选择集过滤器的辅助类来帮助用户用更简单的方式来创建选择集的过滤器。 - -## 内裤过滤器对象与cad过滤器对应关系 - -IFoxCad内裤对于DxfCode.Operator枚举构建了一些辅助函数来表达关系运算和逻辑运算;提供了dxf函数来表达组码。其对应的关系如下表: - -| 内裤过滤器对象、函数 | cad .net api 过滤器对象、函数、枚举 | 备注 | -|:----------:|:------------------------:|:-------------------:| -| OpFilter | SelectionFilter | 隐式转换 | -| OpOr | "" | | -| Op.Or | "" | | -| OpAnd | "" | | -| Op.And | "" | | -| OpNot | "" | | -| OpXor | "" | | -| OpEqual | 相等运算 | | -| OpComp | 比较运算符 | | -| Dxf() | 组码函数 | 仅用于过滤器中,不是组码操作函数 | -| ! | "" | | -| == | "=" | | -| != | "!=" | | -| > | ">" | | -| < | "<" | | -| >= | ">=" 或 ">,>,*" | ">,>,*"用于跟point3d比较 | -| <= | "<=" 或 "<,<,*" | "<,<,*"用于跟point3d比较 | -| & | "" | | -| ^ | "" | | -| \| | "" | | - -## 具体用法 - -IFoxCad内裤提供了三种方式来构建过滤器,其实大同小异,就是写法不一样,用户可以根据自己的喜好来选择。 - -- 第一种 - - ```csharp - var fd = - new OpOr //定义一个 (-4 . "") - { - !new OpAnd //定义(-4 . "")(-4 . "not>") - { - { 0, "line" }, //{组码,组码值} - { 8, "0" }, //{组码,组码值} - }, - new OpAnd //定义(-4 . "") - { - !new OpEqual(0, "circle"), //定义(-4 . "") - { 8, "2" }, //{组码,组码值} - { 10, new Point3d(10,10,0), ">,>,*" } //(-4 . ">,>,*")(10 10 10 0) - }, - }; - editor.SelectAll(fd); //这里直接传入fd就可以了 - ``` - - 以上代码的含义为:选择的对象为不是位于0图层的直线,或者位于2图层的组码10的x坐标>10,y坐标>10的非圆图元。其同含义的lisp代码如下: - - ```lisp - '((-4 . "") - (-4 . "not>") - (-4 . "") - (8 . "2") - (-4 . ">,>,*")(10 10 10 0) - (-4 . "and>") - (-4 . "or>")) - ``` - -- 第二种 - - ```csharp - var p = new Point3d(10, 10, 0); - var f = OpFilter.Bulid(e => - !(e.Dxf(0) == "line" & e.Dxf(8) == "0") - | e.Dxf(0) != "circle" - & e.Dxf(8) == "2" - & e.Dxf(10) >= p); - editor.SelectAll(f); //这里直接传入f就可以了 - ``` - - 代码含义如第一种。 - -- 第三种 - - ```csharp - var f2 = OpFilter.Bulid( - e =>e.Or( - !e.And(e.Dxf(0) == "line", e.Dxf(8) == "0"), - e.And(e.Dxf(0) != "circle", e.Dxf(8) == "2", e.Dxf(10) >= new Point3d(10, 10, 0))) - ); - editor.SelectAll(f2); //这里直接传入f2就可以了 - ``` - - 代码含义如第一种,第三种和第二种的写法非常像,区别就是关于 and 、or 、not 等运算符,一个是采用c#的语法,一个是采用定义的函数。and 与&等价,or与|等价,not 与!等价。 \ No newline at end of file diff --git a/docs/SymbolTable.md b/docs/SymbolTable.md deleted file mode 100644 index a5144baea56a722688da09f929cfd04e9d243ed7..0000000000000000000000000000000000000000 --- a/docs/SymbolTable.md +++ /dev/null @@ -1,146 +0,0 @@ -# 符号表用法 - -每个图形文件都包含有9个固定的符号表。不能往数据库里添加新的符号表。如图层表(LayerTable),其中包含图层表记录,还有块表(BlockTable),其中包含块表记录等。所有的图形实体(线、圆、弧等等)都属于一个块表记录。缺省情况下,任何图形文件都包含为模型空间和图纸空间预定义的块表记录。每个符号表都有对应的符号表记录,可以理解为符号表是一个集合,而符号表记录是这个集合的元素。CAD的符号表和符号表记录的对应关系如下: - -| 名称 | 符号表 | 符号表记录 | -|:-------:|:--------------:|:--------------------:| -| 块表 | BlockTable | BlockTableRecord | -| 标注样式表 | DimStyleTable | DimStyleTableRecord | -| 图层表 | LayerTable | LayerTableRecord | -| 线型表 | LinetypeTable | LinetypeTableRecord | -| 注册应用程序表 | RegAppTable | RegAppTableRecord | -| 字体样式表 | TextStyleTable | TextStyleTableRecord | -| 坐标系表 | UcsTable | UcsTableRecord | -| 视口表 | ViewportTable | ViewportTableRecord | -| 视图表 | ViewTable | ViewTableRecord | - -那么如何来操作这些符号表呢?下面是一个新建图层的例子: - -```csharp -Document acDoc = Application.DocumentManager.MdiActiveDocument; -Database acCurDb = acDoc.Database; -using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction()) -{ - // 返回当前数据库的图层表 - LayerTable acLyrTbl = acTrans.GetObject(acCurDb.LayerTableId,OpenMode.ForRead) as LayerTable; - // 检查图层表里是否有图层 MyLayer - if (acLyrTbl.Has("MyLayer") != true) - { - // 以写模式打开图层表 - acLyrTbl.UpgradeOpen(); - // 新创建一个图层表记录,并命名为”MyLayer” - LayerTableRecord acLyrTblRec = new LayerTableRecord(); - acLyrTblRec.Name = "MyLayer"; - // 添加新的图层表记录到图层表,添加事务 - acLyrTbl.Add(acLyrTblRec); - acTrans.AddNewlyCreatedDBObject(acLyrTblRec, true); - //提交修改 - acTrans.Commit(); - } - // 关闭事务,回收内存; -} -``` - -上面的例子用了20多行的代码来完成一个很简单的功能,这就是AutoCAD提供的api太过于基础,没有进行进一步的封装造成。那么如果我们单独为图层表封装一个函数来处理图层表,其他的8个符号表也要同样的各自封装函数,这样看起来没什么问题,但是对于代码的复用却没有很好的考虑进去。仔细思考一下,其实对于符号来说无非就是增删改三个主要的操作等,对于符号表记录来说无非就是一些属性的操作,增加实体的操作等。那么有没有一种办法可以统一管理9个符号表呢?其实AutoCAD提供了9个符号表和符号表记录的抽象基类,SymbolTable和SymbolTableRecord,但是这两个类提供的功能又很简单,只有寥寥几个函数和属性,完全不能满足我们的需求。因此ifoxcad内裤提供了符号表类来封装9个符号表的大部分功能。那么用内裤来完成上述的操作是什么样子的呢?见下面的例子: - -```csharp -// 以下代码采用最新的c#版本语法 -using var tr = new DBTrans(); // 打开事务 -var layertable = tr.LayerTable.Add("MyLayer"); //添加图层 -``` - -同样的功能我们只需要两行就可以搞定了。那么有同学会问了,我同样单独对每个符号表的封装一样可以达到这个效果?是的,确实可以达到一样的效果,但是我只封装了一次,只是针对符号表的差异部分做了一些增量的处理,其他的代码都是复用的,而你要写9次。 - -言归正传,通过上述的例子,我们会发现几个现象: - -1. 符号表的操作是在事务内。 -2. 符号表成了事务的属性 -3. 添加符号表记录到符号表调用Add函数就可以了(其实提供了好多的重载,来完成不同的细粒度的操作)。 - -符号表的操作都在事务内,这样由事务统一管理符号表的变动,减少出错的可能。 - -符号表作为事务的属性,那么获取符号表记录就变成了属性的索引值。`var layertable = tr.LayerTable["MyLayer"];` - -不管是什么符号表,都是一个Add函数搞定添加操作。 - -而删除就是:`tr.LayerTable.Remove("1");` *注意,这里的关于删除图层的操作需要调用Delete函数* - -看,我教会了你操作图层表,那么其他的8个表你都会了,都是一样的操作。 - -## 块表添加图元 - -一般的情况下,添加图元的操作都是要在事务里完成。目前大部分的添加图元的自定义函数都是DataBase或Editor对象的扩展函数。但是实际上添加图元的本质是读写图形数据库,具体的手段是对块表里的块表记录的读写。而实际的操作其实都是在事务里完成,所以符合cad操作规则的写法其实应该是事务作为一系列操作的主体来进行。因此ifoxcad内裤的封装思路为:扩展块表记录的函数,在事务管理器类里通过属性调用AddEntity函数来添加图元。 - -对于这个添加图元的操作,一共分为如下几步: - -1. 创建图元对象,可以在事务外创建,也可以在事务内创建。 -2. 打开要添加图元的块表记录,在事务内打开。 -3. 添加图元到块表记录 - -下面看示例: - -- 添加图元到当前空间 - - ```csharp - // 以下代码采用最新的c#版本语法 - using var tr = new DBTrans(); //开启事务管理器 - var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); //定义一个直线 - tr.CurrentSpace.AddEntity(line1); // 将直线添加到当前绘图空间的块表记录 - ``` - -- 添加图元到模型/图纸空间 - - ```csharp - // 以下代码采用最新的c#版本语法 - using var tr = new DBTrans(); //开启事务管理器 - var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); //定义一个直线 - tr.CurrentSpace.AddEntity(line1); // 将直线添加到当前绘图空间的块表记录 - tr.ModelSpace.AddEntity(line1); // 将直线添加到当前模型空间的块表记录 - tr.PaperSpace.AddEntity(line1); // 将直线添加到当前图纸空间的块表记录 - ``` - -- 添加图元到块表 - - ```csharp - // 以下代码采用最新的c#版本语法 - using var tr = new DBTrans(); //开启事务管理器 - var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); //定义一个直线 - var btr = tr.BlockTable.Add("test"); //定义一个块表记录 - btr.AddEntity(line1); // 将直线添加到当前控件的块表记录 - ``` - - 那么大家猜一猜,这个添加到块表是实现了一种什么样的功能。 - -- 块表 - - 块表这里需要特殊的说明一下: - - 比如说添加一个块,用如下代码: - - `tr.BlockTable.Add(blockName, btr => btr.AddEntity(ents));` - - 这里的blockName就是块名,ents就是图元列表。这种方式虽然可以更细粒度的控制定义的块。 - - 插入块参照,比如: - - `tr.InsertBlock(point,objectid); // 用于插入块参照,提供了重载函数来满足不同的需求` - -- 其他函数的介绍 - - `tr.BlockTable.GetRecord()` 函数,可以获取到块表的块表记录,同理层表等符号表也有同样的函数。 - - `tr.BlockTable.GetRecordFrom()` 函数,可以从文件拷贝块表记录,同理层表等符号表也有同样的函数。 - - `tr.BlockTable.GetBlockFrom()` 函数,从文件拷贝块定义,同理层表等符号表也有同样用途的函数。 - -- 添加图元函数 - - 内裤提供了一些便利的添加图元函数,可以不用先定义一个entity对象,然后添加到块表记录。 - - ```csharp - using var tr = new DBTrans(); - tr.CurrentSpace.AddLine(new Point3d(0,0,0),new Point3d(1,1,0)); - tr.CurrentSpace.AddCircle(new Point3d(0,0,0),10); - ``` - - diff --git a/docs/WPF.md b/docs/WPF.md deleted file mode 100644 index 73f4f1116be4ef9cff68117b0f2fd86acf32d382..0000000000000000000000000000000000000000 --- a/docs/WPF.md +++ /dev/null @@ -1,353 +0,0 @@ - - -# WPF支持 - -在项目文件里将``替换为``。 - -在``标签里的`NET45`下面添加: -```xml -true -true -``` - -最后的项目文件如下: - -```xml - - - net47 - - true - - true - - - -``` - -# mvvm模式支持 - -## 一、简单mvvm的实现 - -使用WPF的最佳实践就是采用mvvm模式,为了支持在cad插件里使用mvvm,ifoxcad内裤定义了两个简单基类来完成属性通知和命令定义。当然这是一种及其简单的mvvm模式的支持,你还要自己手动来写大部分的代码来实现完整的mvvm模式。 - -要实现mvvm模式,要新建一个XXXView文件,一个XXXViewModel文件。我们应该采用一种通用的命名约定,即所有的gui显示都有XXXView来完成,而所有的业务逻辑都由XXXViewModel来完成。下面以一个具体的示例来说明怎么在cad的插件里使用mvvm模式。 - -1. 将我们上一节建立的MyWindow1文件改名为MyWindowView,然后将涉及到的类名也全部更改为MyWindowView。 - -2. 然后将MyWindowView.xaml文件的内容改为: - -```xaml - - - - - - - - -``` - -就是添加了一个文本框,一个按钮。 - -3. 新建MyWindowViewModel.cs文件,内容如下: - -```c# -using IFoxCad.WPF; // 这里引入IFoxCad.WPF命名空间,以便可以使用ViewModelBase和RelayCommand - -namespace Test -{ - class MyWindowViewModel : ViewModelBase - { - // 定义一个属性用于在文本框里显示 - private string _name; - public string Name - { - get { return _name; } - set - { - Set(ref _name, value); - } - } - - // 定义一个命令用于按钮的点击动作 - private RelayCommand clickCommand; - public RelayCommand ClickCommand - { - get - { - if (clickCommand == null) - { - clickCommand = new RelayCommand( - execute => Name = "hello " + Name, // 定义要执行的行为 - can => {return !string.IsNullOrEmpty(Name);}); // 定义命令是否可用 - } - return clickCommand; - } - } - // 初始化Name属性为 World - public MyWindowViewModel() - { - Name = "World"; - } - } -} - -``` - -这里需要注意的是,定义的属性是为了将属性绑定到文本框的Text属性上,这个叫做数据绑定。然后wpf里对于我们winform里的事件其实采用的更高级一些的命令来完成。本示例,定义的命令也是一个属性,这个属性返回一个RelayCommand对象的实例,这是实例的初始化函数包括两个部分,一个是要执行的动作,第二个是确定什么条件下按钮是不可用的,这个是通过命令是否可用来完成,是要命令是不能执行的,wpf会自动将控件切换为不可用状态,使其不可点击。 - -4. 现在回过头来对在xaml里将刚刚的viewmodel里定义的属性和命令绑定到控件上。 - -```xaml - - -``` - -将这两行代码替换一下。然后在后台代码里(MyWindowView.xaml.cs)添加一行代码将viewmodel绑定到view上。 - -```c# -public MyWindowView() -{ - InitializeComponent(); - DataContext = new MyWindowViewModel(); //这里将一个viewmodel的实例绑定到view的DataContext属性上。 -} -``` - -5. 至此,一个简单的wpf的mvvm模式的代码就完成了,下面的代码演示了怎么在cad里显示这个wpf窗体。 - -```c# -[CommandMethod("test")] -public void Test() -{ - var test = new MyWindowView(); - Application.ShowModalWindow(test); -} -``` - -6. 最后,这个窗体的效果是,当你点击按钮时,文本框的文字前面会加上hello。当你将文本框的文字全部删除后,按钮会变成不可用状态。如果你在试验的时候没有这个效果,这是cad的延迟导致的。多删除几次试几次后就会如期运行。 - -## 二、mvvm中的事件处理 - -在WPF里,并不是所有的控件都提供了commad属性用于绑定命令,所以还是需要进行控件的事件处理的,比如窗口的Loaded事件,鼠标事件,键盘事件等。关于WPF的事件处理,IFoxCad内裤提供了两种方式进行处理,一种就是利用 **Microsoft.Xaml.Behaviors.dll** 这个类库,利用了 **i:Interaction.Triggers** 标签在xaml文件里将命令绑定到事件上,这种方式是网上比较常见的一种方式;第二种是自定义了一个xaml标签 **eb:EventBinding** ,利用这个标签将命令绑定到事件上。两种方式实现的效果是一样的,但是 **eb:EventBinding** 标签绑定的方式的代码量要小一些。 - -下面就两种方式实现同一种事件处理的效果提供了两种方式的代码示例作为说明。由于两种方式的差异主要在xaml文件里,ViewModel的代码是一样的。因此主要讲述两种xaml的差异部分,ViewModel的代码直接贴在下面不做讲解。 - -```c# -public class TestViewModel : ViewModelBase -{ - - private bool _IsReceiveMouseMove = true; - public bool IsReceiveMouseMove - { - get { return _IsReceiveMouseMove; } - set - { - Set(ref _IsReceiveMouseMove, value); - } - } - - private string _tipText; - public string TipText - { - get { return _tipText; } - set - { - Set(ref _tipText, value); - } - } - - - - private RelayCommand loadedCommand; - - public RelayCommand LoadedCommand - { - get - { - if (loadedCommand == null) - { - loadedCommand = new RelayCommand(execute => MessageBox.Show("程序加载完毕!")); - - } - return loadedCommand; - } - - } - - private RelayCommand mouseMoveCommand; - public RelayCommand MouseMoveCommand - { - get - { - if (mouseMoveCommand == null) - { - mouseMoveCommand = - new RelayCommand( - e => - { - var point = e.GetPosition(e.Device.Target); - var left = "左键放开"; - var mid = "中键放开"; - var right = "右键放开"; - - if (e.LeftButton == MouseButtonState.Pressed) - { - left = "左键放下"; - } - if (e.MiddleButton == MouseButtonState.Pressed) - { - mid = "中键放下"; - } - if (e.RightButton == MouseButtonState.Pressed) - { - right = "右键放下"; - } - - TipText = $"当前鼠标位置 X:{point.X} Y:{point.Y} 当前鼠标状态:{left} {mid} {right}."; - }, - o => IsReceiveMouseMove); - } - return mouseMoveCommand; - } - } -} -``` - -### 2.1 自定义标签的方式 - -首先是在xaml里引入命名空间。 - -`xmlns:eb="clr-namespace:IFoxCAD.WPF;assembly=IFoxCAD.WPF"` - -然后 - -`Loaded="{eb:EventBinding Command=LoadedCommand}"` - -`MouseMove="{eb:EventBinding Command=MouseMoveCommand,CommandParameter=$e}"` 这里要注意的是显式的传入了鼠标移动事件的参数。 - -注意命令参数部分,如果这个事件是带参数的,或者说这个命令是带参数的,要传入参数。 - -关于命令及命令参数使用方式如下: - -- Command - 1. `{eb:EventBinding}` 利用简单的名字匹配来自动搜寻命令,也就是说不用指定命令名,不是很推荐。 - 2. `{eb:EventBinding Command=CommandName}` 指定命令名,建议总是使用这种方式 - -- CommandParameter - 1. `$e` (事件参数,这里特指的是事件本身带的参数,也就是你以前写事件的处理函数时候的XXXXEventArgs e这个参数) - 2. `$this` or ​`$this.Property` (view本身或者属性) - 3. `string` (要传入的字符串) - -完整的xaml代码如下: - -```xaml - - - - - -``` - -### 2.2 利用Behaviors的方式 - -首先nuget安装**Microsoft.Xaml.Behaviors.Wpf**包。 - -然后在xaml文件里,引入命名空间。 - -`xmlns:eb="clr-namespace:IFoxCad.WPF;assembly=IFoxCad"` - -`xmlns:i="http://schemas.microsoft.com/xaml/behaviors"` - -然后绑定命令到事件上: - -```xaml - - - - - - - - -``` - -细心的同学可能会发现绑定命令的地方标签是不一样的。 - -**i:InvokeCommandAction** 这个标签是由 **Microsoft.Xaml.Behaviors.Wpf** 包提供的。 - -**eb:EventCommand** 这个标签是由IFoxCad内裤提供的。 - -两者的区别就是InvokeCommandAction 是不能传入事件的参数的,所以为了处理事件参数自定义了EventCommand。就如同上面的鼠标移动事件,是有时间参数要处理的,所以用了自定义的EventCommand,虽然xaml文件里没有显式的传入这个参数。 - -虽然InvokeCommandAction这个标签的后面是可以带命令参数的,比如: - -```xaml - - - - - -``` - -但是这个命令参数是不能处理事件自带的参数的 。 - -最后是完整的xaml代码: - -```xaml - - - - - - - - - - - - - - -``` - -### 2.3 关于两种方式的选择 - -送给选择困难症的:如果可以选择自定义标签的方式,简单一些。遇到问题解决不了,就用behaviors的方式,网上的资源丰富一些,也许能找到你的答案。 - -## 三、 关于mvvm模式的建议 - -我们并不推荐严格的mvvm模式,主要原因是要引入比如message模式等方式处理类似窗口关闭,窗口间通信等问题。鉴于cad插件的界面复杂程度还没到后台事件满天飞,逻辑复杂的地步,因此后台写点事件处理,界面和后逻辑混在一起也未尝不可。 - -仅仅是建议,你爱怎样就怎样。 - diff --git a/docs/autoreg.md b/docs/autoreg.md deleted file mode 100644 index 72f377c24b7129336ebfa5a8e22f55fbc57697c5..0000000000000000000000000000000000000000 --- a/docs/autoreg.md +++ /dev/null @@ -1,62 +0,0 @@ -## 自动加载与初始化 - -### 1、简单版 - -为了将程序集的初始化和通过写注册表的方式实现自动加载统一设置,减少每次重复的工作量,类裤提供了`AutoLoad`抽象类来完成此功能,只要在需要初始化的类继承`AutoLoad`类,然后实现`Initialize()` 和 `Terminate()` 两个函数就可以了。 -特别强调的是,一个程序集里只能有一个类继承,不管是不是同一个命名空间。 - -如果要将dll的目录加入支持文件目录,请在 `Initialize` 函数中调用`AppendSupportPath(CurrentDirectory.FullName);` - -其他需要初始化执行的函数及设置都需要在 `Initialize` 函数中执行。 - -### 2、功能版 - -使用特性进行分段初始化是目前最佳选择,下面的说明已和最新版本不符,等待修正吧。 - -```csharp - using Autodesk.AutoCAD.Runtime; - using IFoxCAD.Cad; - using System; - using System.Reflection; - -/* - * 自动执行接口 - * 这里必须要实现一次这个接口,才能使用 IFoxInitialize 特性进行自动执行 - */ -public class CmdINI : AutoRegAssem -{ - // 这里可以写任何普通的函数,也可以写下面 AutoTest 类里的实现了 IFoxInitialize 特性的初始化函数 - // 继承AutoRegAssem的主要作用是写注册表用来自动加载dll,同时执行实现了 IFoxInitialize 特性的函数 - // 注意这里的自动执行是在cad启动后,加载了dll之后执行,而不是运行命令后执行。 - - [IFoxInitialize] - public void InitOne() - { - // TODO 您想在加载dll之后自动执行的函数 - // 可以随便在哪里类里 可以多次实现 IFoxInitialize 特性 - } - -} - -// 其他的类中的函数: -// 实现自动接口之后,在任意一个函数上面使用此特性,减少每次改动 CmdINI 类 -public class AutoTest -{ - [IFoxInitialize] - public void Initialize() - { - // TODO 您想在加载dll之后自动执行的函数 - } - [IFoxInitialize] - public void InitTwo() - { - // TODO 您想在加载dll之后自动执行的函数 - // 可以随便在哪里类里 可以多次实现 IFoxInitialize 特性 - } - [IFoxInitialize(isInitialize: false)] // 特性的参数为false的时候就表示卸载时执行的函数 - public void Terminate() - { - // TODO 您想在关闭cad时自动执行的函数 - } -} -``` diff --git "a/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png" "b/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png" deleted file mode 100644 index a9d08c483b80f21d4b0ac6a0afe80f9b6b4233e6..0000000000000000000000000000000000000000 Binary files "a/docs/png/ifoxcad\347\224\250\346\210\267\344\272\244\346\265\201\347\276\244\347\276\244\344\272\214\347\273\264\347\240\201.png" and /dev/null differ diff --git a/docs/png/nuget.png b/docs/png/nuget.png deleted file mode 100644 index d0af980fedd9eca39d0e0bf787111685242994ac..0000000000000000000000000000000000000000 Binary files a/docs/png/nuget.png and /dev/null differ diff --git a/docs/png/nuget1.png b/docs/png/nuget1.png deleted file mode 100644 index 91983ffef3b246ea796296b14fe09963663de184..0000000000000000000000000000000000000000 Binary files a/docs/png/nuget1.png and /dev/null differ diff --git a/docs/png/standard.png b/docs/png/standard.png deleted file mode 100644 index dfc34fecb32120f54436115208a4abaea2dac516..0000000000000000000000000000000000000000 Binary files a/docs/png/standard.png and /dev/null differ diff --git "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" index f96d39d487c1f6c2af8a2f3257fa3cc3bbfd619d..ee3a985ec0fb36b41e94505d3f8f96379e1c029b 100644 --- "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" +++ "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" @@ -71,42 +71,30 @@ IFoxCAD是基于NFOX类库的重制版,主要是提供一个最小化的内核 ## 一、组织结构图 - IFoxCAD - - - IFoxCAD.Basal - cad以外常用的类库 - - - LinqEx - linq扩展类 - - - LoopList - 环链表 - - - IFoxCAD.Cad - cad相关的类库 - - - Runtime - 包含系统级别的功能 - - - AcadVersion - cad版本号类 - - AssemInfo - 程序集信息 - - AutoRegAssem - 程序集加载类型 - - DBTrans - 事务处理类 - - Env - 系统管理类 - - SymbolTable - 符号表类 - - - ExtensionMethod - 扩展函数,以Ex结尾 - - - SymbolTableEx - 符号表扩展类 - - SymbolTableRecordEx - 符号表记录扩展类 - - EntityEx - 实体扩展类 - - 。。。。。。 - - - ResultData - - - 待补充。。。 - - - SelectionFilter +``` +├───bin -- 用于放置生成的nuget包和dll +├───docs -- 架构及api定义说明文档 +├───src -- 源码目录 +│ ├───CADShared -- 共享项目,所有的代码都在这里 +│ │ ├───Algorithms -- 基础算法和数据结构 +│ │ ├───Assoc -- 关联函数 +│ │ ├───Basal -- 一些基础类的函数 +│ │ ├───ExtensionMethod -- 扩展函数 +│ │ ├───Initialize -- 初始化 +│ │ ├───PE -- PE +│ │ ├───ResultData -- 扩展数据 +│ │ ├───Runtime -- 核心类 +│ │ └───SelectionFilter -- 选择集过滤器类 +│ ├───IFoxCAD.AutoCad -- AutoCAD的类库,内部除了globalusing外无其他代码 +│ └───IFoxCAD.ZwCad -- AutoCAD的类库,内部除了globalusing外无其他代码 +└───tests -- 测试类 + ├───TestAcad2025 -- autocad测试 + ├───TestShared -- 共享项目,所有的测试代码都在这里 + └───TestZcad2025 -- zwcad测试 - - 待补充。。。 - - - IFoxCAD.WPF - wpf的mvvm模式相关的类库 - - ## 二、关于DBTrans类的说明 + ``` + +## 二、关于DBTrans类的说明 ### 2.1 为什么要构建DBTrans类? @@ -128,17 +116,18 @@ DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的 属性: -- Top ---返回当前事务 +- Top ---返回当前DBTrans对象 - Database ---数据库 - Document ---文档 - Editor ---命令行 -- Trans ---事务管理器 +- Transaction ---事务 构造函数: -- DBTrans(Document doc = null, bool commit = true) +- DBTrans(Document? doc = null, bool commit = true, bool docLock = false) - DBTrans(Database database, bool commit = true) -- DBTrans(string fileName, bool commit = true) +- DBTrans(string fileName, bool commit = true, FileOpenMode fileOpenMode = FileOpenMode.OpenForReadAndWriteNoShare, + string? password = null, bool activeOpen = false) 符号表: @@ -152,10 +141,27 @@ DBTrans的每个实例都具有这些属性,而这些属性就对应于cad的 - ViewTable 视图表 - ViewportTable 视口表 +字典: + +- NamedObjectsDict 命名对象字典 +- GroupDict 组字典 +- MLeaderStyleDict 多重引线样式字典 +- MLStyleDict 多线样式字典 +- MaterialDict 材质字典 +- TableStyleDict 表格样式字典 +- VisualStyleDict 视觉样式字典 +- ColorDict 颜色字典 +- PlotSettingsDict 打印设置字典 +- PlotStyleNameDict 打印样式表名字典 +- LayoutDict 布局字典 +- DataLinkDict 数据链接字典 +- DetailViewStyleDict 详细视图样式字典 +- SectionViewStyleDict 剖面视图样式字典 + 方法: - GetObject ---根据对象id获取图元对象 -- 。。。 +- Task 前台后台任务分别处理 接口: diff --git "a/docs/\345\205\263\344\272\216\346\211\251\345\261\225\345\207\275\346\225\260\347\232\204\350\257\264\346\230\216.md" "b/docs/\345\205\263\344\272\216\346\211\251\345\261\225\345\207\275\346\225\260\347\232\204\350\257\264\346\230\216.md" deleted file mode 100644 index 41d9336e6e47afa45e72ad28de9cc455d510d320..0000000000000000000000000000000000000000 --- "a/docs/\345\205\263\344\272\216\346\211\251\345\261\225\345\207\275\346\225\260\347\232\204\350\257\264\346\230\216.md" +++ /dev/null @@ -1,15 +0,0 @@ -# 关于扩展函数的说明 - -## 一、命名规则 - -扩展函数全部都放在 **ExtensionMethod** 文件夹里。 - -然后每个类别都需要分别建立一个以EX为结尾的文件。比如: - -DBObjectEx 实体对象扩展类 - -SymbolTableRecordEx 实体对象扩展类 - -EditorEx.cs 表示关于命令的扩展 - -![输入图片说明](https://images.gitee.com/uploads/images/2021/0701/225314_5b34dd8d_9063830.png "屏幕截图.png") diff --git a/readme.md b/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..1e9570c669295da03aa67b9dc0d74958db582b66 --- /dev/null +++ b/readme.md @@ -0,0 +1,49 @@ +# IFoxCAD 说明 + +基于.NET的Cad二次开发类库。 + +#### 一、项目来源 + +起初 **雪山飞狐(又狐哥)** 在明经论坛发布了[开源库](http://bbs.mjtd.com/thread-75701-1-1.html),后来狐哥自己的项目进行了极大的丰富后形成NFox类库。然后 **落魄山人** 在征得 雪山飞狐的同意后,对NFox类库进行了整理,增加了注释等,重新发布了NFox类库。 + +后来,经过一段时间的更新后,由于莫名其妙的原因NFox类库挂掉了。而这时山人同学已经基本吃透NFox类库,考虑到NFox的封装过于复杂,遂进行了重构。 + +重构的类库命名为IFoxCAD, 寓意为:**I(爱)Fox(狐哥)**,本项目发布于**Inspire Function(中文名:跃动方程)** 组织下,感谢 **小轩轩** 给起的名字。 + +可以加群交流: + +[点击链接加入群聊【IFoxCad交流群】](https://qm.qq.com/q/tJZELgdzHi) + + **QQ群为丐群,所以也可以加入qq频道交流:** + +[点击链接加入QQ频道【CAD二次开发】](https://pd.qq.com/s/2wmmkv4c2) + +#### 二、 使用帮助 + +IFoxCAD的项目文档请看 **[IFoxCAD类库从入门到精通](https://www.kdocs.cn/l/cc6ZXSa0vMgD)**。 + +IFoxCAD的API文档请看 **[IFoxCAD API 文档](https://inspirefunction.github.io/ifoxdoc/)**。**请注意这个网站需要科学浏览** + + +#### 三、IFoxCad 项目模版 + +目前由于IFoxCad的版本分为0.5、0.6、0.7三个大的版本同时在发布,所以项目模版分为两个主要的版本: + +- vs模版插件 +- net项目模版 + +建议使用net项目模版来创建项目,具体的区别可以去上面的文档里查看 **[4.4 IFoxCad 项目模版](https://kdocs.cn/l/cc6ZXSa0vMgD?linkname=ulYcRm6f9a)** + +#### 四、使用IFoxCad的几种方式 + +目前IFoxCad的几种使用方式: +**[4.5 使用IFoxCad的几种方式](https://kdocs.cn/l/cc6ZXSa0vMgD?linkname=mhBJO1Vchu)** + +#### 五、参与项目的方式 + +期待你的参与,你可以做如下的工作来帮助IFoxCad发展: + +- 如果你在使用的过程中发现IFoxCad的某些不足或者bug,你可以在 [项目issues](https://gitee.com/inspirefunction/ifoxcad/issues) 里提交issue来供开发人员进行完善。 +- 帮助开发人员编写使用文档,文档地址见 **[IFoxCAD类库从入门到精通](https://www.kdocs.cn/l/cc6ZXSa0vMgD)** +- fork本项目,修复bug,增加功能,并提交pr。 + diff --git a/src/Basal/Directory.Build.props b/src/Basal/Directory.Build.props deleted file mode 100644 index 77a2d3711db05b158825e750d59ed1f4f864e9a9..0000000000000000000000000000000000000000 --- a/src/Basal/Directory.Build.props +++ /dev/null @@ -1,37 +0,0 @@ - - - - 0.5.2.4 - 完善源码包,源码包映射原始目录 - - - - preview - enable - true - ..\..\..\bin\$(Configuration)\ - true - true - True - True - - - - - - InspireFunction - xsfhlzh;vicwjb;liuqihong - InspireFunction - 基于.NET的二次开发基本类库. - MIT - true - https://gitee.com/inspirefunction/ifoxcad - https://gitee.com/inspirefunction/ifoxcad.git - git - IFox;C#;NET;Common;Basal - - - - - - \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/CLS/Index.cs b/src/Basal/IFox.Basal.Shared/CLS/Index.cs deleted file mode 100644 index b84f4dffd68334952188669e6fa487d76dcb89d0..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/CLS/Index.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -#if !NOINDEX -namespace System; - - -#if NET45 -using System.Runtime.CompilerServices; -#endif -/// Represent a type can be used to index a collection either from the start or the end. -/// -/// Index is used by the C# compiler to support the new index syntax -/// -/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 } ; -/// int lastElement = someArray[^1]; // lastElement = 5 -/// -/// -public readonly struct Index : IEquatable -{ - private readonly int _value; - - /// Construct an Index using a value and indicating if the index is from the start or from the end. - /// The index value. it has to be zero or positive number. - /// Indicating if the index is from the start or from the end. - /// - /// If the Index constructed from the end, index value 1 means pointing at the last element and index value 0 means pointing at beyond last element. - /// -#if NET45 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public Index(int value, bool fromEnd = false) - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); - } - - if (fromEnd) - _value = ~value; - else - _value = value; - } - - // The following private constructors mainly created for perf reason to avoid the checks - private Index(int value) - { - _value = value; - } - - /// Create an Index pointing at first element. - public static Index Start => new(0); - - /// Create an Index pointing at beyond last element. - public static Index End => new(~0); - - /// Create an Index from the start at the position indicated by the value. - /// The index value from the start. -#if NET45 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public static Index FromStart(int value) - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); - } - - return new Index(value); - } - - /// Create an Index from the end at the position indicated by the value. - /// The index value from the end. -#if NET45 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public static Index FromEnd(int value) - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative"); - } - - return new Index(~value); - } - - /// Returns the index value. - public int Value - { - get - { - if (_value < 0) - return ~_value; - else - return _value; - } - } - - /// Indicates whether the index is from the start or the end. - public bool IsFromEnd => _value < 0; - - /// Calculate the offset from the start using the giving collection length. - /// The length of the collection that the Index will be used with. length has to be a positive value - /// - /// For performance reason, we don't validate the input length parameter and the returned offset value against negative values. - /// we don't validate either the returned offset is greater than the input length. - /// It is expected Index will be used with collections which always have non negative length/count. If the returned offset is negative and - /// then used to index a collection will get out of range exception which will be same affect as the validation. - /// -#if NET45 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - public int GetOffset(int length) - { - int offset = _value; - if (IsFromEnd) - { - // offset = length - (~value) - // offset = length + (~(~value) + 1) - // offset = length + value + 1 - - offset += length + 1; - } - return offset; - } - - /// Indicates whether the current Index object is equal to another object of the same type. - /// An object to compare with this object - public override bool Equals(object? value) => value is Index index && _value == index._value; - - /// Indicates whether the current Index object is equal to another Index object. - /// An object to compare with this object - public bool Equals(Index other) => _value == other._value; - - /// Returns the hash code for this instance. - public override int GetHashCode() => _value; - - /// Converts integer number to an Index. - public static implicit operator Index(int value) => FromStart(value); - - /// Converts the value of the current Index object to its equivalent string representation. - public override string ToString() - { - if (IsFromEnd) - return "^" + ((uint)Value).ToString(); - - return ((uint)Value).ToString(); - } -} - -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/CLS/Range.cs b/src/Basal/IFox.Basal.Shared/CLS/Range.cs deleted file mode 100644 index 0318216b8a9dc01a2712633037053f66bdf83c07..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/CLS/Range.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -#if !NORANGE -namespace System; - - - -#if NET45 -using System.Runtime.CompilerServices; -#endif - -/// Represent a range has start and end indexes. -/// -/// Range is used by the C# compiler to support the range syntax. -/// -/// int[] someArray = new int[5] { 1, 2, 3, 4, 5 }; -/// int[] subArray1 = someArray[0..2]; // { 1, 2 } -/// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 } -/// -/// -public readonly struct Range : IEquatable -{ - /// Represent the inclusive start index of the Range. - public Index Start { get; } - - /// Represent the exclusive end index of the Range. - public Index End { get; } - - /// Construct a Range object using the start and end indexes. - /// Represent the inclusive start index of the range. - /// Represent the exclusive end index of the range. - public Range(Index start, Index end) - { - Start = start; - End = end; - } - - /// Indicates whether the current Range object is equal to another object of the same type. - /// An object to compare with this object - public override bool Equals(object? value) => - value is Range r && - r.Start.Equals(Start) && - r.End.Equals(End); - - /// Indicates whether the current Range object is equal to another Range object. - /// An object to compare with this object - public bool Equals(Range other) => other.Start.Equals(Start) && other.End.Equals(End); - - /// Returns the hash code for this instance. - public override int GetHashCode() - { - return Start.GetHashCode() * 31 + End.GetHashCode(); - } - - /// Converts the value of the current Range object to its equivalent string representation. - public override string ToString() - { - return Start + ".." + End; - } - - /// Create a Range object starting from start index to the end of the collection. - public static Range StartAt(Index start) => new(start, Index.End); - - /// Create a Range object starting from first element in the collection to the end Index. - public static Range EndAt(Index end) => new(Index.Start, end); - - /// Create a Range object starting from first element to the end. - public static Range All => new(Index.Start, Index.End); - - /// Calculate the start offset and length of range object using a collection length. - /// The length of the collection that the range will be used with. length has to be a positive value. - /// - /// For performance reason, we don't validate the input length parameter against negative values. - /// It is expected Range will be used with collections which always have non negative length/count. - /// We validate the range is inside the length scope though. - /// -#if NET45 - [MethodImpl(MethodImplOptions.AggressiveInlining)] -#endif - // [CLSCompliant(false)] - public (int Offset, int Length) GetOffsetAndLength(int length) - { - int start; - Index startIndex = Start; - if (startIndex.IsFromEnd) - start = length - startIndex.Value; - else - start = startIndex.Value; - - int end; - Index endIndex = End; - if (endIndex.IsFromEnd) - end = length - endIndex.Value; - else - end = endIndex.Value; - - if ((uint)end > (uint)length || (uint)start > (uint)end) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } - - return (start, end - start); - } -} - -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/CLS/RuntimeHelpers.cs b/src/Basal/IFox.Basal.Shared/CLS/RuntimeHelpers.cs deleted file mode 100644 index 841c0d59100a271c323809fdee0fedd34f618f1e..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/CLS/RuntimeHelpers.cs +++ /dev/null @@ -1,57 +0,0 @@ - -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using IFoxCAD.Basal; - -namespace System.Runtime.CompilerServices; - -/* - * 1.编译提示多个程序集中定义,屏蔽不了,但是不影响编译 - * 2.发现可以通过定义一个条件编译常量来进行屏蔽。 - * 3.普通包会提示编译器缺少GetSubArray函数,但是源码包不会。所以解决方案就是使用普通包的时候安装TA.System.Runtime.CompilerServices.RuntimeHelpers.GetSubArray nuget包来解决,此包为一个符号包,不会生成多余的dll - */ - - -#if !NORuntimeHelpers -/// -/// -/// -internal static class RuntimeHelpers - -{ - /// - /// Slices the specified array using the specified range. - /// - public static T[] GetSubArray(T[] array, Range range) - { - //if (array == null) - // throw new ArgumentNullException(nameof(array)); - array.NotNull(nameof(array)); - - (int offset, int length) = range.GetOffsetAndLength(array.Length); - - if (default(T)! != null || typeof(T[]) == array.GetType()) // NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) - { - // We know the type of the array to be exactly T[]. - if (length == 0) - { - // return Array.Empty(); - return new T[0]; - } - - var dest = new T[length]; - Array.Copy(array, offset, dest, 0, length); - return dest; - } - else - { - // The array is actually a U[] where U:T. - T[] dest = (T[])Array.CreateInstance(array.GetType().GetElementType()!, length); - Array.Copy(array, offset, dest, 0, length); - return dest; - } - } -} -#endif diff --git a/src/Basal/IFox.Basal.Shared/CLS/TupleElementNamesAttribute.cs b/src/Basal/IFox.Basal.Shared/CLS/TupleElementNamesAttribute.cs deleted file mode 100644 index 93e61930c31b8277948fa060629cb1d813a04ba1..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/CLS/TupleElementNamesAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace System.Runtime.CompilerServices; - -/// -/// Indicates that the use of on a member is meant to be treated as a tuple with element names. -/// -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Event)] -public sealed class TupleElementNamesAttribute : Attribute -{ - private readonly string[] _transformNames; - - /// - /// Initializes a new instance of the class. - /// - /// - /// Specifies, in a pre-order depth-first traversal of a type's - /// construction, which occurrences are - /// meant to carry element names. - /// - /// - /// This constructor is meant to be used on types that contain an - /// instantiation of that contains - /// element names. For instance, if C is a generic type with - /// two type parameters, then a use of the constructed type C{, might be intended to - /// treat the first type argument as a tuple with element names and the - /// second as a tuple without element names. In which case, the - /// appropriate attribute specification should use a - /// transformNames value of { "name1", "name2", null, null, - /// null }. - /// - public TupleElementNamesAttribute(string[] transformNames) - { - _transformNames = transformNames ?? throw new ArgumentNullException(nameof(transformNames)); - } - - /// - /// Specifies, in a pre-order depth-first traversal of a type's - /// construction, which elements are - /// meant to carry element names. - /// - public IList TransformNames => _transformNames; -} \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/CLS/ValueTuple.cs b/src/Basal/IFox.Basal.Shared/CLS/ValueTuple.cs deleted file mode 100644 index c20902433c6b2e27faccc0f8cf436837c42e460b..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/CLS/ValueTuple.cs +++ /dev/null @@ -1,2152 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// #pragma warning disable SA1141 // explicitly not using tuple syntax in tuple implementation -#if !NOVALUETUPLE - -using System.Diagnostics; -using System.Numerics.Hashing; -/* - * 惊惊: - * 首先是因为有人想要编译的时候只形成一个dll,然后把元组塞入IFox,同时也补充了NET35没有元组的遗憾. - * - * 而利用nuget元组包必然会形成依赖地狱. - * - * 如果你的工程使用了nuget元组包,就造成了必须要剔除IFox. - * - * 改IFox的元组命名空间倒是可以分离两者,但是 vs编译器 无法识别带其他命名空间的元组. - * 所以元组本身就是冲突的,需要把其他元组卸载掉,由IFox提供. - */ - -/* - * 1. 元组是net47之后提供的特性,所以net47之前的版本是都没有的 - * 2. 通过定义常量的办法将元组屏蔽,很奇怪的是源码包可以,但是普通包不行,所以推荐使用源码包 index和range的情况类似 - * 这种问题就没有很好的解决方式,因为用了ifox就不能用其他的index,range,valuetuple类库,但是其他的三方库却依赖 - * 这些类库,所以还是使用源码包吧。 -*/ - -#if NET35 -namespace System.Collections -{ - public interface IStructuralComparable - { - int CompareTo(object? other, IComparer comparer); - } - public interface IStructuralEquatable - { - bool Equals(object? other, IEqualityComparer comparer); - int GetHashCode(IEqualityComparer comparer); - } -} -#endif - - - -namespace System.Numerics.Hashing -{ - internal static class HashHelpers - { - public static readonly int RandomSeed = Guid.NewGuid().GetHashCode(); - - public static int Combine(int h1, int h2) - { - unchecked - { - // RyuJIT optimizes this to use the ROL instruction - // Related GitHub pull request: dotnet/coreclr#1830 - - // RyuJIT 对此进行了优化以使用 ROL 指令 - // 相关 GitHub 拉取请求:dotnet/coreclr#1830 - uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27); - return ((int)rol5 + h1) ^ h2; - } - } - } -} - - - - -namespace System -{ - - // internal static class SR - internal sealed partial class SR - { - // public const string ArgumentException_ValueTupleIncorrectType = "The parameter should be a ValueTuple type of appropriate arity."; - // public const string ArgumentException_ValueTupleLastArgumentNotAValueTuple = "The TRest type argument of ValueTuple`8 must be a ValueTuple."; - public const string ArgumentException_ValueTupleIncorrectType = "该参数应该是适当数量的 ValueTuple 类型."; - public const string ArgumentException_ValueTupleLastArgumentNotAValueTuple = "ValueTuple`8 的 TREST 类型参数必须是 ValueTuple."; - } - - // Helper so we can call some tuple methods recursively without knowing the underlying types. - /// - /// 帮助器,因此我们可以在不知道底层类型的情况下递归调用一些元组方法. - /// - internal interface ITupleInternal - { - int GetHashCode(IEqualityComparer comparer); - int Size { get; } - string ToStringEnd(); - } - - - // The ValueTuple types (from arity 0 to 8) comprise the runtime implementation that underlies tuples in C# and struct tuples in F#. - // Aside from created via language syntax, they are most easily created via the ValueTuple.Create factory methods. - // The System.ValueTuple types differ from the System.Tuple types in that: - // - they are structs rather than classes, - // - they are mutable rather than readonly, and - // - their members (such as Item1, Item2, etc) are fields rather than properties. - /// - /// ValueTuple 类型(从 arity 0 到 8)包含运行时实现,它是 C# 中的元组和 F# 中的结构元组的基础. - /// 除了通过语言语法创建之外,它们最容易通过 ValueTuple.Create 工厂方法创建. - /// System.ValueTuple 类型与 System.Tuple 类型的不同之处在于: - /// - 它们是结构而不是类, - /// - 它们是可变的而不是只读的,并且 - /// - 它们的成员(例如 Item1、Item2 等)是字段而不是属性. - /// - public struct ValueTuple - : IEquatable, IStructuralEquatable, IStructuralComparable, IComparable, IComparable, ITupleInternal - { - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if is a . - public override bool Equals(object obj) - { - return obj is ValueTuple; - } - - /// Returns a value indicating whether this instance is equal to a specified value. - /// An instance to compare to this instance. - /// true if has the same value as this instance; otherwise, false. - public bool Equals(ValueTuple other) - { - return true; - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - return other is ValueTuple; - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return 0; - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - return 0; - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return 0; - } - - /// Returns the hash code for this instance. - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return 0; - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return 0; - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return 0; - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (). - /// - public override string ToString() - { - return "()"; - } - - string ITupleInternal.ToStringEnd() - { - return ")"; - } - - int ITupleInternal.Size => 0; - - /// Creates a new struct 0-tuple. - /// A 0-tuple. - public static ValueTuple Create() => new(); - - /// Creates a new struct 1-tuple, or singleton. - /// The type of the first component of the tuple. - /// The value of the first component of the tuple. - /// A 1-tuple (singleton) whose value is (item1). - public static ValueTuple Create(T1 item1) => new(item1); - - /// Creates a new struct 2-tuple, or pair. - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// A 2-tuple (pair) whose value is (item1, item2). - public static ValueTuple Create(T1 item1, T2 item2) => new(item1, item2); - - /// Creates a new struct 3-tuple, or triple. - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The type of the third component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - /// A 3-tuple (triple) whose value is (item1, item2, item3). - public static ValueTuple Create(T1 item1, T2 item2, T3 item3) => - new(item1, item2, item3); - - /// Creates a new struct 4-tuple, or quadruple. - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The type of the third component of the tuple. - /// The type of the fourth component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - /// The value of the fourth component of the tuple. - /// A 4-tuple (quadruple) whose value is (item1, item2, item3, item4). - public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4) => - new(item1, item2, item3, item4); - - /// Creates a new struct 5-tuple, or quintuple. - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The type of the third component of the tuple. - /// The type of the fourth component of the tuple. - /// The type of the fifth component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - /// The value of the fourth component of the tuple. - /// The value of the fifth component of the tuple. - /// A 5-tuple (quintuple) whose value is (item1, item2, item3, item4, item5). - public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) => - new(item1, item2, item3, item4, item5); - - /// Creates a new struct 6-tuple, or sextuple. - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The type of the third component of the tuple. - /// The type of the fourth component of the tuple. - /// The type of the fifth component of the tuple. - /// The type of the sixth component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - /// The value of the fourth component of the tuple. - /// The value of the fifth component of the tuple. - /// The value of the sixth component of the tuple. - /// A 6-tuple (sextuple) whose value is (item1, item2, item3, item4, item5, item6). - public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) => - new(item1, item2, item3, item4, item5, item6); - - /// Creates a new struct 7-tuple, or septuple. - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The type of the third component of the tuple. - /// The type of the fourth component of the tuple. - /// The type of the fifth component of the tuple. - /// The type of the sixth component of the tuple. - /// The type of the seventh component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - /// The value of the fourth component of the tuple. - /// The value of the fifth component of the tuple. - /// The value of the sixth component of the tuple. - /// The value of the seventh component of the tuple. - /// A 7-tuple (septuple) whose value is (item1, item2, item3, item4, item5, item6, item7). - public static ValueTuple Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) => - new(item1, item2, item3, item4, item5, item6, item7); - - /// Creates a new struct 8-tuple, or octuple. - /// The type of the first component of the tuple. - /// The type of the second component of the tuple. - /// The type of the third component of the tuple. - /// The type of the fourth component of the tuple. - /// The type of the fifth component of the tuple. - /// The type of the sixth component of the tuple. - /// The type of the seventh component of the tuple. - /// The type of the eighth component of the tuple. - /// The value of the first component of the tuple. - /// The value of the second component of the tuple. - /// The value of the third component of the tuple. - /// The value of the fourth component of the tuple. - /// The value of the fifth component of the tuple. - /// The value of the sixth component of the tuple. - /// The value of the seventh component of the tuple. - /// The value of the eighth component of the tuple. - /// An 8-tuple (octuple) whose value is (item1, item2, item3, item4, item5, item6, item7, item8). - public static ValueTuple> Create(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, T8 item8) => - new(item1, item2, item3, item4, item5, item6, item7, ValueTuple.Create(item8)); - - internal static int CombineHashCodes(int h1, int h2) - { - return HashHelpers.Combine(HashHelpers.Combine(HashHelpers.RandomSeed, h1), h2); - } - - internal static int CombineHashCodes(int h1, int h2, int h3) - { - return HashHelpers.Combine(CombineHashCodes(h1, h2), h3); - } - - internal static int CombineHashCodes(int h1, int h2, int h3, int h4) - { - return HashHelpers.Combine(CombineHashCodes(h1, h2, h3), h4); - } - - internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5) - { - return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4), h5); - } - - internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6) - { - return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4, h5), h6); - } - - internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7) - { - return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4, h5, h6), h7); - } - - internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8) - { - return HashHelpers.Combine(CombineHashCodes(h1, h2, h3, h4, h5, h6, h7), h8); - } - } - - /// Represents a 1-tuple, or singleton, as a value type. - /// The type of the tuple's only component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - { - /// - /// The current instance's first component. - /// - public T1 Item1; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - public ValueTuple(T1 item1) - { - Item1 = item1; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current - /// instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its field - /// is equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1); - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null || other is not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - return Comparer.Default.Compare(Item1, objTuple.Item1); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - return Comparer.Default.Compare(Item1, other.Item1); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - return comparer.Compare(Item1, objTuple.Item1); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return EqualityComparer.Default.GetHashCode(Item1); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return comparer.GetHashCode(Item1); - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return comparer.GetHashCode(Item1); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1), - /// where Item1 represents the value of . If the field is , - /// it is represented as . - /// - public override string ToString() - { - return "(" + Item1?.ToString() + ")"; - } - - string ITupleInternal.ToStringEnd() - { - return Item1?.ToString() + ")"; - } - - int ITupleInternal.Size => 1; - } - - /// - /// Represents a 2-tuple, or pair, as a value type. - /// - /// The type of the tuple's first component. - /// The type of the tuple's second component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - { - /// - /// The current instance's first component. - /// - public T1 Item1; - - /// - /// The current instance's first component. - /// - public T2 Item2; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - /// The value of the tuple's second component. - public ValueTuple(T1 item1, T2 item2) - { - Item1 = item1; - Item2 = item2; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its fields - /// are equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1) - && EqualityComparer.Default.Equals(Item2, other.Item2); - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object based on a specified comparison method. - /// - /// The object to compare with this instance. - /// An object that defines the method to use to evaluate whether the two objects are equal. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// - /// This member is an explicit interface member implementation. It can be used only when the - /// instance is cast to an interface. - /// - /// The implementation is called only if other is not , - /// and if it can be successfully cast (in C#) or converted (in Visual Basic) to a - /// whose components are of the same types as those of the current instance. The IStructuralEquatable.Equals(Object, IEqualityComparer) method - /// first passes the values of the objects to be compared to the - /// implementation. If this method call returns , the method is - /// called again and passed the values of the two instances. - /// - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other is null or not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1) - && comparer.Equals(Item2, objTuple.Item2); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return CompareTo((ValueTuple)other); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - int c = Comparer.Default.Compare(Item1, other.Item1); - if (c != 0) return c; - - return Comparer.Default.Compare(Item2, other.Item2); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - int c = comparer.Compare(Item1, objTuple.Item1); - if (c != 0) return c; - - return comparer.Compare(Item2, objTuple.Item2); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2)); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - private int GetHashCodeCore(IEqualityComparer comparer) - { - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), - comparer.GetHashCode(Item2)); - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1, Item2), - /// where Item1 and Item2 represent the values of the - /// and fields. If either field value is , - /// it is represented as . - /// - public override string ToString() - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ")"; - } - - string ITupleInternal.ToStringEnd() - { - return Item1?.ToString() + ", " + Item2?.ToString() + ")"; - } - - int ITupleInternal.Size => 2; - } - - /// - /// Represents a 3-tuple, or triple, as a value type. - /// - /// The type of the tuple's first component. - /// The type of the tuple's second component. - /// The type of the tuple's third component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - { - /// - /// The current instance's first component. - /// - public T1 Item1; - /// - /// The current instance's second component. - /// - public T2 Item2; - /// - /// The current instance's third component. - /// - public T3 Item3; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - /// The value of the tuple's second component. - /// The value of the tuple's third component. - public ValueTuple(T1 item1, T2 item2, T3 item3) - { - Item1 = item1; - Item2 = item2; - Item3 = item3; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current - /// instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its fields - /// are equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1) - && EqualityComparer.Default.Equals(Item2, other.Item2) - && EqualityComparer.Default.Equals(Item3, other.Item3); - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null || other is not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1) - && comparer.Equals(Item2, objTuple.Item2) - && comparer.Equals(Item3, objTuple.Item3); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return CompareTo((ValueTuple)other); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - int c = Comparer.Default.Compare(Item1, other.Item1); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item2, other.Item2); - if (c != 0) return c; - - return Comparer.Default.Compare(Item3, other.Item3); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - int c = comparer.Compare(Item1, objTuple.Item1); - if (c != 0) return c; - - c = comparer.Compare(Item2, objTuple.Item2); - if (c != 0) return c; - - return comparer.Compare(Item3, objTuple.Item3); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3)); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - private int GetHashCodeCore(IEqualityComparer comparer) - { - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), - comparer.GetHashCode(Item2), - comparer.GetHashCode(Item3)); - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1, Item2, Item3). - /// If any field value is , it is represented as . - /// - public override string ToString() - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ")"; - } - - string ITupleInternal.ToStringEnd() - { - return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ")"; - } - - int ITupleInternal.Size => 3; - } - - /// - /// Represents a 4-tuple, or quadruple, as a value type. - /// - /// The type of the tuple's first component. - /// The type of the tuple's second component. - /// The type of the tuple's third component. - /// The type of the tuple's fourth component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - { - /// - /// The current instance's first component. - /// - public T1 Item1; - /// - /// The current instance's second component. - /// - public T2 Item2; - /// - /// The current instance's third component. - /// - public T3 Item3; - /// - /// The current instance's fourth component. - /// - public T4 Item4; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - /// The value of the tuple's second component. - /// The value of the tuple's third component. - /// The value of the tuple's fourth component. - public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4) - { - Item1 = item1; - Item2 = item2; - Item3 = item3; - Item4 = item4; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current - /// instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its fields - /// are equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1) - && EqualityComparer.Default.Equals(Item2, other.Item2) - && EqualityComparer.Default.Equals(Item3, other.Item3) - && EqualityComparer.Default.Equals(Item4, other.Item4); - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null || other is not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1) - && comparer.Equals(Item2, objTuple.Item2) - && comparer.Equals(Item3, objTuple.Item3) - && comparer.Equals(Item4, objTuple.Item4); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return CompareTo((ValueTuple)other); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - int c = Comparer.Default.Compare(Item1, other.Item1); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item2, other.Item2); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item3, other.Item3); - if (c != 0) return c; - - return Comparer.Default.Compare(Item4, other.Item4); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - int c = comparer.Compare(Item1, objTuple.Item1); - if (c != 0) return c; - - c = comparer.Compare(Item2, objTuple.Item2); - if (c != 0) return c; - - c = comparer.Compare(Item3, objTuple.Item3); - if (c != 0) return c; - - return comparer.Compare(Item4, objTuple.Item4); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4)); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - private int GetHashCodeCore(IEqualityComparer comparer) - { - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), - comparer.GetHashCode(Item2), - comparer.GetHashCode(Item3), - comparer.GetHashCode(Item4)); - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1, Item2, Item3, Item4). - /// If any field value is , it is represented as . - /// - public override string ToString() - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")"; - } - - string ITupleInternal.ToStringEnd() - { - return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ")"; - } - - int ITupleInternal.Size => 4; - } - - /// - /// Represents a 5-tuple, or quintuple, as a value type. - /// - /// The type of the tuple's first component. - /// The type of the tuple's second component. - /// The type of the tuple's third component. - /// The type of the tuple's fourth component. - /// The type of the tuple's fifth component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - { - /// - /// The current instance's first component. - /// - public T1 Item1; - /// - /// The current instance's second component. - /// - public T2 Item2; - /// - /// The current instance's third component. - /// - public T3 Item3; - /// - /// The current instance's fourth component. - /// - public T4 Item4; - /// - /// The current instance's fifth component. - /// - public T5 Item5; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - /// The value of the tuple's second component. - /// The value of the tuple's third component. - /// The value of the tuple's fourth component. - /// The value of the tuple's fifth component. - public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5) - { - Item1 = item1; - Item2 = item2; - Item3 = item3; - Item4 = item4; - Item5 = item5; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current - /// instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its fields - /// are equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1) - && EqualityComparer.Default.Equals(Item2, other.Item2) - && EqualityComparer.Default.Equals(Item3, other.Item3) - && EqualityComparer.Default.Equals(Item4, other.Item4) - && EqualityComparer.Default.Equals(Item5, other.Item5); - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null || other is not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1) - && comparer.Equals(Item2, objTuple.Item2) - && comparer.Equals(Item3, objTuple.Item3) - && comparer.Equals(Item4, objTuple.Item4) - && comparer.Equals(Item5, objTuple.Item5); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return CompareTo((ValueTuple)other); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - int c = Comparer.Default.Compare(Item1, other.Item1); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item2, other.Item2); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item3, other.Item3); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item4, other.Item4); - if (c != 0) return c; - - return Comparer.Default.Compare(Item5, other.Item5); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - int c = comparer.Compare(Item1, objTuple.Item1); - if (c != 0) return c; - - c = comparer.Compare(Item2, objTuple.Item2); - if (c != 0) return c; - - c = comparer.Compare(Item3, objTuple.Item3); - if (c != 0) return c; - - c = comparer.Compare(Item4, objTuple.Item4); - if (c != 0) return c; - - return comparer.Compare(Item5, objTuple.Item5); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5)); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - private int GetHashCodeCore(IEqualityComparer comparer) - { - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), - comparer.GetHashCode(Item2), - comparer.GetHashCode(Item3), - comparer.GetHashCode(Item4), - comparer.GetHashCode(Item5)); - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1, Item2, Item3, Item4, Item5). - /// If any field value is , it is represented as . - /// - public override string ToString() - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ")"; - } - - string ITupleInternal.ToStringEnd() - { - return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ")"; - } - - int ITupleInternal.Size => 5; - } - - /// - /// Represents a 6-tuple, or sixtuple, as a value type. - /// - /// The type of the tuple's first component. - /// The type of the tuple's second component. - /// The type of the tuple's third component. - /// The type of the tuple's fourth component. - /// The type of the tuple's fifth component. - /// The type of the tuple's sixth component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - { - /// - /// The current instance's first component. - /// - public T1 Item1; - /// - /// The current instance's second component. - /// - public T2 Item2; - /// - /// The current instance's third component. - /// - public T3 Item3; - /// - /// The current instance's fourth component. - /// - public T4 Item4; - /// - /// The current instance's fifth component. - /// - public T5 Item5; - /// - /// The current instance's sixth component. - /// - public T6 Item6; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - /// The value of the tuple's second component. - /// The value of the tuple's third component. - /// The value of the tuple's fourth component. - /// The value of the tuple's fifth component. - /// The value of the tuple's sixth component. - public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6) - { - Item1 = item1; - Item2 = item2; - Item3 = item3; - Item4 = item4; - Item5 = item5; - Item6 = item6; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current - /// instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its fields - /// are equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1) - && EqualityComparer.Default.Equals(Item2, other.Item2) - && EqualityComparer.Default.Equals(Item3, other.Item3) - && EqualityComparer.Default.Equals(Item4, other.Item4) - && EqualityComparer.Default.Equals(Item5, other.Item5) - && EqualityComparer.Default.Equals(Item6, other.Item6); - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null || other is not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1) - && comparer.Equals(Item2, objTuple.Item2) - && comparer.Equals(Item3, objTuple.Item3) - && comparer.Equals(Item4, objTuple.Item4) - && comparer.Equals(Item5, objTuple.Item5) - && comparer.Equals(Item6, objTuple.Item6); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return CompareTo((ValueTuple)other); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - int c = Comparer.Default.Compare(Item1, other.Item1); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item2, other.Item2); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item3, other.Item3); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item4, other.Item4); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item5, other.Item5); - if (c != 0) return c; - - return Comparer.Default.Compare(Item6, other.Item6); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - int c = comparer.Compare(Item1, objTuple.Item1); - if (c != 0) return c; - - c = comparer.Compare(Item2, objTuple.Item2); - if (c != 0) return c; - - c = comparer.Compare(Item3, objTuple.Item3); - if (c != 0) return c; - - c = comparer.Compare(Item4, objTuple.Item4); - if (c != 0) return c; - - c = comparer.Compare(Item5, objTuple.Item5); - if (c != 0) return c; - - return comparer.Compare(Item6, objTuple.Item6); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6)); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - private int GetHashCodeCore(IEqualityComparer comparer) - { - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), - comparer.GetHashCode(Item2), - comparer.GetHashCode(Item3), - comparer.GetHashCode(Item4), - comparer.GetHashCode(Item5), - comparer.GetHashCode(Item6)); - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1, Item2, Item3, Item4, Item5, Item6). - /// If any field value is , it is represented as . - /// - public override string ToString() - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ")"; - } - - string ITupleInternal.ToStringEnd() - { - return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ")"; - } - - int ITupleInternal.Size => 6; - } - - /// - /// Represents a 7-tuple, or sentuple, as a value type. - /// - /// The type of the tuple's first component. - /// The type of the tuple's second component. - /// The type of the tuple's third component. - /// The type of the tuple's fourth component. - /// The type of the tuple's fifth component. - /// The type of the tuple's sixth component. - /// The type of the tuple's seventh component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - { - /// - /// The current instance's first component. - /// - public T1 Item1; - /// - /// The current instance's second component. - /// - public T2 Item2; - /// - /// The current instance's third component. - /// - public T3 Item3; - /// - /// The current instance's fourth component. - /// - public T4 Item4; - /// - /// The current instance's fifth component. - /// - public T5 Item5; - /// - /// The current instance's sixth component. - /// - public T6 Item6; - /// - /// The current instance's seventh component. - /// - public T7 Item7; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - /// The value of the tuple's second component. - /// The value of the tuple's third component. - /// The value of the tuple's fourth component. - /// The value of the tuple's fifth component. - /// The value of the tuple's sixth component. - /// The value of the tuple's seventh component. - public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) - { - Item1 = item1; - Item2 = item2; - Item3 = item3; - Item4 = item4; - Item5 = item5; - Item6 = item6; - Item7 = item7; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current - /// instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its fields - /// are equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1) - && EqualityComparer.Default.Equals(Item2, other.Item2) - && EqualityComparer.Default.Equals(Item3, other.Item3) - && EqualityComparer.Default.Equals(Item4, other.Item4) - && EqualityComparer.Default.Equals(Item5, other.Item5) - && EqualityComparer.Default.Equals(Item6, other.Item6) - && EqualityComparer.Default.Equals(Item7, other.Item7); - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null || other is not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1) - && comparer.Equals(Item2, objTuple.Item2) - && comparer.Equals(Item3, objTuple.Item3) - && comparer.Equals(Item4, objTuple.Item4) - && comparer.Equals(Item5, objTuple.Item5) - && comparer.Equals(Item6, objTuple.Item6) - && comparer.Equals(Item7, objTuple.Item7); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return CompareTo((ValueTuple)other); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - int c = Comparer.Default.Compare(Item1, other.Item1); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item2, other.Item2); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item3, other.Item3); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item4, other.Item4); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item5, other.Item5); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item6, other.Item6); - if (c != 0) return c; - - return Comparer.Default.Compare(Item7, other.Item7); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - int c = comparer.Compare(Item1, objTuple.Item1); - if (c != 0) return c; - - c = comparer.Compare(Item2, objTuple.Item2); - if (c != 0) return c; - - c = comparer.Compare(Item3, objTuple.Item3); - if (c != 0) return c; - - c = comparer.Compare(Item4, objTuple.Item4); - if (c != 0) return c; - - c = comparer.Compare(Item5, objTuple.Item5); - if (c != 0) return c; - - c = comparer.Compare(Item6, objTuple.Item6); - if (c != 0) return c; - - return comparer.Compare(Item7, objTuple.Item7); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7)); - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - private int GetHashCodeCore(IEqualityComparer comparer) - { - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), - comparer.GetHashCode(Item2), - comparer.GetHashCode(Item3), - comparer.GetHashCode(Item4), - comparer.GetHashCode(Item5), - comparer.GetHashCode(Item6), - comparer.GetHashCode(Item7)); - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1, Item2, Item3, Item4, Item5, Item6, Item7). - /// If any field value is , it is represented as . - /// - public override string ToString() - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ")"; - } - - string ITupleInternal.ToStringEnd() - { - return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ")"; - } - - int ITupleInternal.Size => 7; - } - - /// - /// Represents an 8-tuple, or octuple, as a value type. - /// - /// The type of the tuple's first component. - /// The type of the tuple's second component. - /// The type of the tuple's third component. - /// The type of the tuple's fourth component. - /// The type of the tuple's fifth component. - /// The type of the tuple's sixth component. - /// The type of the tuple's seventh component. - /// The type of the tuple's eighth component. - public struct ValueTuple - : IEquatable>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable>, ITupleInternal - where TRest : struct - { - /// - /// The current instance's first component. - /// - public T1 Item1; - /// - /// The current instance's second component. - /// - public T2 Item2; - /// - /// The current instance's third component. - /// - public T3 Item3; - /// - /// The current instance's fourth component. - /// - public T4 Item4; - /// - /// The current instance's fifth component. - /// - public T5 Item5; - /// - /// The current instance's sixth component. - /// - public T6 Item6; - /// - /// The current instance's seventh component. - /// - public T7 Item7; - /// - /// The current instance's eighth component. - /// - public TRest Rest; - - /// - /// Initializes a new instance of the value type. - /// - /// The value of the tuple's first component. - /// The value of the tuple's second component. - /// The value of the tuple's third component. - /// The value of the tuple's fourth component. - /// The value of the tuple's fifth component. - /// The value of the tuple's sixth component. - /// The value of the tuple's seventh component. - /// The value of the tuple's eight component. - public ValueTuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) - { - if (rest is not ITupleInternal) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleLastArgumentNotAValueTuple); - } - - Item1 = item1; - Item2 = item2; - Item3 = item3; - Item4 = item4; - Item5 = item5; - Item6 = item6; - Item7 = item7; - Rest = rest; - } - - /// - /// Returns a value that indicates whether the current instance is equal to a specified object. - /// - /// The object to compare with this instance. - /// if the current instance is equal to the specified object; otherwise, . - /// - /// The parameter is considered to be equal to the current instance under the following conditions: - /// - /// It is a value type. - /// Its components are of the same types as those of the current instance. - /// Its components are equal to those of the current instance. Equality is determined by the default object equality comparer for each component. - /// - /// - public override bool Equals(object obj) - { - return obj is ValueTuple tuple && Equals(tuple); - } - - /// - /// Returns a value that indicates whether the current - /// instance is equal to a specified . - /// - /// The tuple to compare with this instance. - /// if the current instance is equal to the specified tuple; otherwise, . - /// - /// The parameter is considered to be equal to the current instance if each of its fields - /// are equal to that of the current instance, using the default comparer for that field's type. - /// - public bool Equals(ValueTuple other) - { - return EqualityComparer.Default.Equals(Item1, other.Item1) - && EqualityComparer.Default.Equals(Item2, other.Item2) - && EqualityComparer.Default.Equals(Item3, other.Item3) - && EqualityComparer.Default.Equals(Item4, other.Item4) - && EqualityComparer.Default.Equals(Item5, other.Item5) - && EqualityComparer.Default.Equals(Item6, other.Item6) - && EqualityComparer.Default.Equals(Item7, other.Item7) - && EqualityComparer.Default.Equals(Rest, other.Rest); - } - - bool IStructuralEquatable.Equals(object? other, IEqualityComparer comparer) - { - if (other == null || other is not ValueTuple) return false; - - var objTuple = (ValueTuple)other; - - return comparer.Equals(Item1, objTuple.Item1) - && comparer.Equals(Item2, objTuple.Item2) - && comparer.Equals(Item3, objTuple.Item3) - && comparer.Equals(Item4, objTuple.Item4) - && comparer.Equals(Item5, objTuple.Item5) - && comparer.Equals(Item6, objTuple.Item6) - && comparer.Equals(Item7, objTuple.Item7) - && comparer.Equals(Rest, objTuple.Rest); - } - - int IComparable.CompareTo(object other) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - return CompareTo((ValueTuple)other); - } - - /// Compares this instance to a specified instance and returns an indication of their relative values. - /// An instance to compare. - /// - /// A signed number indicating the relative values of this instance and . - /// Returns less than zero if this instance is less than , zero if this - /// instance is equal to , and greater than zero if this instance is greater - /// than . - /// - public int CompareTo(ValueTuple other) - { - int c = Comparer.Default.Compare(Item1, other.Item1); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item2, other.Item2); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item3, other.Item3); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item4, other.Item4); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item5, other.Item5); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item6, other.Item6); - if (c != 0) return c; - - c = Comparer.Default.Compare(Item7, other.Item7); - if (c != 0) return c; - - return Comparer.Default.Compare(Rest, other.Rest); - } - - int IStructuralComparable.CompareTo(object? other, IComparer comparer) - { - if (other == null) return 1; - - if (other is not ValueTuple) - { - throw new ArgumentException(SR.ArgumentException_ValueTupleIncorrectType, nameof(other)); - } - - var objTuple = (ValueTuple)other; - - int c = comparer.Compare(Item1, objTuple.Item1); - if (c != 0) return c; - - c = comparer.Compare(Item2, objTuple.Item2); - if (c != 0) return c; - - c = comparer.Compare(Item3, objTuple.Item3); - if (c != 0) return c; - - c = comparer.Compare(Item4, objTuple.Item4); - if (c != 0) return c; - - c = comparer.Compare(Item5, objTuple.Item5); - if (c != 0) return c; - - c = comparer.Compare(Item6, objTuple.Item6); - if (c != 0) return c; - - c = comparer.Compare(Item7, objTuple.Item7); - if (c != 0) return c; - - return comparer.Compare(Rest, objTuple.Rest); - } - - /// - /// Returns the hash code for the current instance. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple - if (Rest is not ITupleInternal rest) - { - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7)); - } - - int size = rest.Size; - if (size >= 8) { return rest.GetHashCode(); } - - // In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest - int k = 8 - size; - switch (k) - { - case 1: - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item7), - rest.GetHashCode()); - case 2: - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7), - rest.GetHashCode()); - case 3: - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7), - rest.GetHashCode()); - case 4: - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7), - rest.GetHashCode()); - case 5: - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7), - rest.GetHashCode()); - case 6: - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7), - rest.GetHashCode()); - case 7: - case 8: - return ValueTuple.CombineHashCodes(EqualityComparer.Default.GetHashCode(Item1), - EqualityComparer.Default.GetHashCode(Item2), - EqualityComparer.Default.GetHashCode(Item3), - EqualityComparer.Default.GetHashCode(Item4), - EqualityComparer.Default.GetHashCode(Item5), - EqualityComparer.Default.GetHashCode(Item6), - EqualityComparer.Default.GetHashCode(Item7), - rest.GetHashCode()); - } - - Debug.Assert(false, "Missed all cases for computing ValueTuple hash code"); - return -1; - } - - int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - private int GetHashCodeCore(IEqualityComparer comparer) - { - // We want to have a limited hash in this case. We'll use the last 8 elements of the tuple - if (Rest is not ITupleInternal rest) - { - return ValueTuple.CombineHashCodes( - comparer.GetHashCode(Item1), - comparer.GetHashCode(Item2), - comparer.GetHashCode(Item3), - comparer.GetHashCode(Item4), - comparer.GetHashCode(Item5), - comparer.GetHashCode(Item6), - comparer.GetHashCode(Item7)); - } - - int size = rest.Size; - if (size >= 8) { return rest.GetHashCode(comparer); } - - // In this case, the rest member has less than 8 elements so we need to combine some our elements with the elements in rest - int k = 8 - size; - switch (k) - { - case 1: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item7), rest.GetHashCode(comparer)); - case 2: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item6), comparer.GetHashCode(Item7), rest.GetHashCode(comparer)); - case 3: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item5), comparer.GetHashCode(Item6), comparer.GetHashCode(Item7), - rest.GetHashCode(comparer)); - case 4: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item4), comparer.GetHashCode(Item5), comparer.GetHashCode(Item6), - comparer.GetHashCode(Item7), rest.GetHashCode(comparer)); - case 5: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item3), comparer.GetHashCode(Item4), comparer.GetHashCode(Item5), - comparer.GetHashCode(Item6), comparer.GetHashCode(Item7), rest.GetHashCode(comparer)); - case 6: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item2), comparer.GetHashCode(Item3), comparer.GetHashCode(Item4), - comparer.GetHashCode(Item5), comparer.GetHashCode(Item6), comparer.GetHashCode(Item7), - rest.GetHashCode(comparer)); - case 7: - case 8: - return ValueTuple.CombineHashCodes(comparer.GetHashCode(Item1), comparer.GetHashCode(Item2), comparer.GetHashCode(Item3), - comparer.GetHashCode(Item4), comparer.GetHashCode(Item5), comparer.GetHashCode(Item6), - comparer.GetHashCode(Item7), rest.GetHashCode(comparer)); - } - - Debug.Assert(false, "Missed all cases for computing ValueTuple hash code"); - return -1; - } - - int ITupleInternal.GetHashCode(IEqualityComparer comparer) - { - return GetHashCodeCore(comparer); - } - - /// - /// Returns a string that represents the value of this instance. - /// - /// The string representation of this instance. - /// - /// The string returned by this method takes the form (Item1, Item2, Item3, Item4, Item5, Item6, Item7, Rest). - /// If any field value is , it is represented as . - /// - public override string ToString() - { - if (Rest is not ITupleInternal rest) - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")"; - } - else - { - return "(" + Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + rest.ToStringEnd(); - } - } - - string ITupleInternal.ToStringEnd() - { - if (Rest is not ITupleInternal rest) - { - return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + Rest.ToString() + ")"; - } - else - { - return Item1?.ToString() + ", " + Item2?.ToString() + ", " + Item3?.ToString() + ", " + Item4?.ToString() + ", " + Item5?.ToString() + ", " + Item6?.ToString() + ", " + Item7?.ToString() + ", " + rest.ToStringEnd(); - } - } - - int ITupleInternal.Size - { - get - { - // ITupleInternal? rest = Rest as ITupleInternal; - // return rest == null ? 8 : 7 + rest.Size; - return Rest is not ITupleInternal rest ? 8 : 7 + rest.Size; - } - } - } - -} - -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/ExpressionTrees/ParameterRebinder.cs b/src/Basal/IFox.Basal.Shared/ExpressionTrees/ParameterRebinder.cs deleted file mode 100644 index e4dfcd4b761f4392fa297105cf7a855d1ac8af69..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/ExpressionTrees/ParameterRebinder.cs +++ /dev/null @@ -1,41 +0,0 @@ -#if NET45 -namespace IFoxCAD.Basal; - -/// -/// ذ -/// -public class ParameterRebinder : SqlExpressionVisitor -{ - private readonly Dictionary map; - /// - /// ذ - /// - /// ֵ - public ParameterRebinder(Dictionary map) - { - this.map = map ?? new Dictionary(); - } - /// - /// 滻 - /// - /// ֵ - /// ʽ - /// ʽ - public static Expression? ReplaceParameters(Dictionary map, Expression expression) - { - return new ParameterRebinder(map).Visit(expression); - } - /// - /// ʲ - /// - /// ʽ - /// ʽ - protected override Expression VisitParameter(ParameterExpression expression) - { - if (map.TryGetValue(expression, out var parameterExpression)) - expression = parameterExpression; - - return base.VisitParameter(expression); - } -} -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/ExpressionTrees/PredicateBuilder.cs b/src/Basal/IFox.Basal.Shared/ExpressionTrees/PredicateBuilder.cs deleted file mode 100644 index 7153e7901983cbca5dff2f4e0ad03b7b02358951..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/ExpressionTrees/PredicateBuilder.cs +++ /dev/null @@ -1,83 +0,0 @@ - -#if NET45 -namespace IFoxCAD.Basal; -/// -/// Predicateίй -/// -public static class PredicateBuilder -{ - /// - /// ίбʽ - /// - /// ķ - /// - public static Expression> True() - { - return param => true; - } - /// - /// ؼٵίбʽ - /// - /// ķ - /// - public static Expression> False() - { - return param => false; - } - /// - /// predicateί - /// - /// - /// ίбʽ - /// ίбʽ - public static Expression> Create(Expression> predicate) - { - return predicate; - } - /// - /// ʾıʽ - /// - /// - /// һ - /// ڶ - /// ʽ - public static Expression> And(this Expression> first, Expression> second) - { - return first.Compose(second, Expression.AndAlso); - } - /// - /// ʾıʽ - /// - /// - /// һ - /// ڶ - /// ʽ - public static Expression> Or(this Expression> first, Expression> second) - { - return first.Compose(second, Expression.OrElse); - } - /// - /// Ƿıʽ - /// - /// - /// ʽ - /// ʽ - public static Expression> Not(this Expression> expression) - { - return Expression.Lambda>(Expression.Not(expression.Body), expression.Parameters); - } - - private static Expression Compose(this Expression first, Expression second, Func merge) - { - var map = first.Parameters.Select((f, i) => new{f,s = second.Parameters[i]}).ToDictionary(p => p.s, p => p.f); - var expression = ParameterRebinder.ReplaceParameters(map, second.Body); - if (expression != null) - { - return Expression.Lambda(merge(first.Body, expression), first.Parameters); - } - return first; - - } -} - -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/ExpressionTrees/SqlExpressionVisitor.cs b/src/Basal/IFox.Basal.Shared/ExpressionTrees/SqlExpressionVisitor.cs deleted file mode 100644 index bfd62836c6627f7f1cf251d8d8dee76cdb6cca35..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/ExpressionTrees/SqlExpressionVisitor.cs +++ /dev/null @@ -1,450 +0,0 @@ -#if NET45 -namespace IFoxCAD.Basal; - -/// -/// sqlʽ -/// -public abstract class SqlExpressionVisitor -{ - /// - /// - /// - /// ʽ - /// ʽ - /// - protected virtual Expression? Visit(Expression expression) - { - if (expression is null) - return null; - - return expression.NodeType switch - { - ExpressionType.Add => VisitBinary((BinaryExpression)expression), - ExpressionType.AddChecked => VisitBinary((BinaryExpression)expression), - ExpressionType.And => VisitBinary((BinaryExpression)expression), - ExpressionType.AndAlso => VisitBinary((BinaryExpression)expression), - ExpressionType.ArrayIndex => VisitBinary((BinaryExpression)expression), - ExpressionType.Coalesce => VisitBinary((BinaryExpression)expression), - ExpressionType.Divide => VisitBinary((BinaryExpression)expression), - ExpressionType.Equal => VisitBinary((BinaryExpression)expression), - ExpressionType.ExclusiveOr => VisitBinary((BinaryExpression)expression), - ExpressionType.GreaterThan => VisitBinary((BinaryExpression)expression), - ExpressionType.GreaterThanOrEqual => VisitBinary((BinaryExpression)expression), - ExpressionType.LeftShift => VisitBinary((BinaryExpression)expression), - ExpressionType.LessThan => VisitBinary((BinaryExpression)expression), - ExpressionType.LessThanOrEqual => VisitBinary((BinaryExpression)expression), - ExpressionType.Modulo => VisitBinary((BinaryExpression)expression), - ExpressionType.Multiply => VisitBinary((BinaryExpression)expression), - ExpressionType.MultiplyChecked => VisitBinary((BinaryExpression)expression), - ExpressionType.NotEqual => VisitBinary((BinaryExpression)expression), - ExpressionType.Or => VisitBinary((BinaryExpression)expression), - ExpressionType.OrElse => VisitBinary((BinaryExpression)expression), - ExpressionType.RightShift => VisitBinary((BinaryExpression)expression), - ExpressionType.Subtract => VisitBinary((BinaryExpression)expression), - ExpressionType.SubtractChecked => VisitBinary((BinaryExpression)expression), - ExpressionType.ArrayLength => VisitUnary((UnaryExpression)expression), - ExpressionType.Convert => VisitUnary((UnaryExpression)expression), - ExpressionType.ConvertChecked => VisitUnary((UnaryExpression)expression), - ExpressionType.Negate => VisitUnary((UnaryExpression)expression), - ExpressionType.NegateChecked => VisitUnary((UnaryExpression)expression), - ExpressionType.Not => VisitUnary((UnaryExpression)expression), - ExpressionType.Quote => VisitUnary((UnaryExpression)expression), - ExpressionType.TypeAs => VisitUnary((UnaryExpression)expression), - ExpressionType.Call => VisitMethodCall((MethodCallExpression)expression), - ExpressionType.Conditional => VisitConditional((ConditionalExpression)expression), - ExpressionType.Constant => VisitConstant((ConstantExpression)expression), - ExpressionType.Invoke => VisitInvocation((InvocationExpression)expression), - ExpressionType.Lambda => VisitLambda((LambdaExpression)expression), - ExpressionType.ListInit => VisitListInit((ListInitExpression)expression), - ExpressionType.MemberAccess => VisitMemberAccess((MemberExpression)expression), - ExpressionType.MemberInit => VisitMemberInit((MemberInitExpression)expression), - ExpressionType.New => VisitNew((NewExpression)expression), - ExpressionType.NewArrayInit => VisitNewArray((NewArrayExpression)expression), - ExpressionType.NewArrayBounds => VisitNewArray((NewArrayExpression)expression), - ExpressionType.Parameter => VisitParameter((ParameterExpression)expression), - ExpressionType.TypeIs => VisitTypeIs((TypeBinaryExpression)expression), - _ => throw new RuntimeBinderException(nameof(expression.NodeType)) - }; - } - /// - /// ߰ - /// - /// 󶨵 - /// 󶨵 - /// - protected virtual MemberBinding VisitBinding(MemberBinding binding) - { - return binding.BindingType switch - { - MemberBindingType.Assignment => VisitMemberAssignment((MemberAssignment)binding), - MemberBindingType.MemberBinding => VisitMemberMemberBinding((MemberMemberBinding)binding), - MemberBindingType.ListBinding => VisitMemberListBinding((MemberListBinding)binding), - _ => throw new RuntimeBinderException(nameof(binding.BindingType)) - }; - } - /// - /// ʼϳʼ趨 - /// - /// ϳʼ趨 - /// ϳʼ趨 - protected virtual ElementInit VisitElementInitializer(ElementInit initializer) - { - var arguments = VisitExpressionList(initializer.Arguments); - - if (arguments != initializer.Arguments) - return Expression.ElementInit(initializer.AddMethod, arguments); - - return initializer; - } - /// - /// һԪ - /// - /// һԪ - /// ʽ - protected virtual Expression VisitUnary(UnaryExpression unary) - { - var operand = Visit(unary.Operand); - - if (operand != unary.Operand) - return Expression.MakeUnary(unary.NodeType, operand, unary.Type, unary.Method); - - return unary; - } - /// - /// ʶ - /// - /// - /// ʽ - protected virtual Expression VisitBinary(BinaryExpression binary) - { - var left = Visit(binary.Left); - var right = Visit(binary.Right); - var conversion = Visit(binary.Conversion); - - if (left == binary.Left && right == binary.Right && conversion == binary.Conversion) - return binary; - - if (binary.NodeType == ExpressionType.Coalesce && binary.Conversion != null) - return Expression.Coalesce(left, right, conversion as LambdaExpression); - - return Expression.MakeBinary(binary.NodeType, left, right, binary.IsLiftedToNull, binary.Method); - } - /// - /// - /// - /// - /// ʽ - protected virtual Expression VisitTypeIs(TypeBinaryExpression typeBinary) - { - var expression = Visit(typeBinary.Expression); - - if (expression != typeBinary.Expression) - return Expression.TypeIs(expression, typeBinary.TypeOperand); - - return typeBinary; - } - /// - /// ʳֵ - /// - /// ֵ - /// ʽ - protected virtual Expression VisitConstant(ConstantExpression constant) - { - return constant; - } - /// - /// - /// - /// - /// ʽ - protected virtual Expression VisitConditional(ConditionalExpression conditional) - { - var test = Visit(conditional.Test); - var ifTrue = Visit(conditional.IfTrue); - var ifFalse = Visit(conditional.IfFalse); - - if (test != conditional.Test) - return Expression.Condition(test, ifTrue, ifFalse); - - if (ifTrue != conditional.IfTrue) - return Expression.Condition(test, ifTrue, ifFalse); - - if (ifFalse != conditional.IfFalse) - return Expression.Condition(test, ifTrue, ifFalse); - - return conditional; - } - /// - /// ʲ - /// - /// - /// ʽ - protected virtual Expression VisitParameter(ParameterExpression parameter) - { - return parameter; - } - /// - /// ʳԱ - /// - /// Ա - /// ʽ - protected virtual Expression VisitMemberAccess(MemberExpression member) - { - var expression = Visit(member.Expression); - - if (expression != member.Expression) - return Expression.MakeMemberAccess(expression, member.Member); - - return member; - } - /// - /// ʷ - /// - /// - /// ʽ - protected virtual Expression VisitMethodCall(MethodCallExpression methodCall) - { - var instance = Visit(methodCall.Object); - var arguments = (IEnumerable)VisitExpressionList(methodCall.Arguments); - - if (instance != methodCall.Object || !Equals(arguments, methodCall.Arguments)) - return Expression.Call(instance, methodCall.Method, arguments); - - return methodCall; - } - /// - /// ʱʽ - /// - /// ʽ - /// ʽֻ - protected virtual ReadOnlyCollection VisitExpressionList(ReadOnlyCollection original) - { - var index1 = 0; - var expressions = default(List); - - for (var count = original.Count; index1 < count; ++index1) - { - var expression = Visit(original[index1]); - if (expression != null) - { - if (expressions != null) - { - expressions.Add(expression); - } - - else if (expression != original[index1]) - { - expressions = new List(count); - - for (var index2 = 0; index2 < index1; ++index2) - expressions.Add(original[index2]); - - expressions.Add(expression); - } - } - - } - - return expressions != null ? expressions.AsReadOnly() : original; - } - /// - /// ʳԱֵ - /// - /// Աֵ - /// - protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment) - { - var expression = Visit(assignment.Expression); - - if (expression != assignment.Expression) - return Expression.Bind(assignment.Member, expression); - - return assignment; - } - /// - /// ¶ԱijԱ - /// - /// ¶ԱijԱ - /// ¶ԱijԱ - protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) - { - var bindings = VisitBindingList(binding.Bindings); - - if (!Equals(bindings, binding.Bindings)) - return Expression.MemberBind(binding.Member, bindings); - - return binding; - } - /// - /// ʳԱʼ - /// - /// Աʼ - /// Աʼ - protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding) - { - var initializers = VisitElementInitializerList(binding.Initializers); - - if (!Equals(initializers, binding.Initializers)) - return Expression.ListBind(binding.Member, initializers); - - return binding; - } - /// - /// ʳԱʼб - /// - /// Աʼб - /// Աʼб - protected virtual IEnumerable VisitBindingList(ReadOnlyCollection original) - { - var index1 = 0; - var bindings = default(List); - - for (var count = original.Count; index1 < count; ++index1) - { - var memberBinding = VisitBinding(original[index1]); - - if (bindings != null) - { - bindings.Add(memberBinding); - } - - else if (memberBinding != original[index1]) - { - bindings = new List(count); - - for (var index2 = 0; index2 < index1; ++index2) - bindings.Add(original[index2]); - - bindings.Add(memberBinding); - } - } - - return (IEnumerable)bindings! ?? original; - } - /// - /// ʼ趨 - /// - /// 趨 - /// 趨 - protected virtual IEnumerable VisitElementInitializerList(ReadOnlyCollection original) - { - var index1 = 0; - var initializers = default(List); - - for (var count = original.Count; index1 < count; ++index1) - { - var initializer = VisitElementInitializer(original[index1]); - - if (initializers != null) - { - initializers.Add(initializer); - } - - else if (initializer != original[index1]) - { - initializers = new List(count); - - for (var index2 = 0; index2 < index1; ++index2) - initializers.Add(original[index2]); - - initializers.Add(initializer); - } - } - - return (IEnumerable)initializers! ?? original; - } - /// - /// lambdaʽ - /// - /// lambdaʽ - /// ʽ - protected virtual Expression VisitLambda(LambdaExpression lambda) - { - var body = Visit(lambda.Body); - - if (body != lambda.Body) - return Expression.Lambda(lambda.Type, body, lambda.Parameters); - - return lambda; - } - /// - /// ʹ캯 - /// - /// 캯 - /// - protected virtual NewExpression VisitNew(NewExpression expression) - { - var arguments = VisitExpressionList(expression.Arguments); - - if (Equals(arguments, expression.Arguments)) - return expression; - - if (expression.Members != null) - return Expression.New(expression.Constructor, arguments, expression.Members); - - return Expression.New(expression.Constructor, arguments); - } - /// - /// ʳԱʼ - /// - /// Աʼ - /// ʽ - protected virtual Expression VisitMemberInit(MemberInitExpression memberInit) - { - var expression = VisitNew(memberInit.NewExpression); - var bindings = VisitBindingList(memberInit.Bindings); - - if (expression != memberInit.NewExpression || !Equals(bindings, memberInit.Bindings)) - return Expression.MemberInit(expression, bindings); - - return memberInit; - } - /// - /// ʼϳʼ - /// - /// ϳʼ - /// ʽ - protected virtual Expression VisitListInit(ListInitExpression listInit) - { - var expression = VisitNew(listInit.NewExpression); - var initializers = VisitElementInitializerList(listInit.Initializers); - - if (expression != listInit.NewExpression || !Equals(initializers, listInit.Initializers)) - return Expression.ListInit(expression, initializers); - - return listInit; - } - /// - /// - /// - /// - /// ʽ - protected virtual Expression VisitNewArray(NewArrayExpression newArray) - { - var expressions = VisitExpressionList(newArray.Expressions); - - if (Equals(expressions, newArray.Expressions)) - return newArray; - - if (newArray.NodeType == ExpressionType.NewArrayInit) - return Expression.NewArrayInit(newArray.Type.GetElementType(), expressions); - - return Expression.NewArrayBounds(newArray.Type.GetElementType(), expressions); - } - /// - /// ίеñʽ - /// - /// ίеñʽ - /// ʽ - protected virtual Expression VisitInvocation(InvocationExpression invocation) - { - var arguments = VisitExpressionList(invocation.Arguments); - var expression = Visit(invocation.Expression); - - if (arguments != invocation.Arguments || expression != invocation.Expression) - return Expression.Invoke(expression, arguments); - - return invocation; - } -} -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/General/ArgumentNullEx.cs b/src/Basal/IFox.Basal.Shared/General/ArgumentNullEx.cs deleted file mode 100644 index b9691436a9c76b7fb28b2c8998b0fa97bec54d31..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/General/ArgumentNullEx.cs +++ /dev/null @@ -1,23 +0,0 @@ - - -namespace IFoxCAD.Basal -{ - /// - /// 参数null检查类 - /// - public static class ArgumentNullEx - { - /// - /// 检查参数是否为 null - /// - /// 参数类型 - /// 参数 - /// 参数为null时的提示信息 - /// - public static void NotNull(this T? argument, string? argumentExpression = null) - { - if (argument == null) throw new ArgumentNullException(paramName: argumentExpression); - } - - } -} diff --git a/src/Basal/IFox.Basal.Shared/General/DictEx.cs b/src/Basal/IFox.Basal.Shared/General/DictEx.cs deleted file mode 100644 index 296fb163a24bdbc93f562e4d79b79f3fa1f88e39..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/General/DictEx.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace IFoxCAD.Basal; - -public static class DictEx -{ - // public static TKey? GetKey(this IDictionary dict!!, TKey key!!) - // { - // if (dict.ContainsKey(key)) - // { - // foreach (var item in dict.Keys) - // if (key.Equals(item)) - // return item; - // } - // return default; - // } -} diff --git a/src/Basal/IFox.Basal.Shared/General/LinkedHashMap.cs b/src/Basal/IFox.Basal.Shared/General/LinkedHashMap.cs deleted file mode 100644 index 0e6232c6c37ca087577550cd01dcb2714c1e30a5..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/General/LinkedHashMap.cs +++ /dev/null @@ -1,171 +0,0 @@ -namespace IFoxCAD.Basal; - - -/// -/// A least-recently-used cache stored like a dictionary. -/// -/// -/// The type of the key to the cached item -/// -/// -/// The type of the cached item. -/// -/// -/// Derived from https://stackoverflow.com/a/3719378/240845 -/// https://stackoverflow.com/users/240845/mheyman -/// -public class LinkedHashMap -{ - private readonly Dictionary> cacheMap = new(); - - private readonly LinkedList lruList = new(); - - private readonly Action? dispose; - - /// - /// Initializes a new instance of the - /// class. - /// - /// - /// Maximum number of elements to cache. - /// - /// - /// When elements cycle out of the cache, disposes them. May be null. - /// - public LinkedHashMap(int capacity, Action? dispose = null) - { - this.Capacity = capacity; - this.dispose = dispose; - } - - /// - /// Gets the capacity of the cache. - /// - public int Capacity { get; } - - /// Gets the value associated with the specified key. - /// - /// The key of the value to get. - /// - /// - /// When this method returns, contains the value associated with the specified - /// key, if the key is found; otherwise, the default value for the type of the - /// parameter. This parameter is passed - /// uninitialized. - /// - /// - /// true if the - /// contains an element with the specified key; otherwise, false. - /// - public bool TryGetValue(TKey key, out TValue? value) - { - lock (this.cacheMap) - { - if (this.cacheMap.TryGetValue(key, out LinkedListNode.MapItem> node)) - { - value = node.Value.Value; - this.lruList.Remove(node); - this.lruList.AddLast(node); - return true; - } - - value = default; - return false; - } - } - - /// - /// Looks for a value for the matching . If not found, - /// calls to retrieve the value and add it to - /// the cache. - /// - /// - /// The key of the value to look up. - /// - /// - /// Generates a value if one isn't found. - /// - /// - /// The requested value. - /// - public TValue Get(TKey key, Func valueGenerator) - { - lock (this.cacheMap) - { - TValue value; - if (this.cacheMap.TryGetValue(key, out LinkedListNode.MapItem> node)) - { - value = node.Value.Value; - this.lruList.Remove(node); - this.lruList.AddLast(node); - } - else - { - value = valueGenerator(); - if (this.cacheMap.Count >= this.Capacity) - { - this.RemoveFirst(); - } - - MapItem cacheItem = new(key, value); - node = new LinkedListNode(cacheItem); - this.lruList.AddLast(node); - this.cacheMap.Add(key, node); - } - - return value; - } - } - - /// - /// Adds the specified key and value to the dictionary. - /// - /// - /// The key of the element to add. - /// - /// - /// The value of the element to add. The value can be null for reference types. - /// - public void Add(TKey key, TValue value) - { - lock (this.cacheMap) - { - if (this.cacheMap.Count >= this.Capacity) - { - this.RemoveFirst(); - } - - MapItem cacheItem = new(key, value); - LinkedListNode node = new(cacheItem); - this.lruList.AddLast(node); - this.cacheMap.Add(key, node); - } - } - - private void RemoveFirst() - { - // Remove from LRUPriority - LinkedListNode node = this.lruList.First; - this.lruList.RemoveFirst(); - - // Remove from cache - this.cacheMap.Remove(node.Value.Key); - - // dispose - this.dispose?.Invoke(node.Value.Value); - } - - private class MapItem - { - public MapItem(TKey k, TValue v) - { - this.Key = k; - this.Value = v; - } - - public TKey Key { get; } - - public TValue Value { get; } - } -} - diff --git a/src/Basal/IFox.Basal.Shared/General/LinkedHashSet.cs b/src/Basal/IFox.Basal.Shared/General/LinkedHashSet.cs deleted file mode 100644 index 6efaa04d11abd67c4904dbcd5750863b5f7da9b3..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/General/LinkedHashSet.cs +++ /dev/null @@ -1,222 +0,0 @@ -namespace IFoxCAD.Basal; - -public class LinkedHashSet : ICollection where T : IComparable -{ - private readonly IDictionary> m_Dictionary; - private readonly LoopList m_LinkedList; - - public LinkedHashSet() - { - m_Dictionary = new Dictionary>(); - m_LinkedList = new LoopList(); - } - - public LoopListNode? First => m_LinkedList.First; - - public LoopListNode? Last => m_LinkedList.Last; - - public LoopListNode? MinNode { get; set; } - - public bool Add(T item) - { - if (m_Dictionary.ContainsKey(item)) - return false; - var node = m_LinkedList.AddLast(item); - m_Dictionary.Add(item, node); - - if (MinNode is null) - { - MinNode = node; - } - else - { - if (item.CompareTo(MinNode.Value) < 0) - { - MinNode = node; - } - } - - - - return true; - } - - void ICollection.Add(T item) - { - Add(item); - } - - public LoopListNode AddFirst(T value) - { - if (m_Dictionary.ContainsKey(value)) - { - return m_Dictionary[value]; - } - var node = m_LinkedList.AddFirst(value); - m_Dictionary.Add(value, node); - if (MinNode is null) - { - MinNode = node; - } - else - { - if (value.CompareTo(MinNode.Value) < 0) - { - MinNode = node; - } - } - return node; - } - - public void AddRange(IEnumerable collection) - { - foreach (var item in collection) - { - Add(item); - } - } - - - public void Clear() - { - m_LinkedList.Clear(); - m_Dictionary.Clear(); - } - - public bool Remove(T item) - { - bool found = m_Dictionary.TryGetValue(item, out LoopListNode node); - if (!found) return false; - m_Dictionary.Remove(item); - m_LinkedList.Remove(node); - return true; - } - - public int Count - { - get { return m_Dictionary.Count; } - } - - public void For(LoopListNode from, Action action) - { - var first = from; - var last = from; - if (first is null) return; - - for (int i = 0; i < Count; i++) - { - action.Invoke(i, first!.Value, last!.Value); - first = first.Next; - last = last.Previous; - } - } - - public List ToList() - { - return m_LinkedList.ToList(); - } - - [System.Diagnostics.DebuggerStepThrough] - public IEnumerator GetEnumerator() - { - return m_LinkedList.GetEnumerator(); - } - - [System.Diagnostics.DebuggerStepThrough] - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - - public bool Contains(T item) - { - return m_Dictionary.ContainsKey(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - // m_LinkedList.CopyTo(array, arrayIndex); - return; - } - - public bool SetFirst(LoopListNode node) - { - return m_LinkedList.SetFirst(node); - } - - public LinkedHashSet Clone() - { - var newset = new LinkedHashSet(); - foreach (var item in this) - { - newset.Add(item); - } - return newset; - } - - public virtual bool IsReadOnly - { - get { return m_Dictionary.IsReadOnly; } - } - - public override string ToString() - { - return m_LinkedList.ToString(); - } - - public void UnionWith(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public void IntersectWith(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public void ExceptWith(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public bool IsSubsetOf(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public void SymmetricExceptWith(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public bool IsSupersetOf(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public bool IsProperSupersetOf(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public bool IsProperSubsetOf(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public bool Overlaps(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - public bool SetEquals(IEnumerable other) - { - throw GetNotSupportedDueToSimplification(); - } - - private static Exception GetNotSupportedDueToSimplification() - { - return new NotSupportedException("This method is not supported due to simplification of example code."); - } -} \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/General/ListEx.cs b/src/Basal/IFox.Basal.Shared/General/ListEx.cs deleted file mode 100644 index 528b6ad614eaf66f74ee4f27a7bd0f417a649241..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/General/ListEx.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace IFoxCAD.Basal; - - -public static class ListEx -{ - public static bool EqualsAll(this IList a, IList b) - { - return EqualsAll(a, b, null); - // there is a slight performance gain in passing null here. - // It is how it is done in other parts of the framework. - } - - public static bool EqualsAll(this IList a, IList b, IEqualityComparer? comparer) - { - if (a is null) - return b is null; - else if (b is null) - return false; - - if (a.Count != b.Count) - return false; - - comparer ??= EqualityComparer.Default; - - for (int i = 0; i < a.Count; i++) - if (!comparer.Equals(a[i], b[i])) - return false; - return true; - } -} diff --git a/src/Basal/IFox.Basal.Shared/General/LoopState.cs b/src/Basal/IFox.Basal.Shared/General/LoopState.cs deleted file mode 100644 index 76ff63fae9fce2ba6fabd8e8635bb84b67ae637e..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/General/LoopState.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace IFoxCAD.Basal; - -#line hidden // 调试的时候跳过它 -/// -/// 控制循环结束 -/// -public class LoopState -{ - const int PLS_NONE = 0; - const int PLS_EXCEPTIONAL = 1; - const int PLS_BROKEN = 2; - const int PLS_STOPPED = 4; - const int PLS_CANCELED = 8; - - private volatile int _flag = PLS_NONE; - - public bool IsRun => _flag == PLS_NONE; - public bool IsExceptional => (_flag & PLS_EXCEPTIONAL) == PLS_EXCEPTIONAL; - public bool IsBreak => (_flag & PLS_BROKEN) == PLS_BROKEN; - public bool IsStop => (_flag & PLS_STOPPED) == PLS_STOPPED; - public bool IsCancel => (_flag & PLS_CANCELED) == PLS_CANCELED; - - public void Exceptional() - { - if ((_flag & PLS_EXCEPTIONAL) != PLS_EXCEPTIONAL) - _flag |= PLS_EXCEPTIONAL; - } - public void Break() => _flag = PLS_BROKEN; - public void Stop() => _flag = PLS_STOPPED; - public void Cancel() => _flag = PLS_CANCELED; - public void Reset() => _flag = PLS_NONE; -} -#line default - -/// -/// 控制程序流程 -/// -public class ProState -{ - const int PLS_NONE = 0; // 初始化(构造就立马运行,将导致构造函数中也被检测,这是浪费性能及挖坑给自己的) - const int PLS_RUN = 1; // 运行 - const int PLS_BROKEN = 2; - const int PLS_STOPPED = 4; - const int PLS_CANCELED = 8; - const int PLS_EXCEPTIONAL = 16; // 异常 用于附加状态 - - private volatile int _flag = PLS_NONE; - - public bool IsNone => _flag == PLS_NONE; - public bool IsRun => (_flag & PLS_RUN) == PLS_RUN; - public bool IsBreak => (_flag & PLS_BROKEN) == PLS_BROKEN; - public bool IsStop => (_flag & PLS_STOPPED) == PLS_STOPPED; - public bool IsCancel => (_flag & PLS_CANCELED) == PLS_CANCELED; - public bool IsExceptional => (_flag & PLS_EXCEPTIONAL) == PLS_EXCEPTIONAL; - - public void Exceptional() - { - if ((_flag & PLS_EXCEPTIONAL) != PLS_EXCEPTIONAL) - _flag |= PLS_EXCEPTIONAL; - } - public void Break() => _flag = PLS_BROKEN; - public void Stop() => _flag = PLS_STOPPED; - public void Cancel() => _flag = PLS_CANCELED; - public void Start() => _flag = PLS_RUN; - public void None() => _flag = PLS_NONE; -} -#line default \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/IFox.Basal.Shared.projitems b/src/Basal/IFox.Basal.Shared/IFox.Basal.Shared.projitems deleted file mode 100644 index 814c3818c166aeba98c640233005b2acd6387cab..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/IFox.Basal.Shared.projitems +++ /dev/null @@ -1,42 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - c823514a-2bc2-45c2-aced-18924a7b80bf - - - IFox.Basal.Shared - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/IFox.Basal.Shared.shproj b/src/Basal/IFox.Basal.Shared/IFox.Basal.Shared.shproj deleted file mode 100644 index e04b5b68e529f1f58915661291d96b71846eb154..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/IFox.Basal.Shared.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - c823514a-2bc2-45c2-aced-18924a7b80bf - 14.0 - - - - - - - - diff --git a/src/Basal/IFox.Basal.Shared/Sortedset/ISet.cs b/src/Basal/IFox.Basal.Shared/Sortedset/ISet.cs deleted file mode 100644 index 22b95092cf3957a7fee1c032bbc7eaa033db5286..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/Sortedset/ISet.cs +++ /dev/null @@ -1,65 +0,0 @@ -#if NET35 -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== -/*============================================================ -** -** Interface: ISet -** -** kimhamil -** -** -** Purpose: Base interface for all generic sets. -** -** -===========================================================*/ -namespace System.Collections.Generic -{ - using System; - using System.Runtime.CompilerServices; - - - /// - /// Generic collection that guarantees the uniqueness of its elements, as defined - /// by some comparer. It also supports basic set operations such as Union, Intersection, - /// Complement and Exclusive Complement. - /// - public interface ISet : ICollection - { - // Add ITEM to the set, return true if added, false if duplicate - new bool Add(T item); - - // Transform this set into its union with the IEnumerable other - void UnionWith(IEnumerable other); - - // Transform this set into its intersection with the IEnumberable other - void IntersectWith(IEnumerable other); - - // Transform this set so it contains no elements that are also in other - void ExceptWith(IEnumerable other); - - // Transform this set so it contains elements initially in this or in other, but not both - void SymmetricExceptWith(IEnumerable other); - - // Check if this set is a subset of other - bool IsSubsetOf(IEnumerable other); - - // Check if this set is a superset of other - bool IsSupersetOf(IEnumerable other); - - // Check if this set is a subset of other, but not the same as it - bool IsProperSupersetOf(IEnumerable other); - - // Check if this set is a superset of other, but not the same as it - bool IsProperSubsetOf(IEnumerable other); - - // Check if this set has any elements in common with other - bool Overlaps(IEnumerable other); - - // Check if this set contains the same and only the same elements as other - bool SetEquals(IEnumerable other); - } -} -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/Sortedset/SR.cs b/src/Basal/IFox.Basal.Shared/Sortedset/SR.cs deleted file mode 100644 index 88b2bcf35a702a7d6f7ce1c8b5076234ec99799d..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/Sortedset/SR.cs +++ /dev/null @@ -1,902 +0,0 @@ -#if NET35 -#pragma warning disable CS8603 // 可能返回 null 引用。 -namespace System; - - -using System; -using System.Reflection; -using System.Globalization; -using System.Resources; -using System.Text; -using System.ComponentModel; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -[AttributeUsage(AttributeTargets.All)] -internal sealed class SRDescriptionAttribute : DescriptionAttribute -{ - public SRDescriptionAttribute(string description) - { - DescriptionValue = SR.GetString(description); - } - - public SRDescriptionAttribute(string description, string resourceSet) - { - ResourceManager rm = new ResourceManager(resourceSet, Assembly.GetExecutingAssembly()); - DescriptionValue = rm.GetString(description); - System.Diagnostics.Debug.Assert(DescriptionValue != null, string.Format(CultureInfo.CurrentCulture, "String resource {0} not found.", new object[] { description })); - } -} - -[AttributeUsage(AttributeTargets.All)] -internal sealed class SRCategoryAttribute : CategoryAttribute -{ - private string resourceSet = String.Empty; - - public SRCategoryAttribute(string category) - : base(category) - { - } - - public SRCategoryAttribute(string category, string resourceSet) - : base(category) - { - this.resourceSet = resourceSet; - } - - protected override string GetLocalizedString(string value) - { - if (this.resourceSet.Length > 0) - { - ResourceManager rm = new ResourceManager(resourceSet, Assembly.GetExecutingAssembly()); - String localizedString = rm.GetString(value); - System.Diagnostics.Debug.Assert(localizedString != null, string.Format(CultureInfo.CurrentCulture, "String resource {0} not found.", new object[] { value })); - return localizedString; - } - else - { - return SR.GetString(value); - } - } -} - -[AttributeUsage(AttributeTargets.All)] -internal sealed class SRDisplayNameAttribute : DisplayNameAttribute -{ - public SRDisplayNameAttribute(string name) - { - DisplayNameValue = SR.GetString(name); - } - - public SRDisplayNameAttribute(string name, string resourceSet) - { - ResourceManager rm = new ResourceManager(resourceSet, Assembly.GetExecutingAssembly()); - DisplayNameValue = rm.GetString(name); - System.Diagnostics.Debug.Assert(DisplayNameValue != null, string.Format(CultureInfo.CurrentCulture, "String resource {0} not found.", new object[] { name })); - } -} - -/// -/// AutoGenerated resource class. Usage: -/// -/// string s = SR.GetString(SR.MyIdenfitier); -/// -internal sealed partial class SR -{ -#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。 - static SR loader = null; -#pragma warning restore CS8625 // 无法将 null 字面量转换为非 null 的引用类型。 - ResourceManager resources; - - internal SR() - { - resources = new System.Resources.ResourceManager("System.Workflow.ComponentModel.StringResources", Assembly.GetExecutingAssembly()); - } - - private static SR GetLoader() - { - if (loader == null) - loader = new SR(); - return loader; - } - - private static CultureInfo Culture - { - get { return null/*use ResourceManager default, CultureInfo.CurrentUICulture*/; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal static string GetString(string name, params object[] args) - { - return GetString(SR.Culture, name, args); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal static string GetString(CultureInfo culture, string name, params object[] args) - { - SR sys = GetLoader(); - if (sys == null) - return null; - string res = sys.resources.GetString(name, culture); - System.Diagnostics.Debug.Assert(res != null, string.Format(CultureInfo.CurrentCulture, "String resource {0} not found.", new object[] { name })); - if (args != null && args.Length > 0) - return string.Format(CultureInfo.CurrentCulture, res, args); - return res; - } - - internal static string GetString(string name) - { - return GetString(SR.Culture, name); - } - - internal static string GetString(CultureInfo culture, string name) - { - SR sys = GetLoader(); - if (sys == null) - return null; - string res = sys.resources.GetString(name, culture); - System.Diagnostics.Debug.Assert(res != null, string.Format(CultureInfo.CurrentCulture, "String resource {0} not found.", new object[] { name })); - return res; - } - - // All these strings should be present in StringResources.resx - internal const string Activity = "Activity"; - internal const string Handlers = "Handlers"; - internal const string Conditions = "Conditions"; - internal const string ConditionedActivityConditions = "ConditionedActivityConditions"; - internal const string Correlations = "Correlations"; - internal const string CorrelationSet = "CorrelationSet"; - internal const string NameDescr = "NameDescr"; - internal const string EnabledDescr = "EnabledDescr"; - internal const string DescriptionDescr = "DescriptionDescr"; - internal const string UnlessConditionDescr = "UnlessConditionDescr"; - internal const string InitializeDescr = "InitializeDescr"; - internal const string CatchTypeDescr = "CatchTypeDescr"; - internal const string ExceptionTypeDescr = "ExceptionTypeDescr"; - internal const string FaultDescription = "FaultDescription"; - internal const string FaultTypeDescription = "FaultTypeDescription"; - internal const string ContainingAssemblyDescr = "ContainingAssemblyDescr"; - internal const string ExecutionModeDescr = "ExecutionModeDescr"; - internal const string Error_ReadOnlyTemplateActivity = "Error_ReadOnlyTemplateActivity"; - internal const string Error_TypeNotString = "Error_TypeNotString"; - internal const string Error_InvalidErrorType = "Error_InvalidErrorType"; - internal const string Error_LiteralConversionFailed = "Error_LiteralConversionFailed"; - internal const string Error_TypeNotPrimitive = "Error_TypeNotPrimitive"; - internal const string CompletedCaleeDescr = "CompletedCaleeDescr"; - internal const string ProxyClassDescr = "ProxyClassDescr"; - internal const string ActivitySetDescr = "ActivitySetDescr"; - internal const string VersionDescr = "VersionDescr"; - internal const string ActivationDescr = "ActivationDescr"; - internal const string CorrelationSetsDescr = "CorrelationSetsDescr"; - internal const string CompanionClassDescr = "CompanionClassDescr"; - internal const string TransactionTypeDescr = "TransactionTypeDescr"; - internal const string SynchronizedDescr = "SynchronizedDescr"; - internal const string IsolationLevelDescr = "IsolationLevelDescr"; - internal const string TimeoutDescr = "TimeoutDescr"; - internal const string BatchableDescr = "BatchableDescr"; - internal const string LRTTimeoutDescr = "LRTTimeoutDescr"; - internal const string OnGetCalleeCountDescr = "OnGetCalleeCountDescr"; - internal const string CompensatableActivityDescr = "CompensatableActivityDescr"; - internal const string OnAfterEventDescr = "OnAfterEventDescr"; - internal const string OnBeforeMethodInvokeDescr = "OnBeforeMethodInvokeDescr"; - internal const string AssignedToDescr = "AssignedToDescr"; - internal const string TypeDescr = "TypeDescr"; - internal const string TemplateActivityDescr = "TemplateActivityDescr"; - internal const string ErrorMessageDescr = "ErrorMessageDescr"; - internal const string WebServiceSynchronizedDescr = "WebServiceSynchronizedDescr"; - internal const string CorrelationSetDescr = "CorrelationSetDescr"; - internal const string ExecutionTypeDescr = "ExecutionTypeDescr"; - internal const string RoleDescr = "RoleDescr"; - internal const string OnInitializeClonesDescr = "OnInitializeClonesDescr"; - internal const string CorrelationSetDisplayName = "CorrelationSetDisplayName"; - internal const string PastingActivities = "PastingActivities"; - internal const string DeletingActivities = "DeletingActivities"; - internal const string DragDropActivities = "DragDropActivities"; - internal const string ChangingEnabled = "ChangingEnabled"; - internal const string ChangingHandler = "ChangingHandler"; - internal const string ChangingParameter = "ChangingParameter"; - internal const string CollectionItem = "CollectionItem"; - internal const string AddingConditionalBranch = "AddingConditionalBranch"; - internal const string AddingEventActivity = "AddingEventActivity"; - internal const string AddingListenBranch = "AddingListenBranch"; - internal const string AddingParallelBranch = "AddingParallelBranch"; - internal const string CurrentProject = "CurrentProject"; - internal const string ReferencedAssemblies = "ReferencedAssemblies"; - internal const string CollectionText = "CollectionText"; - internal const string ParameterDescription = "ParameterDescription"; - internal const string InvokeParameterDescription = "InvokeParameterDescription"; - internal const string ParametersDescription = "ParametersDescription"; - internal const string ChangingParameters = "ChangingParameters"; - internal const string Condition = "ConditionRule"; - internal const string MovingActivities = "MovingActivities"; - internal const string MemberNameDescr = "MemberNameDescr"; - internal const string OnScopeInitializedDescr = "OnScopeInitializedDescr"; - internal const string OnGeneratorInitializedDescr = "OnGeneratorInitializedDescr"; - internal const string OnScopeCompletedDescr = "OnScopeCompletedDescr"; - internal const string OnGeneratorCompletedDescr = "OnGeneratorCompletedDescr"; - internal const string DataElementRuntimeTypeDescr = "DataElementRuntimeTypeDescr"; - internal const string RuleConditionReferencesDescr = "RuleConditionReferencesDescr"; - internal const string CreateActivityFromToolbox = "CreateActivityFromToolbox"; - internal const string MoveMultipleActivities = "MoveMultipleActivities"; - internal const string MoveSingleActivity = "MoveSingleActivity"; - internal const string CutMultipleActivities = "CutMultipleActivities"; - internal const string CutSingleActivity = "CutSingleActivity"; - internal const string CutActivity = "CutActivity"; - internal const string FaultActivityDescription = "FaultActivityDescription"; - internal const string NullConditionExpression = "NullConditionExpression"; - internal const string ParameterTypeDescription = "ParameterTypeDescription"; - internal const string ParameterCategory = "ParameterCategory"; - internal const string ParameterDirectionDescription = "ParameterDirectionDescription"; - internal const string ParameterElementDescription = "ParameterElementDescription"; - internal const string ParameterDlgDescription = "ParameterDlgDescription"; - internal const string ParameterDlgHeader = "ParameterDlgHeader"; - internal const string SuspendActivityDescription = "SuspendActivityDescription"; - internal const string SuspendErrorMessageDescr = "SuspendErrorMessageDescr"; - internal const string TerminateActivityDescription = "TerminateActivityDescription"; - internal const string TerminateErrorMessageDescr = "TerminateErrorMessageDescr"; - internal const string DeclarationCategory = "DeclarationCategory"; - internal const string NoValidActivityPropertiesAvailable = "NoValidActivityPropertiesAvailable"; - internal const string ChooseActivityDatasource = "ChooseActivityDatasource"; - internal const string Promote = "Promote"; - internal const string Type = "Type"; - internal const string NoMatchingActivityProperties = "NoMatchingActivityProperties"; - internal const string ActivityBindIDDescription = "ActivityBindIDDescription"; - internal const string ActivityBindPathDescription = "ActivityBindPathDescription"; - internal const string XPathDescription = "XPathDescription"; - internal const string TransformerDescription = "TransformerDescription"; - internal const string CustomPropertiesCollectionFormHeader = "CustomPropertiesCollectionFormHeader"; - internal const string CustomPropertiesCollectionFormDescription = "CustomPropertiesCollectionFormDescription"; - internal const string BaseTypePropertyName = "BaseTypePropertyName"; - internal const string CustomActivityBaseClassTypeFilterProviderDesc = "CustomActivityBaseClassTypeFilterProviderDesc"; - internal const string CustomActivityDesignerTypeFilterProviderDesc = "CustomActivityDesignerTypeFilterProviderDesc"; - internal const string CustomActivityValidatorTypeFilterProviderDesc = "CustomActivityValidatorTypeFilterProviderDesc"; - internal const string CustomActivityExecutorTypeFilterProviderDesc = "CustomActivityExecutorTypeFilterProviderDesc"; - internal const string GenericParameters = "GenericParameters"; - internal const string ToolboxItem = "ToolboxItem"; - internal const string ToolboxItemCompanionClassDesc = "ToolboxItemCompanionClassDesc"; - internal const string Error_SerializationInsufficientState = "Error_SerializationInsufficientState"; - internal const string Error_ActivityHasParent = "Error_ActivityHasParent"; - internal const string Error_CompensantionParentNotScope = "Error_CompensantionParentNotScope"; - internal const string Error_ConditionedActivityParentNotCAG = "Error_ConditionedActivityParentNotCAG"; - internal const string Error_CorrelationTypeNotComparable = "Error_CorrelationTypeNotComparable"; - internal const string Error_ArgumentTypeNotMatchParameter = "Error_ArgumentTypeNotMatchParameter"; - internal const string Error_TypeTypeMismatch = "Error_TypeTypeMismatch"; - internal const string Error_ParameterTypeMismatch = "Error_ParameterTypeMismatch"; - internal const string Error_InvokeParameterTypeMismatch = "Error_InvokeParameterTypeMismatch"; - internal const string Error_ParameterPropertyNotSet = "Error_ParameterPropertyNotSet"; - internal const string Error_DataSourceNameNotSet = "Error_DataSourceNameNotSet"; - internal const string Error_DataSourceInvalidIdentifier = "Error_DataSourceInvalidIdentifier"; - internal const string Error_ParameterTypeNotExist = "Error_ParameterTypeNotExist"; - internal const string Error_InvalidParameterName = "Error_InvalidParameterName"; - internal const string Error_InvalidParameterType = "Error_InvalidParameterType"; - internal const string Error_InvalidParameterElement = "Error_InvalidParameterElement"; - internal const string Error_InvalidPropertyType = "Error_InvalidPropertyType"; - internal const string Error_TypeNotResolvedInMethodName = "Error_TypeNotResolvedInMethodName"; - internal const string Error_DelegateNoInvoke = "Error_DelegateNoInvoke"; - internal const string Error_TypeNotDelegate = "Error_TypeNotDelegate"; - internal const string Error_MethodSignatureMismatch = "Error_MethodSignatureMismatch"; - internal const string Error_MethodReturnTypeMismatch = "Error_MethodReturnTypeMismatch"; - internal const string Error_PropertyNotSet = "Error_PropertyNotSet"; - internal const string Error_ScopeCouldNotBeResolved = "Error_ScopeCouldNotBeResolved"; - internal const string Error_IfElseNotAllIfElseBranchDecl = "Error_ConditionalNotAllConditionalBranchDecl"; - internal const string Error_TypeTypeMismatchAmbiguity = "Error_TypeTypeMismatchAmbiguity"; - internal const string Error_InvalidCorrelationSetDatasource = "Error_InvalidCorrelationSetDatasource"; - internal const string Error_InvalidCorrelationSetType = "Error_InvalidCorrelationSetType"; - internal const string Error_MissingCorrelationParameterAttribute = "Error_MissingCorrelationParameterAttribute"; - internal const string Error_CorrelationTypeNotConsistent = "Error_CorrelationTypeNotConsistent"; - internal const string Error_CorrelationInvalid = "Error_CorrelationInvalid"; - internal const string Error_MissingDelegateMethod = "Error_MissingDelegateMethod"; - internal const string Error_MissingHostInterface = "Error_MissingHostInterface"; - internal const string Error_MissingMethodName = "Error_MissingMethodName"; - internal const string Error_NoBoundType = "Error_NoBoundType"; - internal const string Error_PortTypeNotAnInterface = "Error_PortTypeNotAnInterface"; - internal const string Error_MethodNotExists = "Error_MethodNotExists"; - internal const string Error_InvalidRequestResponseMethod = "Error_InvalidRequestResponseMethod"; - internal const string General_MissingService = "General_MissingService"; - internal const string Error_ScopeDuplicatedNameActivity = "Error_ScopeDuplicatedNameActivity"; - internal const string Error_DuplicatedActivityID = "Error_DuplicatedActivityID"; - internal const string Error_DuplicatedParameterName = "Error_DuplicatedParameterName"; - internal const string Error_ScopeMissingSerializableAttribute = "Error_ScopeMissingSerializableAttribute"; - internal const string Error_FieldNotExists = "Error_FieldNotExists"; - internal const string Error_PropertyNotExists = "Error_PropertyNotExists"; - internal const string Error_FieldTypeMismatch = "Error_FieldTypeMismatch"; - internal const string Error_PropertyTypeMismatch = "Error_PropertyTypeMismatch"; - internal const string Error_TypeNotResolvedInFieldName = "Error_TypeNotResolvedInFieldName"; - internal const string Error_TypeNotResolvedInPropertyName = "Error_TypeNotResolvedInPropertyName"; - internal const string Error_FieldGenericParamTypeMismatch = "Error_FieldGenericParamTypeMismatch"; - internal const string Error_TypeNotResolved = "Error_TypeNotResolved"; - internal const string Error_TypeIsUnboundedGeneric = "Error_TypeIsUnboundedGeneric"; - internal const string Error_MissingRootActivity = "Error_MissingRootActivity"; - internal const string Error_PropertyNotReadable = "Error_PropertyNotReadable"; - internal const string Error_PropertyNotWritable = "Error_PropertyNotWritable"; - internal const string Error_NotCompositeActivity = "Error_NotCompositeActivity"; - internal const string Error_TypeNotExist = "Error_TypeNotExist"; - internal const string Error_ActivityRefNotResolved = "Error_ActivityRefNotResolved"; - internal const string Error_ActivityRefNotMatchType = "Error_ActivityRefNotMatchType"; - internal const string Error_ActivityValidation = "Error_ActivityValidation"; - internal const string Error_ActiveChildExist = "Error_ActiveChildExist"; - internal const string Error_ActiveChildContextExist = "Error_ActiveChildContextExist"; - internal const string Error_CannotCompleteContext = "Error_CannotCompleteContext"; - internal const string Error_NoPasteSupport = "Error_NoPasteSupport"; - internal const string Error_UnknownSerializationStore = "Error_UnknownSerializationStore"; - internal const string Error_MissingCorrelationSet = "Error_MissingCorrelationSet"; - internal const string Error_CreateVariable = "Error_CreateVariable"; - internal const string Error_DuplicateCorrelationSetName = "Error_DuplicateCorrelationSetName"; - internal const string Error_DragDropInvalid = "Error_DragDropInvalid"; - internal const string AddingImplicitActivity = "AddingImplicitActivity"; - internal const string Failure_DoDefaultAction = "Failure_DoDefaultAction"; - internal const string Failure_DoDefaultActionCaption = "Failure_DoDefaultActionCaption"; - internal const string Error_FaultInsideAtomicScope = "Error_FaultInsideAtomicScope"; - internal const string Error_ListenNotMoreThanOneDelay = "Error_ListenNotMoreThanOneDelay"; - internal const string Error_AtomicScopeWithFaultHandlersActivityDecl = "Error_AtomicScopeWithFaultHandlersActivityDecl"; - internal const string Error_AtomicScopeWithCancellationHandlerActivity = "Error_AtomicScopeWithCancellationHandlerActivity"; - internal const string Error_ScopeDuplicateFaultHandlerActivityForAll = "Error_ScopeDuplicateFaultHandlerActivityForAll"; - internal const string Error_ScopeDuplicateFaultHandlerActivityFor = "Error_ScopeDuplicateFaultHandlerActivityFor"; - internal const string Error_AtomicScopeNestedInNonLRT = "Error_AtomicScopeNestedInNonLRT"; - internal const string Error_LRTScopeNestedInNonLRT = "Error_LRTScopeNestedInNonLRT"; - internal const string Error_CAGNotAllChildrenConditioned = "Error_CAGNotAllChildrenConditioned"; - internal const string Error_ConditionedActivityChildCount = "Error_ConditionedActivityChildCount"; - internal const string Error_NegativeValue = "Error_NegativeValue"; - internal const string Error_MethodWithReturnType = "Error_MethodWithReturnType"; - internal const string Error_SendReceiveOrderIncorrect = "Error_SendReceiveOrderIncorrect"; - internal const string Error_ReceiveSendOrderIncorrect = "Error_ReceiveSendOrderIncorrect"; - internal const string Error_CompensateBadNesting = "Error_CompensateBadNesting"; - internal const string Error_ReferencedAssemblyIsInvalid = "Error_ReferencedAssemblyIsInvalid"; - internal const string Error_TypeToXsdConversion = "Error_TypeToXsdConversion"; - internal const string Error_FieldTypeNotResolved = "Error_FieldTypeNotResolved"; - internal const string Error_PropertyTypeNotResolved = "Error_PropertyTypeNotResolved"; - internal const string Error_CouldNotDeserializeXomlFile = "Error_CouldNotDeserializeXomlFile"; - internal const string Error_InternalCompilerError = "Error_InternalCompilerError"; - internal const string Error_TypeNotAsseblyQualified = "Error_TypeNotAsseblyQualified"; - internal const string CompilerWarning_StandardAssemlbyInReferences = "CompilerWarning_StandardAssemlbyInReferences"; - internal const string Error_SuspendInAtomicScope = "Error_SuspendInAtomicScope"; - internal const string Error_InvalidActivityExecutionContext = "Error_InvalidActivityExecutionContext"; - internal const string Error_NoRuntimeAvailable = "Error_NoRuntimeAvailable"; - internal const string Error_CanNotChangeAtRuntime = "Error_CanNotChangeAtRuntime"; - internal const string Error_DataContextNotInitialized = "Error_DataContextNotInitialized"; - internal const string Error_DataContextAlreadyInitialized = "Error_DataContextAlreadyInitialized"; - internal const string Error_ParseActivityNameDoesNotExist = "Error_ParseActivityNameDoesNotExist"; - internal const string Error_NoParameterPropertyDeclared = "Error_NoParameterPropertyDeclared"; - internal const string Error_PropertyInvalidIdentifier = "Error_PropertyInvalidIdentifier"; - internal const string Error_WorkflowDefinitionModified = "Error_WorkflowDefinitionModified"; - internal const string Error_FieldAlreadyExist = "Error_FieldAlreadyExist"; - internal const string Failure_FieldAlreadyExist = "Failure_FieldAlreadyExist"; - internal const string Error_DifferentTypeFieldExists = "Error_DifferentTypeFieldExists"; - internal const string Error_RootActivityTypeInvalid = "Error_RootActivityTypeInvalid"; - internal const string Error_RootActivityTypeInvalid2 = "Error_RootActivityTypeInvalid2"; - internal const string Error_CannotCompile_No_XClass = "Error_CannotCompile_No_XClass"; - internal const string Error_TemplateActivityIsNotActivity = "Error_TemplateActivityIsNotActivity"; - internal const string Error_TypeIsNotRootActivity = "Error_TypeIsNotRootActivity"; - internal const string Error_NoTypeProvider = "Error_NoTypeProvider"; - internal const string Error_NotCodeGeneratorType = "Error_NotCodeGeneratorType"; - internal const string Error_NotDataContext = "Error_NotDataContext"; - internal const string Error_MissingDefaultConstructor = "Error_MissingDefaultConstructor"; - internal const string Error_ContextStackItemMissing = "Error_ContextStackItemMissing"; - internal const string Error_UnexpectedArgumentType = "Error_UnexpectedArgumentType"; - internal const string Error_EmptyArgument = "Error_EmptyArgument"; - internal const string Error_DPAlreadyExist = "Error_DPAlreadyExist"; - internal const string Error_DuplicateDynamicProperty = "Error_DuplicateDynamicProperty"; - internal const string Error_DynamicPropertyTypeValueMismatch = "Error_DynamicPropertyTypeValueMismatch"; - internal const string Error_DynamicPropertyNoSupport = "Error_DynamicPropertyNoSupport"; - internal const string Error_NoContextForDatasource = "Error_NoContextForDatasource"; - internal const string Error_NoContextForDatasourceCaption = "Error_NoContextForDatasourceCaption"; - internal const string Error_DataSourceHasParent = "Error_DataSourceHasParent"; - internal const string OnTaskCompletedDescr = "OnTaskCompletedDescr"; - internal const string OnTaskInitializedDescr = "OnTaskInitializedDescr"; - internal const string Error_InvalidXmlData = "Error_InvalidXmlData"; - internal const string Error_HandlerNotOnRoot = "Error_HandlerNotOnRoot"; - internal const string Error_InvalidArgumentIndex = "Error_InvalidArgumentIndex"; - internal const string Error_UITypeEditorTypeNotUITypeEditor = "Error_UITypeEditorTypeNotUITypeEditor"; - internal const string FilterDescription_UITypeEditor = "FilterDescription_UITypeEditor"; - internal const string Error_UserCodeFilesNotAllowed = "Error_UserCodeFilesNotAllowed"; - internal const string Error_CodeWithinNotAllowed = "Error_CodeWithinNotAllowed"; - internal const string Error_TypeNotAuthorized = "Error_TypeNotAuthorized"; - internal const string Error_CantDetermineBaseType = "Error_CantDetermineBaseType"; - internal const string Error_MultipleSelectNotSupportedForBindAndPromote = "Error_MultipleSelectNotSupportedForBindAndPromote"; - internal const string Error_CantDetermineBaseTypeCaption = "Error_CantDetermineBaseTypeCaption"; - internal const string Error_CantDeterminePropertyBaseType = "Error_CantDeterminePropertyBaseType"; - internal const string Error_NullCustomActivityTypeName = "Error_NullCustomActivityTypeName"; - internal const string Error_InvalidAttribute = "Error_InvalidAttribute"; - internal const string Error_InvalidAttributes = "Error_InvalidAttributes"; - internal const string Error_ConfigFileMissingOrInvalid = "Error_ConfigFileMissingOrInvalid"; - internal const string Error_CantHaveContextActivity = "Error_CantHaveContextActivity"; - internal const string Error_SynchronizedNeedsDataContext = "Error_SynchronizedNeedsDataContext"; - internal const string Error_MoreThanOneFaultHandlersActivityDecl = "Error_MoreThanOneFaultHandlersActivityDecl"; - internal const string Error_MoreThanOneEventHandlersDecl = "Error_MoreThanOneEventHandlersDecl"; - internal const string Error_MoreThanOneCancelHandler = "Error_MoreThanOneCancelHandler"; - internal const string Error_MetaDataInterfaceMissing = "Error_MetaDataInterfaceMissing"; - internal const string Error_NonActivityExecutor = "Error_NonActivityExecutor"; - internal const string Error_DynamicUpdateEvaluation = "Error_DynamicUpdateEvaluation"; - internal const string Error_CollectionHasNullEntry = "Error_CollectionHasNullEntry"; - internal const string Error_MissingContextProperty = "Error_MissingContextProperty"; - internal const string Error_AssociatedDesignerMissing = "Error_AssociatedDesignerMissing"; - internal const string Error_MissingContextActivityProperty = "Error_MissingContextActivityProperty"; - internal const string Error_MissingActivityProperty = "Error_MissingActivityProperty"; - internal const string Error_MissingOwnerTypeProperty = "Error_MissingOwnerTypeProperty"; - internal const string Error_DOIsNotAnActivity = "Error_DOIsNotAnActivity"; - internal const string Error_PropertyCanBeOnlyCleared = "Error_PropertyCanBeOnlyCleared"; - internal const string Error_PropertyDefaultTypeMismatch = "Error_PropertyDefaultTypeMismatch"; - internal const string Error_PropertyDefaultIsReference = "Error_PropertyDefaultIsReference"; - // workflow load errors - internal const string Error_WorkflowLoadFailed = "Error_WorkflowLoadFailed"; - internal const string Error_WorkflowLoadValidationFailed = "Error_WorkflowLoadValidationFailed"; - internal const string Error_WorkflowLoadDeserializationFailed = "Error_WorkflowLoadDeserializationFailed"; - internal const string Error_WorkflowLoadTypeMismatch = "Error_WorkflowLoadTypeMismatch"; - internal const string Error_WorkflowLoadInvalidXoml = "Error_WorkflowLoadInvalidXoml"; - internal const string Error_WorkflowLoadNotValidRootType = "Error_WorkflowLoadNotValidRootType"; - internal const string Error_CantCreateInstanceOfComponent = "Error_CantCreateInstanceOfComponent"; - internal const string Error_NotComponentFactoryType = "Error_NotComponentFactoryType"; - internal const string Error_WorkflowTerminated = "Error_WorkflowTerminated"; - - // serializer errrors - internal const string Error_SerializerAttributesFoundInComplexProperty = "Error_SerializerAttributesFoundInComplexProperty"; - internal const string Error_InvalidDataFound = "Error_InvalidDataFound"; - internal const string Error_InvalidDataFoundForType = "Error_InvalidDataFoundForType"; - internal const string Error_InvalidDataFoundForType1 = "Error_InvalidDataFoundForType1"; - internal const string Error_SerializerTypeNotResolved = "Error_SerializerTypeNotResolved"; - internal const string Error_MarkupSerializerTypeNotResolved = "Error_MarkupSerializerTypeNotResolved"; - internal const string Error_SerializerTypeNotResolvedWithInnerError = "Error_SerializerTypeNotResolvedWithInnerError"; - internal const string Error_SerializerNotAvailable = "Error_SerializerNotAvailable"; - internal const string Error_SerializerNotAvailableForSerialize = "Error_SerializerNotAvailableForSerialize"; - internal const string Error_SerializerCreateInstanceFailed = "Error_SerializerCreateInstanceFailed"; - internal const string Error_SerializerAddChildFailed = "Error_SerializerAddChildFailed"; - internal const string Error_SerializerNoPropertyAvailable = "Error_SerializerNoPropertyAvailable"; - internal const string Error_SerializerPrimitivePropertyReadOnly = "Error_SerializerPrimitivePropertyReadOnly"; - internal const string Error_SerializerCantChangeIsLocked = "Error_SerializerCantChangeIsLocked"; - internal const string Error_SerializerPrimitivePropertySetFailed = "Error_SerializerPrimitivePropertySetFailed"; - internal const string Error_SerializerPropertyGetFailed = "Error_SerializerPropertyGetFailed"; - internal const string Error_SerializerPrimitivePropertyNoLogic = "Error_SerializerPrimitivePropertyNoLogic"; - internal const string Error_SerializerPrimitivePropertyParentIsNull = "Error_SerializerPrimitivePropertyParentIsNull"; - internal const string Error_SerializerComplexPropertySetFailed = "Error_SerializerComplexPropertySetFailed"; - internal const string Error_SerializerNoChildNotion = "Error_SerializerNoChildNotion"; - internal const string Error_SerializerNoDynamicPropertySupport = "Error_SerializerNoDynamicPropertySupport"; - internal const string Error_SerializerNoSerializeLogic = "Error_SerializerNoSerializeLogic"; - internal const string Error_SerializerReadOnlyPropertyAndValueIsNull = "Error_SerializerReadOnlyPropertyAndValueIsNull"; - internal const string Error_SerializerReadOnlyParametersNoChild = "Error_SerializerReadOnlyParametersNoChild"; - internal const string Error_SerializerNotParameterBindingObject = "Error_SerializerNotParameterBindingObject"; - internal const string Error_SerializerThrewException = "Error_SerializerThrewException"; - internal const string Error_ActivityCollectionSerializer = "Error_ActivityCollectionSerializer"; - internal const string Error_MissingClassAttribute = "Error_MissingClassAttribute"; - internal const string Error_MissingClassAttributeValue = "Error_MissingClassAttributeValue"; - internal const string ExecutorCreationFailedErrorMessage = "ExecutorCreationFailedErrorMessage"; - internal const string VariableGetterCode_VB = "VariableGetterCode_VB"; - internal const string VariableGetterCode_CS = "VariableGetterCode_CS"; - internal const string VariableSetterCode_VB = "VariableSetterCode_VB"; - internal const string VariableSetterCode_CS = "VariableSetterCode_CS"; - internal const string StaticVariableGetterCode_VB = "StaticVariableGetterCode_VB"; - internal const string StaticVariableGetterCode_CS = "StaticVariableGetterCode_CS"; - internal const string StaticVariableSetterCode_VB = "StaticVariableSetterCode_VB"; - internal const string StaticVariableSetterCode_CS = "StaticVariableSetterCode_CS"; - internal const string EnterCodeBesidesCode_VB = "EnterCodeBesidesCode_VB"; - internal const string EnterCodeBesidesCode_CS = "EnterCodeBesidesCode_CS"; - internal const string LeaveCodeBesides1Code_VB = "LeaveCodeBesides1Code_VB"; - internal const string LeaveCodeBesides2Code_VB = "LeaveCodeBesides2Code_VB"; - internal const string LeaveCodeBesides1Code_CS = "LeaveCodeBesides1Code_CS"; - internal const string LeaveCodeBesides2Code_CS = "LeaveCodeBesides2Code_CS"; - internal const string VariableSetterName = "VariableSetterName"; - internal const string VariableGetterName = "VariableGetterName"; - internal const string HandlerGetterName = "HandlerGetterName"; - internal const string WorkflowCreatorName = "WorkflowCreatorName"; - internal const string ActivityMethod = "ActivityMethod"; - internal const string CustomActivityPrivateField = "CustomActivityPrivateField"; - internal const string InitializedVariableDeclaration_VB = "InitializedVariableDeclaration_VB"; - internal const string InitializedVariableDeclaration_CS = "InitializedVariableDeclaration_CS"; - internal const string In = "In"; - internal const string Out = "Out"; - internal const string Ref = "Ref"; - internal const string Required = "Required"; - internal const string Optional = "Optional"; - internal const string Parameters = "Parameters"; - internal const string Properties = "Properties"; - internal const string Error_RecursionDetected = "Error_RecursionDetected"; - internal const string Warning_UnverifiedRecursion = "Warning_UnverifiedRecursion"; - internal const string AddConstructorCode = "AddConstructorCode"; - internal const string Error_UninitializedCorrelation = "Error_UninitializedCorrelation"; - internal const string Error_CorrelationAlreadyInitialized = "Error_CorrelationAlreadyInitialized"; - internal const string Error_CorrelatedSendReceiveAtomicScope = "Error_CorrelatedSendReceiveAtomicScope"; - internal const string Warning_ActivityValidation = "Warning_ActivityValidation"; - internal const string Warning_EmptyBehaviourActivity = "Warning_EmptyBehaviourActivity"; - internal const string Error_ParallelActivationNoCorrelation = "Error_ParallelActivationNoCorrelation"; - internal const string Error_MethodNotAccessible = "Error_MethodNotAccessible"; - internal const string Error_FieldNotAccessible = "Error_FieldNotAccessible"; - internal const string Error_PropertyNotAccessible = "Error_PropertyNotAccessible"; - internal const string Error_GenericArgumentsNotAllowed = "Error_GenericArgumentsNotAllowed"; - internal const string Error_InvalidIdentifier = "Error_InvalidIdentifier"; - internal const string Error_InvalidLanguageIdentifier = "Error_InvalidLanguageIdentifier"; - internal const string DuplicateActivityIdentifier = "DuplicateActivityIdentifier"; - internal const string Error_MissingAttribute = "Error_MissingAttribute"; - internal const string Error_LoadUIPropertiesFile = "Error_LoadUIPropertiesFile"; - internal const string Error_SerializerEventGetFailed = "Error_SerializerEventGetFailed"; - internal const string Error_SerializerEventFailed = "Error_SerializerEventFailed"; - internal const string Error_SerializerNoMemberFound = "Error_SerializerNoMemberFound"; - internal const string Error_DynamicEventConflict = "Error_DynamicEventConflict"; - internal const string Error_SerializerMemberSetFailed = "Error_SerializerMemberSetFailed"; - internal const string Error_ContentPropertyCouldNotBeFound = "Error_ContentPropertyCouldNotBeFound"; - internal const string Error_ContentPropertyValueInvalid = "Error_ContentPropertyValueInvalid"; - internal const string Error_ContentPropertyNoSetter = "Error_ContentPropertyNoSetter"; - internal const string Error_ContentCanNotBeConverted = "Error_ContentCanNotBeConverted"; - internal const string Error_ContentPropertyCanNotBeNull = "Error_ContentPropertyCanNotBeNull"; - internal const string Error_SerializerTypeMismatch = "Error_SerializerTypeMismatch"; - internal const string Error_CouldNotAddValueInContentProperty = "Error_CouldNotAddValueInContentProperty"; - internal const string Error_SerializerTypeRequirement = "Error_SerializerTypeRequirement"; - internal const string Error_CanNotAddActivityInBlackBoxActivity = "Error_CanNotAddActivityInBlackBoxActivity"; - internal const string Error_ContentPropertyCanNotSupportCompactFormat = "Error_ContentPropertyCanNotSupportCompactFormat"; - internal const string Error_ContentPropertyNoMultipleContents = "Error_ContentPropertyNoMultipleContents"; - internal const string Error_InternalSerializerError = "Error_InternalSerializerError"; - internal const string Error_DictionarySerializerNonDictionaryObject = "Error_DictionarySerializerNonDictionaryObject"; - internal const string Error_DictionarySerializerKeyNotFound = "Error_DictionarySerializerKeyNotFound"; - internal const string Error_InvalidCancelActivityState = "Error_InvalidCancelActivityState"; - internal const string Error_InvalidCompensateActivityState = "Error_InvalidCompensateActivityState"; - internal const string Error_InvalidCloseActivityState = "Error_InvalidCloseActivityState"; - internal const string Error_SealedPropertyMetadata = "Error_SealedPropertyMetadata"; - internal const string Error_MemberNotFound = "Error_MemberNotFound"; - internal const string Error_EmptyPathValue = "Error_EmptyPathValue"; - internal const string Error_InvalidCompensatingState = "Error_InvalidCompensatingState"; - internal const string Error_InvalidCancelingState = "Error_InvalidCancelingState"; - internal const string Error_InvalidClosingState = "Error_InvalidClosingState"; - internal const string Error_InvalidStateToExecuteChild = "Error_InvalidStateToExecuteChild"; - internal const string Error_InvalidExecutionState = "Error_InvalidExecutionState"; - internal const string Error_InvalidInitializingState = "Error_InvalidInitializingState"; - internal const string Error_InvalidInvokingState = "Error_InvalidInvokingState"; - internal const string Error_NotRegisteredAs = "Error_NotRegisteredAs"; - internal const string Error_AlreadyRegisteredAs = "Error_AlreadyRegisteredAs"; - internal const string Error_InsertingChildControls = "Error_InsertingChildControls"; - internal const string Error_EmptyToolTipRectangle = "Error_EmptyToolTipRectangle"; - internal const string Error_EmptyRectangleValue = "Error_EmptyRectangleValue"; - internal const string Error_InvalidShadowRectangle = "Error_InvalidShadowRectangle"; - internal const string Error_InvalidShadowDepth = "Error_InvalidShadowDepth"; - internal const string Error_InvalidLightSource = "Error_InvalidLightSource"; - internal const string Error_ChangingDock = "Error_ChangingDock"; - internal const string Error_NullOrEmptyValue = "Error_NullOrEmptyValue"; - internal const string Error_InvalidStateImages = "Error_InvalidStateImages"; - internal const string Error_InvalidConnectorSegment = "Error_InvalidConnectorSegment"; - internal const string Error_InvalidConnectorSource = "Error_InvalidConnectorSource"; - internal const string Error_CreatingToolTip = "Error_CreatingToolTip"; - internal const string Error_InvalidDockStyle = "Error_InvalidDockStyle"; - internal const string Error_InvalidConnectorValue = "Error_InvalidConnectorValue"; - internal const string Error_InvalidDesignerVerbValue = "Error_InvalidDesignerVerbValue"; - internal const string Error_InvalidRuntimeType = "Error_InvalidRuntimeType"; - internal const string Error_InvalidArgumentValue = "Error_InvalidArgumentValue"; - internal const string Error_InvalidRadiusValue = "Error_InvalidRadiusValue"; - internal const string ToolTipString = "ToolTipString"; - - // Collection Editor Resources - internal const string CollectionEditorCaption = "CollectionEditorCaption"; - internal const string CollectionEditorProperties = "CollectionEditorProperties"; - internal const string CollectionEditorPropertiesMultiSelect = "CollectionEditorPropertiesMultiSelect"; - internal const string CollectionEditorPropertiesNone = "CollectionEditorPropertiesNone"; - internal const string CollectionEditorCantRemoveItem = "CollectionEditorCantRemoveItem"; - internal const string CollectionEditorUndoBatchDesc = "CollectionEditorUndoBatchDesc"; - internal const string CollectionEditorInheritedReadOnlySelection = "CollectionEditorInheritedReadOnlySelection"; - internal const string Error_ParameterAlreadyExists = "Error_ParameterAlreadyExists"; - internal const string Error_PropertyAlreadyExists = "Error_PropertyAlreadyExists"; - internal const string Error_HiddenPropertyAlreadyExists = "Error_HiddenPropertyAlreadyExists"; - internal const string Error_CorrelationInUse = "Error_CorrelationInUse"; - internal const string Error_ItemNotExists = "Error_ItemNotExists"; - internal const string Error_NoHelpAvailable = "Error_NoHelpAvailable"; - internal const string Error_DuplicateWorkflow = "Error_DuplicateWorkflow"; - internal const string Error_Recursion = "Error_Recursion"; - internal const string Error_RootActivity = "Error_RootActivity"; - internal const string Error_ConditionDefinitionDeserializationFailed = "Error_ConditionDefinitionDeserializationFailed"; - internal const string Error_InvalidConditionDefinition = "Error_InvalidConditionDefinition"; - internal const string SR_InvokeTransactionalFromAtomic = "SR_InvokeTransactionalFromAtomic"; - internal const string Error_SuspendInAtomicCallChain = "Error_SuspendInAtomicCallChain"; - internal const string Error_LiteralPassedToOutRef = "Error_LiteralPassedToOutRef"; - internal const string Error_GeneratorShouldContainSingleActivity = "Error_GeneratorShouldContainSingleActivity"; - internal const string Error_DeclaringPropertyNotSupported = "Error_DeclaringPropertyNotSupported"; - internal const string Error_DeclaringEventNotSupported = "Error_DeclaringEventNotSupported"; - internal const string Error_DynamicEventNotSupported = "Error_DynamicEventNotSupported"; - internal const string Error_DynamicPropertyNotSupported = "Error_DynamicPropertyNotSupported"; - internal const string Error_ParameterTypeResolution = "Error_ParameterTypeResolution"; - - // Dynamic Validations - internal const string Error_DynamicActivity = "Error_DynamicActivity"; - internal const string Error_DynamicActivity2 = "Error_DynamicActivity2"; - internal const string Error_CompilerValidationFailed = "Error_CompilerValidationFailed"; - internal const string Error_RuntimeValidationFailed = "Error_RuntimeValidationFailed"; - internal const string Error_TransactionAlreadyCanceled = "Error_TransactionAlreadyCanceled"; - internal const string Error_RemoveExecutingActivity = "Error_RemoveExecutingActivity"; - internal const string Error_InsideAtomicScope = "Error_InsideAtomicScope"; - internal const string SuspendReason_WorkflowChange = "SuspendReason_WorkflowChange"; - - // type filtering - internal const string FilterDescription_ParameterDeclaration = "FilterDescription_ParameterDeclaration"; - internal const string FilterDescription_GenericArgument = "FilterDescription_GenericArgument"; - - - internal const string LibraryPathIsInvalid = "LibraryPathIsInvalid"; - - // Activity Set - internal const string Error_CreateValidator = "Error_CreateValidator"; - internal const string Error_InvalidPackageFile = "Error_InvalidPackageFile"; - internal const string Error_AddAssemblyRef = "Error_AddAssemblyRef"; - internal const string Error_AssemblyBadImage = "Error_AssemblyBadImage"; - internal const string BindPropertySetterName = "BindPropertySetterName"; - - // Bind validations - internal const string Error_CannotResolveActivity = "Error_CannotResolveActivity"; - internal const string Error_CannotResolveRelativeActivity = "Error_CannotResolveRelativeActivity"; - internal const string Error_PathNotSetForActivitySource = "Error_PathNotSetForActivitySource"; - internal const string Error_InvalidMemberPath = "Error_InvalidMemberPath"; - internal const string Error_TargetTypeMismatch = "Error_TargetTypeMismatch"; - internal const string Warning_ParameterBinding = "Warning_ParameterBinding"; - internal const string Error_ReferencedActivityPropertyNotBind = "Error_ReferencedActivityPropertyNotBind"; - internal const string Error_TargetTypeDataSourcePathMismatch = "Error_TargetTypeDataSourcePathMismatch"; - internal const string Bind_ActivityDataSourceRecursionDetected = "Bind_ActivityDataSourceRecursionDetected"; - internal const string Bind_DuplicateDataSourceNames = "Bind_DuplicateDataSourceNames"; - internal const string Error_PathNotSetForXmlDataSource = "Error_PathNotSetForXmlDataSource"; - internal const string Error_XmlDocumentLoadFailed = "Error_XmlDocumentLoadFailed"; - internal const string Error_XmlDataSourceInvalidPath = "Error_XmlDataSourceInvalidPath"; - internal const string Error_XmlDataSourceMultipleNodes = "Error_XmlDataSourceMultipleNodes"; - internal const string Error_XmlDataSourceInvalidXPath = "Error_XmlDataSourceInvalidXPath"; - internal const string Error_InvalidObjectRefFormat = "Error_InvalidObjectRefFormat"; - internal const string Error_ReadOnlyDataSource = "Error_ReadOnlyDataSource"; - internal const string Error_HandlerReadOnly = "Error_HandlerReadOnly"; - internal const string Error_XmlDataSourceReadOnly = "Error_XmlDataSourceReadOnly"; - internal const string Error_DataSourceNotExist = "Error_DataSourceNotExist"; - internal const string Error_PropertyNoGetter = "Error_PropertyNoGetter"; - internal const string Error_PropertyNoSetter = "Error_PropertyNoSetter"; - internal const string Error_PropertyHasNoGetterDefined = "Error_PropertyHasNoGetterDefined"; - internal const string Error_PropertyHasNoSetterDefined = "Error_PropertyHasNoSetterDefined"; - internal const string Error_PropertyReferenceNoGetter = "Error_PropertyReferenceNoGetter"; - internal const string Error_PropertyReferenceGetterNoAccess = "Error_PropertyReferenceGetterNoAccess"; - internal const string Error_PropertyHasIndexParameters = "Error_PropertyHasIndexParameters"; - internal const string Error_ReadOnlyField = "Error_ReadOnlyField"; - internal const string Error_NoEnclosingContext = "Error_NoEnclosingContext"; - internal const string Error_NestedPersistOnClose = "Error_NestedPersistOnClose"; - internal const string Error_NestedCompensatableActivity = "Error_NestedCompensatableActivity"; - internal const string Error_InvalidActivityForObjectDatasource = "Error_InvalidActivityForObjectDatasource"; - internal const string Error_DataSourceTypeConversionFailed = "Error_DataSourceTypeConversionFailed"; - internal const string Error_BindDialogWrongPropertyType = "Error_BindDialogWrongPropertyType"; - internal const string Error_BindDialogNoValidPropertySelected = "Error_BindDialogNoValidPropertySelected"; - internal const string Error_BindDialogBindNotValid = "Error_BindDialogBindNotValid"; - internal const string Error_BindDialogCanNotBindToItself = "Error_BindDialogCanNotBindToItself"; - internal const string Error_BindActivityReference = "Error_BindActivityReference"; - internal const string Error_NoTargetTypeForMethod = "Error_NoTargetTypeForMethod"; - internal const string Error_MethodDataSourceIsReadOnly = "Error_MethodDataSourceIsReadOnly"; - internal const string Error_NotMethodDataSource = "Error_NotMethodDataSource"; - internal const string Error_MethodDataSourceWithPath = "Error_MethodDataSourceWithPath"; - internal const string Error_PathSyntax = "Error_PathSyntax"; - internal const string Error_UnmatchedParen = "Error_UnmatchedParen"; - internal const string Error_UnmatchedBracket = "Error_UnmatchedBracket"; - internal const string Error_MemberWithSameNameExists = "Error_MemberWithSameNameExists"; - internal const string Error_ActivityIdentifierCanNotBeEmpty = "Error_ActivityIdentifierCanNotBeEmpty"; - internal const string Error_InvalidActivityIdentifier = "Error_InvalidActivityIdentifier"; - internal const string Error_ActivityBindTypeConversionError = "Error_ActivityBindTypeConversionError"; - internal const string EmptyValue = "EmptyValue"; - internal const string Error_PropertyTypeNotDefined = "Error_PropertyTypeNotDefined"; - - internal const string Error_CompilationFailed = "Error_CompilationFailed"; - internal const string Error_MissingCompilationContext = "Error_MissingCompilationContext"; - - internal const string InvokeWorkflowReference_VB = "InvokeWorkflowReference_VB"; - internal const string InvokeWorkflowReference_CS = "InvokeWorkflowReference_CS"; - internal const string Error_InvalidListItem = "Error_InvalidListItem"; - - internal const string ParserMapPINoWhitespace = "ParserMapPINoWhitespace"; - internal const string ParserMapPIBadCharEqual = "ParserMapPIBadCharEqual"; - internal const string ParserMapPIBadCharQuote = "ParserMapPIBadCharQuote"; - internal const string ParserMapPIBadKey = "ParserMapPIBadKey"; - internal const string ParserMapPIMissingKey = "ParserMapPIMissingKey"; - internal const string ParserMapPIKeyNotSet = "ParserMapPIKeyNotSet"; - internal const string ParserMismatchDelimiter = "ParserMismatchDelimiter"; - internal const string ParserDanglingClause = "ParserDanglingClause"; - internal const string UnknownDefinitionTag = "UnknownDefinitionTag"; - internal const string CDATASection = "CDATASection"; - internal const string TextSection = "TextSection"; - internal const string IncorrectSyntax = "IncorrectSyntax"; - internal const string IncorrectTypeSyntax = "IncorrectTypeSyntax"; - internal const string Error_MultipleRootActivityCreator = "Error_MultipleRootActivityCreator"; - internal const string Error_MustHaveParent = "Error_MustHaveParent"; - - // Workflow References - internal const string Error_ReferenceObjNotInitialized = "Error_ReferenceObjNotInitialized"; - internal const string Error_ReferenceInitResourceManager = "Error_ReferenceInitResourceManager"; - internal const string Error_ResourceReferenceGetObject = "Error_ResourceReferenceGetObject"; - internal const string Error_RefBindCantFindRef = "Error_RefBindCantFindRef"; - internal const string Error_RefBindMissingReferenceName = "Error_RefBindMissingReferenceName"; - internal const string Error_RefBindMissingAttribute = "Error_RefBindMissingAttribute"; - internal const string Error_ReferenceLoad = "Error_ReferenceLoad"; - internal const string Error_ReferenceMissingAttribute = "Error_ReferenceMissingAttribute"; - internal const string Error_ReferenceInvalidResourceFile = "Error_ReferenceInvalidResourceFile"; - internal const string Error_ReferenceEmptyName = "Error_ReferenceEmptyName"; - - internal const string HandlerInvokerName = "HandlerInvokerName"; - internal const string HandlerInvokerSwitchPrefix_CS = "HandlerInvokerSwitchPrefix_CS"; - internal const string HandlerInvokerSwitchPrefix_VB = "HandlerInvokerSwitchPrefix_VB"; - internal const string HandlerInvokerSwitchSuffix_CS = "HandlerInvokerSwitchSuffix_CS"; - internal const string HandlerInvokerSwitchSuffix_VB = "HandlerInvokerSwitchSuffix_VB"; - internal const string HandlerInvokerCaseBegin_CS = "HandlerInvokerCaseBegin_CS"; - internal const string HandlerInvokerCaseBegin_VB = "HandlerInvokerCaseBegin_VB"; - - // Activity Category - internal const string Standard = "Standard"; - internal const string Base = "Base"; - - // CustomActivityDesigner - internal const string ValidatorCompanionClassDesc = "ValidatorCompanionClassDesc"; - internal const string ExecutorCompanionClassDesc = "ExecutorCompanionClassDesc"; - internal const string DesignerCompanionClassDesc = "DesignerCompanionClassDesc"; - internal const string CustomActivityBaseTypeDesc = "CustomActivityBaseTypeDesc"; - internal const string ActivityProperties = "ActivityProperties"; - internal const string ActivityPropertiesDesc = "ActivityPropertiesDesc"; - internal const string CompanionClasses = "CompanionClasses"; - internal const string ActivityDesc = "Activity"; - internal const string Error_TypeConversionFailed = "Error_TypeConversionFailed"; - internal const string SupportDataContext = "SupportDataContext"; - internal const string AdvancedCategory = "AdvancedCategory"; - internal const string SupportDataContextDesc = "SupportDataContextDesc"; - internal const string BaseCompanionClassName = "BaseCompanionClassName"; - internal const string BaseCompanionClassDesc = "BaseCompanionClassDesc"; - internal const string Designer = "Designer"; - internal const string Validator = "Validator"; - internal const string Executor = "Executor"; - internal const string BaseActivityType = "BaseActivityType"; - internal const string Error_NotBuiltInActivity = "Error_NotBuiltInActivity"; - internal const string NoChildActivities_Message = "NoChildActivities_Message"; - internal const string NoChildActivities_Caption = "NoChildActivities_Caption"; - internal const string Error_CustomActivityCantCreate = "Error_CustomActivityCantCreate"; - internal const string Error_CantChangeBuiltInActivity = "Error_CantChangeBuiltInActivity"; - internal const string Error_CantAddBeforeBuiltInActivity = "Error_CantAddBeforeBuiltInActivity"; - internal const string Error_CantAddAfterNonBuiltInActivity = "Error_CantAddAfterNonBuiltInActivity"; - internal const string Error_CannotAddRemoveChildActivities = "Error_CannotAddRemoveChildActivities"; - internal const string Error_CantFindBuiltInActivity = "Error_CantFindBuiltInActivity"; - internal const string Error_MissingBaseCompanionClassAttribute = "Error_MissingBaseCompanionClassAttribute"; - internal const string Error_CantFindBuiltInParent = "Error_CantFindBuiltInParent"; - internal const string Error_CantCreateInstanceOfBaseType = "Error_CantCreateInstanceOfBaseType"; - internal const string Error_CustomActivityTypeCouldNotBeFound = "Error_CustomActivityTypeCouldNotBeFound"; - internal const string None = "None"; - internal const string AtomicTransaction = "AtomicTransaction"; - internal const string LocalDataContext = "LocalDataContext"; - internal const string LocalDataContextDesc = "LocalDataContextDesc"; - internal const string CompanionClass = "CompanionClass"; - internal const string Error_AlreadyRootActivity = "Error_AlreadyRootActivity"; - internal const string RootActivityName = "RootActivityName"; - internal const string RootActivityNameDesc = "RootActivityNameDesc"; - internal const string CustomProperties = "CustomProperties"; - internal const string VisibleDescr = "VisibleDescr"; - internal const string EditableDescr = "EditableDescr"; - internal const string Error_CantCreateMethod = "Error_CantCreateMethod"; - internal const string Error_CantEditNullValue = "Error_CantEditNullValue"; - internal const string Error_CompanionTypeNotSet = "Error_CompanionTypeNotSet"; - internal const string Error_CompanionClassNameCanNotBeEmpty = "Error_CompanionClassNameCanNotBeEmpty"; - internal const string Error_CouldNotEmitFieldInLocalDataContext = "Error_CouldNotEmitFieldInLocalDataContext"; - internal const string Error_CouldNotEmitMethodInLocalDataContext = "Error_CouldNotEmitMethodInLocalDataContext"; - internal const string Error_DerivationFromTypeWithLocalDataContext = "Error_DerivationFromTypeWithLocalDataContext"; - internal const string Error_CompanionTypeDerivationError = "Error_CompanionTypeDerivationError"; - internal const string Error_CantCreateDataContextClass = "Error_CantCreateDataContextClass"; - internal const string ArrayExistingBind = "ArrayExistingBind"; - internal const string Error_NoMatchingFieldsOrProperties = "Error_NoMatchingFieldsOrProperties"; - internal const string ChooseFieldPropertyDatasource = "ChooseFieldPropertyDatasource"; - - internal const string SupportsTransaction = "SupportsTransaction"; - internal const string SupportsExceptions = "SupportsExceptions"; - internal const string SupportsCancellationHandlerActivity = "SupportsCancellationHandlerActivity"; - internal const string SupportsEvents = "SupportsEvents"; - internal const string SupportsDataSources = "SupportsDataSources"; - internal const string SupportsCompensationHandler = "SupportsCompensationHandler"; - internal const string SupportsCompensationHandlerDesc = "SupportsCompensationHandlerDesc"; - internal const string SupportsTransactionDesc = "SupportsTransactionDesc"; - internal const string SupportsExceptionsDesc = "SupportsExceptionsDesc"; - internal const string SupportsCancelHandlerDesc = "SupportsCancelHandlerDesc"; - internal const string SupportsEventsDesc = "SupportsEventsDesc"; - internal const string TransactionDesc = "TransactionDesc"; - - internal const string Error_BaseTypeMustBeActivity = "Error_BaseTypeMustBeActivity"; - internal const string ExistingActivityBindTitle = "ExistingActivityBindTitle"; - internal const string ExistingActivityBindLabel = "ExistingActivityBindLabel"; - internal const string ExistingFieldPropBindTitle = "ExistingFieldPropBindTitle"; - internal const string ExistingFieldPropBindLabel = "ExistingFieldPropBindLabel"; - internal const string ProvidesSynchronization = "ProvidesSynchronization"; - internal const string ProvidesSynchronizationDesc = "ProvidesSynchronizationDesc"; - internal const string SynchronizationHandles = "SynchronizationHandles"; - internal const string SynchronizationHandlesDesc = "SynchronizationHandlesDesc"; - - internal const string Error_TransactionAlreadyApplied = "Error_TransactionAlreadyApplied"; - internal const string Error_BindBaseTypeNotSpecified = "Error_BindBaseTypeNotSpecified"; - internal const string NonDelegateTargetType = "NonDelegateTargetType"; - internal const string Error_ClassnameNotInRootNamespace = "Error_ClassnameNotInRootNamespace"; - internal const string Error_CantUseCurrentProjectTypeAsBase = "Error_CantUseCurrentProjectTypeAsBase"; - internal const string Error_UnboundGenericType = "Error_UnboundGenericType"; - internal const string Error_UnboundGenericTypeDataSource = "Error_UnboundGenericTypeDataSource"; - internal const string Error_BaseTypeUnknown = "Error_BaseTypeUnknown"; - internal const string Error_UnconfiguredBind = "Error_UnconfiguredBind"; - internal const string Error_CanNotEmitMemberInLocalDataContext = "Error_CanNotEmitMemberInLocalDataContext"; - internal const string Error_DesignedTypeNotFound = "Error_DesignedTypeNotFound"; - internal const string Error_PathCouldNotBeResolvedToMember = "Error_PathCouldNotBeResolvedToMember"; - internal const string Error_EdittingNullCollection = "Error_EdittingNullCollection"; - internal const string Error_MoreThanOneCompensationDecl = "Error_MoreThanOneCompensationDecl"; - internal const string Error_ParentDoesNotSupportCompensation = "Error_ParentDoesNotSupportCompensation"; - internal const string Error_CantResolveEventHandler = "Error_CantResolveEventHandler"; - internal const string Error_XSDObjectTypeNotSerializable = "Error_XSDObjectTypeNotSerializable"; - internal const string AEC_InvalidActivity = "AEC_InvalidActivity"; - internal const string GetDynamicActivities_InvalidActivity = "GetDynamicActivities_InvalidActivity"; - internal const string AEC_InvalidNestedActivity = "AEC_InvalidNestedActivity"; - internal const string Error_IDNotSetForActivitySource = "Error_IDNotSetForActivitySource"; - internal const string Error_InvalidCustomPropertyName = "Error_InvalidCustomPropertyName"; - internal const string Error_InvalidCustomPropertyType = "Error_InvalidCustomPropertyType"; - - internal const string Error_DPReadOnly = "Error_DPReadOnly"; - internal const string Error_DPMetaPropertyBinding = "Error_DPMetaPropertyBinding"; - internal const string Error_DPSetValueBind = "Error_DPSetValueBind"; - internal const string Error_DPSetValueHandler = "Error_DPSetValueHandler"; - internal const string Error_DPGetValueHandler = "Error_DPGetValueHandler"; - internal const string Error_DPAddHandlerNonEvent = "Error_DPAddHandlerNonEvent"; - internal const string Error_DPAddHandlerMetaProperty = "Error_DPAddHandlerMetaProperty"; - internal const string Error_DPRemoveHandlerBind = "Error_DPRemoveHandlerBind"; - internal const string Error_LanguageNeedsToBeVBCSharp = "Error_LanguageNeedsToBeVBCSharp"; - internal const string Error_TargetFxNotSupported = "Error_TargetFxNotSupported"; - internal const string Error_CantConvertValueValue = "Error_CantConvertValueValue"; - internal const string Error_TypeIsNotValid = "Error_TypeIsNotValid"; - internal const string Error_TypePropertyInvalid = "Error_TypePropertyInvalid"; - internal const string Error_EventCantBeMetaProperty = "Error_EventCantBeMetaProperty"; - internal const string Error_EventMustBeDelegate = "Error_EventMustBeDelegate"; - internal const string Error_DPPropertyTypeMissing = "Error_DPPropertyTypeMissing"; - - internal const string TransactionalContextActivityDescription = "TransactionalContextActivityDescription"; - internal const string CompensatableTransactionalContextActivityDescription = "CompensatableTransactionalContextActivityDescription"; - internal const string SynchronizationScopeActivityDescription = "SynchronizationScopeActivityDescription"; - internal const string SequenceActivityDescription = "SequenceActivityDescription"; - internal const string CompensateActivityDescription = "CompensateActivityDescription"; - internal const string Error_CompensateBadTargetTX = "Error_CompensateBadTargetTX"; - internal const string Error_CancelHandlerParentNotScope = "Error_CancelHandlerParentNotScope"; - internal const string FaultHandlerActivityDescription = "FaultHandlerActivityDescription"; - internal const string Error_ExceptionTypeNotException = "Error_ExceptionTypeNotException"; - internal const string Error_FaultIsNotOfFaultType = "Error_FaultIsNotOfFaultType"; - internal const string Error_FaultTypeNoDefaultConstructor = "Error_FaultTypeNoDefaultConstructor"; - internal const string FilterDescription_FaultHandlerActivity = "FilterDescription_FaultHandlerActivity"; - internal const string Error_FaultHandlerActivityParentNotFaultHandlersActivity = "Error_FaultHandlerActivityParentNotFaultHandlersActivity"; - internal const string Error_FaultHandlerActivityAllMustBeLast = "Error_FaultHandlerActivityAllMustBeLast"; - internal const string Error_FaultHandlersActivityDeclNotAllFaultHandlerActivityDecl = "Error_FaultHandlersActivityDeclNotAllFaultHandlerActivityDecl"; - internal const string Error_FaultHandlerActivityWrongOrder = "Error_FaultHandlerActivityWrongOrder"; - internal const string Error_SenderMustBeActivityExecutionContext = "Error_SenderMustBeActivityExecutionContext"; - internal const string Error_XomlWorkflowHasCode = "Error_XomlWorkflowHasCode"; - internal const string Error_WrongParamForActivityResolveEventArgs = "Error_WrongParamForActivityResolveEventArgs"; - internal const string Error_ValidatorThrewException = "Error_ValidatorThrewException"; - internal const string Error_Missing_CanModifyProperties_True = "Error_Missing_CanModifyProperties_True"; - internal const string Error_Missing_CanModifyProperties_False = "Error_Missing_CanModifyProperties_False"; - internal const string Error_ModelingConstructsCanNotContainModelingConstructs = "Error_ModelingConstructsCanNotContainModelingConstructs"; - internal const string Error_RootIsNotEnabled = "Error_RootIsNotEnabled"; - internal const string Error_MissingSetAccessor = "Error_MissingSetAccessor"; - internal const string Error_MissingAddHandler = "Error_MissingAddHandler"; - internal const string Error_MissingCLRProperty = "Error_MissingCLRProperty"; - - internal const string Error_NotReadOnlyProperty = "Error_NotReadOnlyProperty"; - internal const string Error_InvalidDependencyProperty = "Error_InvalidDependencyProperty"; - internal const string Error_ActivityNameExist = "Error_ActivityNameExist"; - internal const string CannotCreateAttribute = "CannotCreateAttribute"; - internal const string NamespaceAndDeclaringTypeCannotBeNull = "NamespaceAndDeclaringTypeCannotBeNull"; - internal const string NotElementType = "NotElementType"; - - // Layout persistence errors - internal const string Error_LayoutSerializationActivityNotFound = "Error_LayoutSerializationActivityNotFound"; - internal const string Error_LayoutSerializationAssociatedActivityNotFound = "Error_LayoutSerializationAssociatedActivityNotFound"; - internal const string Error_LayoutSerializationPersistenceSupport = "Error_LayoutSerializationPersistenceSupport"; - internal const string Error_LayoutSerializationRootDesignerNotFound = "Error_LayoutSerializationRootDesignerNotFound"; - internal const string Error_ParameterCannotBeEmpty = "Error_ParameterCannotBeEmpty"; - internal const string InvalidExecutionStatus = "InvalidExecutionStatus"; - internal const string Error_LayoutDeserialization = "Error_LayoutDeserialization"; - internal const string Error_LayoutSerialization = "Error_LayoutSerialization"; - - internal const string Error_SerializerStackOverflow = "Error_SerializerStackOverflow"; - internal const string Error_InvalidActivityForWorkflowChanges = "Error_InvalidActivityForWorkflowChanges"; - internal const string Error_InvalidMemberType = "Error_InvalidMemberType"; - internal const string Error_BindPathNullValue = "Error_BindPathNullValue"; - internal const string Error_MarkupExtensionMissingTerminatingCharacter = "Error_MarkupExtensionMissingTerminatingCharacter"; - internal const string Error_MarkupExtensionDeserializeFailed = "Error_MarkupExtensionDeserializeFailed"; - internal const string Error_ApplyDynamicChangeFailed = "Error_ApplyDynamicChangeFailed"; - internal const string Error_ActivityCircularReference = "Error_ActivityCircularReference"; - internal const string Error_ValidatorTypeIsInvalid = "Error_ValidatorTypeIsInvalid"; - internal const string Error_InvalidServiceProvider = "Error_InvalidServiceProvider"; - internal const string Error_InvalidRootForWorkflowChanges = "Error_InvalidRootForWorkflowChanges"; - internal const string Error_ExtraCharacterFoundAtEnd = "Error_ExtraCharacterFoundAtEnd"; - internal const string Error_WorkflowChangesNotSupported = "Error_WorkflowChangesNotSupported"; - internal const string Error_TypeSystemAttributeArgument = "Error_TypeSystemAttributeArgument"; - - internal const string Error_InvalidElementFoundForType = "Error_InvalidElementFoundForType"; - internal const string Error_ActivitySaveLoadNotCalled = "Error_ActivitySaveLoadNotCalled"; - internal const string Error_CanNotBindProperty = "Error_CanNotBindProperty"; -} -#pragma warning restore CS8603 // 可能返回 null 引用。 - -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/Sortedset/Sortedset.cs b/src/Basal/IFox.Basal.Shared/Sortedset/Sortedset.cs deleted file mode 100644 index 66a6a7f50279475f9524d491193fc933709b7b46..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/Sortedset/Sortedset.cs +++ /dev/null @@ -1,2901 +0,0 @@ -#if NET35 -#pragma warning disable CS8603 // 可能返回 null 引用。 -#pragma warning disable CS8601 // 引用类型赋值可能为 null。 -#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 -#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。 -#pragma warning disable IDE0059 // 不需要赋值 -#pragma warning disable CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型。 -#pragma warning disable CS8602 // 解引用可能出现空引用。 -#pragma warning disable CS8604 // 引用类型参数可能为 null。 -// #define USING_HASH_SET -// ==++== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// ==--== -/*============================================================ -** -** Class: SortedSet -** -** Purpose: A generic sorted set. -** -** Date: August 15, 2008 -** -===========================================================*/ - - -namespace System.Collections.Generic -{ - using IFoxCAD.Basal; - using System; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Runtime.Serialization; - - - - // - // A binary search tree is a red-black tree if it satisfies the following red-black properties: - // 1. Every node is either red or black - // 2. Every leaf (nil node) is black - // 3. If a node is red, then both its children are black - // 4. Every simple path from a node to a descendant leaf contains the same number of black nodes - // - // The basic idea of red-black tree is to represent 2-3-4 trees as standard BSTs but to add one extra bit of information - // per node to encode 3-nodes and 4-nodes. - // 4-nodes will be represented as: B - // R R - // 3 -node will be represented as: B or B - // R B B R - // - // For a detailed description of the algorithm, take a look at "Algorithms" by Robert Sedgewick. - // - - internal delegate bool TreeWalkPredicate(SortedSet.Node node); - - internal enum TreeRotation - { - LeftRotation = 1, - RightRotation = 2, - RightLeftRotation = 3, - LeftRightRotation = 4, - } - - [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "by design name choice")] - [DebuggerTypeProxy(nameof(SortedSet))]/*这句改了*/ - [DebuggerDisplay("Count = {Count}")] -#if !FEATURE_NETCORE - [Serializable] - public class SortedSet : ISet, ICollection, ICollection, ISerializable, IDeserializationCallback// , IReadOnlyCollection - { -#else - public class SortedSet : ISet, ICollection, ICollection, IReadOnlyCollection { -#endif // !FEATURE_NETCORE - #region local variables/constants - Node root; - IComparer comparer; - int count; - int version; - private Object _syncRoot; - - private const String ComparerName = "Comparer"; - private const String CountName = "Count"; - private const String ItemsName = "Items"; - private const String VersionName = "Version"; - // needed for enumerator - private const String TreeName = "Tree"; - private const String NodeValueName = "Item"; - private const String EnumStartName = "EnumStarted"; - private const String ReverseName = "Reverse"; - private const String EnumVersionName = "EnumVersion"; - -#if !FEATURE_NETCORE - // needed for TreeSubset - private const String minName = "Min"; - private const String maxName = "Max"; - private const String lBoundActiveName = "lBoundActive"; - private const String uBoundActiveName = "uBoundActive"; - - private SerializationInfo siInfo; // A temporary variable which we need during deserialization. -#endif - internal const int StackAllocThreshold = 100; - - #endregion - - #region Constructors - public SortedSet() - { - this.comparer = Comparer.Default; - } - - public SortedSet(IComparer comparer) - { - if (comparer == null) - { - this.comparer = Comparer.Default; - } - else - { - this.comparer = comparer; - } - } - - - public SortedSet(IEnumerable collection) : this(collection, Comparer.Default) - { - } - - public SortedSet(IEnumerable collection, IComparer comparer) - : this(comparer) - { - //if (collection == null) - //{ - // throw new ArgumentNullException("collection"); - //} - collection.NotNull(nameof(collection)); - // these are explicit type checks in the mould of HashSet. It would have worked better - // with something like an ISorted (we could make this work for SortedList.Keys etc) - SortedSet baseTreeSubSet = collection as TreeSubSet; - if (collection is SortedSet baseSortedSet && baseTreeSubSet == null && AreComparersEqual(this, baseSortedSet)) - { - // breadth first traversal to recreate nodes - if (baseSortedSet.Count == 0) - { - count = 0; - version = 0; - root = null; - return; - } - - - // pre order way to replicate nodes - Stack theirStack = new(2 * Log2(baseSortedSet.Count) + 2); - Stack myStack = new(2 * Log2(baseSortedSet.Count) + 2); - Node theirCurrent = baseSortedSet.root; - Node myCurrent = (theirCurrent != null ? new SortedSet.Node(theirCurrent.Item, theirCurrent.IsRed) : null); - root = myCurrent; - while (theirCurrent != null) - { - theirStack.Push(theirCurrent); - myStack.Push(myCurrent); - myCurrent.Left = (theirCurrent.Left != null ? new SortedSet.Node(theirCurrent.Left.Item, theirCurrent.Left.IsRed) : null); - theirCurrent = theirCurrent.Left; - myCurrent = myCurrent.Left; - } - while (theirStack.Count != 0) - { - theirCurrent = theirStack.Pop(); - myCurrent = myStack.Pop(); - Node theirRight = theirCurrent.Right; - Node myRight = null; - if (theirRight != null) - { - myRight = new SortedSet.Node(theirRight.Item, theirRight.IsRed); - } - myCurrent.Right = myRight; - - while (theirRight != null) - { - theirStack.Push(theirRight); - myStack.Push(myRight); - myRight.Left = (theirRight.Left != null ? new SortedSet.Node(theirRight.Left.Item, theirRight.Left.IsRed) : null); - theirRight = theirRight.Left; - myRight = myRight.Left; - } - } - count = baseSortedSet.count; - version = 0; - } - else - { // As it stands, you're doing an NlogN sort of the collection - List els = new(collection); - els.Sort(this.comparer); - for (int i = 1; i < els.Count; i++) - { - if (comparer.Compare(els[i], els[i - 1]) == 0) - { - els.RemoveAt(i); - i--; - } - } - root = ConstructRootFromSortedArray(els.ToArray(), 0, els.Count - 1, null); - count = els.Count; - version = 0; - } - } - - -#if !FEATURE_NETCORE - - protected SortedSet(SerializationInfo info, StreamingContext context) - { - siInfo = info; - } -#endif - #endregion - - #region Bulk Operation Helpers - private void AddAllElements(IEnumerable collection) - { - foreach (T item in collection) - { - if (!this.Contains(item)) - Add(item); - } - } - - private void RemoveAllElements(IEnumerable collection) - { - T min = this.Min; - T max = this.Max; - foreach (T item in collection) - { - if (!(comparer.Compare(item, min) < 0 || comparer.Compare(item, max) > 0) && this.Contains(item)) - this.Remove(item); - } - } - - private bool ContainsAllElements(IEnumerable collection) - { - foreach (T item in collection) - { - if (!this.Contains(item)) - { - return false; - } - } - return true; - } - - // - // Do a in order walk on tree and calls the delegate for each node. - // If the action delegate returns false, stop the walk. - // - // Return true if the entire tree has been walked. - // Otherwise returns false. - // - internal bool InOrderTreeWalk(TreeWalkPredicate action) - { - return InOrderTreeWalk(action, false); - } - - // Allows for the change in traversal direction. Reverse visits nodes in descending order - internal virtual bool InOrderTreeWalk(TreeWalkPredicate action, bool reverse) - { - if (root == null) - { - return true; - } - - // The maximum height of a red-black tree is 2*lg(n+1). - // See page 264 of "Introduction to algorithms" by Thomas H. Cormen - // note: this should be logbase2, but since the stack grows itself, we - // don't want the extra cost - Stack stack = new(2 * (int)(SortedSet.Log2(Count + 1))); - Node current = root; - while (current != null) - { - stack.Push(current); - current = (reverse ? current.Right : current.Left); - } - while (stack.Count != 0) - { - current = stack.Pop(); - if (!action(current)) - { - return false; - } - - Node node = (reverse ? current.Left : current.Right); - while (node != null) - { - stack.Push(node); - node = (reverse ? node.Right : node.Left); - } - } - return true; - } - - // - // Do a left to right breadth first walk on tree and - // calls the delegate for each node. - // If the action delegate returns false, stop the walk. - // - // Return true if the entire tree has been walked. - // Otherwise returns false. - // - internal virtual bool BreadthFirstTreeWalk(TreeWalkPredicate action) - { - if (root == null) - { - return true; - } - - List processQueue = new() - { - root - }; - Node current; - - while (processQueue.Count != 0) - { - current = processQueue[0]; - processQueue.RemoveAt(0); - if (!action(current)) - { - return false; - } - if (current.Left != null) - { - processQueue.Add(current.Left); - } - if (current.Right != null) - { - processQueue.Add(current.Right); - } - } - return true; - } - #endregion - - #region Properties - public int Count - { - get - { - VersionCheck(); - return count; - } - } - - public IComparer Comparer - { - get - { - return comparer; - } - } - - bool ICollection.IsReadOnly - { - get - { - return false; - } - } - - bool ICollection.IsSynchronized - { - get - { - return false; - } - } - - object ICollection.SyncRoot - { - get - { - if (_syncRoot == null) - { - System.Threading.Interlocked.CompareExchange(ref _syncRoot, new Object(), null); - } - return _syncRoot; - } - } - #endregion - - #region Subclass helpers - - // virtual function for subclass that needs to update count - internal virtual void VersionCheck() { } - - - // virtual function for subclass that needs to do range checks - internal virtual bool IsWithinRange(T item) - { - return true; - } - #endregion - - #region ICollection Members - /// - /// Add the value ITEM to the tree, returns true if added, false if duplicate - /// - /// item to be added - public bool Add(T item) - { - return AddIfNotPresent(item); - } - - void ICollection.Add(T item) - { - AddIfNotPresent(item); - } - - - /// - /// Adds ITEM to the tree if not already present. Returns TRUE if value was successfully added - /// or FALSE if it is a duplicate - /// - internal virtual bool AddIfNotPresent(T item) - { - if (root == null) - { // empty tree - root = new Node(item, false); - count = 1; - version++; - return true; - } - - // - // Search for a node at bottom to insert the new node. - // If we can guanratee the node we found is not a 4-node, it would be easy to do insertion. - // We split 4-nodes along the search path. - // - Node current = root; - Node parent = null; - Node grandParent = null; - Node greatGrandParent = null; - - // even if we don't actually add to the set, we may be altering its structure (by doing rotations - // and such). so update version to disable any enumerators/subsets working on it - version++; - - - int order = 0; - while (current != null) - { - order = comparer.Compare(item, current.Item); - if (order == 0) - { - // We could have changed root node to red during the search process. - // We need to set it to black before we return. - root.IsRed = false; - return false; - } - - // split a 4-node into two 2-nodes - if (Is4Node(current)) - { - Split4Node(current); - // We could have introduced two consecutive red nodes after split. Fix that by rotation. - if (IsRed(parent)) - { - InsertionBalance(current, ref parent, grandParent, greatGrandParent); - } - } - greatGrandParent = grandParent; - grandParent = parent; - parent = current; - current = (order < 0) ? current.Left : current.Right; - } - - Debug.Assert(parent != null, "Parent node cannot be null here!"); - // ready to insert the new node - Node node = new(item); - if (order > 0) - { - parent.Right = node; - } - else - { - parent.Left = node; - } - - // the new node will be red, so we will need to adjust the colors if parent node is also red - if (parent.IsRed) - { - InsertionBalance(node, ref parent, grandParent, greatGrandParent); - } - - // Root node is always black - root.IsRed = false; - ++count; - return true; - } - - /// - /// Remove the T ITEM from this SortedSet. Returns true if successfully removed. - /// - /// - /// - public bool Remove(T item) - { - return this.DoRemove(item); // so it can be made non-virtual - } - - internal virtual bool DoRemove(T item) - { - if (root == null) - { - return false; - } - - - // Search for a node and then find its succesor. - // Then copy the item from the succesor to the matching node and delete the successor. - // If a node doesn't have a successor, we can replace it with its left child (if not empty.) - // or delete the matching node. - // - // In top-down implementation, it is important to make sure the node to be deleted is not a 2-node. - // Following code will make sure the node on the path is not a 2 Node. - - // even if we don't actually remove from the set, we may be altering its structure (by doing rotations - // and such). so update version to disable any enumerators/subsets working on it - version++; - - Node current = root; - Node parent = null; - Node grandParent = null; - Node match = null; - Node parentOfMatch = null; - bool foundMatch = false; - while (current != null) - { - if (Is2Node(current)) - { // fix up 2-Node - if (parent == null) - { // current is root. Mark it as red - current.IsRed = true; - } - else - { - Node sibling = GetSibling(current, parent); - if (sibling.IsRed) - { - // If parent is a 3-node, flip the orientation of the red link. - // We can acheive this by a single rotation - // This case is converted to one of other cased below. - Debug.Assert(!parent.IsRed, "parent must be a black node!"); - if (parent.Right == sibling) - { - RotateLeft(parent); - } - else - { - RotateRight(parent); - } - - parent.IsRed = true; - sibling.IsRed = false; // parent's color - // sibling becomes child of grandParent or root after rotation. Update link from grandParent or root - ReplaceChildOfNodeOrRoot(grandParent, parent, sibling); - // sibling will become grandParent of current node - grandParent = sibling; - if (parent == match) - { - parentOfMatch = sibling; - } - - // update sibling, this is necessary for following processing - sibling = (parent.Left == current) ? parent.Right : parent.Left; - } - Debug.Assert(sibling != null || sibling.IsRed == false, "sibling must not be null and it must be black!"); - - if (Is2Node(sibling)) - { - Merge2Nodes(parent, current, sibling); - } - else - { - // current is a 2-node and sibling is either a 3-node or a 4-node. - // We can change the color of current to red by some rotation. - TreeRotation rotation = RotationNeeded(parent, current, sibling); - Node newGrandParent = null; - switch (rotation) - { - case TreeRotation.RightRotation: - Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!"); - Debug.Assert(sibling.Left.IsRed, "Left child of sibling must be red!"); - sibling.Left.IsRed = false; - newGrandParent = RotateRight(parent); - break; - case TreeRotation.LeftRotation: - Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!"); - Debug.Assert(sibling.Right.IsRed, "Right child of sibling must be red!"); - sibling.Right.IsRed = false; - newGrandParent = RotateLeft(parent); - break; - - case TreeRotation.RightLeftRotation: - Debug.Assert(parent.Right == sibling, "sibling must be left child of parent!"); - Debug.Assert(sibling.Left.IsRed, "Left child of sibling must be red!"); - newGrandParent = RotateRightLeft(parent); - break; - - case TreeRotation.LeftRightRotation: - Debug.Assert(parent.Left == sibling, "sibling must be left child of parent!"); - Debug.Assert(sibling.Right.IsRed, "Right child of sibling must be red!"); - newGrandParent = RotateLeftRight(parent); - break; - } - - newGrandParent.IsRed = parent.IsRed; - parent.IsRed = false; - current.IsRed = true; - ReplaceChildOfNodeOrRoot(grandParent, parent, newGrandParent); - if (parent == match) - { - parentOfMatch = newGrandParent; - } - grandParent = newGrandParent; - } - } - } - - // we don't need to compare any more once we found the match - int order = foundMatch ? -1 : comparer.Compare(item, current.Item); - if (order == 0) - { - // save the matching node - foundMatch = true; - match = current; - parentOfMatch = parent; - } - - grandParent = parent; - parent = current; - - if (order < 0) - { - current = current.Left; - } - else - { - current = current.Right; // continue the search in right sub tree after we find a match - } - } - - // move successor to the matching node position and replace links - if (match != null) - { - ReplaceNode(match, parentOfMatch, parent, grandParent); - --count; - } - - if (root != null) - { - root.IsRed = false; - } - return foundMatch; - } - - public virtual void Clear() - { - root = null; - count = 0; - ++version; - } - - - public virtual bool Contains(T item) - { - return FindNode(item) != null; - } - - - - - public void CopyTo(T[] array) - { - CopyTo(array, 0, Count); - } - - public void CopyTo(T[] array, int index) - { - CopyTo(array, index, Count); - } - - public void CopyTo(T[] array, int index, int count) - { - if (array == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - } - - if (index < 0) - { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index); - } - - if (count < 0) - { - throw new ArgumentOutOfRangeException("count", SR.GetString("SR.ArgumentOutOfRange_NeedNonNegNum")); - } - - // will array, starting at arrayIndex, be able to hold elements? Note: not - // checking arrayIndex >= array.Length (consistency with list of allowing - // count of 0; subsequent check takes care of the rest) - if (index > array.Length || count > array.Length - index) - { - throw new ArgumentException(SR.GetString("SR.Arg_ArrayPlusOffTooSmall")); - } - // upper bound - count += index; - - InOrderTreeWalk(delegate (Node node) - { - if (index >= count) - { - return false; - } - else - { - array[index++] = node.Item; - return true; - } - }); - } - - void ICollection.CopyTo(Array array, int index) - { - if (array == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array); - } - - if (array.Rank != 1) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported); - } - - if (array.GetLowerBound(0) != 0) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound); - } - - if (index < 0) - { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.arrayIndex, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - } - - if (array.Length - index < Count) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); - } - - if (array is T[] tarray) - { - CopyTo(tarray, index); - } - else - { - object[] objects = array as object[]; - if (objects == null) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType); - } - - try - { - InOrderTreeWalk(delegate (Node node) { objects[index++] = node.Item; return true; }); - } - catch (ArrayTypeMismatchException) - { - ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidArrayType); - } - } - } - - #endregion - - #region IEnumerable members - [System.Diagnostics.DebuggerStepThrough] - public Enumerator GetEnumerator() - { - return new Enumerator(this); - } - - [System.Diagnostics.DebuggerStepThrough] - IEnumerator IEnumerable.GetEnumerator() - { - return new Enumerator(this); - } - - [System.Diagnostics.DebuggerStepThrough] - IEnumerator IEnumerable.GetEnumerator() - { - return new Enumerator(this); - } - #endregion - - #region Tree Specific Operations - - private static Node GetSibling(Node node, Node parent) - { - if (parent.Left == node) - { - return parent.Right; - } - return parent.Left; - } - - // After calling InsertionBalance, we need to make sure current and parent up-to-date. - // It doesn't matter if we keep grandParent and greatGrantParent up-to-date - // because we won't need to split again in the next node. - // By the time we need to split again, everything will be correctly set. - // - private void InsertionBalance(Node current, ref Node parent, Node grandParent, Node greatGrandParent) - { - Debug.Assert(grandParent != null, "Grand parent cannot be null here!"); - bool parentIsOnRight = (grandParent.Right == parent); - bool currentIsOnRight = (parent.Right == current); - - Node newChildOfGreatGrandParent; - if (parentIsOnRight == currentIsOnRight) - { // same orientation, single rotation - newChildOfGreatGrandParent = currentIsOnRight ? RotateLeft(grandParent) : RotateRight(grandParent); - } - else - { // different orientaton, double rotation - newChildOfGreatGrandParent = currentIsOnRight ? RotateLeftRight(grandParent) : RotateRightLeft(grandParent); - // current node now becomes the child of greatgrandparent - parent = greatGrandParent; - } - // grand parent will become a child of either parent of current. - grandParent.IsRed = true; - newChildOfGreatGrandParent.IsRed = false; - - ReplaceChildOfNodeOrRoot(greatGrandParent, grandParent, newChildOfGreatGrandParent); - } - - private static bool Is2Node(Node node) - { - Debug.Assert(node != null, "node cannot be null!"); - return IsBlack(node) && IsNullOrBlack(node.Left) && IsNullOrBlack(node.Right); - } - - private static bool Is4Node(Node node) - { - return IsRed(node.Left) && IsRed(node.Right); - } - - private static bool IsBlack(Node node) - { - return (node != null && !node.IsRed); - } - - private static bool IsNullOrBlack(Node node) - { - return (node == null || !node.IsRed); - } - - private static bool IsRed(Node node) - { - return (node != null && node.IsRed); - } - - private static void Merge2Nodes(Node parent, Node child1, Node child2) - { - Debug.Assert(IsRed(parent), "parent must be be red"); - // combing two 2-nodes into a 4-node - parent.IsRed = false; - child1.IsRed = true; - child2.IsRed = true; - } - - // Replace the child of a parent node. - // If the parent node is null, replace the root. - private void ReplaceChildOfNodeOrRoot(Node parent, Node child, Node newChild) - { - if (parent != null) - { - if (parent.Left == child) - { - parent.Left = newChild; - } - else - { - parent.Right = newChild; - } - } - else - { - root = newChild; - } - } - - // Replace the matching node with its succesor. - private void ReplaceNode(Node match, Node parentOfMatch, Node succesor, Node parentOfSuccesor) - { - if (succesor == match) - { // this node has no successor, should only happen if right child of matching node is null. - Debug.Assert(match.Right == null, "Right child must be null!"); - succesor = match.Left; - } - else - { - Debug.Assert(parentOfSuccesor != null, "parent of successor cannot be null!"); - Debug.Assert(succesor.Left == null, "Left child of succesor must be null!"); - Debug.Assert((succesor.Right == null && succesor.IsRed) || (succesor.Right.IsRed && !succesor.IsRed), "Succesor must be in valid state"); - if (succesor.Right != null) - { - succesor.Right.IsRed = false; - } - - if (parentOfSuccesor != match) - { // detach succesor from its parent and set its right child - parentOfSuccesor.Left = succesor.Right; - succesor.Right = match.Right; - } - - succesor.Left = match.Left; - } - - if (succesor != null) - { - succesor.IsRed = match.IsRed; - } - - ReplaceChildOfNodeOrRoot(parentOfMatch, match, succesor); - } - - internal virtual Node FindNode(T item) - { - Node current = root; - while (current != null) - { - int order = comparer.Compare(item, current.Item); - if (order == 0) - { - return current; - } - else - { - current = (order < 0) ? current.Left : current.Right; - } - } - - return null; - } - - // used for bithelpers. Note that this implementation is completely different - // from the Subset's. The two should not be mixed. This indexes as if the tree were an array. - // http://en.wikipedia.org/wiki/Binary_Tree#Methods_for_storing_binary_trees - internal virtual int InternalIndexOf(T item) - { - Node current = root; - int count = 0; - while (current != null) - { - int order = comparer.Compare(item, current.Item); - if (order == 0) - { - return count; - } - else - { - current = (order < 0) ? current.Left : current.Right; - count = (order < 0) ? (2 * count + 1) : (2 * count + 2); - } - } - return -1; - } - - - - internal Node FindRange(T from, T to) - { - return FindRange(from, to, true, true); - } - internal Node FindRange(T from, T to, bool lowerBoundActive, bool upperBoundActive) - { - Node current = root; - while (current != null) - { - if (lowerBoundActive && comparer.Compare(from, current.Item) > 0) - { - current = current.Right; - } - else - { - if (upperBoundActive && comparer.Compare(to, current.Item) < 0) - { - current = current.Left; - } - else - { - return current; - } - } - } - - return null; - } - - internal void UpdateVersion() - { - ++version; - } - - - private static Node RotateLeft(Node node) - { - Node x = node.Right; - node.Right = x.Left; - x.Left = node; - return x; - } - - private static Node RotateLeftRight(Node node) - { - Node child = node.Left; - Node grandChild = child.Right; - - node.Left = grandChild.Right; - grandChild.Right = node; - child.Right = grandChild.Left; - grandChild.Left = child; - return grandChild; - } - - private static Node RotateRight(Node node) - { - Node x = node.Left; - node.Left = x.Right; - x.Right = node; - return x; - } - - private static Node RotateRightLeft(Node node) - { - Node child = node.Right; - Node grandChild = child.Left; - - node.Right = grandChild.Left; - grandChild.Left = node; - child.Left = grandChild.Right; - grandChild.Right = child; - return grandChild; - } - /// - /// Testing counter that can track rotations - /// - - - private static TreeRotation RotationNeeded(Node parent, Node current, Node sibling) - { - Debug.Assert(IsRed(sibling.Left) || IsRed(sibling.Right), "sibling must have at least one red child"); - if (IsRed(sibling.Left)) - { - if (parent.Left == current) - { - return TreeRotation.RightLeftRotation; - } - return TreeRotation.RightRotation; - } - else - { - if (parent.Left == current) - { - return TreeRotation.LeftRotation; - } - return TreeRotation.LeftRightRotation; - } - } - - /// - /// Used for deep equality of SortedSet testing - /// - /// - public static IEqualityComparer> CreateSetComparer() - { - return new SortedSetEqualityComparer(); - } - - /// - /// Create a new set comparer for this set, where this set's members' equality is defined by the - /// memberEqualityComparer. Note that this equality comparer's definition of equality must be the - /// same as this set's Comparer's definition of equality - /// - public static IEqualityComparer> CreateSetComparer(IEqualityComparer memberEqualityComparer) - { - return new SortedSetEqualityComparer(memberEqualityComparer); - } - - - /// - /// Decides whether these sets are the same, given the comparer. If the EC's are the same, we can - /// just use SetEquals, but if they aren't then we have to manually check with the given comparer - /// - internal static bool SortedSetEquals(SortedSet set1, SortedSet set2, IComparer comparer) - { - // handle null cases first - if (set1 == null) - { - return (set2 == null); - } - else if (set2 == null) - { - // set1 != null - return false; - } - - if (AreComparersEqual(set1, set2)) - { - if (set1.Count != set2.Count) - return false; - - return set1.SetEquals(set2); - } - else - { - bool found = false; - foreach (T item1 in set1) - { - found = false; - foreach (T item2 in set2) - { - if (comparer.Compare(item1, item2) == 0) - { - found = true; - break; - } - } - if (!found) - return false; - } - return true; - } - } - - - // This is a little frustrating because we can't support more sorted structures - private static bool AreComparersEqual(SortedSet set1, SortedSet set2) - { - return set1.Comparer.Equals(set2.Comparer); - } - - - private static void Split4Node(Node node) - { - node.IsRed = true; - node.Left.IsRed = false; - node.Right.IsRed = false; - } - - /// - /// Copies this to an array. Used for DebugView - /// - /// - internal T[] ToArray() - { - T[] newArray = new T[Count]; - CopyTo(newArray); - return newArray; - } - - - #endregion - - #region ISet Members - - /// - /// Transform this set into its union with the IEnumerable OTHER - /// Attempts to insert each element and rejects it if it exists. - /// NOTE: The caller object is important as UnionWith uses the Comparator - /// associated with THIS to check equality - /// Throws ArgumentNullException if OTHER is null - /// - /// - public void UnionWith(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - - SortedSet s = other as SortedSet; - TreeSubSet t = this as TreeSubSet; - - if (t != null) - VersionCheck(); - - if (s != null && t == null && this.count == 0) - { - SortedSet dummy = new(s, this.comparer); - this.root = dummy.root; - this.count = dummy.count; - this.version++; - return; - } - - - if (s != null && t == null && AreComparersEqual(this, s) && (s.Count > this.Count / 2)) - { // this actually hurts if N is much greater than M the /2 is arbitrary - // first do a merge sort to an array. - T[] merged = new T[s.Count + this.Count]; - int c = 0; - Enumerator mine = this.GetEnumerator(); - Enumerator theirs = s.GetEnumerator(); - bool mineEnded = !mine.MoveNext(), theirsEnded = !theirs.MoveNext(); - while (!mineEnded && !theirsEnded) - { - int comp = Comparer.Compare(mine.Current, theirs.Current); - if (comp < 0) - { - merged[c++] = mine.Current; - mineEnded = !mine.MoveNext(); - } - else if (comp == 0) - { - merged[c++] = theirs.Current; - mineEnded = !mine.MoveNext(); - theirsEnded = !theirs.MoveNext(); - } - else - { - merged[c++] = theirs.Current; - theirsEnded = !theirs.MoveNext(); - } - } - - if (!mineEnded || !theirsEnded) - { - Enumerator remaining = (mineEnded ? theirs : mine); - do - { - merged[c++] = remaining.Current; - } while (remaining.MoveNext()); - } - - // now merged has all c elements - - // safe to gc the root, we have all the elements - root = null; - - - root = SortedSet.ConstructRootFromSortedArray(merged, 0, c - 1, null); - count = c; - version++; - } - else - { - AddAllElements(other); - } - } - - - private static Node ConstructRootFromSortedArray(T[] arr, int startIndex, int endIndex, Node redNode) - { - // what does this do? - // you're given a sorted array... say 1 2 3 4 5 6 - // 2 cases: - // If there are odd # of elements, pick the middle element (in this case 4), and compute - // its left and right branches - // If there are even # of elements, pick the left middle element, save the right middle element - // and call the function on the rest - // 1 2 3 4 5 6 -> pick 3, save 4 and call the fn on 1,2 and 5,6 - // now add 4 as a red node to the lowest element on the right branch - // 3 3 - // 1 5 -> 1 5 - // 2 6 2 4 6 - // As we're adding to the leftmost of the right branch, nesting will not hurt the red-black properties - // Leaf nodes are red if they have no sibling (if there are 2 nodes or if a node trickles - // down to the bottom - - - // the iterative way to do this ends up wasting more space than it saves in stack frames (at - // least in what i tried) - // so we're doing this recursively - // base cases are described below - int size = endIndex - startIndex + 1; - if (size == 0) - { - return null; - } - Node root = null; - if (size == 1) - { - root = new Node(arr[startIndex], false); - if (redNode != null) - { - root.Left = redNode; - } - } - else if (size == 2) - { - root = new Node(arr[startIndex], false) - { - Right = new Node(arr[endIndex], false) - }; - root.Right.IsRed = true; - if (redNode != null) - { - root.Left = redNode; - } - } - else if (size == 3) - { - root = new Node(arr[startIndex + 1], false) - { - Left = new Node(arr[startIndex], false), - Right = new Node(arr[endIndex], false) - }; - if (redNode != null) - { - root.Left.Left = redNode; - } - } - else - { - int midpt = ((startIndex + endIndex) / 2); - root = new Node(arr[midpt], false) - { - Left = ConstructRootFromSortedArray(arr, startIndex, midpt - 1, redNode) - }; - if (size % 2 == 0) - { - root.Right = ConstructRootFromSortedArray(arr, midpt + 2, endIndex, new Node(arr[midpt + 1], true)); - } - else - { - root.Right = ConstructRootFromSortedArray(arr, midpt + 1, endIndex, null); - } - } - return root; - } - - - /// - /// Transform this set into its intersection with the IEnumerable OTHER - /// NOTE: The caller object is important as IntersectionWith uses the - /// comparator associated with THIS to check equality - /// Throws ArgumentNullException if OTHER is null - /// - /// - public virtual void IntersectWith(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - - if (Count == 0) - return; - - // HashSet optimizations can't be done until equality comparers and comparers are related - - // Technically, this would work as well with an ISorted - TreeSubSet t = this as TreeSubSet; - if (t != null) - VersionCheck(); - // only let this happen if i am also a SortedSet, not a SubSet - if (other is SortedSet s && t == null && AreComparersEqual(this, s)) - { - // first do a merge sort to an array. - T[] merged = new T[this.Count]; - int c = 0; - Enumerator mine = this.GetEnumerator(); - Enumerator theirs = s.GetEnumerator(); - bool mineEnded = !mine.MoveNext(), theirsEnded = !theirs.MoveNext(); - T max = Max; - T min = Min; - - while (!mineEnded && !theirsEnded && Comparer.Compare(theirs.Current, max) <= 0) - { - int comp = Comparer.Compare(mine.Current, theirs.Current); - if (comp < 0) - { - mineEnded = !mine.MoveNext(); - } - else if (comp == 0) - { - merged[c++] = theirs.Current; - mineEnded = !mine.MoveNext(); - theirsEnded = !theirs.MoveNext(); - } - else - { - theirsEnded = !theirs.MoveNext(); - } - } - - // now merged has all c elements - - // safe to gc the root, we have all the elements - root = null; - - root = SortedSet.ConstructRootFromSortedArray(merged, 0, c - 1, null); - count = c; - version++; - } - else - { - IntersectWithEnumerable(other); - } - } - - internal virtual void IntersectWithEnumerable(IEnumerable other) - { - // - List toSave = new(this.Count); - foreach (T item in other) - { - if (this.Contains(item)) - { - toSave.Add(item); - this.Remove(item); - } - } - this.Clear(); - AddAllElements(toSave); - } - - - - /// - /// Transform this set into its complement with the IEnumerable OTHER - /// NOTE: The caller object is important as ExceptWith uses the - /// comparator associated with THIS to check equality - /// Throws ArgumentNullException if OTHER is null - /// - /// - public void ExceptWith(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - - if (count == 0) - return; - - if (other == this) - { - this.Clear(); - return; - } - - - if (other is SortedSet asSorted && AreComparersEqual(this, asSorted)) - { - // outside range, no point doing anything - if (!(comparer.Compare(asSorted.Max, this.Min) < 0 || comparer.Compare(asSorted.Min, this.Max) > 0)) - { - T min = this.Min; - T max = this.Max; - foreach (T item in other) - { - if (comparer.Compare(item, min) < 0) - continue; - if (comparer.Compare(item, max) > 0) - break; - Remove(item); - } - } - } - else - { - RemoveAllElements(other); - } - } - - /// - /// Transform this set so it contains elements in THIS or OTHER but not both - /// NOTE: The caller object is important as SymmetricExceptWith uses the - /// comparator associated with THIS to check equality - /// Throws ArgumentNullException if OTHER is null - /// - /// - public void SymmetricExceptWith(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - if (this.Count == 0) - { - this.UnionWith(other); - return; - } - - if (other == this) - { - this.Clear(); - return; - } - - - -#if USING_HASH_SET - HashSet asHash = other as HashSet; -#endif - if (other is SortedSet asSorted && AreComparersEqual(this, asSorted)) - { - SymmetricExceptWithSameEC(asSorted); - } -#if USING_HASH_SET - else if (asHash != null && this.comparer.Equals(Comparer.Default) && asHash.Comparer.Equals(EqualityComparer.Default)) { - SymmetricExceptWithSameEC(asHash); - } -#endif - else - { - // need perf improvement on this - T[] elements = (new List(other)).ToArray(); - Array.Sort(elements, this.Comparer); - SymmetricExceptWithSameEC(elements); - } - } - - // OTHER must be a set - internal void SymmetricExceptWithSameEC(ISet other) - { - foreach (T item in other) - { - // yes, it is classier to say - // if (!this.Remove(item))this.Add(item); - // but this ends up saving on rotations - if (this.Contains(item)) - { - this.Remove(item); - } - else - { - this.Add(item); - } - } - } - - // OTHER must be a sorted array - internal void SymmetricExceptWithSameEC(T[] other) - { - if (other.Length == 0) - { - return; - } - T last = other[0]; - for (int i = 0; i < other.Length; i++) - { - while (i < other.Length && i != 0 && comparer.Compare(other[i], last) == 0) - i++; - if (i >= other.Length) - break; - if (this.Contains(other[i])) - { - this.Remove(other[i]); - } - else - { - this.Add(other[i]); - } - last = other[i]; - } - } - - - /// - /// Checks whether this Tree is a subset of the IEnumerable other - /// - /// - /// - [System.Security.SecuritySafeCritical] - public bool IsSubsetOf(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - if (Count == 0) - return true; - - - if (other is SortedSet asSorted && AreComparersEqual(this, asSorted)) - { - if (this.Count > asSorted.Count) - return false; - return IsSubsetOfSortedSetWithSameEC(asSorted); - } - else - { - // worst case: mark every element in my set and see if i've counted all - // O(MlogN) - - ElementCount result = CheckUniqueAndUnfoundElements(other, false); - return (result.uniqueCount == Count && result.unfoundCount >= 0); - } - } - - private bool IsSubsetOfSortedSetWithSameEC(SortedSet asSorted) - { - SortedSet prunedOther = asSorted.GetViewBetween(this.Min, this.Max); - foreach (T item in this) - { - if (!prunedOther.Contains(item)) - return false; - } - return true; - } - - - /// - /// Checks whether this Tree is a proper subset of the IEnumerable other - /// - /// - /// - [System.Security.SecuritySafeCritical] - public bool IsProperSubsetOf(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - if ((other as ICollection) != null) - { - if (Count == 0) - return (other as ICollection).Count > 0; - } - - -#if USING_HASH_SET - // do it one way for HashSets - HashSet asHash = other as HashSet; - if (asHash != null && comparer.Equals(Comparer.Default) && asHash.Comparer.Equals(EqualityComparer.Default)) { - return asHash.IsProperSupersetOf(this); - } -#endif - // another for sorted sets with the same comparer - if (other is SortedSet asSorted && AreComparersEqual(this, asSorted)) - { - if (this.Count >= asSorted.Count) - return false; - return IsSubsetOfSortedSetWithSameEC(asSorted); - } - - - // worst case: mark every element in my set and see if i've counted all - // O(MlogN). - ElementCount result = CheckUniqueAndUnfoundElements(other, false); - return (result.uniqueCount == Count && result.unfoundCount > 0); - } - - - /// - /// Checks whether this Tree is a super set of the IEnumerable other - /// - /// - /// - public bool IsSupersetOf(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - if ((other as ICollection) != null && (other as ICollection).Count == 0) - return true; - - // do it one way for HashSets -#if USING_HASH_SET - HashSet asHash = other as HashSet; - if (asHash != null && comparer.Equals(Comparer.Default) && asHash.Comparer.Equals(EqualityComparer.Default)) { - return asHash.IsSubsetOf(this); - } -#endif - // another for sorted sets with the same comparer - if (other is SortedSet asSorted && AreComparersEqual(this, asSorted)) - { - if (this.Count < asSorted.Count) - return false; - SortedSet pruned = GetViewBetween(asSorted.Min, asSorted.Max); - foreach (T item in asSorted) - { - if (!pruned.Contains(item)) - return false; - } - return true; - } - // and a third for everything else - return ContainsAllElements(other); - } - - /// - /// Checks whether this Tree is a proper super set of the IEnumerable other - /// - /// - /// - [System.Security.SecuritySafeCritical] - public bool IsProperSupersetOf(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - if (Count == 0) - return false; - - if ((other as ICollection) != null && (other as ICollection).Count == 0) - return true; - -#if USING_HASH_SET - // do it one way for HashSets - - HashSet asHash = other as HashSet; - if (asHash != null && comparer.Equals(Comparer.Default) && asHash.Comparer.Equals(EqualityComparer.Default)) { - return asHash.IsProperSubsetOf(this); - } -#endif - // another way for sorted sets - if (other is SortedSet asSorted && AreComparersEqual(asSorted, this)) - { - if (asSorted.Count >= this.Count) - return false; - SortedSet pruned = GetViewBetween(asSorted.Min, asSorted.Max); - foreach (T item in asSorted) - { - if (!pruned.Contains(item)) - return false; - } - return true; - } - - - // worst case: mark every element in my set and see if i've counted all - // O(MlogN) - // slight optimization, put it into a HashSet and then check can do it in O(N+M) - // but slower in better cases + wastes space - ElementCount result = CheckUniqueAndUnfoundElements(other, true); - return (result.uniqueCount < Count && result.unfoundCount == 0); - } - - - - /// - /// Checks whether this Tree has all elements in common with IEnumerable other - /// - /// - /// - [System.Security.SecuritySafeCritical] - public bool SetEquals(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); -#if USING_HASH_SET - HashSet asHash = other as HashSet; - if (asHash != null && comparer.Equals(Comparer.Default) && asHash.Comparer.Equals(EqualityComparer.Default)) { - return asHash.SetEquals(this); - } -#endif - if (other is SortedSet asSorted && AreComparersEqual(this, asSorted)) - { - IEnumerator mine = this.GetEnumerator(); - IEnumerator theirs = asSorted.GetEnumerator(); - bool mineEnded = !mine.MoveNext(); - bool theirsEnded = !theirs.MoveNext(); - while (!mineEnded && !theirsEnded) - { - if (Comparer.Compare(mine.Current, theirs.Current) != 0) - { - return false; - } - mineEnded = !mine.MoveNext(); - theirsEnded = !theirs.MoveNext(); - } - return mineEnded && theirsEnded; - } - - // worst case: mark every element in my set and see if i've counted all - // O(N) by size of other - ElementCount result = CheckUniqueAndUnfoundElements(other, true); - return (result.uniqueCount == Count && result.unfoundCount == 0); - } - - - - /// - /// Checks whether this Tree has any elements in common with IEnumerable other - /// - /// - /// - public bool Overlaps(IEnumerable other) - { - //if (other == null) - //{ - // throw new ArgumentNullException("other"); - //} - other.NotNull(nameof(other)); - if (this.Count == 0) - return false; - - if ((other as ICollection != null) && (other as ICollection).Count == 0) - return false; - - if (other is SortedSet asSorted && AreComparersEqual(this, asSorted) && (comparer.Compare(Min, asSorted.Max) > 0 || comparer.Compare(Max, asSorted.Min) < 0)) - { - return false; - } -#if USING_HASH_SET - HashSet asHash = other as HashSet; - if (asHash != null && comparer.Equals(Comparer.Default) && asHash.Comparer.Equals(EqualityComparer.Default)) { - return asHash.Overlaps(this); - } -#endif - foreach (T item in other) - { - if (this.Contains(item)) - { - return true; - } - } - return false; - } - - /// - /// This works similar to HashSet's CheckUniqueAndUnfound (description below), except that the bit - /// array maps differently than in the HashSet. We can only use this for the bulk boolean checks. - /// - /// Determines counts that can be used to determine equality, subset, and superset. This - /// is only used when other is an IEnumerable and not a HashSet. If other is a HashSet - /// these properties can be checked faster without use of marking because we can assume - /// other has no duplicates. - /// - /// The following count checks are performed by callers: - /// 1. Equals: checks if unfoundCount = 0 and uniqueFoundCount = Count; i.e. everything - /// in other is in this and everything in this is in other - /// 2. Subset: checks if unfoundCount >= 0 and uniqueFoundCount = Count; i.e. other may - /// have elements not in this and everything in this is in other - /// 3. Proper subset: checks if unfoundCount > 0 and uniqueFoundCount = Count; i.e - /// other must have at least one element not in this and everything in this is in other - /// 4. Proper superset: checks if unfound count = 0 and uniqueFoundCount strictly less - /// than Count; i.e. everything in other was in this and this had at least one element - /// not contained in other. - /// - /// An earlier implementation used delegates to perform these checks rather than returning - /// an ElementCount struct; however this was changed due to the perf overhead of delegates. - /// - /// - /// Allows us to finish faster for equals and proper superset - /// because unfoundCount must be 0. - /// - // - // - // - // - // - // - [System.Security.SecurityCritical] - private unsafe ElementCount CheckUniqueAndUnfoundElements(IEnumerable other, bool returnIfUnfound) - { - ElementCount result; - - // need special case in case this has no elements. - if (Count == 0) - { - int numElementsInOther = 0; - foreach (T item in other) - { - numElementsInOther++; - // break right away, all we want to know is whether other has 0 or 1 elements - break; - } - result.uniqueCount = 0; - result.unfoundCount = numElementsInOther; - return result; - } - - - int originalLastIndex = Count; - int intArrayLength = BitHelper.ToIntArrayLength(originalLastIndex); - - BitHelper bitHelper; - if (intArrayLength <= StackAllocThreshold) - { - int* bitArrayPtr = stackalloc int[intArrayLength]; - bitHelper = new BitHelper(bitArrayPtr, intArrayLength); - } - else - { - int[] bitArray = new int[intArrayLength]; - bitHelper = new BitHelper(bitArray, intArrayLength); - } - - // count of items in other not found in this - int unfoundCount = 0; - // count of unique items in other found in this - int uniqueFoundCount = 0; - - foreach (T item in other) - { - int index = InternalIndexOf(item); - if (index >= 0) - { - if (!bitHelper.IsMarked(index)) - { - // item hasn't been seen yet - bitHelper.MarkBit(index); - uniqueFoundCount++; - } - } - else - { - unfoundCount++; - if (returnIfUnfound) - { - break; - } - } - } - - result.uniqueCount = uniqueFoundCount; - result.unfoundCount = unfoundCount; - return result; - } - public int RemoveWhere(Predicate match) - { - //if (match == null) - //{ - // throw new ArgumentNullException("match"); - //} - match.NotNull(nameof(match)); - List matches = new(this.Count); - - BreadthFirstTreeWalk(delegate (Node n) - { - if (match(n.Item)) - { - matches.Add(n.Item); - } - return true; - }); - // reverse breadth first to (try to) incur low cost - int actuallyRemoved = 0; - for (int i = matches.Count - 1; i >= 0; i--) - { - if (this.Remove(matches[i])) - { - actuallyRemoved++; - } - } - - return actuallyRemoved; - } - - - #endregion - - #region ISorted Members - - - public T Min - { - get - { - T ret = default; - InOrderTreeWalk(delegate (SortedSet.Node n) { ret = n.Item; return false; }); - return ret; - } - } - - public T Max - { - get - { - T ret = default; - InOrderTreeWalk(delegate (SortedSet.Node n) { ret = n.Item; return false; }, true); - return ret; - } - } - - public IEnumerable Reverse() - { - Enumerator e = new(this, true); - while (e.MoveNext()) - { - yield return e.Current; - } - } - - - /// - /// Returns a subset of this tree ranging from values lBound to uBound - /// Any changes made to the subset reflect in the actual tree - /// - /// Lowest Value allowed in the subset - /// Highest Value allowed in the subset - public virtual SortedSet GetViewBetween(T lowerValue, T upperValue) - { - if (Comparer.Compare(lowerValue, upperValue) > 0) - { - throw new ArgumentException("lowerBound is greater than upperBound"); - } - return new TreeSubSet(this, lowerValue, upperValue, true, true); - } - -#if DEBUG - - /// - /// debug status to be checked whenever any operation is called - /// - /// - internal virtual bool VersionUpToDate() - { - return true; - } -#endif - - - /// - /// This class represents a subset view into the tree. Any changes to this view - /// are reflected in the actual tree. Uses the Comparator of the underlying tree. - /// - /// -#if !FEATURE_NETCORE - [Serializable] - internal sealed class TreeSubSet : SortedSet, ISerializable, IDeserializationCallback - { -#else - internal sealed class TreeSubSet : SortedSet { -#endif - SortedSet underlying; - T min, max; - // these exist for unbounded collections - // for instance, you could allow this subset to be defined for i>10. The set will throw if - // anything <=10 is added, but there is no upperbound. These features Head(), Tail(), were punted - // in the spec, and are not available, but the framework is there to make them available at some point. - bool lBoundActive, uBoundActive; - // used to see if the count is out of date - - -#if DEBUG - internal override bool VersionUpToDate() - { - return (this.version == underlying.version); - } -#endif - - public TreeSubSet(SortedSet Underlying, T Min, T Max, bool lowerBoundActive, bool upperBoundActive) - : base(Underlying.Comparer) - { - underlying = Underlying; - min = Min; - max = Max; - lBoundActive = lowerBoundActive; - uBoundActive = upperBoundActive; - root = underlying.FindRange(min, max, lBoundActive, uBoundActive); // root is first element within range - count = 0; - version = -1; - VersionCheckImpl(); - } - -#if !FEATURE_NETCORE - /// - /// For serialization and deserialization - /// - private TreeSubSet() - { - comparer = null; - } - - - [SuppressMessage("Microsoft.Usage", "CA2236:CallBaseClassMethodsOnISerializableTypes", Justification = "special case TreeSubSet serialization")] - private TreeSubSet(SerializationInfo info, StreamingContext context) - { - siInfo = info; - OnDeserializationImpl(info); - } -#endif // !FEATURE_NETCORE - - /// - /// Additions to this tree need to be added to the underlying tree as well - /// - - internal override bool AddIfNotPresent(T item) - { - if (!IsWithinRange(item)) - { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.collection); - } - - bool ret = underlying.AddIfNotPresent(item); - VersionCheck(); -#if DEBUG - Debug.Assert(this.VersionUpToDate() && this.root == this.underlying.FindRange(min, max)); -#endif - - return ret; - } - - - public override bool Contains(T item) - { - VersionCheck(); -#if DEBUG - Debug.Assert(this.VersionUpToDate() && this.root == this.underlying.FindRange(min, max)); -#endif - return base.Contains(item); - } - - internal override bool DoRemove(T item) - { - if (!IsWithinRange(item)) - { - return false; - } - - bool ret = underlying.Remove(item); - VersionCheck(); -#if DEBUG - Debug.Assert(this.VersionUpToDate() && this.root == this.underlying.FindRange(min, max)); -#endif - return ret; - } - - public override void Clear() - { - if (count == 0) - { - return; - } - - List toRemove = new(); - BreadthFirstTreeWalk(delegate (Node n) { toRemove.Add(n.Item); return true; }); - while (toRemove.Count != 0) - { - underlying.Remove(toRemove[^1]); - toRemove.RemoveAt(toRemove.Count - 1); - } - root = null; - count = 0; - version = underlying.version; - } - - - internal override bool IsWithinRange(T item) - { - int comp = (lBoundActive ? Comparer.Compare(min, item) : -1); - if (comp > 0) - { - return false; - } - comp = (uBoundActive ? Comparer.Compare(max, item) : 1); - if (comp < 0) - { - return false; - } - return true; - } - - internal override bool InOrderTreeWalk(TreeWalkPredicate action, Boolean reverse) - { - VersionCheck(); - - if (root == null) - { - return true; - } - - // The maximum height of a red-black tree is 2*lg(n+1). - // See page 264 of "Introduction to algorithms" by Thomas H. Cormen - Stack stack = new(2 * (int)SortedSet.Log2(count + 1)); // this is not exactly right if count is out of date, but the stack can grow - Node current = root; - while (current != null) - { - if (IsWithinRange(current.Item)) - { - stack.Push(current); - current = (reverse ? current.Right : current.Left); - } - else if (lBoundActive && Comparer.Compare(min, current.Item) > 0) - { - current = current.Right; - } - else - { - current = current.Left; - } - } - - while (stack.Count != 0) - { - current = stack.Pop(); - if (!action(current)) - { - return false; - } - - Node node = (reverse ? current.Left : current.Right); - while (node != null) - { - if (IsWithinRange(node.Item)) - { - stack.Push(node); - node = (reverse ? node.Right : node.Left); - } - else if (lBoundActive && Comparer.Compare(min, node.Item) > 0) - { - node = node.Right; - } - else - { - node = node.Left; - } - } - } - return true; - } - - internal override bool BreadthFirstTreeWalk(TreeWalkPredicate action) - { - VersionCheck(); - - if (root == null) - { - return true; - } - - List processQueue = new() - { - root - }; - Node current; - - while (processQueue.Count != 0) - { - current = processQueue[0]; - processQueue.RemoveAt(0); - if (IsWithinRange(current.Item) && !action(current)) - { - return false; - } - if (current.Left != null && (!lBoundActive || Comparer.Compare(min, current.Item) < 0)) - { - processQueue.Add(current.Left); - } - if (current.Right != null && (!uBoundActive || Comparer.Compare(max, current.Item) > 0)) - { - processQueue.Add(current.Right); - } - } - return true; - } - - internal override SortedSet.Node FindNode(T item) - { - if (!IsWithinRange(item)) - { - return null; - } - VersionCheck(); -#if DEBUG - Debug.Assert(this.VersionUpToDate() && this.root == this.underlying.FindRange(min, max)); -#endif - return base.FindNode(item); - } - - // this does indexing in an inefficient way compared to the actual sortedset, but it saves a - // lot of space - internal override int InternalIndexOf(T item) - { - int count = -1; - foreach (T i in this) - { - count++; - if (Comparer.Compare(item, i) == 0) - return count; - } -#if DEBUG - Debug.Assert(this.VersionUpToDate() && this.root == this.underlying.FindRange(min, max)); -#endif - return -1; - } - /// - /// checks whether this subset is out of date. updates if necessary. - /// - internal override void VersionCheck() - { - VersionCheckImpl(); - } - - private void VersionCheckImpl() - { - Debug.Assert(underlying != null, "Underlying set no longer exists"); - if (this.version != underlying.version) - { - this.root = underlying.FindRange(min, max, lBoundActive, uBoundActive); - this.version = underlying.version; - count = 0; - InOrderTreeWalk(delegate (Node n) { count++; return true; }); - } - } - - - - // This passes functionality down to the underlying tree, clipping edges if necessary - // There's nothing gained by having a nested subset. May as well draw it from the base - // Cannot increase the bounds of the subset, can only decrease it - public override SortedSet GetViewBetween(T lowerValue, T upperValue) - { - if (lBoundActive && Comparer.Compare(min, lowerValue) > 0) - { - // lBound = min; - throw new ArgumentOutOfRangeException("lowerValue"); - } - if (uBoundActive && Comparer.Compare(max, upperValue) < 0) - { - // uBound = max; - throw new ArgumentOutOfRangeException("upperValue"); - } - TreeSubSet ret = (TreeSubSet)underlying.GetViewBetween(lowerValue, upperValue); - return ret; - } - - internal override void IntersectWithEnumerable(IEnumerable other) - { - List toSave = new(this.Count); - foreach (T item in other) - { - if (this.Contains(item)) - { - toSave.Add(item); - this.Remove(item); - } - } - this.Clear(); - this.AddAllElements(toSave); -#if DEBUG - Debug.Assert(this.VersionUpToDate() && this.root == this.underlying.FindRange(min, max)); -#endif - } - -#if !FEATURE_NETCORE - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) - { - GetObjectData(info, context); - } - - protected override void GetObjectData(SerializationInfo info, StreamingContext context) - { - if (info == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info); - } - info.AddValue(maxName, max, typeof(T)); - info.AddValue(minName, min, typeof(T)); - info.AddValue(lBoundActiveName, lBoundActive); - info.AddValue(uBoundActiveName, uBoundActive); - base.GetObjectData(info, context); - } - - void IDeserializationCallback.OnDeserialization(Object sender) - { - // don't do anything here as its already been done by the constructor - // OnDeserialization(sender); - } - - protected override void OnDeserialization(Object sender) - { - OnDeserializationImpl(sender); - } - - private void OnDeserializationImpl(Object sender) - { - if (siInfo == null) - { - ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_InvalidOnDeser); - } - - comparer = (IComparer)siInfo.GetValue(ComparerName, typeof(IComparer)); - int savedCount = siInfo.GetInt32(CountName); - max = (T)siInfo.GetValue(maxName, typeof(T)); - min = (T)siInfo.GetValue(minName, typeof(T)); - lBoundActive = siInfo.GetBoolean(lBoundActiveName); - uBoundActive = siInfo.GetBoolean(uBoundActiveName); - underlying = new SortedSet(); - - if (savedCount != 0) - { - T[] items = (T[])siInfo.GetValue(ItemsName, typeof(T[])); - - if (items == null) - { - ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MissingValues); - } - - for (int i = 0; i < items.Length; i++) - { - underlying.Add(items[i]); - } - } - underlying.version = siInfo.GetInt32(VersionName); - count = underlying.count; - version = underlying.version - 1; - VersionCheck(); // this should update the count to be right and update root to be right - - if (count != savedCount) - { - ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MismatchedCount); - } - siInfo = null; - } -#endif // !FEATURE_NETCORE - } - - - #endregion - - #region Serialization methods - -#if !FEATURE_NETCORE - // LinkDemand here is unnecessary as this is a methodimpl and linkdemand from the interface should suffice - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) - { - GetObjectData(info, context); - } - - protected virtual void GetObjectData(SerializationInfo info, StreamingContext context) - { - if (info == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info); - } - - info.AddValue(CountName, count); // This is the length of the bucket array. - info.AddValue(ComparerName, comparer, typeof(IComparer)); - info.AddValue(VersionName, version); - - if (root != null) - { - T[] items = new T[Count]; - CopyTo(items, 0); - info.AddValue(ItemsName, items, typeof(T[])); - } - } - - void IDeserializationCallback.OnDeserialization(Object sender) - { - OnDeserialization(sender); - } - - protected virtual void OnDeserialization(Object sender) - { - if (comparer != null) - { - return; // Somebody had a dependency on this class and fixed us up before the ObjectManager got to it. - } - - if (siInfo == null) - { - ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_InvalidOnDeser); - } - - comparer = (IComparer)siInfo.GetValue(ComparerName, typeof(IComparer)); - int savedCount = siInfo.GetInt32(CountName); - - if (savedCount != 0) - { - T[] items = (T[])siInfo.GetValue(ItemsName, typeof(T[])); - - if (items == null) - { - ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MissingValues); - } - - for (int i = 0; i < items.Length; i++) - { - Add(items[i]); - } - } - - version = siInfo.GetInt32(VersionName); - if (count != savedCount) - { - ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_MismatchedCount); - } - siInfo = null; - } -#endif // !FEATURE_NETCORE - #endregion - - #region Helper Classes - internal class Node - { - public bool IsRed; - public T Item; - public Node Left; - public Node Right; - - public Node(T item) - { - // The default color will be red, we never need to create a black node directly. - this.Item = item; - IsRed = true; - } - - public Node(T item, bool isRed) - { - // The default color will be red, we never need to create a black node directly. - this.Item = item; - this.IsRed = isRed; - } - } - - [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "not an expected scenario")] -#if !FEATURE_NETCORE - [Serializable] - public struct Enumerator : IEnumerator, IEnumerator, ISerializable, IDeserializationCallback - { -#else - public struct Enumerator : IEnumerator, IEnumerator { -#endif - private SortedSet tree; - private int version; - - - private Stack.Node> stack; - private SortedSet.Node current; - static readonly SortedSet.Node dummyNode = new(default); - - private bool reverse; - -#if !FEATURE_NETCORE - private readonly SerializationInfo siInfo; -#endif - internal Enumerator(SortedSet set) - { - tree = set; - // this is a hack to make sure that the underlying subset has not been changed since - // - tree.VersionCheck(); - - version = tree.version; - - // 2lg(n + 1) is the maximum height - stack = new Stack.Node>(2 * (int)SortedSet.Log2(set.Count + 1)); - current = null; - reverse = false; -#if !FEATURE_NETCORE - siInfo = null; -#endif - Intialize(); - } - - internal Enumerator(SortedSet set, bool reverse) - { - tree = set; - // this is a hack to make sure that the underlying subset has not been changed since - // - tree.VersionCheck(); - version = tree.version; - - // 2lg(n + 1) is the maximum height - stack = new Stack.Node>(2 * (int)SortedSet.Log2(set.Count + 1)); - current = null; - this.reverse = reverse; -#if !FEATURE_NETCORE - siInfo = null; -#endif - Intialize(); - } - -#if !FEATURE_NETCORE - private Enumerator(SerializationInfo info, StreamingContext context) - { - tree = null; - version = -1; - current = null; - reverse = false; - stack = null; - this.siInfo = info; - } - - void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) - { - GetObjectData(info, context); - } - - private void GetObjectData(SerializationInfo info, StreamingContext context) - { - if (info == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info); - } - info.AddValue(TreeName, tree, typeof(SortedSet)); - info.AddValue(EnumVersionName, version); - info.AddValue(ReverseName, reverse); - info.AddValue(EnumStartName, !NotStartedOrEnded); - info.AddValue(NodeValueName, (current == null ? dummyNode.Item : current.Item), typeof(T)); - } - - void IDeserializationCallback.OnDeserialization(Object sender) - { - OnDeserialization(sender); - } - - private void OnDeserialization(Object sender) - { - if (siInfo == null) - { - ThrowHelper.ThrowSerializationException(ExceptionResource.Serialization_InvalidOnDeser); - } - - tree = (SortedSet)siInfo.GetValue(TreeName, typeof(SortedSet)); - version = siInfo.GetInt32(EnumVersionName); - reverse = siInfo.GetBoolean(ReverseName); - bool EnumStarted = siInfo.GetBoolean(EnumStartName); - stack = new Stack.Node>(2 * (int)SortedSet.Log2(tree.Count + 1)); - current = null; - if (EnumStarted) - { - T item = (T)siInfo.GetValue(NodeValueName, typeof(T)); - Intialize(); - // go until it reaches the value we want - while (this.MoveNext()) - { - if (tree.Comparer.Compare(this.Current, item) == 0) - break; - } - } - } -#endif // !FEATURE_NETCORE - - - private void Intialize() - { - current = null; - SortedSet.Node node = tree.root; - Node next = null, other = null; - while (node != null) - { - next = (reverse ? node.Right : node.Left); - other = (reverse ? node.Left : node.Right); - if (tree.IsWithinRange(node.Item)) - { - stack.Push(node); - node = next; - } - else if (next == null || !tree.IsWithinRange(next.Item)) - { - node = other; - } - else - { - node = next; - } - } - } - - public bool MoveNext() - { - // this is a hack to make sure that the underlying subset has not been changed since - // - tree.VersionCheck(); - - if (version != tree.version) - { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); - } - - if (stack.Count == 0) - { - current = null; - return false; - } - - current = stack.Pop(); - SortedSet.Node node = (reverse ? current.Left : current.Right); - - Node next = null, other = null; - while (node != null) - { - next = (reverse ? node.Right : node.Left); - other = (reverse ? node.Left : node.Right); - if (tree.IsWithinRange(node.Item)) - { - stack.Push(node); - node = next; - } - else if (other == null || !tree.IsWithinRange(other.Item)) - { - node = next; - } - else - { - node = other; - } - } - return true; - } - - public void Dispose() - { - } - - public T Current - { - get - { - if (current != null) - { - return current.Item; - } - return default; - } - } - - object IEnumerator.Current - { - get - { - if (current == null) - { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumOpCantHappen); - } - - return current.Item; - } - } - - internal bool NotStartedOrEnded - { - get - { - return current == null; - } - } - - internal void Reset() - { - if (version != tree.version) - { - ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion); - } - - stack.Clear(); - Intialize(); - } - - void IEnumerator.Reset() - { - Reset(); - } - } - - - - internal struct ElementCount - { - internal int uniqueCount; - internal int unfoundCount; - } - #endregion - - #region misc - - /// - /// Searches the set for a given value and returns the equal value it finds, if any. - /// - /// The value to search for. - /// The value from the set that the search found, or the default value of when the search yielded no match. - /// A value indicating whether the search was successful. - /// - /// This can be useful when you want to reuse a previously stored reference instead of - /// a newly constructed one (so that more sharing of references can occur) or to look up - /// a value that has more complete data than the value you currently have, although their - /// comparer functions indicate they are equal. - /// - public bool TryGetValue(T equalValue, out T actualValue) - { - Node node = FindNode(equalValue); - if (node != null) - { - actualValue = node.Item; - return true; - } - actualValue = default; - return false; - } - - // used for set checking operations (using enumerables) that rely on counting - private static int Log2(int value) - { - // Contract.Requires(value>0) - int c = 0; - while (value > 0) - { - c++; - value >>= 1; - } - return c; - } - #endregion - } - - /// - /// A class that generates an IEqualityComparer for this SortedSet. Requires that the definition of - /// equality defined by the IComparer for this SortedSet be consistent with the default IEqualityComparer - /// for the type T. If not, such an IEqualityComparer should be provided through the constructor. - /// - internal class SortedSetEqualityComparer : IEqualityComparer> - { - private readonly IComparer comparer; - private readonly IEqualityComparer e_comparer; - - public SortedSetEqualityComparer() : this(null, null) - { - } - - public SortedSetEqualityComparer(IComparer comparer) : this(comparer, null) - { - } - - public SortedSetEqualityComparer(IEqualityComparer memberEqualityComparer) : this(null, memberEqualityComparer) - { - } - - /// - /// Create a new SetEqualityComparer, given a comparer for member order and another for member equality (these - /// must be consistent in their definition of equality) - /// - public SortedSetEqualityComparer(IComparer comparer, IEqualityComparer memberEqualityComparer) - { - if (comparer == null) - this.comparer = Comparer.Default; - else - this.comparer = comparer; - if (memberEqualityComparer == null) - e_comparer = EqualityComparer.Default; - else - e_comparer = memberEqualityComparer; - } - - - // using comparer to keep equals properties in tact; don't want to choose one of the comparers - public bool Equals(SortedSet x, SortedSet y) - { - return SortedSet.SortedSetEquals(x, y, comparer); - } - // IMPORTANT: this part uses the fact that GetHashCode() is consistent with the notion of equality in - // the set - public int GetHashCode(SortedSet obj) - { - int hashCode = 0; - if (obj != null) - { - foreach (T t in obj) - { - hashCode ^= (e_comparer.GetHashCode(t) & 0x7FFFFFFF); - } - } // else returns hashcode of 0 for null HashSets - return hashCode; - } - - // Equals method for the comparer itself. - public override bool Equals(Object obj) - { - if (obj is not SortedSetEqualityComparer comparer) - { - return false; - } - return (this.comparer == comparer.comparer); - } - - public override int GetHashCode() - { - return comparer.GetHashCode() ^ e_comparer.GetHashCode(); - } - } -} - - - -#pragma warning restore CS8604 // 引用类型参数可能为 null。 -#pragma warning restore CS8602 // 解引用可能出现空引用。 -#pragma warning restore CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型。 -#pragma warning restore IDE0059 // 不需要赋值 -#pragma warning restore CS8625 // 无法将 null 字面量转换为非 null 的引用类型。 -#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 -#pragma warning restore CS8601 // 引用类型赋值可能为 null。 -#pragma warning restore CS8603 // 可能返回 null 引用。 -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/Sortedset/ThrowHelper.cs b/src/Basal/IFox.Basal.Shared/Sortedset/ThrowHelper.cs deleted file mode 100644 index ebb2f410b502a822cb15b51bdcdf468ea60ee07c..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/Sortedset/ThrowHelper.cs +++ /dev/null @@ -1,381 +0,0 @@ -#if NET35 -#pragma warning disable IDE0059 // 不需要赋值 -#pragma warning disable CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型。 - -namespace System -{ - // This file defines an internal class used to throw exceptions in BCL code. - // The main purpose is to reduce code size. - // - // The old way to throw an exception generates quite a lot IL code and assembly code. - // Following is an example: - // C# source - // throw new ArgumentNullException("key", SR.GetString("ArgumentNull_Key")); - // IL code: - // IL_0003: ldstr "key" - // IL_0008: ldstr "ArgumentNull_Key" - // IL_000d: call string System.Environment::GetResourceString(string) - // IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string) - // IL_0017: throw - // which is 21bytes in IL. - // - // So we want to get rid of the ldstr and call to Environment.GetResource in IL. - // In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the - // argument name and resource name in a small integer. The source code will be changed to - // ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key); - // - // The IL code will be 7 bytes. - // IL_0008: ldc.i4.4 - // IL_0009: ldc.i4.4 - // IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument) - // IL_000f: ldarg.0 - // - // This will also reduce the Jitted code size a lot. - // - // It is very important we do this for generic classes because we can easily generate the same code - // multiple times for different instantiation. - // - // < - - - - - - - - - - -#if !SILVERLIGHT - using System.Runtime.Serialization; -#endif - - using System.Diagnostics; - internal static class ThrowHelper - { - internal static void ThrowWrongKeyTypeArgumentException(object key, Type targetType) - { - throw new ArgumentException(SR.GetString("SR.Arg_WrongType", key, targetType), "key"); - } - - internal static void ThrowWrongValueTypeArgumentException(object value, Type targetType) - { - throw new ArgumentException(SR.GetString("SR.Arg_WrongType", value, targetType), "value"); - } - - internal static void ThrowKeyNotFoundException() - { - throw new System.Collections.Generic.KeyNotFoundException(); - } - - internal static void ThrowArgumentException(ExceptionResource resource) - { - throw new ArgumentException(SR.GetString(GetResourceName(resource))); - } - - internal static void ThrowArgumentNullException(ExceptionArgument argument) - { - throw new ArgumentNullException(GetArgumentName(argument)); - } - - internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) - { - throw new ArgumentOutOfRangeException(GetArgumentName(argument)); - } - - internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource) - { - throw new ArgumentOutOfRangeException(GetArgumentName(argument), SR.GetString(GetResourceName(resource))); - } - - internal static void ThrowInvalidOperationException(ExceptionResource resource) - { - throw new InvalidOperationException(SR.GetString(GetResourceName(resource))); - } - -#if !SILVERLIGHT - internal static void ThrowSerializationException(ExceptionResource resource) - { - throw new SerializationException(SR.GetString(GetResourceName(resource))); - } -#endif - - internal static void ThrowNotSupportedException(ExceptionResource resource) - { - throw new NotSupportedException(SR.GetString(GetResourceName(resource))); - } - - // Allow nulls for reference types and Nullable, but not for value types. - internal static void IfNullAndNullsAreIllegalThenThrow(object value, ExceptionArgument argName) - { - // Note that default(T) is not equal to null for value types except when T is Nullable. - if (value == null && !(default(T) == null)) - ThrowHelper.ThrowArgumentNullException(argName); - } - - // - // This function will convert an ExceptionArgument enum value to the argument name string. - // - internal static string GetArgumentName(ExceptionArgument argument) - { - string argumentName = null; - - switch (argument) - { - case ExceptionArgument.array: - argumentName = "array"; - break; - - case ExceptionArgument.arrayIndex: - argumentName = "arrayIndex"; - break; - - case ExceptionArgument.capacity: - argumentName = "capacity"; - break; - - case ExceptionArgument.collection: - argumentName = "collection"; - break; - - case ExceptionArgument.converter: - argumentName = "converter"; - break; - - case ExceptionArgument.count: - argumentName = "count"; - break; - - case ExceptionArgument.dictionary: - argumentName = "dictionary"; - break; - - case ExceptionArgument.index: - argumentName = "index"; - break; - - case ExceptionArgument.info: - argumentName = "info"; - break; - - case ExceptionArgument.key: - argumentName = "key"; - break; - - case ExceptionArgument.match: - argumentName = "match"; - break; - - case ExceptionArgument.obj: - argumentName = "obj"; - break; - - case ExceptionArgument.queue: - argumentName = "queue"; - break; - - case ExceptionArgument.stack: - argumentName = "stack"; - break; - - case ExceptionArgument.startIndex: - argumentName = "startIndex"; - break; - - case ExceptionArgument.value: - argumentName = "value"; - break; - - case ExceptionArgument.item: - argumentName = "item"; - break; - - default: - Debug.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum."); - return string.Empty; - } - - return argumentName; - } - - // - // This function will convert an ExceptionResource enum value to the resource string. - // - internal static string GetResourceName(ExceptionResource resource) - { - string resourceName = null; - - switch (resource) - { - case ExceptionResource.Argument_ImplementIComparable: - resourceName = "SR.Argument_ImplementIComparable"; - break; - - case ExceptionResource.Argument_AddingDuplicate: - resourceName = "SR.Argument_AddingDuplicate"; - break; - - case ExceptionResource.ArgumentOutOfRange_Index: - resourceName = "SR.ArgumentOutOfRange_Index"; - break; - - case ExceptionResource.ArgumentOutOfRange_NeedNonNegNum: - resourceName = "SR.ArgumentOutOfRange_NeedNonNegNum"; - break; - - case ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired: - resourceName = "SR.ArgumentOutOfRange_NeedNonNegNumRequired"; - break; - - case ExceptionResource.ArgumentOutOfRange_SmallCapacity: - resourceName = "SR.ArgumentOutOfRange_SmallCapacity"; - break; - - case ExceptionResource.Arg_ArrayPlusOffTooSmall: - resourceName = "SR.Arg_ArrayPlusOffTooSmall"; - break; - - case ExceptionResource.Arg_RankMultiDimNotSupported: - resourceName = "SR.Arg_MultiRank"; - break; - - case ExceptionResource.Arg_NonZeroLowerBound: - resourceName = "SR.Arg_NonZeroLowerBound"; - break; - - case ExceptionResource.Argument_InvalidArrayType: - resourceName = "SR.Invalid_Array_Type"; - break; - - case ExceptionResource.Argument_InvalidOffLen: - resourceName = "SR.Argument_InvalidOffLen"; - break; - - case ExceptionResource.InvalidOperation_CannotRemoveFromStackOrQueue: - resourceName = "SR.InvalidOperation_CannotRemoveFromStackOrQueue"; - break; - - case ExceptionResource.InvalidOperation_EmptyCollection: - resourceName = "SR.InvalidOperation_EmptyCollection"; - break; - - case ExceptionResource.InvalidOperation_EmptyQueue: - resourceName = "SR.InvalidOperation_EmptyQueue"; - break; - - case ExceptionResource.InvalidOperation_EnumOpCantHappen: - resourceName = "SR.InvalidOperation_EnumOpCantHappen"; - break; - - case ExceptionResource.InvalidOperation_EnumFailedVersion: - resourceName = "SR.InvalidOperation_EnumFailedVersion"; - break; - - case ExceptionResource.InvalidOperation_EmptyStack: - resourceName = "SR.InvalidOperation_EmptyStack"; - break; - - case ExceptionResource.InvalidOperation_EnumNotStarted: - resourceName = "SR.InvalidOperation_EnumNotStarted"; - break; - - case ExceptionResource.InvalidOperation_EnumEnded: - resourceName = "SR.InvalidOperation_EnumEnded"; - break; - - case ExceptionResource.NotSupported_KeyCollectionSet: - resourceName = "SR.NotSupported_KeyCollectionSet"; - break; - - case ExceptionResource.NotSupported_SortedListNestedWrite: - resourceName = "SR.NotSupported_SortedListNestedWrite"; - break; - -#if !SILVERLIGHT - case ExceptionResource.Serialization_InvalidOnDeser: - resourceName = "SR.Serialization_InvalidOnDeser"; - break; - - case ExceptionResource.Serialization_MissingValues: - resourceName = "SR.Serialization_MissingValues"; - break; - - case ExceptionResource.Serialization_MismatchedCount: - resourceName = "SR.Serialization_MismatchedCount"; - break; -#endif - - case ExceptionResource.NotSupported_ValueCollectionSet: - resourceName = "SR.NotSupported_ValueCollectionSet"; - break; - - default: - Debug.Assert(false, "The enum value is not defined, please checked ExceptionArgumentName Enum."); - return string.Empty; - } - - return resourceName; - } - } - - // - // The convention for this enum is using the argument name as the enum name - // - internal enum ExceptionArgument - { - obj, - dictionary, - array, - info, - key, - collection, - match, - converter, - queue, - stack, - capacity, - index, - startIndex, - value, - count, - arrayIndex, - item, - } - - // - // The convention for this enum is using the resource name as the enum name - // - internal enum ExceptionResource - { - Argument_ImplementIComparable, - ArgumentOutOfRange_NeedNonNegNum, - ArgumentOutOfRange_NeedNonNegNumRequired, - Arg_ArrayPlusOffTooSmall, - Argument_AddingDuplicate, - Serialization_InvalidOnDeser, - Serialization_MismatchedCount, - Serialization_MissingValues, - Arg_RankMultiDimNotSupported, - Arg_NonZeroLowerBound, - Argument_InvalidArrayType, - NotSupported_KeyCollectionSet, - ArgumentOutOfRange_SmallCapacity, - ArgumentOutOfRange_Index, - Argument_InvalidOffLen, - NotSupported_ReadOnlyCollection, - InvalidOperation_CannotRemoveFromStackOrQueue, - InvalidOperation_EmptyCollection, - InvalidOperation_EmptyQueue, - InvalidOperation_EnumOpCantHappen, - InvalidOperation_EnumFailedVersion, - InvalidOperation_EmptyStack, - InvalidOperation_EnumNotStarted, - InvalidOperation_EnumEnded, - NotSupported_SortedListNestedWrite, - NotSupported_ValueCollectionSet, - } -} - -#pragma warning restore CS8600 // 将 null 字面量或可能为 null 的值转换为非 null 类型。 -#pragma warning restore IDE0059 // 不需要赋值 -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/Sortedset/bithelper.cs b/src/Basal/IFox.Basal.Shared/Sortedset/bithelper.cs deleted file mode 100644 index 665b435773868605715b476dc681a1647f43e7a3..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/Sortedset/bithelper.cs +++ /dev/null @@ -1,170 +0,0 @@ -#if NET35 -#pragma warning disable CS8603 // 可能返回 null 引用。 -#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 - - -using System; -using System.Collections; -using System.Text; - -namespace System.Collections.Generic -{ - /// - /// ABOUT: - /// Helps with operations that rely on bit marking to indicate whether an item in the - /// collection should be added, removed, visited already, etc. - /// - /// BitHelper doesn't allocate the array; you must pass in an array or ints allocated on the - /// stack or heap. ToIntArrayLength() tells you the int array size you must allocate. - /// - /// USAGE: - /// Suppose you need to represent a bit array of length (i.e. logical bit array length) - /// BIT_ARRAY_LENGTH. Then this is the suggested way to instantiate BitHelper: - /// *************************************************************************** - /// int intArrayLength = BitHelper.ToIntArrayLength(BIT_ARRAY_LENGTH); - /// BitHelper bitHelper; - /// if (intArrayLength less than stack alloc threshold) - /// int* m_arrayPtr = stackalloc int[intArrayLength]; - /// bitHelper = new BitHelper(m_arrayPtr, intArrayLength); - /// else - /// int[] m_arrayPtr = new int[intArrayLength]; - /// bitHelper = new BitHelper(m_arrayPtr, intArrayLength); - /// *************************************************************************** - /// - /// IMPORTANT: - /// The second ctor args, length, should be specified as the length of the int array, not - /// the logical bit array. Because length is used for bounds checking into the int array, - /// it's especially important to get this correct for the stackalloc version. See the code - /// samples above; this is the value gotten from ToIntArrayLength(). - /// - /// The length ctor argument is the only exception; for other methods -- MarkBit and - /// IsMarked -- pass in values as indices into the logical bit array, and it will be mapped - /// to the position within the array of ints. - /// - /// - - - - - unsafe internal class BitHelper - { // should not be serialized - private const byte MarkedBitFlag = 1; - private const byte IntSize = 32; - - // m_length of underlying int array (not logical bit array) - private int m_length; - - // ptr to stack alloc'd array of ints - [System.Security.SecurityCritical] - private int* m_arrayPtr; - - // array of ints - private int[] m_array; - - // whether to operate on stack alloc'd or heap alloc'd array - private bool useStackAlloc; - - /// - /// Instantiates a BitHelper with a heap alloc'd array of ints - /// - /// int array to hold bits - /// length of int array - // - // - // - // - [System.Security.SecurityCritical] - internal BitHelper(int* bitArrayPtr, int length) - { - this.m_arrayPtr = bitArrayPtr; - this.m_length = length; - useStackAlloc = true; - } - - /// - /// Instantiates a BitHelper with a heap alloc'd array of ints - /// - /// int array to hold bits - /// length of int array - internal BitHelper(int[] bitArray, int length) - { - this.m_array = bitArray; - this.m_length = length; - } - - /// - /// Mark bit at specified position - /// - /// - // - // - // - [System.Security.SecurityCritical] - internal unsafe void MarkBit(int bitPosition) - { - if (useStackAlloc) - { - int bitArrayIndex = bitPosition / IntSize; - if (bitArrayIndex < m_length && bitArrayIndex >= 0) - { - m_arrayPtr[bitArrayIndex] |= (MarkedBitFlag << (bitPosition % IntSize)); - } - } - else - { - int bitArrayIndex = bitPosition / IntSize; - if (bitArrayIndex < m_length && bitArrayIndex >= 0) - { - m_array[bitArrayIndex] |= (MarkedBitFlag << (bitPosition % IntSize)); - } - } - } - - /// - /// Is bit at specified position marked? - /// - /// - /// - // - // - // - [System.Security.SecurityCritical] - internal unsafe bool IsMarked(int bitPosition) - { - if (useStackAlloc) - { - int bitArrayIndex = bitPosition / IntSize; - if (bitArrayIndex < m_length && bitArrayIndex >= 0) - { - return ((m_arrayPtr[bitArrayIndex] & (MarkedBitFlag << (bitPosition % IntSize))) != 0); - } - return false; - } - else - { - int bitArrayIndex = bitPosition / IntSize; - if (bitArrayIndex < m_length && bitArrayIndex >= 0) - { - return ((m_array[bitArrayIndex] & (MarkedBitFlag << (bitPosition % IntSize))) != 0); - } - return false; - } - } - - /// - /// How many ints must be allocated to represent n bits. Returns (n+31)/32, but - /// avoids overflow - /// - /// - /// - internal static int ToIntArrayLength(int n) - { - return n > 0 ? ((n - 1) / IntSize + 1) : 0; - } - } -} - -#pragma warning restore CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。 -#pragma warning restore CS8603 // 可能返回 null 引用。 - -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/WindowsAPI/MouseHook.cs b/src/Basal/IFox.Basal.Shared/WindowsAPI/MouseHook.cs deleted file mode 100644 index 400e4a792998e0d143e0b0dbb76e11b4695eeecb..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Shared/WindowsAPI/MouseHook.cs +++ /dev/null @@ -1,287 +0,0 @@ -namespace IFoxCAD.Basal; - -public class MouseHook -{ - /// - /// 鼠标按下事件 - /// - public event MouseEventHandler? MouseDown; - /// - /// 松开鼠标事件 - /// - public event MouseEventHandler? MouseUp; - /// - /// 鼠标移动事件 - /// - public event MouseEventHandler? MouseMove; - /// - /// 鼠标滚轮事件 - /// - public event MouseEventHandler? MouseWheel; - /// - /// 鼠标单击事件 - /// - public event EventHandler? Click; - /// - /// 鼠标双击事件 - /// - public event EventHandler? DoubleClick; - - - bool _isHookBreak = false; - /// - /// 否决本次输入:设置不向下回调 - /// - public void Vote() - { - _isHookBreak = true; - } - - /// 不要试图省略此变量,否则将会导致GC变量池满后释放
- /// 提示:激活 CallbackOnCollectedDelegate 托管调试助手(MDA) - internal static WindowsAPI.CallBack? HookProc; - internal static IntPtr _NextHookProc;//挂载成功的标记 - public readonly Process Process; - - - [DllImport("user32.dll", EntryPoint = "GetDoubleClickTime")] - public extern static int GetDoubleClickTime(); - static readonly Stopwatch _watch = new(); - - /// - /// 安装鼠标钩子 - /// - /// 低级钩子超时时间 - public MouseHook(int setLowLevel = 25000) - { - _NextHookProc = IntPtr.Zero; - Process = Process.GetCurrentProcess(); - WindowsAPI.CheckLowLevelHooksTimeout(setLowLevel); - _watch.Start(); - } - - void UnHook() - { - if (_NextHookProc != IntPtr.Zero) - { - WindowsAPI.UnhookWindowsHookEx(_NextHookProc); - _NextHookProc = IntPtr.Zero; - } - } - - /// - /// 设置钩子 - /// - /// false进程钩子,true全局钩子 - public void SetHook(bool processHook = false) - { - UnHook(); - if (_NextHookProc != IntPtr.Zero) - return; - - if (processHook) - { - HookProc = (nCode, wParam, lParam) => { - if (nCode >= 0 && HookTask(nCode, wParam, lParam)) - return (IntPtr)1; - return WindowsAPI.CallNextHookEx(_NextHookProc, nCode, wParam, lParam); - }; - _NextHookProc = WindowsAPI.SetWindowsHookEx(HookType.WH_MOUSE, HookProc, - IntPtr.Zero, WindowsAPI.GetCurrentThreadId()); - } - else - { - var moduleHandle = WindowsAPI.GetModuleHandle(Process.MainModule.ModuleName); - HookProc = (nCode, wParam, lParam) => { - if (nCode >= 0 && HookTask(nCode, wParam, lParam)) - return (IntPtr)1; - return WindowsAPI.CallNextHookEx(_NextHookProc, nCode, wParam, lParam); - }; - _NextHookProc = WindowsAPI.SetWindowsHookEx(HookType.WH_MOUSE_LL, HookProc, - moduleHandle, 0); - } - } - - - - MouseButtons _button; - int _clickCount = 0; - bool _down = false; - bool _up = false; - bool _ck = false; - - /// - /// 钩子的消息处理 - /// - /// - /// - /// - /// false不终止回调,true终止回调 - bool HookTask(int nCode, int wParam, IntPtr lParam) - { - if (MouseDown is null - && MouseUp is null - && MouseMove is null - && MouseWheel is null - && Click is null - && DoubleClick is null) - return false; - - _button = MouseButtons.None; - _clickCount = 0; - _down = false; - _up = false; - _ck = false; - - switch ((WM)wParam) - { - case WM.WM_LBUTTONDOWN: - _button = MouseButtons.Left; - _clickCount = 1; - _down = true; - _ck = true; - break; - case WM.WM_LBUTTONUP: - _button = MouseButtons.Left; - _clickCount = 1; - _up = true; - break; - case WM.WM_LBUTTONDBLCLK: - _button = MouseButtons.Left; - _clickCount = 2; - _ck = true; - break; - case WM.WM_RBUTTONDOWN: - _button = MouseButtons.Right; - _clickCount = 1; - _down = true; - _ck = true; - break; - case WM.WM_RBUTTONUP: - _button = MouseButtons.Right; - _clickCount = 1; - _up = true; - break; - case WM.WM_RBUTTONDBLCLK: - _button = MouseButtons.Right; - _clickCount = 2; - _ck = true; - break; - case WM.WM_MBUTTONDOWN: - _button = MouseButtons.Middle; - _clickCount = 1; - _ck = true; - break; - case WM.WM_MOUSEWHEEL: - // 滚轮 - break; - case WM.WM_MOUSEMOVE: - // 移动 - // 假设想要限制鼠标在屏幕中的移动区域能够在此处设置 - // 后期须要考虑实际的x y的容差 - // if (!Screen.PrimaryScreen.Bounds.Contains(e.X, e.Y)) - // // return 1; - // if (button == MouseButtons.Left) - // { - // GetCursorPos(out POINT pt); - // // 防止频繁获取导致出错 - // if (pt0ld.Leng(pt) > 20) - // pt0ld = pt; - // } - break; - } - - // 从回调函数中得到鼠标的信息 - var mouseMsg = MouseHookStruct.Create(lParam); - MouseEventArgs e = new(_button, _clickCount, mouseMsg.Point.X, mouseMsg.Point.Y, 0); - if (_down) - MouseDown?.Invoke(this, e); - if (_up) - MouseUp?.Invoke(this, e); - if (_ck) - Click?.Invoke(this, e); - if (_clickCount == 2) - { - // 如果不用时间控制,那么双击会执行两次 - if (_watch.Elapsed.TotalMilliseconds > GetDoubleClickTime()) - { - DoubleClick?.Invoke(this, e); - _watch.Reset(); - _watch.Start(); - } - } - MouseMove?.Invoke(this, e); - MouseWheel?.Invoke(this, e); - - // 屏蔽此输入 - if (_isHookBreak) - return true; - - return false; - } - - - /// - /// Hook鼠标数据结构 - /// - [StructLayout(LayoutKind.Sequential)] - public struct MouseHookStruct - { - /// - /// 鼠标在屏幕上的x,y坐标 - /// - public Point Point; - /// - /// 点击窗体的句柄 - /// - public IntPtr hWnd; - /// - /// 消息 - /// - public int wHitTestCode; - /// - /// 扩展信息,可以使用GetMessageExtraInfo的返回值 - /// - public int dwExtraInfo; - - public static MouseHookStruct Create(IntPtr lParam) - { - return (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct)); - } - - public void ToPtr(IntPtr lParam) - { - Marshal.StructureToPtr(this, lParam, true); - } - } - - - #region IDisposable接口相关函数 - public bool IsDisposed { get; private set; } = false; - - /// - /// 手动调用释放 - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// 析构函数调用释放 - /// - ~MouseHook() - { - Dispose(false); - } - - protected virtual void Dispose(bool disposing) - { - // 不重复释放,并设置已经释放 - if (IsDisposed) return; - IsDisposed = true; - UnHook(); - } - #endregion -} \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Source/IFox.Basal.Source.csproj b/src/Basal/IFox.Basal.Source/IFox.Basal.Source.csproj deleted file mode 100644 index 4a5496ddc3770d91d3adc5dafa32ab4850a3ec52..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal.Source/IFox.Basal.Source.csproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - netstandard1.0 - true - $(AssemblyName) - $(Version) - true - - - - CS8021 - true - false - contentFiles - true - false - false - true - - - - - true - $(ContentTargetFolders)\cs\any\$(PackageId)\ - false - - - true - - - - true - $(ContentTargetFolders)\any\any\$(PackageId)\ - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Basal/IFox.Basal/GlobalUsings.cs b/src/Basal/IFox.Basal/GlobalUsings.cs deleted file mode 100644 index 35cc1cd67e92eaf57e0061ef6762df7472b42d5b..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal/GlobalUsings.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 系统引用 -global using System; -global using System.Collections; -global using System.Collections.Generic; -global using System.IO; -global using System.Linq; -global using System.Text; -global using System.Reflection; -global using System.ComponentModel; -global using System.Runtime.InteropServices; -global using System.Diagnostics; -global using System.Drawing; -global using System.Windows.Forms; -global using Microsoft.Win32; -global using System.Runtime.CompilerServices; -global using System.Threading; -global using System.Linq.Expressions; -global using System.Collections.ObjectModel; - - -#if NET45 -global using Microsoft.CSharp.RuntimeBinder; -#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal/IFox.Basal.csproj b/src/Basal/IFox.Basal/IFox.Basal.csproj deleted file mode 100644 index db74995c7f83db9baef373bd0b064fee99c77449..0000000000000000000000000000000000000000 --- a/src/Basal/IFox.Basal/IFox.Basal.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - NET35;NET40;NET45 - true - true - MSB3270 - - - - - 4.7.0 - - - - - - - diff --git a/src/CAD/Directory.Build.props b/src/CAD/Directory.Build.props deleted file mode 100644 index 84265c22fa5b98facccfc1186d83eba545c9b5c4..0000000000000000000000000000000000000000 --- a/src/CAD/Directory.Build.props +++ /dev/null @@ -1,34 +0,0 @@ - - - - 0.5.2.4 - 补充2023的信息 - - - - preview - enable - true - ..\..\..\bin\$(Configuration)\ - true - true - True - True - - - - - InspireFunction - xsfhlzh;vicwjb;liuqihong - InspireFunction - 基于.NET的二次开发基本类库. - MIT - true - https://gitee.com/inspirefunction/ifoxcad - https://gitee.com/inspirefunction/ifoxcad.git - git - IFox;CAD;AutoCad;C#;NET;GStarCAD;ZWCAD - - - - \ No newline at end of file diff --git a/src/CAD/IFox.CAD.ACAD/IFox.CAD.ACAD.csproj b/src/CAD/IFox.CAD.ACAD/IFox.CAD.ACAD.csproj deleted file mode 100644 index 4b999214c35f4585bed44e5a4102ba9e43324099..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.ACAD/IFox.CAD.ACAD.csproj +++ /dev/null @@ -1,54 +0,0 @@ - - - - NET35;NET40;NET45 - true - true - MSB3270 - - - - DEBUG - - - $(Configuration);acad;ac2009 - - - $(Configuration);acad;ac2013 - - - $(Configuration);acad;ac2015 - - - - - - - - - - - - - - - - True - - - - - - - - - - - - - - - - - - diff --git a/src/CAD/IFox.CAD.GCAD/GlobalUsings.cs b/src/CAD/IFox.CAD.GCAD/GlobalUsings.cs deleted file mode 100644 index 08de9aa6def451afa40d8019aa538ef8678972ed..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.GCAD/GlobalUsings.cs +++ /dev/null @@ -1,51 +0,0 @@ -/// 系统引用 -global using System; -global using System.Collections; -global using System.Collections.Generic; -global using System.IO; -global using System.Linq; -global using System.Text; -global using System.Reflection; -global using System.Text.RegularExpressions; -global using Microsoft.Win32; -global using System.ComponentModel; -global using System.Runtime.InteropServices; -global using System.Collections.Specialized; - -global using Exception = System.Exception; - -global using Registry = Microsoft.Win32.Registry; -global using RegistryKey = Microsoft.Win32.RegistryKey; - -/// cad 引用 -global using GrxCAD.ApplicationServices; -global using GrxCAD.EditorInput; -global using GrxCAD.Colors; -global using GrxCAD.DatabaseServices; -global using GrxCAD.Geometry; -global using GrxCAD.Runtime; -global using Acap = GrxCAD.ApplicationServices.Application; -global using Acgi = GrxCAD.GraphicsInterface; - -global using GrxCAD.DatabaseServices.Filters; -global using GrxCAD; - -global using GrxCAD.Internal; - -// jig命名空间会引起Viewport/Polyline等等重义,最好逐个引入 using Autodesk.AutoCAD.GraphicsInterface -global using GrxCAD.GraphicsInterface; -global using WorldDraw = GrxCAD.GraphicsInterface.WorldDraw; -global using Manager = GrxCAD.GraphicsSystem.Manager; -global using Group = GrxCAD.DatabaseServices.Group; -global using Viewport = GrxCAD.DatabaseServices.Viewport; -global using Polyline = GrxCAD.DatabaseServices.Polyline; -global using Cad_DwgFiler = GrxCAD.DatabaseServices.DwgFiler; -global using Cad_DxfFiler = GrxCAD.DatabaseServices.DxfFiler; -global using Cad_ErrorStatus = GrxCAD.Runtime.ErrorStatus; - -/// ifoxcad.basal 引用 -global using IFoxCAD.Basal; - -#if !NewtonsoftJson -global using System.Web.Script.Serialization; -#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.GCAD/IFox.CAD.GCAD.csproj b/src/CAD/IFox.CAD.GCAD/IFox.CAD.GCAD.csproj deleted file mode 100644 index 506d96e51864e52787ab91b6191c187e3ac076cb..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.GCAD/IFox.CAD.GCAD.csproj +++ /dev/null @@ -1,42 +0,0 @@ - - - - NET48 - - true - true - false - MSB3270 - - - - DEBUG - - - $(Configuration);gcad - - - - - runtime - - - - - - True - - - - - - - - - - - - - - - diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/Graph/Graph.cs b/src/CAD/IFox.CAD.Shared/Algorithms/Graph/Graph.cs deleted file mode 100644 index 30a76f8d70ac7ba35fca36ce403c82f4bc2d1de5..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Algorithms/Graph/Graph.cs +++ /dev/null @@ -1,739 +0,0 @@ -namespace IFoxCAD.Cad; - -using Exception = System.Exception; - -/// -/// 无权无向图实现 -/// IEnumerable 枚举所有顶点; -/// -public sealed class Graph : IGraph, IEnumerable -{ - #region 字段及属性 - /// - /// 存储所有节点的字典,key为顶点的类型,value为邻接表,类型是hashset,不可重复添加点 - /// - /// - readonly Dictionary> vertices = new(); - /// - /// 邻接边表,key为顶点的类型,value为邻接边表,类型是hashset,不可重复添加边 - /// - readonly Dictionary> edges = new(); - /// - /// 为加快索引,引入hash检索 - /// - readonly Dictionary vertexs = new(); - /// - /// 节点数量 - /// - public int VerticesCount => vertices.Count; - - /// - /// Returns a reference vertex. - /// Time complexity: O(1). - /// - private IGraphVertex? ReferenceVertex - { - get - { - using (var enumerator = vertexs.GetEnumerator()) - { - if (enumerator.MoveNext()) - { - return enumerator.Current.Value; - } - } - - return null; - } - } - IGraphVertex? IGraph.ReferenceVertex => ReferenceVertex; - /// - /// 目前点增加点的顺序号,这个点号不随删点而减少的 - /// - private int insertCount; - #endregion - - #region 构造函数 - /// - /// - /// - public Graph() - { - insertCount = 0; // 每次新建对象就将顶点顺序号归零 - } - #endregion - - #region 顶点及边_增 - /// - /// 向该图添加一个新顶点,但是无边; - /// - /// 点 - /// 创建的顶点 - public IGraphVertex AddVertex(Point3d pt) - { - var str = pt.GetHashString(); - if (vertexs.ContainsKey(str)) - return vertexs[str]; - - var vertex = new GraphVertex(pt, insertCount++); - vertices.Add(vertex, new HashSet()); - edges.Add(vertex, new HashSet()); - - vertexs[str] = vertex; - - return vertex; - } - - /// - /// 向该图添加一个边; - /// - /// - public void AddEdge(Curve3d curve) - { - //if (curve == null) - // throw new ArgumentNullException(nameof(curve)); - - curve.NotNull(nameof(curve)); - - var start = AddVertex(curve.StartPoint); - var end = AddVertex(curve.EndPoint); - - // 添加起点的邻接表和邻接边 - vertices[start].Add(end); - edges[start].Add(new GraphEdge(end, curve)); - - // 为了保证点顺序,每个点的邻接边必须按起点-终点,所以添加曲线终点时,将添加一个方向的曲线 - var curtmp = (Curve3d)curve.Clone(); - curtmp = curtmp.GetReverseParameterCurve(); - - // 添加终点的邻接表和邻接边 - vertices[end].Add(start); - edges[end].Add(new GraphEdge(start, curtmp)); - } - #endregion - - #region 顶点及边_删 - /// - /// 从此图中删除现有顶点; - /// - /// 点 - public void RemoveVertex(Point3d pt) - { - var str = pt.GetHashString(); - if (vertexs.ContainsKey(str)) - { - var vertex = vertexs[str]; - - // 删除邻接表里的vertex点,先删除后面的遍历可以少一轮 - vertices.Remove(vertex!); - - // 删除其他顶点的邻接表里的vertex点 - foreach (var item in vertices.Values) - item.Remove(vertex!); - - // 删除邻接边表里的vertex点,先删除后面的遍历可以少一轮 - edges.Remove(vertex!); - - // 删除其他顶点的邻接边表的指向vertex的边 - foreach (var item in edges.Values) - { - item.RemoveWhere(x => vertex.Equals(x.TargetVertex)); - // foreach (var edge in item) - // { - // if (vertex.Equals(edge.TargetVertex)) - // item.Remove(edge); - // } - } - vertexs.Remove(str); - } - } - - /// - /// 从此图中删除一条边; - /// - /// 曲线 - public void RemoveEdge(Curve3d curve) - { - //if (curve == null) - // throw new ArgumentNullException(nameof(curve)); - curve.NotNull(nameof(curve)); - - RemoveVertex(curve.StartPoint); - RemoveVertex(curve.EndPoint); - } - #endregion - - #region 顶点和边_查 - /// - /// 我们在给定的来源和目的地之间是否有边? - /// - /// 起点 - /// 终点 - /// 有边返回 ,反之返回 - public bool HasEdge(IGraphVertex source, IGraphVertex dest) - { - if (!vertices.ContainsKey(source) || !vertices.ContainsKey(dest)) - throw new ArgumentException("源或目标不在此图中;"); - - foreach (var item in edges[source]) - { - if (item.TargetVertex == dest) - return true; - } - return false; - } - - /// - /// 获取边 - /// - /// 起点 - /// 终点 - /// - /// 传入的点不在图中时抛出参数异常 - public IEdge? GetEdge(IGraphVertex source, IGraphVertex dest) - { - if (!vertices.ContainsKey(source) || !vertices.ContainsKey(dest)) - throw new ArgumentException("源或目标不在此图中;"); - - foreach (var item in edges[source]) - { - if (item.TargetVertex.Equals(dest)) - return item; - } - return null; - } - - /// - /// 是否存在顶点,此函数目前未发现有啥用 - /// - /// 顶点 - /// 存在顶点返回 ,反之返回 - public bool ContainsVertex(IGraphVertex value) - { - return vertices.ContainsKey(value); - } - #endregion - - #region 获取邻接表和曲线 - /// - /// 获取顶点的邻接表 - /// - /// 顶点 - /// 邻接表 - public HashSet GetAdjacencyList(IGraphVertex vertex) - { - return vertices[vertex]; - } - - /// - /// 获取顶点的邻接边表 - /// - /// 顶点 - /// 邻接边表 - public HashSet GetAdjacencyEdge(IGraphVertex vertex) - { - return edges[vertex]; - } - - /// - /// 根据顶点表获取曲线集合 - /// - /// 顶点表 - /// 曲线表 - public List GetCurves(List graphVertices) - { - var curves = new List(); - for (int i = 0; i < graphVertices.Count - 1; i++) - { - var cur = graphVertices[i]; - var next = graphVertices[i + 1]; - var edge = GetEdge(cur, next); - if (edge is not null) - curves.Add(edge.TargetEdge); - } - var lastedge = GetEdge(graphVertices[^1], graphVertices[0]); - if (lastedge is not null) - curves.Add(lastedge.TargetEdge); - - return curves; - } - #endregion - - #region 克隆及接口实现 - /// - /// 克隆此图;目测是深克隆 - /// - [System.Diagnostics.DebuggerStepThrough] - public Graph Clone() - { - var newGraph = new Graph(); - - foreach (var vertex in edges.Values) - foreach (var item in vertex) - newGraph.AddEdge(item.TargetEdge); - - return newGraph; - } - - IGraph IGraph.Clone() - { - return Clone(); - } - - /// - /// 节点迭代器 - /// - /// - [System.Diagnostics.DebuggerStepThrough] - public IEnumerator GetEnumerator() - { - return VerticesAsEnumberable.GetEnumerator(); - } - - [System.Diagnostics.DebuggerStepThrough] - IEnumerator? IEnumerable.GetEnumerator() - { - return GetEnumerator() as IEnumerator; - } - /// - /// 节点迭代器 - /// - public IEnumerable VerticesAsEnumberable => - vertices.Select(x => x.Key); - #endregion - - #region 方法 - /// - /// 输出点的邻接表的可读字符串 - /// - /// - public string ToReadable() - { - int i = 1; - string output = string.Empty; - foreach (var node in vertices) - { - var adjacents = string.Empty; - - output = string.Format("{1}\r\n{0}-{2}: [", i, output, node.Key.Data.ToString()); - - foreach (var adjacentNode in node.Value) - adjacents = string.Format("{0}{1},", adjacents, adjacentNode.Data.ToString()); - - if (adjacents.Length > 0) - adjacents = adjacents.TrimEnd(new char[] { ',', ' ' }); - - output = string.Format("{0}{1}]", output, adjacents); - i++; - } - return output; - } - #endregion -} - - -/// -/// 邻接表图实现的顶点; -/// IEnumerable 枚举所有邻接点; -/// -public sealed class GraphVertex : IGraphVertex, IEquatable, IComparable, IComparable -{ - #region 属性 - /// - /// 数据 - /// - public Point3d Data { get; set; } - /// - /// 索引 - /// - public int Index { get; set; } - #endregion - - #region 构造 - /// - /// 邻接表图实现的顶点 - /// - /// 点 - /// 所在节点索引 - public GraphVertex(Point3d value, int index) - { - Data = value; - Index = index; - } - #endregion - - #region 重载运算符_比较 - /// - /// 是否相等 - /// - /// - /// - public bool Equals(IGraphVertex other) - { - return Index == other.Index; - } - /// - /// 是否相等 - /// - /// - /// - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is not IGraphVertex vertex) - return false; - else - return Equals(vertex); - } - /// - /// 计算hashcode - /// - /// - public override int GetHashCode() - { - return Index; - } - /// - /// 比较大小 - /// - /// - /// - public int CompareTo(IGraphVertex other) - { - if (Equals(other)) - return 0; - - if (Index < other.Index) - return -1; - else - return 1; - } - - int IComparable.CompareTo(IGraphVertex other) - { - return CompareTo(other); - } - /// - /// 比较大小 - /// - /// - /// - /// - public int CompareTo(object obj) - { - if (obj is null) - return 1; - - try - { - var other = (GraphVertex)obj; - return CompareTo(other); - } - catch (Exception) - { - throw new ArgumentException("Object is not a IGraphVertex"); - } - } - /// - /// 相等 - /// - /// - /// - /// - public static bool operator ==(GraphVertex person1, GraphVertex person2) - { - if (person1 is null || person2 is null) - return Equals(person1, person2); - - return person1.Equals(person2); - } - /// - /// 不相等 - /// - /// - /// - /// - public static bool operator !=(GraphVertex person1, GraphVertex person2) - { - if (person1 is null || person2 is null) - return !Equals(person1, person2); - - return !person1.Equals(person2); - } - #endregion -} - - -/// -/// 无向图中边的定义 -/// -public sealed class GraphEdge : IEdge, IEquatable -{ - #region 属性 - /// - /// 顶点 - /// - public IGraphVertex TargetVertex { get; set; } - /// - /// 边 - /// - public Curve3d TargetEdge { get; set; } - #endregion - - #region 构造 - /// - /// 无向图中边的定义 - /// - /// 下一点 - /// 下一点之间的曲线 - public GraphEdge(IGraphVertex target, Curve3d edge) - { - TargetVertex = target; - TargetEdge = edge; - } - #endregion - - #region 重载运算符_比较 - /// - /// 是否相等 - /// - /// - /// - public bool Equals(GraphEdge other) - { - if (other is null) - return false; - return TargetVertex == other.TargetVertex && - TargetEdge == other.TargetEdge; - } - /// - /// 是否相等 - /// - /// - /// - public override bool Equals(object obj) - { - if (obj is null) - return false; - if (obj is not GraphEdge personObj) - return false; - else - return Equals(personObj); - } - /// - /// 获取hashcode - /// - /// - public override int GetHashCode() - { - return (TargetVertex.GetHashCode(), TargetEdge.GetHashCode()).GetHashCode(); - } - /// - /// 相等 - /// - /// - /// - /// - public static bool operator ==(GraphEdge person1, GraphEdge person2) - { - if (person1 is null || person2 is null) - return Equals(person1, person2); - - return person1.Equals(person2); - } - /// - /// 不相等 - /// - /// - /// - /// - public static bool operator !=(GraphEdge person1, GraphEdge person2) - { - if (person1 is null || person2 is null) - return !Equals(person1, person2); - - return !person1.Equals(person2); - } - #endregion -} - - -/// -/// 深度优先搜索; -/// -public sealed class DepthFirst -{ - #region 公共方法 - /// - /// 存储所有的边 - /// -#if true - public List> Curve3ds { get; } = new(); -#else - public List> Curve3ds { get; } = new(); -#endif - private HashSet Curved { get; } = new(); - - - /// - /// 找出所有的路径 - /// - /// 图 - public void FindAll(IGraph graph) - { - var total = new HashSet(); - // var graphtmp = graph.Clone(); - foreach (var item in graph.VerticesAsEnumberable) - { - Dfs(graph, new LinkedHashSet { item }, total); - total.Add(item); - } - } - #endregion - - #region 内部方法 - /// - /// 递归 DFS; - /// - /// 图 - /// 已经遍历的路径 -#if true - void Dfs(IGraph graph, LinkedHashSet visited, HashSet totalVisited) - { - var adjlist = graph.GetAdjacencyList(/*startNode*/ visited.First!.Value); // O(1) - foreach (var nextNode in adjlist) // O(n) - { - if (totalVisited.Contains(nextNode)) - { - continue; - } - // 如果下一个点未遍历过 - if (!visited.Contains(nextNode)) // O(1) - { - // 将下一点加入路径集合,并进行下一次递归 - var sub = new LinkedHashSet { nextNode }; - sub.AddRange(visited); // O(n) - Dfs(graph, sub, totalVisited); - } - // 如果下一点遍历过,并且路径大于2,说明已经找到起点 - else if (visited.Count > 2 && nextNode.Equals(visited.Last!.Value)) - { - // 将重复的路径进行过滤,并把新的路径存入结果 - var curstr = Gethashstring(visited); // O(n) - if (Isnew(curstr)) // O(1) - { - Curve3ds.Add(visited); - Curved.Add(curstr.Item1); - } - } - } - } - - - - -#else - - void Dfs(IGraph graph, List visited) - { - var startNode = visited[0]; - IGraphVertex nextNode; - List sub; - - var adjlist = graph.GetAdjacencyList(startNode).ToList(); // O(n) - for (int i = 0; i < adjlist.Count; i++) // O(n) - { - nextNode = adjlist[i]; - - // 如果下一个点未遍历过 - if (!visited.Contains(nextNode)) // O(n) - { - // 将下一点加入路径集合,并进行下一次递归 - sub = new List { nextNode }; - sub.AddRange(visited); // O(n) - Dfs(graph, sub); - } - - // 如果下一点遍历过,并且路径大于2,说明已经找到起点 - else if (visited.Count > 2 && nextNode.Equals(visited[^1])) - { - // 将重复的路径进行过滤,并把新的路径存入结果 - var cur = RotateToSmallest(visited); // O(n) - var inv = Invert(cur,cur[0]); // O(n) - - var curstr = Gethashstring(cur,inv); - // Env.Print(curstr); - if (Isnew(curstr)) - { - Curve3ds.Add(cur); - Curved.Add(curstr.Item1); - } - } - } - } -#endif - - - - - - - - - /// - /// 将列表旋转到最小的值为列表起点 - /// - /// - /// - static List RotateToSmallest(List lst) - { - var index = lst.IndexOf(lst.Min()); - return lst.Skip(index).Concat(lst.Take(index)).ToList(); - } - - /// - /// 将列表反向,并旋转到起点为最小值 - /// - /// - /// - static List Invert(List lst, IGraphVertex vertex) - { - var tmp = lst.ToList(); - tmp.Reverse(); - var index = tmp.IndexOf(vertex); - return tmp.Skip(index).Concat(lst.Take(index)).ToList(); - } - - static (string, string) Gethashstring(List pathone, List pathtwo) - { - var one = new string[pathone.Count]; - var two = new string[pathtwo.Count]; - for (int i = 0; i < pathone.Count; i++) - { - one[i] = pathone[i].Index.ToString(); - two[i] = pathtwo[i].Index.ToString(); - } - return (string.Join("-", one), string.Join("-", two)); - } - - static (string, string) Gethashstring(LinkedHashSet path) - { - var one = new string[path.Count]; - var two = new string[path.Count]; - path.For(path.MinNode!, (i, ver1, ver2) => { - one[i] = ver1.Index.ToString(); - two[i] = ver2.Index.ToString(); - }); - return (string.Join("-", one), string.Join("-", two)); - } - - - bool Isnew((string, string) path) - { - return !Curved.Contains(path.Item1) && !Curved.Contains(path.Item2); - } - - - #endregion -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/Graph/IGraph.cs b/src/CAD/IFox.CAD.Shared/Algorithms/Graph/IGraph.cs deleted file mode 100644 index 3a7eec4091d642bd79cd8e7b96e295d2f3070baf..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Algorithms/Graph/IGraph.cs +++ /dev/null @@ -1,108 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 无向图 -/// -public interface IGraph -{ - /// - /// 顶点的数量 - /// - /// - int VerticesCount { get; } - - /// - /// 是否存在顶点 - /// - /// 顶点键 - /// - bool ContainsVertex(IGraphVertex key); - - /// - /// 顶点的迭代器 - /// - /// - IEnumerable VerticesAsEnumberable { get; } - - /// - /// 是否有边 - /// - /// 源顶点 - /// 目的顶点 - /// - bool HasEdge(IGraphVertex source, IGraphVertex destination); - /// - /// 图克隆函数 - /// - /// - IGraph Clone(); - /// - /// 获取边 - /// - /// - /// - /// - IEdge? GetEdge(IGraphVertex source, IGraphVertex dest); - /// - /// 邻接表 - /// - /// - /// - HashSet GetAdjacencyList(IGraphVertex vertex); - /// - /// 邻接边表 - /// - /// - /// - HashSet GetAdjacencyEdge(IGraphVertex vertex); - /// - /// 当前的节点 - /// - IGraphVertex? ReferenceVertex { get; } - /// - /// 删除节点 - /// - /// 节点的坐标 - void RemoveVertex(Point3d pt); - /// - /// 删除边 - /// - /// 曲线 - void RemoveEdge(Curve3d curve); - -} - -/// -/// 无向图顶点 -/// -/// 顶点数据类型 -public interface IGraphVertex : IComparable -{ - /// - /// 顶点的键 - /// - /// - int Index { get; set; } - - /// - /// 顶点的数据 - /// - Point3d Data { get; } -} -/// -/// 无向图边 -/// -public interface IEdge -{ - /// - /// 边 - /// - Curve3d TargetEdge { get; } - /// - /// 目标顶点 - /// - IGraphVertex TargetVertex { get; } -} - - - diff --git a/src/CAD/IFox.CAD.Shared/Copyclip/BitmapTool.cs b/src/CAD/IFox.CAD.Shared/Copyclip/BitmapTool.cs deleted file mode 100644 index 444acae7cb766ffcff120285ea938b00da53abd0..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Copyclip/BitmapTool.cs +++ /dev/null @@ -1,165 +0,0 @@ -namespace IFoxCAD.Cad; - -using System; -/// -/// bitmap工具类 -/// -public class BitmapTool -{ - // https://blog.csdn.net/shellching/article/details/18405185 - /// Windows不允许程序员直接访问硬件, - /// 它对屏幕的操作是通过环境设备,也就是DC来完成的 - /// 屏幕上的每一个窗口都对应一个DC,可以把DC想象成一个视频缓冲区, - /// 对这这个缓冲区的操作,会表现在这个缓冲区对应的屏幕窗口上. - /// 在窗口的DC之外,可以建立自己的DC,就是说它不对应窗口, - /// 这个方法就是 CreateCompatibleDC,这个DC就是一个内存缓冲区, - /// 通过这个DC你可以把和它兼容的窗口DC保存到这个DC中, - /// 就是说你可以通过它在不同的DC之间拷贝数据. - /// 例如:你先在这个DC中建立好数据,然后在拷贝到窗口的DC就是完成了这个窗口的刷新 - - /// - /// 检索指定窗口的工作区的显示设备上下文(DC)的句柄
- /// 显示设备上下文可以在随后的图形显示界面(GDI)函数中使用,
- /// 以在窗口的工作区中绘制
- ///
- /// - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr GetDC(IntPtr hWnd); - /// - /// - /// - /// - /// - /// - [DllImport("user32.dll")] - public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); - - /// - /// 创建DC - /// - /// - /// - [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC", SetLastError = true)] - public static extern IntPtr CreateCompatibleDC([In] IntPtr hdc); - - /// - /// Creates a bitmap compatible with the device that is associated with the specified device context. - /// - /// A handle to a device context. - /// The bitmap width, in pixels. - /// The bitmap height, in pixels. - /// If the function succeeds, the return value is a handle to the compatible bitmap (DDB). If the function fails, the return value is . - [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap")] - public static extern IntPtr CreateCompatibleBitmap([In] IntPtr hdc, int nWidth, int nHeight); - - /// Selects an object into the specified device context (DC). The new object replaces the previous object of the same type. - /// A handle to the DC. - /// A handle to the object to be selected. - /// - /// If the selected object is not a region and the function succeeds, the return value is a handle to the object being replaced. If the selected object is a region and the function succeeds, the return value is one of the following values. - /// SIMPLEREGION - Region consists of a single rectangle. - /// COMPLEXREGION - Region consists of more than one rectangle. - /// NULLREGION - Region is empty. - /// If an error occurs and the selected object is not a region, the return value is NULL. Otherwise, it is HGDI_ERROR. - /// - /// - /// This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object. - /// An application cannot select a single bitmap into more than one DC at a time. - /// ICM: If the object being selected is a brush or a pen, color management is performed. - /// - [DllImport("gdi32.dll", EntryPoint = "SelectObject")] - public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr hgdiobj); - - /// Deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object. After the object is deleted, the specified handle is no longer valid. - /// A handle to a logical pen, brush, font, bitmap, region, or palette. - /// - /// If the function succeeds, the return value is nonzero. - /// If the specified handle is not valid or is currently selected into a DC, the return value is zero. - /// - /// - /// Do not delete a drawing object (pen or brush) while it is still selected into a DC. - /// When a pattern brush is deleted, the bitmap associated with the brush is not deleted. The bitmap must be deleted independently. - /// - [DllImport("gdi32.dll", EntryPoint = "DeleteObject")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeleteObject([In] IntPtr hObject); - - /// - /// 指定的源设备环境区域中的像素进行位块转换,以传送到目标设备环境 - /// - /// Handle to the destination device context. - /// The leftmost x-coordinate of the destination rectangle (in pixels). - /// The topmost y-coordinate of the destination rectangle (in pixels). - /// The width of the source and destination rectangles (in pixels). - /// The height of the source and the destination rectangles (in pixels). - /// Handle to the source device context. - /// The leftmost x-coordinate of the source rectangle (in pixels). - /// The topmost y-coordinate of the source rectangle (in pixels). - /// A raster-operation code. - /// - /// true if the operation succeedes, false otherwise. To get extended error information, call . - /// - [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop); - /// - /// A raster-operation code enum - /// - public enum TernaryRasterOperations : uint - { - -#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 - SRCCOPY = 0x00CC0020, - SRCPAINT = 0x00EE0086, - SRCAND = 0x008800C6, - SRCINVERT = 0x00660046, - SRCERASE = 0x00440328, - NOTSRCCOPY = 0x00330008, - NOTSRCERASE = 0x001100A6, - MERGECOPY = 0x00C000CA, - MERGEPAINT = 0x00BB0226, - PATCOPY = 0x00F00021, - PATPAINT = 0x00FB0A09, - PATINVERT = 0x005A0049, - DSTINVERT = 0x00550009, - BLACKNESS = 0x00000042, - WHITENESS = 0x00FF0062, - CAPTUREBLT = 0x40000000 //only if WinVer >= 5.0.0 (see wingdi.h) -#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 - } - - /// - /// 截图成为BMP - /// - /// 截图的窗口 - /// 扔出BMP执行任务 - /// - public static void CaptureWndImage(IntPtr hWnd, Action action) - { - //if (action == null) - // throw new ArgumentNullException(nameof(action)); - action.NotNull(nameof(action)); - var hDC = GetDC(hWnd); - var hMemDC = CreateCompatibleDC(hDC); - if (hMemDC == IntPtr.Zero) - return; - - WindowsAPI.GetClientRect(hWnd, out WindowsAPI.IntRect rcClient); - int width = rcClient.Right - rcClient.Left; - int height = rcClient.Bottom - rcClient.Top; - - var hBitmap = CreateCompatibleBitmap(hDC, width, height); - if (hBitmap != IntPtr.Zero) - { - SelectObject(hMemDC, hBitmap); - if (BitBlt(hMemDC, 0, 0, width, height, - hDC, 0, 0, TernaryRasterOperations.SRCCOPY)) - { - action.Invoke(hBitmap); - } - DeleteObject(hBitmap); - } - DeleteObject(hMemDC); - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Copyclip/EmfTool.cs b/src/CAD/IFox.CAD.Shared/Copyclip/EmfTool.cs deleted file mode 100644 index da8ca7d60c207bbb5cbd192cc13dab7e1db00f5c..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Copyclip/EmfTool.cs +++ /dev/null @@ -1,922 +0,0 @@ -namespace IFoxCAD.Cad; - -using System; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.Text; -using static IFoxCAD.Basal.WindowsAPI; -using Point = System.Drawing.Point; -using Size = System.Drawing.Size; - -// DWORD == uint -// WORD == ushort -// LONG == int - -/* - * Console.WriteLine(Marshal.SizeOf(typeof(PlaceableMetaHeader))); - * Console.WriteLine(Marshal.SizeOf(typeof(WindowsMetaHeader))); - * Console.WriteLine(Marshal.SizeOf(typeof(StandardMetaRecord))); - */ - - -// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-metafilepict -// http://www.cppblog.com/zwp/archive/2012/02/25/60225.html -[Serializable] -[StructLayout(LayoutKind.Sequential, Pack = 2)] -public struct MetaFilePict -{ - public MappingModes mm; - public int xExt; - public int yExt; - public IntPtr hMF; //内存图元文件的句柄 -} - -public enum MappingModes : int -{ - MM_TEXT = 1, - MM_LOMETRIC = 2, - MM_HIMETRIC = 3, - MM_LOENGLISH = 4,//逻辑坐标的单位为0.01英寸 - MM_HIENGLISH = 5, - MM_TWIPS = 6, - MM_ISOTROPIC = 7, - MM_ANISOTROPIC = 8, - - //Minimum and Maximum Mapping Mode values - MM_MIN = MM_TEXT, - MM_MAX = MM_ANISOTROPIC, - MM_MAX_FIXEDSCALE = MM_TWIPS, -} - - -//WMF 文件格式: -//https://blog.51cto.com/chenyanxi/803247 -//文件缩放信息:22字节 -[Serializable] -[StructLayout(LayoutKind.Sequential, Pack = 2)] -public struct PlaceableMetaHeader -{ - public uint Key; /* 固定大小以相反顺序出现 9AC6CDD7h */ - public ushort Handle; /* Metafile HANDLE number (always 0) */ - - public short Left; /* Left coordinate in metafile units */ - public short Top; /* Top coordinate in metafile units */ - public short Right; /* Right coordinate in metafile units */ - public short Bottom; /* Bottom coordinate in metafile units */ - - public ushort Inch; /* Number of metafile units per inch */ - public uint Reserved; /* Reserved (always 0) */ - public ushort Checksum; /* Checksum value for previous 10 WORDs */ - - // 微软的wmf文件分为两种一种是标准的图元文件, - // 一种是活动式图元文件,活动式图元文件 与 标准的图元文件 的主要区别是, - // 活动式图元文件包含了图像的原始大小和缩放信息. - /// - /// 是活动式图元文件 - /// - public bool IsActivity => Key == 0x9AC6CDD7; - - /// - /// wmf转为emf
- ///
- /// 文件路径 - /// - /// 错误: ;
- /// 成功: 返回一个增强型图元 emf文件句柄 (位于内存中) - ///
- /// - public static IntPtr Wmf2Emf(string wmfFile) - { - using FileStream file = new(wmfFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // FileShare才能进c盘 - if (file.Length == 0) - throw new IOException("文件字节0长:" + file); - if (file.Length < 5) - throw new IOException("无法校验文件签名:" + file); - - var fileByte = new byte[file.Length]; - file.Read(fileByte, 0, fileByte.Length); - file.Close(); - - var sWMF = BytesToStruct(fileByte); - // 转为emf的地址 - IntPtr hEMF = IntPtr.Zero; - - // 控制输出的时候跟cad一样带有一个矩形框边界,而不是所有图元的包围盒作为边界 - var mpType = new MetaFilePict - { - mm = MappingModes.MM_ANISOTROPIC, - xExt = sWMF.Right - sWMF.Left, - yExt = sWMF.Bottom - sWMF.Top, - hMF = IntPtr.Zero - }; - - // byte[] 指针偏移 - int iOffset = 0; - if (sWMF.IsActivity) - iOffset = Marshal.SizeOf(typeof(PlaceableMetaHeader)); - - unsafe - { - // 安全指针方法 - //IntPtr fileIntPtr = Marshal.UnsafeAddrOfPinnedArrayElement(fileByte, iOffset); - // 不安全指针方法 - fixed (byte* fileIntPtr = &fileByte[iOffset]) - hEMF = EmfTool.SetWinMetaFileBits( - (uint)fileByte.Length, new IntPtr(fileIntPtr), IntPtr.Zero, new IntPtr(&mpType)); - } - return hEMF; - } -} - -public class Emf -{ - public IntPtr EmfHandle; - - /// - /// 转换wmf到emf - /// - /// - public void Wmf2Emf(string wmfFile) - { - EmfHandle = PlaceableMetaHeader.Wmf2Emf(wmfFile);//emf文件句柄 - } - - /// - /// 获取emf结构 - /// - /// - public EnhMetaHeader CreateEnhMetaHeader() - { - if (EmfHandle == IntPtr.Zero) - throw new ArgumentException(nameof(EmfHandle) + "== IntPtr.Zero"); - return EnhMetaHeader.Create(EmfHandle); - } -} - -//紧接文件缩放信息的是 WMFHEAD, 18字节 -[Serializable] -[StructLayout(LayoutKind.Sequential, Pack = 2)] -public struct WindowsMetaHeader -{ - public ushort FileType; /* Type of metafile (0=memory, 1=disk) */ - public ushort HeaderSize; /* Size of header in WORDS (always 9) */ - public ushort Version; /* Version of Microsoft Windows used */ - public uint FileSize; /* Total size of the metafile in WORDs */ - public ushort NumOfObjects; /* Number of objects in the file */ - public uint MaxRecordSize; /* The size of largest record in WORDs */ - public ushort NumOfParams;    /* Not Used (always 0) */ -} - -//紧接 WMFHEAD 的是 WMFRECORD, 14字节 -[Serializable] -[StructLayout(LayoutKind.Sequential, Pack = 2)] -public struct StandardMetaRecord -{ - public uint Size; /* Total size of the record in WORDs */ - public ushort Function; /* Function number (defined in WINDOWS.H) */ - public ushort[] Parameters;  /* Parameter values passed to function */ -} - -// 文件结构:头记录(ENHMETAHEADER),各记录(ENHMETARECORD),文件结尾(EMR_EOF) -// https://www.cnblogs.com/5iedu/p/4706327.html -[Serializable] -[StructLayout(LayoutKind.Sequential, Pack = 2)] -public struct EnhMetaHeader -{ - [Description("记录类型")] - public uint iType; - [Description("结构大小")] - public int nSize; //注意这个大小是含描述字符串的长度,即等于sizeof(ENHMETAHEADER)+nDescription*2 - [Description("外接矩形(单位是像素)")] - public IntRect rclBounds; - [Description("图片矩形(单位是 0.1 毫米)")] - public IntRect rclFrame; - [Description("文件签名")] - public uint dSignature; - [Description("文件版本")] - public uint nVersion; - [Description("文件尺寸")] - public uint nBytes; - [Description("记录数")] - public uint nRecords; - [Description("句柄数")] - public ushort nHandles; - [Description("保留")] - public ushort sReserved; - [Description("说明文本的长度")] - public uint nDescription; - [Description("说明文本的偏移量")] - public uint offDescription; - [Description("调色板的元素数")] - public uint nPalEntries; - [Description("分辨率(像素)")] - public IntSize szlDevice; - [Description("分辨率(毫米)")] - public IntSize szlMillimeters; - [Description("像素格式的尺寸")] - public uint cbPixelFormat; - [Description("像素格式的起始偏移位置")] - public uint offPixelFormat; - [Description("在不含OpenGL记录时,该值为FALSE")] - public uint bOpenGL; - [Description("参考设备的尺寸(微米)")] - public IntSize szlMicrometers; - - public override string ToString() - { - //var tp = GetType(); - //var sb = new StringBuilder(); - //sb.AppendLine(EnumEx.GetDesc(tp, nameof(iType)) + ":" + iType); - - // 输出json - // NET472 System.Text.Json - var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); - string jsonString = serializer.Serialize(this); - return jsonString; - } - - /// - /// 通过wmf创建 - /// - /// - /// - public static EnhMetaHeader Create(string wmf) - { - var emf = PlaceableMetaHeader.Wmf2Emf(wmf); - if (emf == IntPtr.Zero) - throw new ArgumentException(nameof(emf)); - return Create(emf); - } - - /// - /// 通过emf指针创建 - /// - /// 参数1的结构体首地址
- /// 也就是的返回值 - /// - /// - public static EnhMetaHeader Create(IntPtr emf) - { - var len = EmfTool.GetEnhMetaFileHeader(emf, 0, IntPtr.Zero); - if (len == 0) - throw new ArgumentException(nameof(len)); - - IntPtr header = Marshal.AllocHGlobal((int)len); - EmfTool.GetEnhMetaFileHeader(emf, len, header);//这里是切割获取内部的bytes,存放在header - - var result = (EnhMetaHeader)Marshal.PtrToStructure(header, typeof(EnhMetaHeader)); - - Marshal.FreeHGlobal(header); - return result; - } -} - - - -public static class EmfTool -{ - /// - /// 保存 - /// - /// GetEnhMetaFileBits 参数1的结构体首地址 - /// 保存路径 - /// - public static void Save(IntPtr clipTypeData, string file) - { - // 保存emf文件 - // https://blog.csdn.net/tigertianx/article/details/7098490 - var len = EmfTool.GetEnhMetaFileBits(clipTypeData, 0, null!); - if (len != 0) - { - var bytes = new byte[len]; - _ = EmfTool.GetEnhMetaFileBits(clipTypeData, len, bytes); - - using MemoryStream ms1 = new(bytes); - using var bm = Image.FromStream(ms1);//此方法emf保存成任何版本都会变成png - bm.Save(file); - } - } - - /// - /// 返回对一个增强型图元文件的说明 - /// - /// 目标增强型图元文件的句柄 - /// lpszDescription缓冲区的长度 - /// 指定一个预先初始化好的字串缓冲区,准备随同图元文件说明载入; - /// 参考 CreateEnhMetaFile 函数,了解增强型图元文件说明字串的具体格式 - /// - [DllImport("gdi32.dll")] - static extern uint GetEnhMetaFileDescription(IntPtr hemf, uint cchBuffer, [MarshalAs(UnmanagedType.LPStr)] StringBuilder lpDescription); - - /// - /// 获取emf描述 - /// - /// 文件句柄 - /// 描述的内容 - [System.Diagnostics.DebuggerStepThrough] - [System.CodeDom.Compiler.GeneratedCode("InteropSignatureToolkit", "0.9 Beta1")]//初始化时指定生成代码的工具的名称和版本 - public static string? GetEnhMetaFileDescriptionEx(IntPtr clipTypeData) - { - var len = GetEnhMetaFileDescription(clipTypeData, 0, null!); - if (len != 0) - { - StringBuilder desc = new((int)len); - GetEnhMetaFileDescription(clipTypeData, (uint)desc.Capacity, desc); - return desc.ToString(); - } - return null; - } - - public enum DeviceCap : int - { - /// - /// Device driver version - /// - DRIVERVERSION = 0, - /// - /// Device classification - /// - TECHNOLOGY = 2, - /// - /// Horizontal size in millimeters - /// - HORZSIZE = 4, - /// - /// Vertical size in millimeters - /// - VERTSIZE = 6, - /// - /// Horizontal width in pixels - /// - HORZRES = 8, - /// - /// Vertical height in pixels - /// - VERTRES = 10, - /// - /// Number of bits per pixel - /// - BITSPIXEL = 12, - /// - /// Number of planes - /// - PLANES = 14, - /// - /// Number of brushes the device has - /// - NUMBRUSHES = 16, - /// - /// Number of pens the device has - /// - NUMPENS = 18, - /// - /// Number of markers the device has - /// - NUMMARKERS = 20, - /// - /// Number of fonts the device has - /// - NUMFONTS = 22, - /// - /// Number of colors the device supports - /// - NUMCOLORS = 24, - /// - /// Size required for device descriptor - /// - PDEVICESIZE = 26, - /// - /// Curve capabilities - /// - CURVECAPS = 28, - /// - /// Line capabilities - /// - LINECAPS = 30, - /// - /// Polygonal capabilities - /// - POLYGONALCAPS = 32, - /// - /// Text capabilities - /// - TEXTCAPS = 34, - /// - /// Clipping capabilities - /// - CLIPCAPS = 36, - /// - /// Bitblt capabilities - /// - RASTERCAPS = 38, - /// - /// Length of the X leg - /// - ASPECTX = 40, - /// - /// Length of the Y leg - /// - ASPECTY = 42, - /// - /// Length of the hypotenuse - /// - ASPECTXY = 44, - /// - /// Shading and Blending caps - /// - SHADEBLENDCAPS = 45, - - /// - /// Logical pixels inch in X - /// - LOGPIXELSX = 88, - /// - /// Logical pixels inch in Y - /// - LOGPIXELSY = 90, - - /// - /// Number of entries in physical palette - /// - SIZEPALETTE = 104, - /// - /// Number of reserved entries in palette - /// - NUMRESERVED = 106, - /// - /// Actual color resolution - /// - COLORRES = 108, - - // Printing related DeviceCaps. These replace the appropriate Escapes - /// - /// Physical Width in device units - /// - PHYSICALWIDTH = 110, - /// - /// Physical Height in device units - /// - PHYSICALHEIGHT = 111, - /// - /// Physical Printable Area x margin - /// - PHYSICALOFFSETX = 112, - /// - /// Physical Printable Area y margin - /// - PHYSICALOFFSETY = 113, - /// - /// Scaling factor x - /// - SCALINGFACTORX = 114, - /// - /// Scaling factor y - /// - SCALINGFACTORY = 115, - - /// - /// Current vertical refresh rate of the display device (for displays only) in Hz - /// - VREFRESH = 116, - /// - /// Vertical height of entire desktop in pixels - /// - DESKTOPVERTRES = 117, - /// - /// Horizontal width of entire desktop in pixels - /// - DESKTOPHORZRES = 118, - /// - /// Preferred blt alignment - /// - BLTALIGNMENT = 119 - } - - [DllImport("gdi32.dll")] - static extern int GetDeviceCaps(IntPtr hDC, DeviceCap nIndex); - - [DllImport("gdi32.dll")] - static extern int SetMapMode(IntPtr hDC, MappingModes fnMapMode); - - [DllImport("gdi32.dll")] - static extern bool SetViewportOrgEx(IntPtr hDC, int x, int y, Point[] prevPoint); - - [DllImport("gdi32.dll")] - static extern bool SetWindowOrgEx(IntPtr hDC, int x, int y, Point[] prevPoint); - - [DllImport("gdi32.dll")] - static extern bool SetViewportExtEx(IntPtr hDC, int nExtentX, int nExtentY, Size[] prevSize); - - [DllImport("gdi32.dll")] - static extern bool SetWindowExtEx(IntPtr hDC, int nExtentX, int nExtentY, Size[] prevSize); - - [DllImport("Gdi32.dll")] - public static extern int CreatePen(int nPenStyle, int nWidth, int nColor); - - [DllImport("Gdi32.dll")] - public static extern int GetStockObject(int nStockBrush); - - [DllImport("Gdi32.dll")] - public static extern int SelectObject(IntPtr hDC, int hGdiObject); - - [DllImport("Gdi32.dll")] - public static extern int DeleteObject(int hBitmap); - - [DllImport("Gdi32.dll")] - public static extern int MoveToEx(IntPtr hDC, int x, int y, int nPreviousPoint); - - [DllImport("Gdi32.dll")] - public static extern int LineTo(IntPtr hDC, int x, int y); - - [DllImport("Gdi32.dll")] - public static extern int Rectangle(IntPtr hDC, int nLeft, int nTop, int nRight, int nBottom); - - [DllImport("Gdi32.dll")] - public static extern bool DPtoLP(IntPtr hdc, [In, Out] Point[] lpPoints, int nCount); - - - /// - /// 设置emf描述 - /// - /// emf文件句柄 - /// 设置描述 - /// 新的emf指针 - /// - public static void SetEnhMetaFileDescriptionEx(ref IntPtr hMetaFile, string desc) - { - //if (hMetaFile == IntPtr.Zero) - // throw new ArgumentNullException(nameof(hMetaFile)); - hMetaFile.NotNull(nameof(hMetaFile)); - var emh = EnhMetaHeader.Create(hMetaFile);//emf结构 GetEnhMetaFileHeader - // 创建画布句柄 - IntRect intRect = emh.rclFrame; //new(0, 0, 0, 0); - var hMetaDC = EmfTool.CreateEnhMetaFile(IntPtr.Zero, null!, ref intRect, desc); - if (hMetaDC == IntPtr.Zero) - return; - //SetMapMode(hMetaDC, MappingModes.MM_ANISOTROPIC); // 默认的就是这个模式 - //SetMapMode(hMetaDC, MappingModes.MM_HIMETRIC);//逻辑单位:0.01mm - - // 设置单位 - //var size = new IntSize(0, 0); - //EmfTool.SetWindowExtEx(hMetaDC, 0, 0, ref size); - //EmfTool.SetViewportExtEx(hMetaDC, 0, 0, ref size); - //EmfTool.GetEnhMetaFilePaletteEntries() 统一调色 - //SetViewportOrgEx(hMetaDC, 0, 0, null!);//将视口原点设在左下角 - - // 旧的克隆到新的 - /* - * 第18章 图元文件_18.2 增强型图元文件(emf)(2) - * https://blog.51cto.com/u_15082403/3724715 - * 方案2——利用图像的物理尺寸 - * 通过rclFrame字段(是设备单位:0.01mm)显示出来的刻度尺,这样不管在视频显示器 - * 打印机上,显示出来的刻度尺都较为真实 - */ - //目标设备信息 - int cxMms = GetDeviceCaps(hMetaDC, DeviceCap.HORZSIZE);//宽度(单位:mm) - int cyMms = GetDeviceCaps(hMetaDC, DeviceCap.VERTSIZE);//高度(单位:mm) - var cxArea = cxMms; - var cyArea = cyMms; -#if true2 - int cxPix = GetDeviceCaps(hMetaDC, DeviceCap.HORZRES);//宽度(单位:像素) - int cyPix = GetDeviceCaps(hMetaDC, DeviceCap.VERTRES);//高度(单位:像素) - int cxImage = emh.rclFrame.Right - emh.rclFrame.Left; //单位:0.01mm - int cyImage = emh.rclFrame.Bottom - emh.rclFrame.Top; - - // 设置之后图像就没有拉伸了,但是跑偏了 - //将图元文件大小(0.01mm为单位)转换为像素大小 - cxImage = cxImage * cxPix / cxMms / 100; - cyImage = cyImage * cyPix / cyMms / 100; - - //在指定的矩形区内,水平和垂直居中显示图元文件,同时保证了区域的大小为cxImage和cyImage - int left = (cxArea - cxImage) / 2; - int right = (cxArea + cxImage) / 2; - int top = (cyArea - cyImage) / 2; - int bottom = (cyArea + cyImage) / 2; -#else - cxArea = 0; - cyArea = 0; - SetMapMode(hMetaDC, MappingModes.MM_HIMETRIC);//逻辑单位:0.01mm - SetViewportOrgEx(hMetaDC, 0, cyArea, null!);//将视口原点设在左下角 - var pt = new Point(cxArea, 0); - - int cxImage = emh.rclFrame.Right - emh.rclFrame.Left; //单位:0.01mm - int cyImage = emh.rclFrame.Bottom - emh.rclFrame.Top; - - //在指定的矩形区内,水平和垂直居中显示图元文件,同时保证了区域的大小为cxImage和cyImage - int left = (pt.X - cxImage) / 2; - int right = (pt.X + cxImage) / 2; - int top = (pt.Y + cyImage) / 2; //注意,这里与前面例子不同 - int bottom = (pt.Y - cyImage) / 2; //注意,这里与前面例子不同 -#endif - var rect = new IntRect(left, top, right, bottom); - - // 图像拉伸了 - //bool pef = EmfTool.EnumEnhMetaFile(hMetaDC, hMetaFile, IntPtr.Zero, IntPtr.Zero, ref emhValue.rclFrame);// 这个失败 - bool pef = EmfTool.PlayEnhMetaFile(hMetaDC, hMetaFile, ref rect); - if (!pef) - { - DeleteObject(hMetaDC); - Debugger.Break(); - return; - } - // 删除旧的图元文件句柄,返回新的 - var del = EmfTool.DeleteEnhMetaFile(hMetaFile); - if (del) - hMetaFile = EmfTool.CloseEnhMetaFile(hMetaDC); - } - - [DllImport("gdi32.dll", EntryPoint = "GetEnhMetaFileHeader")] - public static extern uint GetEnhMetaFileHeader(IntPtr hemf, uint cbBuffer, IntPtr /*ENHMETAHEADER*/ lpemh); - - - /// - /// 将一个标准Windows图元文件转换成增强型图元文件 - /// - /// 数组的长度 - /// - /// 数组包含了标准图元文件数据.
- /// 常用 GetMetaFileBitsEx 或 GetWinMetaFileBits 函数获得 - /// - /// - /// 用于决定原始格式及图元文件分辨率的一个参考设备场景;
- /// 采用显示器分辨率为: - /// - /// - /// 定义一个图元文件附加参考信息的结构
- /// 为null时,会假定使用当前显示器的 MM_ANISOTROPIC 映射模式 - /// - /// - /// 错误: ;
- /// 成功: 返回一个增强型图元emf文件的指针(位于内存中) - ///
- [DllImport("gdi32.dll", EntryPoint = "SetWinMetaFileBits")] - public static extern IntPtr SetWinMetaFileBits(uint nSize, IntPtr lpMeta16Data, IntPtr hdcRef, IntPtr lpMFP); - /// - /// 获取矢量图的byte - /// - /// - /// - /// - /// - [DllImport("gdi32.dll")] - public static extern uint GetEnhMetaFileBits(IntPtr hemf, uint cbBuffer, byte[] lpbBuffer); - /// - /// byte转换矢量图 - /// - /// - /// - /// - [DllImport("gdi32.dll")] - public static extern IntPtr SetEnhMetaFileBits(uint cbBuffer, byte[] lpBuffer); - /// - /// 删除矢量图 - /// - /// - /// - [DllImport("gdi32.dll")] - public static extern bool DeleteEnhMetaFile(IntPtr hemf); - - /// - /// 创建emf
- /// https://www.cnblogs.com/5iedu/p/4706327.html - ///
- /// 参考设备环境,null以整个屏幕为参考 - /// 指定文件名时,创建磁盘文件(.EMF),为null时创建内存图元文件 - /// 用于描述图元文件的大小和位置(以0.01mm为单位),可用它精确定义图元文件的物理尺寸 - /// 对图元文件的一段说明.包括创建应用程序的名字、一个NULL字符、对图元文件的一段说明以及两个NULL字符. - /// 返回画布句柄DC(图元文件句柄得调用 CloseEnhMetaFile 函数) - [DllImport("gdi32.dll", SetLastError = true)] - public static extern IntPtr CreateEnhMetaFile(IntPtr hdcRef, string szFilename, ref IntRect lpRect, string lpDescription); - - [DllImport("gdi32.dll", SetLastError = true)] - public static extern bool DeleteObject(IntPtr hdcRef); - - /// - /// 在指定的设备场景中画一个增强型图元文件;
- /// 与标准图元文件不同,完成回放后,增强型图元文件会恢复设备场景以前的状态 - ///
- /// 画布句柄 - /// 欲描绘的emf的图元文件句柄 - /// 指定显示区域(逻辑单位)GDI会缩放图像以适应该矩形范围 - /// - [DllImport("gdi32.dll")] - public static extern bool PlayEnhMetaFile(IntPtr hdcRef, IntPtr hemf, ref IntRect lpRect); - - // https://blog.csdn.net/hongke457546235/article/details/17404715 - /// - /// 逻辑单位设置窗口单位 - /// {只能在 MM_ISOTROPIC 或 MM_ANISOTROPIC 模式下使用下面两个函数} - /// - /// 画布句柄 - /// 以逻辑单位表示的新窗口区域的高度 - /// 以逻辑单位表示的新窗口区域的宽度 - /// 保存函数调用前窗口区域尺寸的SIZE结构地址,NULL则表示忽略调用前的尺寸 - [DllImport("gdi32.dll")] - public static extern bool SetWindowExtEx(IntPtr hdcRef, int nHeight, int nWidth, ref IntSize lpSize); - - /// - /// 视口区域的定义 - /// {只能在 MM_ISOTROPIC 或 MM_ANISOTROPIC 模式下使用下面两个函数} - /// - /// - /// - /// - /// - [DllImport("gdi32.dll")] - public static extern bool SetViewportExtEx(IntPtr hdcRef, int nHeight, int nWidth, ref IntSize lpSize); - - /// - /// 旧emf绘制新的hdcEMF中(即回放) - /// - /// 画布句柄 - /// 图元文件句柄 - /// 回调函数 - /// 传给回调函数的额外参数 - /// 在指定的矩形区内显示图元文件 - /// - [DllImport("gdi32.dll", SetLastError = true)] - public static extern bool EnumEnhMetaFile(IntPtr hdcRef, IntPtr hmf, IntPtr proc, IntPtr procParam, ref IntRect lpRect); - - /// - /// 返回图元文件句柄 - /// - /// 画布句柄 - [DllImport("gdi32.dll", SetLastError = true)] - public static extern IntPtr CloseEnhMetaFile(IntPtr hdcRef); - - // https://zhidao.baidu.com/question/646739770512964165/answer/1616737219.html?qq-pf-to=pcqq.c2c - //16位的函数 - [DllImport("gdi32.dll")] - public static extern IntPtr GetMetaFile(string path); - //32位的函数 - [DllImport("gdi32.dll")] - public static extern IntPtr GetEnhMetaFile(string path); - - - - /// - /// EMF保存到文件或者路径 - /// - /// EMF要复制的增强型图元文件的句柄 - /// 指向目标文件名称的指针,为NULL则将源图元文件复制到内存中 - /// - [DllImport("gdi32.dll")] - public static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, string? lpszFile); - - /// - /// 矢量图保存 - /// - /// - /// - public static void SaveMetaFile(this Metafile file, string emfName) - { - //MetafileHeader metafileHeader = file.GetMetafileHeader(); //这句话可要可不要 - IntPtr h = file.GetHenhmetafile(); - CopyEnhMetaFile(h, emfName); - DeleteEnhMetaFile(h); - } - - /// - /// 矢量图 转换 byte[] - /// - /// - /// - public static byte[]? ToByteArray(this Image image) - { - return ToByteArray((Metafile)image); - } - - // https://www.pinvoke.net/default.aspx/gdi32.getenhmetafile - /// - /// 矢量图 转换 byte[] - /// - /// - /// - public static byte[]? ToByteArray(this Metafile mf) - { - byte[]? arr = null; - IntPtr handle = mf.GetHenhmetafile(); - if (handle != IntPtr.Zero) - { - var size = GetEnhMetaFileBits(handle, 0, null!); - if (size != 0) - { - arr = new byte[size]; - _ = GetEnhMetaFileBits(handle, size, arr); - } - DeleteEnhMetaFile(handle); - } - return arr; - } - - /// - /// byte[] 转换 矢量图 - /// - /// - /// 返回值true删除句柄 - /// - public static void ToMetafile(byte[] data, Func task) - { - //if (task == null) - // throw new ArgumentNullException(nameof(task)); - task.NotNull(nameof(task)); - IntPtr hemf = SetEnhMetaFileBits((uint)data.Length, data); - using var mf = new Metafile(hemf, true); - if (task.Invoke(mf)) // 对图像进行操作,就不能进行删除句柄 - DeleteEnhMetaFile(hemf); - } - - -#if false - /// - /// c#获取wmf方式 - /// - /// - /// - public static IntPtr GetMetafile(string wmfFile) - { - using FileStream file = new(wmfFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); // FileShare才能进c盘 - var hEMF2 = IntPtr.Zero; - - using Metafile mf = new(file); - var hEMF = mf.GetHenhmetafile(); - if (hEMF != IntPtr.Zero) - hEMF2 = CopyEnhMetaFile(hEMF, null);// 这句: 句柄无效..cad的wmf文件不识别 - //EmfTool.DeleteEnhMetaFile(hEMF);//托管类应该是封装好的 - return hEMF2; - } - - - /* - * // 这是c#写入wmf流程 - * // c#画的wmf格式是可以的...用这样方式生成的就是可以写剪贴板 - * WindowsAPI.GetClientRect(doc.Window.Handle, out IntRect rcClient); - * int width = rcClient.Right - rcClient.Left; - * int height = rcClient.Bottom - rcClient.Top; - * EmfTool.Export(wmf, width, height);//cad的命令wmfin:不能导入c#自绘的 - * - * //c#方法,但是它读取不了cad的wmf - * wmfMeta = EmfTool.GetMetafile(wmf); - */ - - /// - /// 导出为 Emf 或 Wmf 文件 - /// 相关链接 - /// - /// 文件路径 - /// 窗口宽度 - /// 窗口高度 - /// 是否成功 - public static bool Export(string filePath, int width, int height) - { - try - { - using Bitmap bmp = new(width, height); - using Graphics gs = Graphics.FromImage(bmp); - using Metafile mf = new(filePath, gs.GetHdc()); - using Graphics g = Graphics.FromImage(mf); - Draw(g); - g.Save(); - return true; - } - catch { return false; } - } - - - /// - /// 绘制图形 - /// - /// 用于绘图的Graphics对象 - static void Draw(Graphics g) - { - HatchBrush hb = new(HatchStyle.LightUpwardDiagonal, Color.Black, Color.White); - - g.FillEllipse(Brushes.Gray, 10f, 10f, 200, 200); - g.DrawEllipse(new Pen(Color.Black, 1f), 10f, 10f, 200, 200); - - g.FillEllipse(hb, 30f, 95f, 30, 30); - g.DrawEllipse(new Pen(Color.Black, 1f), 30f, 95f, 30, 30); - - g.FillEllipse(hb, 160f, 95f, 30, 30); - g.DrawEllipse(new Pen(Color.Black, 1f), 160f, 95f, 30, 30); - - g.FillEllipse(hb, 95f, 30f, 30, 30); - g.DrawEllipse(new Pen(Color.Black, 1f), 95f, 30f, 30, 30); - - g.FillEllipse(hb, 95f, 160f, 30, 30); - g.DrawEllipse(new Pen(Color.Black, 1f), 95f, 160f, 30, 30); - - g.FillEllipse(Brushes.Blue, 60f, 60f, 100, 100); - g.DrawEllipse(new Pen(Color.Black, 1f), 60f, 60f, 100, 100); - - g.FillEllipse(Brushes.BlanchedAlmond, 95f, 95f, 30, 30); - g.DrawEllipse(new Pen(Color.Black, 1f), 95f, 95f, 30, 30); - - g.DrawRectangle(new Pen(Brushes.Blue, 0.1f), 6, 6, 208, 208); - - g.DrawLine(new Pen(Color.Black, 0.1f), 110f, 110f, 220f, 25f); - g.DrawString("剖面图", new Font("宋体", 9f), Brushes.Green, 220f, 20f); - } -#endif -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Copyclip/TagClipboardInfo.cs b/src/CAD/IFox.CAD.Shared/Copyclip/TagClipboardInfo.cs deleted file mode 100644 index ed9195be796f8f13f80d39908a0994002a00d658..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Copyclip/TagClipboardInfo.cs +++ /dev/null @@ -1,659 +0,0 @@ -namespace IFoxCAD.Cad; - -using System; -using System.Diagnostics; -using System.Text; -using static IFoxCAD.Basal.WindowsAPI; - -public class ClipboardEnv -{ - // 0x01 将r17写死,代表每个cad版本都去找它,实现不隔离cad版本 - public static string CadVer = "AutoCAD.r17"; - // 0x02 当前版本在r17找不到的时候找,避免按需加载插件的时候无法获取剪贴板 - public static string CadCurrentVer = $"AutoCAD.r{Acap.Version.Major}"; -} - -/// -/// ARX剪贴板结构 -/// -[Serializable] -[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode/*此参数将导致260*2*/)] -public struct TagClipboardInfo : IEquatable -{ - #region 字段,对应arx结构的,不要改动,本结构也不允许再加字段 - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string szTempFile; // 临时文件夹的dwg文件 - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string szSourceFile; // 文件名从中做出选择..是不是指定块表记录? - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] - public string szSignature; - public int nFlags; // kbDragGeometry: 从AutoCAD拖动几何图形 - public Point3D dptInsert; // 插入点的原始世界坐标' - public IntRect rectGDI; // GDI coord 选择集的边界矩形 - public IntPtr mpView; // 用于验证这个对象是在这个视图中创建的 (HWND*) - public int dwThreadId; // AutoCAD thread 创建数据对象 - public int nLen; // 下一段的长度的数据,如果有的话,从chData - public int nType; // 类型的数据,如果有(eExpandedClipDataTypes) - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)] - public string chData; // 数据的开始,如果有 - #endregion - - #region 属性,可以改动 - public string File => szTempFile; - public Point3d Point => new Point3d(dptInsert.X, dptInsert.Y, dptInsert.Z); - -#pragma warning disable CA2211 // 非常量字段应当不可见 - public static IntPtr AcadDwgview - = IntPtr.Zero; - //= AcedGetAcadDwgview(); // c#需要收集这个函数,我先不写,免得中间版本挂了 - - public static int MainWindowThreadId = - (int)WindowsAPI.GetWindowThreadProcessId(Acap.MainWindow.Handle, out uint processId); -#pragma warning restore CA2211 // 非常量字段应当不可见 - #endregion - - #region 构造 - /// - /// cad剪贴板 - /// - /// 临时dwg的保存路径 - /// 粘贴点 - public TagClipboardInfo(string tmpFile, Point3d insert) - { - szTempFile = tmpFile; - szSourceFile = string.Empty; - szSignature = "R15"; //恒定是这个 - nFlags = 0; - dptInsert = new Point3D(insert.X, insert.Y, insert.Z); - rectGDI = IntRect.Zero; - nLen = 0; - nType = 0; - chData = string.Empty; - - // mpView threadid 可能是用来删除的,用于剪贴板回调清理资源时候判断信息 - mpView = AcadDwgview; - dwThreadId = MainWindowThreadId; - } - #endregion - - #region 方法 - public override string ToString() - { - var sb = new StringBuilder(); - sb.AppendLine($"szTempFile:{szTempFile}"); - sb.AppendLine($"szSourceFile:{szSourceFile}"); - sb.AppendLine($"szSignature:{szSignature}"); - sb.AppendLine($"nFlags:{nFlags}"); - sb.AppendLine($"dptInsert:{dptInsert}"); - sb.AppendLine($"rectGDI:{rectGDI}"); - sb.AppendLine($"mpView:{mpView}"); - sb.AppendLine($"dwThreadId:{dwThreadId}"); - sb.AppendLine($"nLen:{nLen}"); - sb.AppendLine($"nType:{nType}"); - sb.AppendLine($"chData:{chData}"); - return sb.ToString(); - } - #endregion - - #region 测试大小 - void GetSize() - { - var v_1 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.szTempFile)).ToInt32(); - var v_2 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.szSourceFile)).ToInt32(); - var v_3 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.szSignature)).ToInt32(); - var v_4 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.nFlags)).ToInt32(); - var v_5 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.dptInsert)).ToInt32(); - var v_6 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.rectGDI)).ToInt32(); - var v_7 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.mpView)).ToInt32(); - var v_8 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.dwThreadId)).ToInt32(); - var v_9 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.nLen)).ToInt32(); - var v_10 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.nType)).ToInt32(); - var v_11 = Marshal.OffsetOf(typeof(TagClipboardInfo), nameof(TagClipboardInfo.chData)).ToInt32(); - var v_12 = Marshal.SizeOf(typeof(TagClipboardInfo)); //1120 - - var v_a = Marshal.SizeOf(typeof(Point3D));//24 - var v_b = Marshal.SizeOf(typeof(IntRect));//16 - } - #endregion - - #region 视口指针 - /* - [CommandMethod(nameof(Test_AcedGetAcadDwgview))] - public void testAcedGetAcadDwgview() - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var ed = doc.Editor; - - var a = AcedGetAcadDwgview().ToString(); //自动执行的时候就存在了 - var b = ed.CurrentViewportObjectId.ToString(); - Debugx.Printl("a == b:" + a == b);//不对 - - var tab = ed.GetCurrentView(); - var c = tab.ObjectId.ToString(); - Debugx.Printl("a == c:" + a == c);//不对 - } - */ - - /// - /// 获取视口指针 - /// -#if NET35 - [DllImport("acad.exe", EntryPoint = "?acedGetAcadDwgView@@YAPAVCView@@XZ")] //acad08 -#else - [DllImport("acad.exe", EntryPoint = "?acedGetAcadDwgView@@YAPEAVCView@@XZ")]//acad21 -#endif - static extern IntPtr AcedGetAcadDwgview(); - #endregion - - #region 重载运算符_比较 - public bool Equals(TagClipboardInfo other) - { - return - szTempFile == other.szTempFile && - szSourceFile == other.szSourceFile && - szSignature == other.szSignature && - nFlags == other.nFlags && - dptInsert == other.dptInsert && - rectGDI == other.rectGDI && - mpView == other.mpView && - dwThreadId == other.dwThreadId && - nLen == other.nLen && - nType == other.nType && - chData == other.chData; - } - public static bool operator !=(TagClipboardInfo a, TagClipboardInfo b) - { - return !(a == b); - } - public static bool operator ==(TagClipboardInfo a, TagClipboardInfo b) - { - return a.Equals(b); - } - public override bool Equals(object obj) - { - return obj is TagClipboardInfo info && Equals(info); - } - public override int GetHashCode() - { - return - szTempFile.GetHashCode() ^ - szSourceFile.GetHashCode() ^ - szSignature.GetHashCode() ^ - nFlags ^ - dptInsert.GetHashCode() ^ - rectGDI.GetHashCode() ^ - mpView.GetHashCode() ^ - dwThreadId ^ - nLen ^ - nType ^ - chData.GetHashCode(); - } - - public IntPtr CloneToPtr() - { - var lParam = Marshal.AllocHGlobal(Marshal.SizeOf(this)); - if (lParam != IntPtr.Zero) - Marshal.StructureToPtr(this, lParam, true); - return lParam; - } - #endregion -} - - -/* - * OLE 剪贴板说明 https://blog.csdn.net/chinabinlang/article/details/9815495 - * 写入时候注意: - * 0x01 c#自带的是com剪贴板 - * 最好不要使用,它不能在已经打开的剪贴板中使用, - * 也无法写入多个cf对象,也就是复制bitmap的时候会覆盖cad图元 - * Clipboard.SetImage(bitmap); - * 0x02 - * 剪贴板写入各种类型 https://blog.csdn.net/glt3953/article/details/8808262 - * - */ - -public partial class ClipTool -{ - /// - /// 侦听剪贴板 - /// - /// - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern bool AddClipboardFormatListener(IntPtr hWnd); - /// - /// 移除侦听剪贴板 - /// - /// - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern bool RemoveClipboardFormatListener(IntPtr hWnd); - /// - /// 将CWnd加入一个窗口链 - /// 每当剪贴板的内容发生变化时,就会通知这些窗口 - /// - /// 句柄 - /// 返回剪贴板观察器链中下一个窗口的句柄 - [DllImport("User32.dll")] - public static extern int SetClipboardViewer(IntPtr hWndNewViewer); - /// - /// 从剪贴板链中移出的窗口句柄 - /// - /// 从剪贴板链中移出的窗口句柄 - /// hWndRemove的下一个在剪贴板链中的窗口句柄 - /// 如果成功,非零;否则为0。 - [DllImport("User32.dll", CharSet = CharSet.Auto)] - public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext); - - - /// - /// 开启剪贴板
- /// 如果另一个窗口已经打开剪贴板,函数会失败.每次成功调用后都应有调用. - ///
- /// - /// - [DllImport("user32.dll", SetLastError = true)] - static extern bool OpenClipboard(IntPtr hWndNewOwner); - /// - /// 关闭剪贴板 - /// - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern bool CloseClipboard(); - /// - /// 根据数据格式获取剪贴板 - /// - /// 数据格式名称 - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern uint RegisterClipboardFormat(string lpszFormat); - /// - /// 获取剪贴板 - /// - /// 通常为但是cad有自己的位码 - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr GetClipboardData(uint uFormat); - /// - /// 设置剪贴板 - /// - /// 通常为但是cad有自己的位码 - /// 指定具有指定格式的数据的句柄,
- /// 该参数为空则为延迟提交:
- /// 有其他程序对剪切板中的数据进行请求时,该程序才会将指定格式的数据写入到剪切板中. - /// - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem); - /// - /// 清空剪切板并释放剪切板内数据的句柄 - /// - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern bool EmptyClipboard(); - /// - /// 枚举剪贴板内数据类型 - /// - /// - /// - [DllImport("user32.dll", SetLastError = true)] - public static extern uint EnumClipboardFormats(uint format); - - - /// - /// 打开剪贴板
- /// 写入之前必须清空,
- /// 否则将导致发送 WM_DESTROYCLIPBOARD 消息到上一次剪贴板拥有者释放资源
- /// 所以写入的时候必须一次性写入多个cf
- ///
- /// 接收返回的栈空间指针用于释放 - /// true写入,false读取 - /// - /// - [System.Diagnostics.DebuggerStepThrough] - public static bool OpenClipboardTask(bool isWrite, Action action) - { - //if (action == null) - // throw new ArgumentNullException(nameof(action)); - action.NotNull(nameof(action)); - bool openFlag = false; - try - { - openFlag = OpenClipboard(IntPtr.Zero); - if (!openFlag) - return false; - if (isWrite) - EmptyClipboard(); - action.Invoke(); - } - catch (Exception e) - { - Debugger.Break(); - Debugx.Printl(e.Message); - } - finally - { - if (openFlag) - CloseClipboard(); - } - return openFlag; - } - - /// - /// 获取剪贴板 - /// - /// 剪贴板的索引名 - /// 返回的结构 - public static bool GetClipboard(string clipKey, out T? tag) - { - bool locked = false; - T? result = default; - - ClipTool.OpenClipboardTask(false, () => { - // 读取剪贴板的指定数据 - var clipKeyFormat = RegisterClipboardFormat(clipKey);//ClipboardEnv.CadVer - var clipTypeData = GetClipboardData(clipKeyFormat); - - // 剪贴板的数据拷贝进去结构体中,会依照数据长度进行拷贝 - locked = WindowsAPI.GlobalLockTask(clipTypeData, ptr => { - // 非托管内存块->托管对象 - result = (T)Marshal.PtrToStructure(ptr, typeof(T)); - }); - }); - - tag = result; - return locked; - } -} - -#if true2 -// 无法备份emf内容 -// https://blog.csdn.net/vencon_s/article/details/46345083 -public static class ClipEx -{ - /// - /// 剪贴板数据保存目标数据列表 - /// - static readonly List _bytes = new(); - /// - /// 剪贴板数据类型列表 - /// - static readonly List _formats = new(); - - /// - /// 遍历剪贴板保存内容 - /// - /// true成功,false失败 - public static bool SaveClip() - { - bool result = ClipTool.OpenClipboardTask(false, free => { - _bytes.Clear(); - _formats.Clear(); - - uint cf = 0; - while (true) - { - cf = ClipTool.EnumClipboardFormats(cf);// 枚举剪贴板所有数据类型 - if (cf == 0) - break; - - _formats.Add(cf); - IntPtr clipTypeData = ClipTool.GetClipboardData(cf); - var locked = WindowsAPI.GlobalLockTask(clipTypeData, prt => { - uint size = WindowsAPI.GlobalSize(clipTypeData); - if (size > 0) - { - var buffer = new byte[size]; - Marshal.Copy(prt, buffer, 0, buffer.Length);// 将剪贴板数据保存到自定义字节数组 - _bytes.Add(buffer); - } - }); - } - }); - if (result) - result = _formats.Count > 0; - return result; - } - - /// - /// 恢复保存的数据 - /// - /// true成功,false失败 - public static bool RestoreClip() - { - if (_formats.Count <= 0) - return false; - - bool result = ClipTool.OpenClipboardTask(true, free => { - for (int i = 0; i < _formats.Count; i++) - { - int size = _bytes[i].Length; - IntPtr structPtr = Marshal.AllocHGlobal(size); - if (size > 0) - { - Marshal.Copy(_bytes[i], 0, structPtr, size); - ClipTool.SetClipboardData(_formats[i], structPtr); - } - } - }); - - if (result) - result = _formats.Count > 0; - return result; - } -} -#endif - - - -/// -/// 剪贴板的CF,也就是它的key -/// -public enum ClipboardFormat : uint -{ - /// - /// Text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals - /// the end of the data. Use this format for ANSI text. - /// - CF_TEXT = 1, - - /// - /// A handle to a bitmap (HBITMAP). - /// - CF_BITMAP = 2, - - /// - /// Handle to a metafile picture format as defined by the METAFILEPICT structure. When passing a - /// CF_METAFILEPICT handle by means of DDE, the application responsible for deleting hMem should - /// also free the metafile referred to by the CF_METAFILEPICT handle. - /// - CF_METAFILEPICT = 3, - - /// - /// Microsoft Symbolic Link (SYLK) format. - /// - CF_SYLK = 4, - - /// - /// Software Arts' Data Interchange Format. - /// - CF_DIF = 5, - - /// - /// Tagged-image file format. - /// - CF_TIFF = 6, - - /// - /// Text format containing characters in the OEM character set. Each line ends with a carriage return/linefeed - /// (CR-LF) combination. A null character signals the end of the data. - /// - CF_OEMTEXT = 7, - - /// - /// A memory object containing a BITMAPINFO structure followed by the bitmap bits. - /// - CF_DIB = 8, - - /// - /// Handle to a color palette. Whenever an application places data in the clipboard that depends on or assumes - /// a color palette, it should place the palette on the clipboard as well. If the clipboard contains data in - /// the (logical color palette) format, the application should use the - /// SelectPalette and RealizePalette functions to realize (compare) any other data in the - /// clipboard against that logical palette. When displaying clipboard data, the clipboard always uses as its - /// current palette any object on the clipboard that is in the CF_PALETTE format. - /// - CF_PALETTE = 9, - - /// - /// Data for the pen extensions to the Microsoft Windows for Pen Computing. - /// - CF_PENDATA = 10, - - /// - /// Represents audio data more complex than can be represented in a CF_WAVE standard wave format. - /// - CF_RIFF = 11, - - /// - /// Represents audio data in one of the standard wave formats, such as 11 kHz or 22 kHz PCM. - /// - CF_WAVE = 12, - - /// - /// Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character - /// signals the end of the data. - /// - CF_UNICODETEXT = 13, - - /// - /// A handle to an enhanced metafile (HENHMETAFILE). - /// - CF_ENHMETAFILE = 14, - - /// - /// A handle to type HDROP that identifies a list of files. An application can retrieve information - /// about the files by passing the handle to the DragQueryFile function. - /// - CF_HDROP = 15, - - /// - /// The data is a handle to the locale identifier associated with text in the clipboard. When you close the - /// clipboard, if it contains CF_TEXT data but no CF_LOCALE data, the system automatically sets - /// the CF_LOCALE format to the current input language. You can use the CF_LOCALE format to - /// associate a different locale with the clipboard text. - /// An application that pastes text from the clipboard can retrieve this format to determine which character - /// set was used to generate the text. - /// Note that the clipboard does not support plain text in multiple character sets. To achieve this, use a - /// formatted text data type such as RTF instead. - /// The system uses the code page associated with CF_LOCALE to implicitly convert from - /// to . Therefore, the correct code page table is used for - /// the conversion. - /// - CF_LOCALE = 16, - - /// - /// A memory object containing a BITMAPV5HEADER structure followed by the bitmap color space - /// information and the bitmap bits. - /// - CF_DIBV5 = 17, - - /// - /// Owner-display format. The clipboard owner must display and update the clipboard viewer window, and receive - /// the , , - /// , , and - /// messages. The hMem parameter must be null. - /// - CF_OWNERDISPLAY = 0x0080, - - /// - /// Text display format associated with a private format. The hMem parameter must be a handle to data - /// that can be displayed in text format in lieu of the privately formatted data. - /// - CF_DSPTEXT = 0x0081, - - /// - /// Bitmap display format associated with a private format. The hMem parameter must be a handle to - /// data that can be displayed in bitmap format in lieu of the privately formatted data. - /// - CF_DSPBITMAP = 0x0082, - - /// - /// Metafile-picture display format associated with a private format. The hMem parameter must be a - /// handle to data that can be displayed in metafile-picture format in lieu of the privately formatted data. - /// - CF_DSPMETAFILEPICT = 0x0083, - - /// - /// Enhanced metafile display format associated with a private format. The hMem parameter must be a - /// handle to data that can be displayed in enhanced metafile format in lieu of the privately formatted data. - /// - CF_DSPENHMETAFILE = 0x008E, - - /// - /// Start of a range of integer values for application-defined GDI object clipboard formats. The end of the - /// range is . Handles associated with clipboard formats in this range are not - /// automatically deleted using the GlobalFree function when the clipboard is emptied. Also, when using - /// values in this range, the hMem parameter is not a handle to a GDI object, but is a handle allocated - /// by the GlobalAlloc function with the GMEM_MOVEABLE flag. - /// - CF_GDIOBJFIRST = 0x0300, - - /// - /// See . - /// - CF_GDIOBJLAST = 0x03FF, - - /// - /// Start of a range of integer values for private clipboard formats. The range ends with - /// . Handles associated with private clipboard formats are not freed - /// automatically, the clipboard owner must free such handles, typically in response to the - /// message. - /// - CF_PRIVATEFIRST = 0x0200, - - /// - /// See . - /// - CF_PRIVATELAST = 0x02FF, -} - -#if true2 -// arx剪贴板头文件的枚举 -enum eClipInfoFlags -{ - kbDragGeometry = 0x01, -}; - -enum eXrefType -{ - kXrefTypeAttach = 1, - kXrefTypeOverlay = 2 -}; - -enum eExpandedClipDataTypes -{ - kDcPlotStyles = 1, - kDcXrefs = 2, - kDcLayouts = 3, - kDcBlocks = 4, - kDcLayers = 5, - kDcDrawings = 6, - kDcLinetypes = 7, - kDcTextStyles = 8, - kDcDimStyles = 9, - kDcBlocksWithAttdef = 10, - //#ifdef ADCHATCH - kDcHatches = 11, - //#endif - kTpXrefs = 12, - kTpImages = 13, - kTpTable = 14, - kDcTableStyles = 15, - kDcMultileaderStyles = 16, - kDcVisualStyles = 17, - kDcSectionViewStyles = 18, - kDcDetailViewStyles = 19, -}; -#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/BlockReferenceEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/BlockReferenceEx.cs deleted file mode 100644 index 203bc5451479e22d9118f6dcedd1941ffd86cb22..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/BlockReferenceEx.cs +++ /dev/null @@ -1,143 +0,0 @@ - - -namespace IFoxCAD.Cad; - -/// -/// 块参照扩展类 -/// -public static class BlockReferenceEx -{ - #region 裁剪块参照 - - private const string filterDictName = "ACAD_FILTER"; - private const string spatialName = "SPATIAL"; - - /// - /// 裁剪块参照 - /// - /// 块参照 - /// 裁剪多边形点表 - public static void ClipBlockRef(this BlockReference bref, IEnumerable pt3ds) - { - Matrix3d mat = bref.BlockTransform.Inverse(); - var pts = - pt3ds - .Select(p => p.TransformBy(mat).Point2d()) - .ToCollection(); - - SpatialFilterDefinition sfd = new(pts, Vector3d.ZAxis, 0.0, 0.0, 0.0, true); - using SpatialFilter sf = new() { Definition = sfd }; - var dict = bref.GetXDictionary()!.GetSubDictionary(true, new string[] { filterDictName })!; - dict.SetAt(spatialName, sf); - // SetToDictionary(dict, spatialName, sf); - } - - /// - /// 裁剪块参照 - /// - /// 块参照 - /// 第一角点 - /// 第二角点 - public static void ClipBlockRef(this BlockReference bref, Point3d pt1, Point3d pt2) - { - Matrix3d mat = bref.BlockTransform.Inverse(); - pt1 = pt1.TransformBy(mat); - pt2 = pt2.TransformBy(mat); - - Point2dCollection pts = new() - { - new Point2d(Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y)), - new Point2d(Math.Max(pt1.X, pt2.X), Math.Max(pt1.Y, pt2.Y)) - }; - - using SpatialFilter sf = new() - { - Definition = new(pts, Vector3d.ZAxis, 0.0, 0.0, 0.0, true) - }; - var dict = bref.GetXDictionary()! - .GetSubDictionary(true, new string[] { filterDictName })!; - dict.SetAt(spatialName, sf); - // SetToDictionary(dict, spatialName, sf); -#if !acad - pts.Dispose(); -#endif - } - #endregion - - #region 属性 - /// - /// 更新动态块属性值 - /// - /// 动态块 - /// 属性值字典 - public static void ChangeBlockProperty(this BlockReference blockReference, - Dictionary propertyNameValues) - { - if (!blockReference.IsDynamicBlock) - return; - - using (blockReference.ForWrite()) - { - foreach (DynamicBlockReferenceProperty item in blockReference.DynamicBlockReferencePropertyCollection) - if (propertyNameValues.ContainsKey(item.PropertyName)) - item.Value = propertyNameValues[item.PropertyName]; - } - } - #endregion - - /// - /// 遍历块内 - /// - /// - /// - /// - /// - [System.Diagnostics.DebuggerStepThrough] - public static void ForEach(this BlockReference brf, Action action, DBTrans? tr = null) - { - //if (action == null) - // throw new ArgumentNullException(nameof(action)); - action.NotNull(nameof(action)); - tr ??= DBTrans.Top; - var btr = tr.GetObject(brf.BlockTableRecord); - if (btr == null) - return; - btr.ForEach(action); - } - /// - /// 遍历块内 - /// - /// - /// - /// - /// - [System.Diagnostics.DebuggerStepThrough] - public static void ForEach(this BlockReference brf, Action action, DBTrans? tr = null) - { - //if (action == null) - // throw new ArgumentNullException(nameof(action)); - action.NotNull(nameof(action)); - tr ??= DBTrans.Top; - var btr = tr.GetObject(brf.BlockTableRecord); - if (btr == null) - return; - btr.ForEach(action); - } - /// - /// 遍历块内 - /// - /// - /// - /// - /// - [System.Diagnostics.DebuggerStepThrough] - public static void ForEach(this BlockReference brf, Action action, DBTrans? tr = null) - { - action.NotNull(nameof(action)); - tr ??= DBTrans.Top; - var btr = tr.GetObject(brf.BlockTableRecord); - if (btr == null) - return; - btr.ForEach(action); - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/DBTextEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/DBTextEx.cs deleted file mode 100644 index 5e01e58596bc75241b3598fe33f56812a3cdb3da..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/DBTextEx.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 单行文字扩展类 -/// -public static class DBTextEx -{ - - /// - /// 更正单行文字的镜像属性 - /// - /// 单行文字 - public static void ValidateMirror(this DBText txt) - { - if (!txt.Database.Mirrtext) - { - txt.IsMirroredInX = false; - txt.IsMirroredInY = false; - } - } - -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/EntityBoundingInfo.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/EntityBoundingInfo.cs deleted file mode 100644 index baf2fc41a80ff0374da398c5843ae93f2880ca79..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/EntityBoundingInfo.cs +++ /dev/null @@ -1,281 +0,0 @@ -#define Debug_Cause_Error -namespace IFoxCAD.Cad; - -/// -/// AABB和OBB信息 -/// -public struct BoundingInfo -{ - public double MinX; - public double MinY; - public double MinZ; - - public double MaxX; - public double MaxY; - public double MaxZ; - - /// - /// AABB这里永远是0 - /// - public double Angle; - public bool IsEffective; - - public Point3d Min => new(MinX, MinY, MinZ); - public Point3d Max => new(MaxX, MaxY, MaxZ); - public Extents3d Extents3d => new(Min, Max); - public Extents2d Extents2d => new(MinX, MinY, MaxX, MaxY); - - public BoundingInfo(double minX, double minY, double minZ, - double maxX, double maxY, double maxZ, - bool isEffective, double angle = 0) - { - MinX = minX; - MinY = minY; - MinZ = minZ; - MaxX = maxX; - MaxY = maxY; - MaxZ = maxZ; - IsEffective = isEffective; - Angle = angle; - } - - public BoundingInfo(Point3d min, Point3d max, bool isEffective, double angle = 0) - : this(min.X, min.Y, min.Z, - max.X, max.Y, max.Z, - isEffective, angle) - { } - - // public BoundingInfo(Rect rect, double angle = 0) - // { - // MinX = rect.X; - // MinY = rect.Y; - // MinZ = 0; - // MaxX = rect.Right; - // MaxY = rect.Top; - // MaxZ = 0; - // Angle = angle; - // } - - public override string ToString() - { - return Extents3d.ToString(); - } - - public void Move(Point3d pt1, Point3d pt2) - { - var ve = pt1 - pt2; - MinX -= ve.X; - MinY -= ve.Y; - MinZ -= ve.Z; - MaxX -= ve.X; - MaxY -= ve.Y; - MaxZ -= ve.Z; - } -} - -public class EntityBoundingInfo -{ - #region 保存异常类型的日志 - /// - /// 包围盒错误文件路径 - /// - public static string BoxLogAddress - { - get - { - _BoxLogAddress ??= LogHelper.GetDefaultOption(nameof(GetBoundingInfo) + ".config"); - return _BoxLogAddress; - } - set { _BoxLogAddress = value; } - } - static string? _BoxLogAddress; - static readonly HashSet _typeNames; - /// - /// 为了保证更好的性能, - /// 只是在第一次调用此功能的时候进行读取, - /// 免得高频调用时候高频触发磁盘 - /// - static EntityBoundingInfo() - { - _typeNames = new(); - if (!File.Exists(BoxLogAddress)) - return; - ExceptionToHashSet(); - } - - /// - /// 读取日志的异常到容器 - /// - static void ExceptionToHashSet() - { - var old_LogAddress = LogHelper.LogAddress; - try - { - LogHelper.OptionFile(BoxLogAddress); - var logTxts = new FileLogger().ReadLog(); - for (int i = 0; i < logTxts.Length; i++) - { - var line = logTxts[i]; - if (line.Contains(nameof(LogTxt.备注信息))) - { - int index = line.IndexOf(":"); - index = line.IndexOf("\"", index) + 1;// 1是"\"" - int index2 = line.IndexOf("\"", index); - var msg = line.Substring(index, index2 - index); - _typeNames.Add(msg); - } - } - } - finally - { - LogHelper.LogAddress = old_LogAddress; - } - } - - /// - /// 写入容器类型到异常日志 - /// - /// - /// - static void ExceptionToLog(Exception e, Entity ent) - { - // 无法处理的错误类型将被记录 - // 如果错误无法try,而是cad直接致命错误,那么此处也不会被写入, - // 这种情况无法避免程序安全性,总不能写了日志再去删除日志词条,这样会造成频繁IO的 - // 遇到一个不认识的类型再去写入?然后记录它是否可以写入? - var old_LogAddress = LogHelper.LogAddress; - var old_FlagOutFile = LogHelper.FlagOutFile; - try - { - LogHelper.FlagOutFile = true; - LogHelper.OptionFile(BoxLogAddress); - e.WriteLog(ent.GetType().Name, LogTarget.FileNotException); - } - finally - { - LogHelper.LogAddress = old_LogAddress; - LogHelper.FlagOutFile = old_FlagOutFile; - } - } - #endregion - - /// - /// 获取图元包围盒 - /// - /// - /// (左下角,右上角,是否有效) - /// 异常: - /// 会将包围盒类型记录到所属路径中,以此查询 - public static BoundingInfo GetBoundingInfo(Entity ent) - { -#if Debug_Cause_Error - // 错误类型处理 - if (ent is AttributeDefinition) // 属性定义 - return new(Point3d.Origin, Point3d.Origin, false); - if (ent is Xline xline)// 参照线 - return new(xline.BasePoint, xline.BasePoint, true); - if (ent is Ray ray)// 射线 - return new(ray.BasePoint, ray.BasePoint, true); -#endif - // 指定类型处理 - if (ent is BlockReference brf) - return GetBoxInfoInBlockReference(brf); - if (ent is MText mText) - return GetBoxInfoInMText(mText); - - if (!_typeNames.Contains(ent.GetType().Name)) // 屏蔽天正等等缺失包围盒的类型 - try - { - return new(ent.GeometricExtents.MinPoint, ent.GeometricExtents.MaxPoint, true); - } - catch (Exception e) { ExceptionToLog(e, ent); } - return new(Point3d.Origin, Point3d.Origin, false); - } - - /// - /// 处理块参照 - /// - static BoundingInfo GetBoxInfoInBlockReference(BlockReference brf) - { - try - { - // 这个获取是原点附近,需要平移到块基点 - var fit = brf.GeometryExtentsBestFit(); - var minX = fit.MinPoint.X + brf.Position.X; - var minY = fit.MinPoint.Y + brf.Position.Y; - var minZ = fit.MinPoint.Z + brf.Position.Z; - var maxX = fit.MaxPoint.X + brf.Position.X; - var maxY = fit.MaxPoint.Y + brf.Position.Y; - var maxZ = fit.MaxPoint.Z + brf.Position.Z; - return new(minX, minY, minZ, maxX, maxY, maxZ, true); - } - catch - { - // 如果是一条参照线的组块,将导致获取包围盒时报错 - // 0x01 是否需要进入块内,然后拿到每个图元的BasePoint再计算中点?感觉过于复杂. - // 0x02 这个时候拿基点走就算了 - return new(brf.Position, brf.Position, true); - } - } - - /// - /// 处理多行文字 - /// - static BoundingInfo GetBoxInfoInMText(MText mtxt) - { - /* - * MText Aussehen - * ------------------------------------ - * | | | - * | | |ht - * | | | - * |-----wl-------插入点------wr-------| - * | | | - * | | |hb - * | | | - * ------------------------------------ - */ - - double width = mtxt.ActualWidth;// 实际宽度 - double height = mtxt.ActualHeight;// 实际高度 - double wl = 0.0; - double hb = 0.0; - - // 对齐方式 - switch (mtxt.Attachment) - { - case AttachmentPoint.TopCenter: - case AttachmentPoint.MiddleCenter: - case AttachmentPoint.BottomCenter: - wl = width * -0.5; - break; - case AttachmentPoint.TopRight: - case AttachmentPoint.MiddleRight: - case AttachmentPoint.BottomRight: - wl = -width; - break; - } - switch (mtxt.Attachment) - { - case AttachmentPoint.TopLeft: - case AttachmentPoint.TopCenter: - case AttachmentPoint.TopRight: - hb = -height;// 下边线到插入点的距离 - break; - case AttachmentPoint.MiddleLeft: - case AttachmentPoint.MiddleCenter: - case AttachmentPoint.MiddleRight: - hb = height * -0.5; - break; - } - - double wr = width + wl; - double ht = height + hb; - - Point3d center = mtxt.Location; - return new(center.X + wl, center.Y + hb, 0, - center.X + wr, center.Y + ht, 0, - true, - mtxt.Rotation); - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/PolylineEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/PolylineEx.cs deleted file mode 100644 index 02681b413e1dd62e0b70c6b142dfecc65434e85a..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/PolylineEx.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 多段线扩展类 -/// -public static class PolylineEx -{ - /// - /// 获取二维多段线的端点坐标 - /// - /// 二维多段线 - /// 事务 - /// 端点坐标集合 - public static IEnumerable GetPoints(this Polyline2d pl2d, DBTrans? trans = null) - { - trans ??= DBTrans.Top; - foreach (ObjectId id in pl2d) - { - var vertex = trans.GetObject(id); - if (vertex != null) - yield return vertex.Position; - } - - } - - /// - /// 获取三维多段线的端点坐标 - /// - /// 三维多段线 - /// 事务 - /// 端点坐标集合 - public static IEnumerable GetPoints(this Polyline3d pl3d, DBTrans? trans = null) - { - trans ??= DBTrans.Top; - foreach (ObjectId id in pl3d) - { - var vertex = trans.GetObject(id); - if (vertex != null) - yield return vertex.Position; - } - } - - /// - /// 获取多段线的端点坐标 - /// - /// 多段线 - /// 端点坐标集合 - public static IEnumerable GetPoints(this Polyline pl) - { - return - Enumerable - .Range(0, pl.NumberOfVertices) - .Select(pl.GetPoint3dAt); - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DwgFilerEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DwgFilerEx.cs deleted file mode 100644 index f91fb4c84011ac6d4f5457cc8ef2370b4ed9a46e..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DwgFilerEx.cs +++ /dev/null @@ -1,87 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// Dwg序列化 -/// -public class DwgFilerEx -{ - #region 成员 - DBObject? _entity; - public DwgFiler DwgFiler { get; private set; } - #endregion - - #region 构造 - /// - /// Dwg序列化 - /// - public DwgFilerEx(DwgFiler? Cad_DwgFiler = null) - { - if (Cad_DwgFiler == null) - Cad_DwgFiler = new(); - DwgFiler = Cad_DwgFiler; - } - - /// - /// Dwg序列化 - /// - public DwgFilerEx(DBObject entity) : this() - { - DwgOut(entity); - } - - #endregion - - #region 方法 - public void DwgOut(DBObject entity) - { - _entity = entity; - _entity.DwgOut(DwgFiler); - } - - public void DwgIn() - { - _entity?.DwgIn(DwgFiler); - } - - /// - /// 反序列化 - /// - /// - /// - public static DwgFilerEx? DeserializeObject(string json) - { -#if NewtonsoftJson - return JsonConvert.DeserializeObject(json); -#else - JavaScriptSerializer serializer = new(); - serializer.RegisterConverters(new[] { new ObjectIdConverter() }); - return serializer.Deserialize(json); -#endif - } - - /// - /// 序列化 - /// - /// - public string SerializeObject() - { -#if NewtonsoftJson - return JsonConvert.SerializeObject(DwgFiler, Formatting.Indented); -#else - JavaScriptSerializer serializer = new(); - serializer.RegisterConverters(new[] { new ObjectIdConverter() }); - return serializer.Serialize(DwgFiler); -#endif - } - - public override string ToString() - { - return DwgFiler.ToString(); - } - - public static implicit operator Cad_DwgFiler(DwgFilerEx df) - { - return df.DwgFiler; - } - #endregion -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DxfFiler.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DxfFiler.cs deleted file mode 100644 index 975c5053c640dbf878328ca621208cebd6de22f8..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DxfFiler.cs +++ /dev/null @@ -1,221 +0,0 @@ -#if acad -namespace IFoxCAD.Cad; - -/* 此处暂未完成,无任何测试,尚且不知道怎么用 */ -using System.Runtime.Remoting; - -public class DxfFiler : Cad_DxfFiler -{ - public DxfFiler(IntPtr unmanagedPointer, [MarshalAs(UnmanagedType.U1)] bool autoDelete) : base(unmanagedPointer, autoDelete) - { - } - - public override bool IsModifyingExistingObject => base.IsModifyingExistingObject; - - public override double Thickness => base.Thickness; - - public override double Elevation => base.Elevation; - - public override bool AtEmbeddedObjectStart => base.AtEmbeddedObjectStart; - - public override bool AtEndOfObject => base.AtEndOfObject; - - public override bool AtExtendedData => base.AtExtendedData; - - public override bool AtEndOfFile => base.AtEndOfFile; - - public override int Precision { get => base.Precision; set => base.Precision = value; } - - public override string ErrorMessage => base.ErrorMessage; - - public override bool AtSubclassData(string value) - { - return base.AtSubclassData(value); - } - - public override object Clone() - { - return base.Clone(); - } - - public override void CopyFrom(RXObject source) - { - base.CopyFrom(source); - } - - public override ObjRef CreateObjRef(Type requestedType) - { - return base.CreateObjRef(requestedType); - } - - public override bool Equals(object obj) - { - return base.Equals(obj); - } - - public override void FilerStatus() - { - base.FilerStatus(); - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - - public override void HaltAtClassBoundaries(bool value) - { - base.HaltAtClassBoundaries(value); - } - - public override object InitializeLifetimeService() - { - return base.InitializeLifetimeService(); - } - - public override void PushBackItem() - { - base.PushBackItem(); - } - - public override ResultBuffer ReadResultBuffer() - { - return base.ReadResultBuffer(); - } - - public override void ResetFilerStatus() - { - base.ResetFilerStatus(); - } - - public override int RewindFiler() - { - return base.RewindFiler(); - } - - public override void SetError(string format, params string[] values) - { - base.SetError(format, values); - } - - public override void SetError(Cad_ErrorStatus value, string format, params string[] values) - { - base.SetError(value, format, values); - } - - public override string ToString() - { - return base.ToString(); - } - - public override void WriteBool(DxfCode opCode, bool value) - { - base.WriteBool(opCode, value); - } - - public override void WriteBoolean(DxfCode opCode, bool value) - { - base.WriteBoolean(opCode, value); - } - - public override void WriteByte(DxfCode opCode, byte value) - { - base.WriteByte(opCode, value); - } - - public override void WriteBytes(DxfCode opCode, byte[] chunk) - { - base.WriteBytes(opCode, chunk); - } - - public override void WriteDouble(DxfCode opCode, double value, int precision) - { - base.WriteDouble(opCode, value, precision); - } - - public override void WriteEmbeddedObjectStart() - { - base.WriteEmbeddedObjectStart(); - } - - public override void WriteHandle(DxfCode opCode, Handle value) - { - base.WriteHandle(opCode, value); - } - - public override void WriteInt16(DxfCode opCode, short value) - { - base.WriteInt16(opCode, value); - } - - public override void WriteInt32(DxfCode opCode, int value) - { - base.WriteInt32(opCode, value); - } - - public override void WriteObjectId(DxfCode opCode, ObjectId value) - { - base.WriteObjectId(opCode, value); - } - - public override void WritePoint2d(DxfCode opCode, Point2d value, int precision) - { - base.WritePoint2d(opCode, value, precision); - } - - public override void WritePoint3d(DxfCode opCode, Point3d value, int precision) - { - base.WritePoint3d(opCode, value, precision); - } - - public override void WriteResultBuffer(ResultBuffer buffer) - { - base.WriteResultBuffer(buffer); - } - - public override void WriteScale3d(DxfCode opCode, Scale3d value, int precision) - { - base.WriteScale3d(opCode, value, precision); - } - - public override void WriteString(DxfCode opCode, string value) - { - base.WriteString(opCode, value); - } - - public override void WriteUInt16(DxfCode opCode, ushort value) - { - base.WriteUInt16(opCode, value); - } - - public override void WriteUInt32(DxfCode opCode, uint value) - { - base.WriteUInt32(opCode, value); - } - - public override void WriteVector2d(DxfCode opCode, Vector2d value, int precision) - { - base.WriteVector2d(opCode, value, precision); - } - - public override void WriteVector3d(DxfCode opCode, Vector3d value, int precision) - { - base.WriteVector3d(opCode, value, precision); - } - - public override void WriteXDataStart() - { - base.WriteXDataStart(); - } - - protected override void DeleteUnmanagedObject() - { - base.DeleteUnmanagedObject(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - } -} -#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/JsonConverter.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/JsonConverter.cs deleted file mode 100644 index 975e511924c53940f2b43910a15fe8154d689b26..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/JsonConverter.cs +++ /dev/null @@ -1,118 +0,0 @@ - - -namespace IFoxCAD.Cad; - -#if NewtonsoftJson -/* - * 参考 https://www.cnblogs.com/fps2tao/p/14798710.html - * json类型转换器,使用方法: - * 在类上面增加此特性: [JsonConverter(typeof(ObjectIdConverter))] - */ -/// -/// json转换器 -/// -public class ObjectIdConverter : JsonConverter -{ - /// - /// 约束类型 - /// - public override bool CanConvert(Type objectType) - { - return typeof(ObjectId) == objectType; - } - - /// - /// 反序列化_把字符串生成对象 - /// - public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) - { - if (reader.Value == null) - return ObjectId.Null; - try - { - using DBTrans tr = new(); - var id = tr.GetObjectId(reader.Value.ToString()); - return id; - } - catch { return ObjectId.Null; } - } - - /// - /// 序列化_写入json - /// - public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) - { - if (value is ObjectId id) - writer.WriteValue(id == ObjectId.Null ? 0 : id.Handle.Value); - } -} -#else -/* - * 参考 https://developer.aliyun.com/article/51053 - * json类型转换器,使用方法: - * public static string SerializeToJson(object obj) - * { - * JavaScriptSerializer serializer = new(); - * serializer.RegisterConverters(new[] { new ObjectIdConverter() }); - * return serializer.Serialize(obj); - * } - * - * public static T DeserializeJson(string jsonString) - * { - * JavaScriptSerializer serializer = new(); - * serializer.RegisterConverters(new[] { new ObjectIdConverter() }); - * return serializer.Deserialize(jsonString); - * } - */ -/// -/// json转换器 -/// -public class ObjectIdConverter : JavaScriptConverter -{ - const string _id = nameof(ObjectId); - - /// - /// 约束类型 - /// - public override IEnumerable SupportedTypes => new[] { typeof(ObjectId) }; - - /// - /// 序列化_写入json - /// - public override IDictionary Serialize(object obj, JavaScriptSerializer serializer) - { - if (obj is not ObjectId id) - return null!; - - Dictionary result = new() - { - { _id, id == ObjectId.Null ? 0 : id.Handle.Value } - }; - return result; - } - - /// - /// 反序列化_把字符串生成对象 - /// - public override object Deserialize(IDictionary dictionary, Type type, JavaScriptSerializer serializer) - { - //if (dictionary == null) - // throw new ArgumentNullException(nameof(dictionary)); - dictionary.NotNull(nameof(dictionary)); - if (type != typeof(ObjectId)) - return null!; - - ObjectId id = ObjectId.Null; - try - { - if (dictionary.TryGetValue(_id, out object va)) - { - using DBTrans tr = new(); - id = tr.GetObjectId(va.ToString()); - } - } - catch { } - return id; - } -} -#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/ObjEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/ObjEx.cs deleted file mode 100644 index 1ad2a17f9ccb1ceb2bf421922367d9852b449972..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/ObjEx.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 对象扩展类 -/// -public static class ObjEx -{ - /// - /// cad的打印 - /// - /// - public static void Print(this object obj) - { - Acap.DocumentManager.MdiActiveDocument.Editor.WriteMessage($"{obj}\n"); - } - /// - /// 系统的打印 - /// - /// - public static void PrintLine(this object obj) - { - Console.WriteLine(obj.ToString()); - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/ObjectIdEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/ObjectIdEx.cs deleted file mode 100644 index a329da5ecb11b68d361aa451748d8f04e8d428cf..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/ObjectIdEx.cs +++ /dev/null @@ -1,98 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 对象id扩展类 -/// -public static class ObjectIdEx -{ - #region GetObject - /// - /// 获取指定类型对象 - /// - /// 指定的泛型 - /// 对象id - /// 打开模式 - /// 事务 - /// 是否打开已删除对象,默认为不打开 - /// 是否打开锁定图层对象,默认为不打开 - /// 指定类型对象 - public static T? GetObject(this ObjectId id, - OpenMode openMode = OpenMode.ForRead, - Transaction? trans = null, - bool openErased = false, - bool openLockedLayer = false) where T : DBObject - { - trans ??= DBTrans.Top.Transaction; - return trans.GetObject(id, openMode, openErased, openLockedLayer) as T; - } - - /// - /// 获取指定类型对象集合 - /// - /// 指定的泛型 - /// 对象id集合 - /// 打开模式 - /// 事务 - /// 是否打开已删除对象,默认为不打开 - /// 是否打开锁定图层对象,默认为不打开 - /// 指定类型对象集合 - [System.Diagnostics.DebuggerStepThrough] - public static IEnumerable GetObject(this IEnumerable ids, - OpenMode openMode = OpenMode.ForRead, - Transaction? trans = null, - bool openErased = false, - bool openLockedLayer = false) where T : DBObject - { - trans ??= DBTrans.Top.Transaction; - return ids.Select(id => id.GetObject(openMode, trans, openErased, openLockedLayer)); - } - - /// - /// 返回符合类型的对象id - /// - /// 对象类型 - /// 对象id集合 - /// 对象id集合 - public static IEnumerable OfType(this IEnumerable ids) where T : DBObject - { - string dxfName = RXClass.GetClass(typeof(T)).DxfName; - return ids.Where(id => id.ObjectClass().DxfName == dxfName); - } - #endregion GetObject - - public static RXClass ObjectClass(this ObjectId id) - { -#if NET35 - return RXClass.GetClass(id.GetType()); -#else - return id.ObjectClass; -#endif - } - - /// - /// id是否有效,未被删除 - /// - /// 对象id - /// id有效返回 ,反之返回 - public static bool IsOk(this ObjectId id) - { - return !id.IsNull && id.IsValid && !id.IsErased && !id.IsEffectivelyErased && id.IsResident; - } - - /// - /// 删除id代表的对象 - /// - /// 对象id - public static void Erase(this ObjectId id) - { - if (id.IsOk()) - { - var ent = id.GetObject()!; - using (ent.ForWrite()) - { - ent.Erase(); - }// 第一种读写权限自动转换写法 - // Env.Editor.Regen(); - } - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/PointEx.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/PointEx.cs deleted file mode 100644 index 2cfa8d2f43f04da02676f071f7da0ed58d4675aa..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/PointEx.cs +++ /dev/null @@ -1,137 +0,0 @@ - - -namespace IFoxCAD.Cad; - -public static class PointEx -{ - /// - /// 获取点的hash字符串,同时可以作为pt的字符串表示 - /// - /// 点 - /// 指示计算几维坐标的标志,1为计算x,2为计算x,y,其他为计算x,y,z - /// 保留的小数位数 - /// hash字符串 - public static string GetHashString(this Point3d pt, int xyz = 3, int decimalRetain = 6) - { - var de = $"f{decimalRetain}"; - return xyz switch - { - 1 => $"({pt.X.ToString(de)})", - 2 => $"({pt.X.ToString(de)},{pt.Y.ToString(de)})", - _ => $"({pt.X.ToString(de)},{pt.Y.ToString(de)},{pt.Z.ToString(de)})" - }; - } - - // 为了频繁触发所以弄个缓存 - static Plane? _PlaneCache; - /// - /// 两点计算弧度范围0到2Pi - /// - /// 起点 - /// 终点 - /// 方向 - /// 弧度值 - public static double GetAngle(this Point3d startPoint, Point3d endPoint, Vector3d? direction = null) - { - if (direction != null) - _PlaneCache = new Plane(Point3d.Origin, direction.Value); - if (_PlaneCache == null) - _PlaneCache = new Plane(Point3d.Origin, Vector3d.ZAxis); - return startPoint.GetVectorTo(endPoint).AngleOnPlane(_PlaneCache); - } - /// - /// 两点计算弧度范围0到2Pi - /// - /// 起点 - /// 终点 - /// 弧度值 - public static double GetAngle(this Point2d startPoint, Point2d endPoint) - { - return startPoint.GetVectorTo(endPoint).Angle; - } - - /// - /// 获取中点 - /// - /// - /// - /// - public static Point2d GetCenter(this Point2d a, Point2d b) - { - // (p1 + p2) / 2; // 溢出风险 - return new Point2d(a.X * 0.5 + b.X * 0.5, - a.Y * 0.5 + b.Y * 0.5); - } - - /// http://www.lee-mac.com/bulgeconversion.html - /// - /// 求凸度,判断三点是否一条直线上 - /// - /// 圆弧起点 - /// 圆弧腰点 - /// 圆弧尾点 - /// 逆时针为正,顺时针为负 - public static double GetArcBulge(this Point2d arc1, Point2d arc2, Point2d arc3, double tol = 1e-10) - { - double dStartAngle = arc2.GetAngle(arc1); - double dEndAngle = arc2.GetAngle(arc3); - // 求的P1P2与P1P3夹角 - var talAngle = (Math.PI - dStartAngle + dEndAngle) / 2; - // 凸度==拱高/半弦长==拱高比值/半弦长比值 - // 有了比值就不需要拿到拱高值和半弦长值了,因为接下来是相除得凸度 - double bulge = Math.Sin(talAngle) / Math.Cos(talAngle); - - // 处理精度 - if (bulge > 0.9999 && bulge < 1.0001) - bulge = 1; - else if (bulge < -0.9999 && bulge > -1.0001) - bulge = -1; - else if (Math.Abs(bulge) < tol) - bulge = 0; - return bulge; - } - - - #region 首尾相连 - /// - /// 首尾相连 - /// - [System.Diagnostics.DebuggerStepThrough] - public static void End2End(this Point2dCollection ptcol) - { - ptcol.NotNull(nameof(ptcol)); - - if (ptcol.Count == 0 || ptcol[0].Equals(ptcol[^1]))// 首尾相同直接返回 - return; - - // 首尾不同,去加一个到最后 - var lst = new Point2d[ptcol.Count + 1]; - for (int i = 0; i < lst.Length; i++) - lst[i] = ptcol[i]; - lst[^1] = lst[0]; - - ptcol.Clear(); - ptcol.AddRange(lst); - } - /// - /// 首尾相连 - /// - [System.Diagnostics.DebuggerStepThrough] - public static void End2End(this Point3dCollection ptcol) - { - ptcol.NotNull(nameof(ptcol)); - if (ptcol.Count == 0 || ptcol[0].Equals(ptcol[^1]))// 首尾相同直接返回 - return; - - // 首尾不同,去加一个到最后 - var lst = new Point3d[ptcol.Count + 1]; - for (int i = 0; i < lst.Length; i++) - lst[i] = ptcol[i]; - lst[^1] = lst[0]; - - ptcol.Clear(); - for (int i = 0; i < lst.Length; i++) - ptcol.Add(lst[i]); - } - #endregion -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Tools.cs b/src/CAD/IFox.CAD.Shared/ExtensionMethod/Tools.cs deleted file mode 100644 index 11277224d98fad85debb811ac456441b0ed327eb..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Tools.cs +++ /dev/null @@ -1,60 +0,0 @@ -using static IFoxCAD.Basal.Timer; - -namespace IFoxCAD.Cad; - -public static class Tools -{ - /// - /// 计时器 - /// - [System.Diagnostics.DebuggerStepThrough] - public static void TestTimes2(int count, string message, Action action) - { - System.Diagnostics.Stopwatch watch = new(); - watch.Start(); // 开始监视代码运行时间 - for (int i = 0; i < count; i++) - action.Invoke();// 需要测试的代码 - watch.Stop(); // 停止监视 - TimeSpan timespan = watch.Elapsed; // 获取当前实例测量得出的总时间 - double time = timespan.TotalMilliseconds; - string name = "毫秒"; - if (timespan.TotalMilliseconds > 1000) - { - time = timespan.TotalSeconds; - name = "秒"; - } - Env.Print($"{message} 代码执行 {count} 次的时间:{time} ({name})"); // 总毫秒数 - } - - /// - /// 纳秒计时器 - /// - [System.Diagnostics.DebuggerStepThrough] - public static void TestTimes(int count, string message, Action action, - TimeEnum timeEnum = TimeEnum.Millisecond) - { - var time = RunTime(() => { - for (int i = 0; i < count; i++) - action(); - }, timeEnum); - - string timeNameZn = ""; - switch (timeEnum) - { - case TimeEnum.Second: - timeNameZn = " 秒"; - break; - case TimeEnum.Millisecond: - timeNameZn = " 毫秒"; - break; - case TimeEnum.Microsecond: - timeNameZn = " 微秒"; - break; - case TimeEnum.Nanosecond: - timeNameZn = " 纳秒"; - break; - } - - Env.Print($"{message} 代码执行 {count} 次的时间:{time} ({timeNameZn})"); - } -} \ No newline at end of file diff --git "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchEx.cs" "b/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchEx.cs" deleted file mode 100644 index 8bfd04310d10da6a1156dc604ad1451830236618..0000000000000000000000000000000000000000 --- "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchEx.cs" +++ /dev/null @@ -1,15 +0,0 @@ -namespace IFoxCAD.Cad; - -public static class HatchEx -{ - /// - /// 遍历填充每条边 - /// - /// - /// - public static void ForEach(this Hatch hatch, Action action) - { - for (int i = 0; i < hatch.NumberOfLoops; i++) - action.Invoke(hatch.GetLoopAt(i)); - } -} \ No newline at end of file diff --git "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/AttachmentPointHelper.cs" "b/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/AttachmentPointHelper.cs" deleted file mode 100644 index f94fd08cbea92d6176635c11e1cf444695eb3586..0000000000000000000000000000000000000000 --- "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/AttachmentPointHelper.cs" +++ /dev/null @@ -1,98 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 文字对齐点帮助类 -/// -public static class AttachmentPointHelper -{ - static readonly Dictionary _alignment = new() - { - { "左上", AttachmentPoint.TopLeft }, - { "中上", AttachmentPoint.TopCenter },// 单行的对齐 - { "右上", AttachmentPoint.TopRight }, - - { "左中", AttachmentPoint.MiddleLeft }, - { "正中", AttachmentPoint.MiddleCenter },// 多行的正中 - { "右中", AttachmentPoint.MiddleRight }, - - { "左对齐", AttachmentPoint.BaseLeft },// ※优先(放在前面优先获取) - { "左", AttachmentPoint.BaseLeft }, - - { "中间", AttachmentPoint.BaseMid }, - - { "右对齐", AttachmentPoint.BaseRight },// ※优先(放在前面优先获取) - { "右", AttachmentPoint.BaseRight }, - - { "左下", AttachmentPoint.BottomLeft }, - { "中下", AttachmentPoint.BottomCenter }, - { "右下", AttachmentPoint.BottomRight }, - - { "对齐", AttachmentPoint.BaseAlign },// ※优先(放在前面优先获取) - { "调整", AttachmentPoint.BaseAlign }, - - { "居中", AttachmentPoint.BaseCenter },// 单行的中 - { "铺满", AttachmentPoint.BaseFit }, - }; - - /// - /// 输入文字获得对齐方式 - /// - /// - /// - public static AttachmentPoint Get(string key) - { - return _alignment[key]; - } - - /// - /// 输入对齐方式获得文字说明 - /// - /// - /// - public static string Get(AttachmentPoint value) - { - return _alignment.FirstOrDefault(q => q.Value == value).Key; - } -} - -#if false -// 反射描述 -// 这些东西cad没有用到啊...所以不纳入了 -public enum AttachmentPoint2 -{ - [Description("下对齐")] - BottomAlign = 14, - [Description("中对齐")] - MiddleAlign = 15,// 0xF - [Description("上对齐")] - TopAlign = 16,// 0x10 - [Description("下铺满")] - BottomFit = 18, - [Description("中铺满")] - MiddleFit = 19, - [Description("上铺满")] - TopFit = 20, - [Description("下居中")] - BottomMid = 22, - [Description("中居中")] - MiddleMid = 23, - [Description("下居中")] - TopMid = 24, -} - -public static Dictionary GetEnumDic(Type enumType) -{ - Dictionary dic = new(); - var fieldinfos = enumType.GetFields(); - for (int i = 0; i < fieldinfos.Length; i++) - { - var field = fieldinfos[i]; - if (field.FieldType.IsEnum) - { - var objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false); - dic.Add(field.Name, ((DescriptionAttribute)objs[0]).Description); - } - } - return dic; -} -#endif \ No newline at end of file diff --git "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/TextEntityAdd.cs" "b/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/TextEntityAdd.cs" deleted file mode 100644 index f9ba03dde0ecad9f96e282bcd3574e47467bf4e6..0000000000000000000000000000000000000000 --- "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/TextEntityAdd.cs" +++ /dev/null @@ -1,62 +0,0 @@ -namespace IFoxCAD.Cad; -#if false -public static partial class EntityAdd -{ - /// - /// 创建单行文字 - /// - /// 数据库 - /// 内容 - /// 插入点 - /// 字体高度 - /// 文字样式 - /// 对齐方式 - /// 对齐点,因样式 可能无效 - /// - public static Entity AddDBTextToEntity(this Database db, - string textContents, - Point3d position, - double textHigh = 2.5, - ObjectId? textStyleId = null, - AttachmentPoint justify = AttachmentPoint.BaseLeft, - Point3d? justifyPoint = null) - { - var TextInfo = new TextInfo( - textContents, - position, - justify, - justifyPoint, - textStyleId, - textHigh); - return TextInfo.AddDBTextToEntity(); - } - - /// - /// 新建多行文字 - /// - /// 数据库 - /// 内容 - /// 插入点 - /// 字体高度 - /// 文字样式 - /// 对齐方式 - /// - public static Entity AddMTextToEntity(this Database db, - string textContents, - Point3d position, - double textHigh = 2.5, - ObjectId? textStyleId = null, - AttachmentPoint justify = AttachmentPoint.BaseLeft) - { - var TextInfo = new TextInfo( - textContents, - position, - justify, - null, - textStyleId, - textHigh); - return TextInfo.AddMTextToEntity(); - } -} - -#endif \ No newline at end of file diff --git "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/TextInfo.cs" "b/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/TextInfo.cs" deleted file mode 100644 index cf010d4f6ee903f2f0e221150a706dd6fed2b47d..0000000000000000000000000000000000000000 --- "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\346\226\207\345\255\227/TextInfo.cs" +++ /dev/null @@ -1,179 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 文字信息类 -/// -public class TextInfo -{ - readonly Database? Database; - readonly string? Contents; - readonly Point3d Position; - /// - /// 文字对齐方式的中文说明 - /// - public string TextJustifyCn => AttachmentPointHelper.Get(TextJustify); - readonly AttachmentPoint TextJustify; - readonly Point3d? AlignmentPoint; - - readonly double TextHeight; - readonly ObjectId? TextStyleId; - - /// - /// 文字信息类 - /// - /// 内容 - /// 基点 - /// 对齐方式 - /// 对齐点(对齐方式是左,此参数无效,为null不为左就报错) - /// 文字样式id - /// 文字高度 - /// 数据库 - public TextInfo(string? contents, - Point3d position, - AttachmentPoint justify, - Point3d? justifyPoint = null, - ObjectId? textStyleId = null, - double textHeight = 2.5, - Database? database = null) - { - Contents = contents; - Position = position; - TextJustify = justify; - - if (justifyPoint is null && TextJustify != AttachmentPoint.BaseLeft) - throw new ArgumentNullException(nameof(justifyPoint)); - - AlignmentPoint = justifyPoint; - TextHeight = textHeight; - TextStyleId = textStyleId; - Database = database; - } - - /// - /// 创建单行文字 - /// - public DBText AddDBTextToEntity() - { - if (string.IsNullOrEmpty(Contents)) - throw new ArgumentNullException(nameof(Contents) + "创建文字无内容"); - - var acText = new DBText(); - - acText.SetDatabaseDefaults(Database ?? DBTrans.Top.Database); - - if (TextStyleId is not null) - acText.SetTextStyleId(TextStyleId.Value); - - acText.Height = TextHeight; // 高度 - acText.TextString = Contents; // 内容 - acText.Position = Position; // 插入点(一定要先设置) - acText.Justify = TextJustify; // 使他们对齐 - // acText.HorizontalMode - - if (AlignmentPoint is not null) - acText.AlignmentPoint = AlignmentPoint.Value; - else if (acText.Justify != AttachmentPoint.BaseLeft) - acText.AlignmentPoint = Position; - - - acText.AdjustAlignment(Database ?? DBTrans.Top.Database); - return acText; - } - - /// - /// 创建多行文字 - /// - /// - public MText AddMTextToEntity() - { - if (string.IsNullOrEmpty(Contents)) - throw new ArgumentNullException(nameof(Contents) + "创建文字无内容"); - - var mText = new MText(); - - mText.SetDatabaseDefaults(Database ?? DBTrans.Top.Database); - - if (TextStyleId is not null) - mText.SetTextStyleId(TextStyleId.Value); - - mText.TextHeight = TextHeight; // 高度 - mText.Contents = Contents; // 内容 - mText.Location = Position; // 插入点(一定要先设置) - - // mText.SetAttachmentMovingLocation(TextJustify); - mText.Attachment = TextJustify;// 使他们对齐 - - return mText; - } -} - - -/// -/// 反射设定对象的文字样式id -/// -public static partial class TextInfoHelper -{ - /// - /// 设置文字样式id - /// - /// 单行文字 - /// 文字样式表记录id - public static void SetTextStyleId(this DBText acText, ObjectId ltrObjectId) - { - SetEntityTxtStyleId(acText, ltrObjectId); - } - - /// - /// 设置文字样式id - /// - /// 多行文字 - /// 文字样式表记录id - public static void SetTextStyleId(this MText acText, ObjectId ltrObjectId) - { - SetEntityTxtStyleId(acText, ltrObjectId); - } - - static void SetEntityTxtStyleId(Entity acText, ObjectId ltrObjectId) - { - GetTextStyleIdType(acText)?.SetValue(acText, ltrObjectId, null); - } - - /// - /// 获取文字样式id - /// - public static ObjectId GetTextStyleId(this DBText acText) - { - return GetEntityTxtStyleId(acText); - } - - /// - /// 获取文字样式id - /// - public static ObjectId GetTextStyleId(this MText acText) - { - return GetEntityTxtStyleId(acText); - } - - static ObjectId GetEntityTxtStyleId(Entity acText) - { - var result = ObjectId.Null; - var id = GetTextStyleIdType(acText)?.GetValue(acText, null); - if (id != null) - result = (ObjectId)id; - return result; - } - - static PropertyInfo? _textStyleId = null; - static PropertyInfo GetTextStyleIdType(Entity acText) - { - if (_textStyleId == null) - { - var entType = acText.GetType(); - var prs = entType.GetProperties(); - _textStyleId = prs.FirstOrDefault(a => a.Name == "TextStyle");// 反射获取属性 - if (_textStyleId == null) - _textStyleId = prs.FirstOrDefault(a => a.Name == "TextStyleId");// 反射获取属性 - } - return _textStyleId; - } -} diff --git a/src/CAD/IFox.CAD.Shared/IFox.CAD.Shared.shproj b/src/CAD/IFox.CAD.Shared/IFox.CAD.Shared.shproj deleted file mode 100644 index ac52df3c3406f9a87de89d676e05a487c47f471c..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/IFox.CAD.Shared.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - 20f254f7-aee5-42ae-a9b3-149bbdc7397f - 14.0 - - - - - - - - diff --git a/src/CAD/IFox.CAD.Shared/ResultData/LispDottedPair.cs b/src/CAD/IFox.CAD.Shared/ResultData/LispDottedPair.cs deleted file mode 100644 index 009d13ed21e098a145309b76afd4e17c31910490..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/ResultData/LispDottedPair.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// lisp点对表的数据封装类 -/// -public class LispDottedPair : LispList -{ - #region 构造函数 - /// - /// 默认无参构造函数 - /// - public LispDottedPair() - { - } - - /// - /// 构造函数 - /// - /// TypedValue 迭代器 - public LispDottedPair(IEnumerable values) : base(values) - { - } - /// - /// 构造函数 - /// - /// 点对表左数 - /// 点对表右数 - public LispDottedPair(TypedValue left, TypedValue right) - { - Add(left); - Add(right); - } - #endregion - - #region 重写 - /// - /// 点对表的值 - /// - public override List Value - { - get - { - var value = new List - { - new TypedValue((int)LispDataType.ListBegin,-1), - new TypedValue((int)LispDataType.DottedPair,-1) - }; - value.InsertRange(1, this); - return value; - } - } - #endregion - - #region 转换器 - - /// - /// LispDottedPair 隐式转换到 TypedValue 数组 - /// - /// TypedValueList 实例 - public static implicit operator TypedValue[](LispDottedPair values) => values.Value.ToArray(); - /// - /// LispDottedPair 隐式转换到 ResultBuffer - /// - /// TypedValueList 实例 - public static implicit operator ResultBuffer(LispDottedPair values) => new(values.Value.ToArray()); - - #endregion -} diff --git a/src/CAD/IFox.CAD.Shared/Runtime/AOP.cs b/src/CAD/IFox.CAD.Shared/Runtime/AOP.cs deleted file mode 100644 index 4bb5cb30a937e1c5139f8405386cec05d86ee2e4..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/AOP.cs +++ /dev/null @@ -1,99 +0,0 @@ -// namespace IFoxCAD.Cad; -// using HarmonyLib; - -// public class IFoxRefuseInjectionTransaction : Attribute -// { -// /// -// /// 拒绝注入事务 -// /// -// public IFoxRefuseInjectionTransaction() -// { -// } -// } - -// public class AOP -// { -// /// -// /// 在此命名空间下的命令末尾注入清空事务栈函数 -// /// -// public static void Run(string nameSpace) -// { -// Dictionary cmdDic = new(); -// AutoClass.AppDomainGetTypes(type => { -// if (type.Namespace != nameSpace) -// return; -// // 类上面特性 -// if (type.IsClass) -// { -// var attr = type.GetCustomAttributes(true); -// if (RefuseInjectionTransaction(attr)) -// return; -// } - -// // 函数上面特性 -// var mets = type.GetMethods();// 获得它的成员函数 -// for (int ii = 0; ii < mets.Length; ii++) -// { -// var method = mets[ii]; -// // 找到特性,特性下面的方法要是Public,否则就被编译器优化掉了. -// var attr = method.GetCustomAttributes(true); -// for (int jj = 0; jj < attr.Length; jj++) -// if (attr[jj] is CommandMethodAttribute cmdAtt) -// { -// if (!RefuseInjectionTransaction(attr)) -// cmdDic.Add(cmdAtt.GlobalName, (cmdAtt, type, method)); -// } -// } -// }); - -// // 运行的命令写在了Test.dll,当然不是ifox.cad类库内了.... -// if (cmdDic.Count == 0) -// return; - -// var harmony = new Harmony(nameSpace); -// var mPrefix = SymbolExtensions.GetMethodInfo(() => IFoxCmdAddFirst());// 进入函数前 -// var mPostfix = SymbolExtensions.GetMethodInfo(() => IFoxCmdAddLast());// 进入函数后 -// var mp1 = new HarmonyMethod(mPrefix); -// var mp2 = new HarmonyMethod(mPostfix); - -// foreach (var item in cmdDic) -// { -// // 原函数执行(空间type,函数名) -// var mOriginal = AccessTools.Method(item.Value.MetType, item.Value.MetInfo.Name); -// // mOriginal.Invoke(); -// // 新函数执行:创造两个函数加入里面 -// var newMet = harmony.Patch(mOriginal, mp1, mp2); -// // newMet.Invoke(); -// } -// } - -// /// -// /// 拒绝注入事务 -// /// -// /// 属性 -// /// -// private static bool RefuseInjectionTransaction(object[] attr) -// { -// bool refuseInjectionTransaction = false; -// for (int kk = 0; kk < attr.Length; kk++) -// { -// if (attr[kk] is IFoxRefuseInjectionTransaction) -// { -// refuseInjectionTransaction = true; -// break; -// } -// } -// return refuseInjectionTransaction; -// } - -// public static void IFoxCmdAddFirst() -// { -// // 此生命周期会在静态事务栈上面,被无限延长 -// var _ = DBTrans.Top; -// } - -// public static void IFoxCmdAddLast() -// { -// DBTrans.FinishDatabase(); -// } -// } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/AcadVersion.cs b/src/CAD/IFox.CAD.Shared/Runtime/AcadVersion.cs deleted file mode 100644 index 6fe6afd2377530470a025ad944778f7d0c5df8bb..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/AcadVersion.cs +++ /dev/null @@ -1,71 +0,0 @@ - - -namespace IFoxCAD.Cad; - -/// -/// cad版本号类 -/// -public static class AcadVersion -{ - private static readonly string _pattern = @"Autodesk\\AutoCAD\\R(\d+)\.(\d+)\\.*?"; - - /// - /// 所有安装的cad的版本号 - /// - public static List Versions - { - get - { - string[] copys = Registry.LocalMachine - .OpenSubKey(@"SOFTWARE\Autodesk\Hardcopy") - .GetValueNames(); - - var _versions = new List(); - for (int i = 0; i < copys.Length; i++) - { - if (!Regex.IsMatch(copys[i], _pattern)) - continue; - - var gs = Regex.Match(copys[i], _pattern).Groups; - var ver = new CadVersion - { - ProductRootKey = copys[i], - ProductName = Registry.LocalMachine - .OpenSubKey("SOFTWARE") - .OpenSubKey(copys[i]) - .GetValue("ProductName") - .ToString(), - - Major = int.Parse(gs[1].Value), - Minor = int.Parse(gs[2].Value), - }; - _versions.Add(ver); - } - return _versions; - } - } - - /// 已打开的cad的版本号 - /// 已打开cad的application对象 - /// cad版本号对象 - public static CadVersion? FromApp(object app) - { - app.NotNull(nameof(app)); - - string acver = app.GetType() - .InvokeMember( - "Version", - BindingFlags.GetProperty, - null, - app, - new object[0]).ToString(); - - var gs = Regex.Match(acver, @"(\d+)\.(\d+).*?").Groups; - int major = int.Parse(gs[1].Value); - int minor = int.Parse(gs[2].Value); - for (int i = 0; i < Versions.Count; i++) - if (Versions[i].Major == major && Versions[i].Minor == minor) - return Versions[i]; - return null; - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/AutoLoad.cs b/src/CAD/IFox.CAD.Shared/Runtime/AutoLoad.cs deleted file mode 100644 index 004ae50f22d48f40c1a093204a598b8a94ab3eda..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/AutoLoad.cs +++ /dev/null @@ -1,128 +0,0 @@ -namespace IFoxCAD.Cad; - -/// -/// 自动加载和初始化抽象类 -/// -public abstract class AutoLoad : IExtensionApplication -{ - private AssemInfo _info = new(); - - /// - /// 程序集的路径 - /// - public static FileInfo Location => new(Assembly.GetCallingAssembly().Location); - - /// - /// 程序集的目录 - /// - public static DirectoryInfo CurrentDirectory => Location.Directory; - - /// - /// 获取程序集的目录 - /// - /// 程序集 - /// 路径对象 - public static DirectoryInfo GetDirectory(Assembly assem) - { - if (assem == null) - { - throw new(nameof(assem)); - } - return new FileInfo(assem.Location).Directory; - } - - /// - /// 初始化程序集信息 - /// - public AutoLoad() - { - Assembly assem = Assembly.GetCallingAssembly(); - _info.Loader = assem.Location; - _info.Fullname = assem.FullName; - _info.Name = assem.GetName().Name; - _info.LoadType = AssemLoadType.Startting; - - if (!SearchForReg()) - { - RegApp(); - } - - } - - #region RegApp - - private static RegistryKey GetAcAppKey() - { -#if NET35 - string key = HostApplicationServices.Current.RegistryProductRootKey; -#else - string key = HostApplicationServices.Current.UserRegistryProductRootKey; -#endif - RegistryKey ackey = Registry.CurrentUser.OpenSubKey(key, true); - return ackey.CreateSubKey("Applications"); - } - - protected void AppendSupportPath(string path) - { -#if NET35 - string key = HostApplicationServices.Current.RegistryProductRootKey; -#else - string key = HostApplicationServices.Current.UserRegistryProductRootKey; -#endif - // 计算机\HKEY_CURRENT_USER\SOFTWARE\Autodesk\AutoCAD\R24.0\ACAD-4101:804 - RegistryKey ackey = Registry.CurrentUser.OpenSubKey($@"{key}\Profiles"); - - var listkey = ackey.GetSubKeyNames(); - foreach (var item in listkey) - { - var acadkey = ackey.OpenSubKey($@"{item}\General", true); - var name = "ACAD"; - var str = acadkey.GetValue(name)?.ToString(); - if (str is not null && !str.Contains(path)) - { - acadkey.SetValue(name, $@"{str}{path};"); - } - - } - - ackey.Close(); - } - - private bool SearchForReg() - { - RegistryKey appkey = GetAcAppKey(); - var regApps = appkey.GetSubKeyNames(); - return regApps.Contains(_info.Name); - } - - /// - /// 在注册表写入自动加载的程序集信息 - /// - public void RegApp() - { - RegistryKey appkey = GetAcAppKey(); - RegistryKey rk = appkey.CreateSubKey(_info.Name); - rk.SetValue("DESCRIPTION", _info.Fullname, RegistryValueKind.String); - rk.SetValue("LOADCTRLS", _info.LoadType, RegistryValueKind.DWord); - rk.SetValue("LOADER", _info.Loader, RegistryValueKind.String); - rk.SetValue("MANAGED", 1, RegistryValueKind.DWord); - appkey.Close(); - - } - -#endregion RegApp - -#region IExtensionApplication 成员 - - /// - /// 初始化函数 - /// - public abstract void Initialize(); - - /// - /// 结束函数 - /// - public abstract void Terminate(); - -#endregion IExtensionApplication 成员 -} diff --git a/src/CAD/IFox.CAD.Shared/Runtime/CadVersion.cs b/src/CAD/IFox.CAD.Shared/Runtime/CadVersion.cs deleted file mode 100644 index d9614bf5c7c21426092421fc4a57244b8327ecf4..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/CadVersion.cs +++ /dev/null @@ -1,92 +0,0 @@ -namespace IFoxCAD.Cad; - -#if ac2009 - -public class CadVersion -{ - /// - /// 主版本 - /// - public int Major { get; set; } - - /// - /// 次版本 - /// - public int Minor { get; set; } - - /// - /// 版本号 - /// - public double ProgId => double.Parse($"{Major}.{Minor}"); - - /// - /// 注册表名称 - /// - public string? ProductName { get; set; } - - /// - /// 注册表位置 - /// - public string? ProductRootKey { get; set; } - - /// - /// 转换为字符串 - /// - /// 表示版本号的字符串 - public override string ToString() - { - return $"名称:{ProductName}\n版本号:{ProgId}\n注册表位置:{ProductRootKey}"; - } - // public override bool Equals(object obj) - // { - // return base.Equals(obj); - // } - - // public override int GetHashCode() - // { - // return base.GetHashCode(); - // } - - // // public override string ToString() - // // { - // // return base.ToString(); - // // } -} -#else -public record CadVersion -{ - /// - /// 主版本 - /// - public int Major; - - /// - /// 次版本 - /// - public int Minor; - - /// - /// 版本号 - /// - public double ProgId => double.Parse($"{Major}.{Minor}"); - - /// - /// 注册表名称 - /// - public string? ProductName; - - /// - /// 注册表位置 - /// - public string? ProductRootKey; - - /// - /// 转换为字符串 - /// - /// 表示版本号的字符串 - public override string ToString() - { - return $"名称:{ProductName}\n版本号:{ProgId}\n注册表位置:{ProductRootKey}"; - } -} -#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/FileOpenMode.cs b/src/CAD/IFox.CAD.Shared/Runtime/FileOpenMode.cs deleted file mode 100644 index b75d403aaf2af061b671a8680197269ec10d7d13..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/FileOpenMode.cs +++ /dev/null @@ -1,85 +0,0 @@ -#if ac2008 // NET35 -namespace Autodesk.AutoCAD.DatabaseServices -{ - [Wrapper("AcDbDatabase::OpenMode")] - public enum FileOpenMode - { - /// - /// 只读模式打开 - /// - OpenForReadAndReadShare = 1, - OpenForReadAndWriteNoShare = 2, - OpenForReadAndAllShare = 3, - OpenTryForReadShare = 4, - } - - public static class FileOpenModeHelper - { - /* - * 这个开图方式会致命错误,不清楚怎么用的文件句柄开图 - * using FileStream fileStream = new(_fileName, FileMode.Open, fileAccess, GetFileShare(fileOpenMode)); - * Database.ReadDwgFile(fileStream.SafeFileHandle.DangerousGetHandle(), true, password); - */ - public static FileShare GetFileShare(FileOpenMode fileOpenMode) - { - // FileAccess fileAccess = FileAccess.Read; - FileShare fileShare = FileShare.Read; - switch (fileOpenMode) - { - // 不完美匹配 - case FileOpenMode.OpenTryForReadShare: - // fileAccess = FileAccess.ReadWrite; - fileShare = FileShare.ReadWrite; - break; - // 完美匹配 - case FileOpenMode.OpenForReadAndAllShare: - // fileAccess = FileAccess.ReadWrite; - fileShare = FileShare.ReadWrite; - break; - // 完美匹配 - case FileOpenMode.OpenForReadAndWriteNoShare: - // fileAccess = FileAccess.ReadWrite; - fileShare = FileShare.None; - break; - // 完美匹配 - case FileOpenMode.OpenForReadAndReadShare: - // fileAccess = FileAccess.Read; - fileShare = FileShare.Read; - break; - } - return fileShare; - } - } -} -#endif - -#if NET35 -namespace Autodesk.AutoCAD.Internal -{ - public class Utils - { - public static void SetFocusToDwgView() - { - IntPtr window; - if (Acap.DocumentManager.Count == 0) - { - window = Acap.MainWindow.Handle; - } - else - { - // 它们是层级关系 - // Main - // -->MDI(大小被 DwgView 局限) - // ---->docW(比MDI大) - // -------->msctls_statusbar32 - // -------->DwgView - var docW = Acap.DocumentManager.MdiActiveDocument.Window.Handle; - var msctls_statusbar32 = IFoxCAD.Basal.WindowsAPI.GetTopWindow(docW); - window = IFoxCAD.Basal.WindowsAPI.GetWindow(msctls_statusbar32, 2U); - } - if (window != IntPtr.Zero) - IFoxCAD.Basal.WindowsAPI.SetFocus(window); - } - } -} -#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/LateBinding.cs b/src/CAD/IFox.CAD.Shared/Runtime/LateBinding.cs deleted file mode 100644 index 45cafa9d7ab915a4f1f19ac4dde26280ea456183..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/LateBinding.cs +++ /dev/null @@ -1,83 +0,0 @@ -namespace IFoxCAD.Com; - -/// -/// 后绑代码工具 -/// -public static class LateBinding -{ - /// - /// 从运行对象表 (ROT) 获取指定对象的运行实例 - /// - /// - /// - public static object GetInstance(string appName) - { - return Marshal.GetActiveObject(appName); - } - /// - /// 创建实例 - /// - /// - /// - public static object CreateInstance(string appName) - { - return Activator.CreateInstance(Type.GetTypeFromProgID(appName)); - } - /// - /// 获取或创建实例 - /// - /// - /// - public static object GetOrCreateInstance(string appName) - { - try { return GetInstance(appName); } - catch { return CreateInstance(appName); } - } - /// - /// 释放实例 - /// - /// - public static void ReleaseInstance(this object obj) - { - Marshal.ReleaseComObject(obj); - } - - /// - /// 获取属性 - /// - /// - /// - /// - /// - public static object GetProperty(this object obj, string propName, params object[] parameter) - { - return obj.GetType().InvokeMember(propName, - BindingFlags.GetProperty, - null, obj, parameter); - } - /// - /// 设置属性 - /// - /// - /// - /// - public static void SetProperty(this object obj, string propName, params object[] parameter) - { - obj.GetType().InvokeMember(propName, - BindingFlags.SetProperty, - null, obj, parameter); - } - /// - /// 执行函数 - /// - /// - /// - /// - /// - public static object Invoke(this object obj, string memberName, params object[] parameter) - { - return obj.GetType().InvokeMember(memberName, - BindingFlags.Public | BindingFlags.InvokeMethod, - null, obj, parameter); - } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/Log.cs b/src/CAD/IFox.CAD.Shared/Runtime/Log.cs deleted file mode 100644 index 812d694be31c88eb0f14862714636d30aa389f27..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/Log.cs +++ /dev/null @@ -1,453 +0,0 @@ -namespace IFoxCAD.Cad; - -using System; -using System.Diagnostics; -using System.Threading; -using Exception = Exception; - -#region 写入日志到不同的环境中 -// https://zhuanlan.zhihu.com/p/338492989 -public abstract class LogBase -{ - public abstract void DeleteLog(); - public abstract string[] ReadLog(); - public abstract void WriteLog(string message); -} - -/// -/// 日志输出环境 -/// -public enum LogTarget -{ - /// - /// 文件(包含错误和备注) - /// - File = 1, - /// - /// 文件(不包含错误,也就是只写备注信息) - /// - FileNotException = 2, - /// - /// 数据库 - /// - Database = 4, - /// - /// windows日志 - /// - EventLog = 8, -} - -/// -/// 写入到文件中 -/// -public class FileLogger : LogBase -{ - public override void DeleteLog() - { - File.Delete(LogHelper.LogAddress); - } - public override string[] ReadLog() - { - List lines = new(); - using (var sr = new StreamReader(LogHelper.LogAddress, true/*自动识别文件头*/)) - { - string line; - while ((line = sr.ReadLine()) != null) - lines.Add(line); - } - return lines.ToArray(); - } - public override void WriteLog(string? message) - { - // 把异常信息输出到文件 - var sw = new StreamWriter(LogHelper.LogAddress, true/*当天日志文件存在就追加,否则就创建*/); - sw.Write(message); - sw.Flush(); - sw.Close(); - sw.Dispose(); - } -} - -/// -/// 写入到数据库(暂时不支持) -/// -public class DBLogger : LogBase -{ - public override void DeleteLog() - { - throw new NotImplementedException(); - } - public override string[] ReadLog() - { - throw new NotImplementedException(); - } - public override void WriteLog(string? message) - { - throw new NotImplementedException(); - } -} - -/// -/// 写入到win日志 -/// -public class EventLogger : LogBase -{ - // 需要win权限 - // https://blog.csdn.net/weixin_38208401/article/details/77870909 - // NET50要加 - // https://docs.microsoft.com/en-us/answers/questions/526018/windows-event-log-with-net-5.html - - public string LogName = "IFoxCadLog"; - public override void DeleteLog() - { -#if !NET5_0 && !NET6_0 - if (EventLog.Exists(LogName)) - EventLog.Delete(LogName); -#endif - } - public override string[] ReadLog() - { - List lines = new(); -#if !NET5_0 && !NET6_0 - try - { - EventLog eventLog = new() - { - Log = LogName - }; - foreach (EventLogEntry entry in eventLog.Entries) - lines.Add(entry.Message); - } - catch (System.Security.SecurityException e) - { - throw new Exception("您没有权限读取win日志::" + e.Message); - } -#endif - return lines.ToArray(); - } - public override void WriteLog(string? message) - { -#if !NET5_0 && !NET6_0 - try - { - EventLog eventLog = new() - { - Source = LogName - }; - eventLog.WriteEntry(message, EventLogEntryType.Information); - } - catch (System.Security.SecurityException e) - { - throw new Exception("您没有权限写入win日志::" + e.Message); - } -#endif - } -} - -#endregion - -#region 静态方法 -public static class LogHelper -{ -#pragma warning disable CA2211 // 非常量字段应当不可见 - /// - /// 日志文件完整路径 - /// - public static string? LogAddress; - /// - /// 输出错误信息到日志文件的开关 - /// - public static bool FlagOutFile = false; - /// - /// 输出错误信息到vs输出窗口的开关 - /// - public static bool FlagOutVsOutput = true; -#pragma warning restore CA2211 // 非常量字段应当不可见 - - /// - /// 读写锁 - /// 当资源处于写入模式时,其他线程写入需要等待本次写入结束之后才能继续写入 - /// - static readonly ReaderWriterLockSlim _logWriteLock = new(); - - /// - /// 提供给外部设置log文件保存路径 - /// - /// null就生成默认配置 - public static void OptionFile(string? newlogAddress = null) - { - _logWriteLock.EnterWriteLock();// 写模式锁定 读写锁 - try - { - LogAddress = newlogAddress; - if (string.IsNullOrEmpty(LogAddress)) - LogAddress = GetDefaultOption(DateTime.Now.ToString("yy-MM-dd") + ".log"); - } - finally - { - _logWriteLock.ExitWriteLock();// 解锁 读写锁 - } - } - - /// - /// 输入文件名,获取保存路径的完整路径 - /// - /// 文件名,null获取默认路径 - /// 创建路径 - /// 完整路径 - public static string GetDefaultOption(string fileName, bool createDirectory = true) - { - // 微软回复:静态构造函数只会被调用一次, - // 并且在它执行完成之前,任何其它线程都不能创建这个类的实例或使用这个类的静态成员 - // https://blog.csdn.net/weixin_34204722/article/details/90095812 - var sb = new StringBuilder(); - sb.Append(Environment.CurrentDirectory); - sb.Append("\\ErrorLog"); - - // 新建文件夹 - if (createDirectory) - { - var path = sb.ToString(); - if (!Directory.Exists(path)) - { - // 设置文件夹属性为普通 - Directory.CreateDirectory(path) - .Attributes = FileAttributes.Normal; - } - } - sb.Append('\\'); - sb.Append(fileName); - return sb.ToString(); - } - - public static string WriteLog(this string? message, - LogTarget target = LogTarget.File) - { - if (message == null) - return string.Empty; - return LogAction(null, message, target); - } - - public static string WriteLog(this Exception? exception, - LogTarget target = LogTarget.File) - { - if (exception == null) - return string.Empty; - return LogAction(exception, null, target); - } - - public static string WriteLog(this Exception? exception, string? message, - LogTarget target = LogTarget.File) - { - if (exception == null) - return string.Empty; - return LogAction(exception, message, target); - } - - - /// 错误 - /// 备注信息 - /// 记录方式 - static string LogAction(Exception? ex, - string? message, - LogTarget target) - { - if (ex == null && message == null) - return string.Empty; - - if (LogAddress == null) - { - if (target == LogTarget.File || - target == LogTarget.FileNotException) - OptionFile(); - } - - // 不写入错误 - if (target == LogTarget.FileNotException) - ex = null; - - try - { - _logWriteLock.EnterWriteLock();// 写模式锁定 读写锁 - - var logtxt = new LogTxt(ex, message); - // var logtxtJson = Newtonsoft.Json.JsonConvert.SerializeObject(logtxt, Formatting.Indented); - var logtxtJson = logtxt?.ToString(); - if (logtxtJson == null) - return string.Empty; - - if (FlagOutFile) - { - LogBase? logger; - switch (target) - { - case LogTarget.File: - logger = new FileLogger(); - logger.WriteLog(logtxtJson); - break; - case LogTarget.FileNotException: - logger = new FileLogger(); - logger.WriteLog(logtxtJson); - break; - case LogTarget.Database: - logger = new DBLogger(); - logger.WriteLog(logtxtJson); - break; - case LogTarget.EventLog: - logger = new EventLogger(); - logger.WriteLog(logtxtJson); - break; - } - } - - if (FlagOutVsOutput) - { - Debugx.Printl("错误日志: " + LogAddress); - Debug.Write(logtxtJson); - } - return logtxtJson; - } - finally - { - _logWriteLock.ExitWriteLock();// 解锁 读写锁 - } - } -} -#endregion - -#region 序列化 -[Serializable] -public class LogTxt -{ - public string? 当前时间; - public string? 备注信息; - public string? 异常信息; - public string? 异常对象; - public string? 触发方法; - public string? 调用堆栈; - - public LogTxt() { } - - public LogTxt(Exception? ex, string? message) : this() - { - if (ex == null && message == null) - throw new ArgumentNullException(nameof(ex)); - - // 以不同语言显示日期 - // DateTime.Now.ToString("f", new System.Globalization.CultureInfo("es-ES")) - // DateTime.Now.ToString("f", new System.Globalization.CultureInfo("zh-cn")) - // 为了最小信息熵,所以用这样的格式,并且我喜欢补0 - 当前时间 = DateTime.Now.ToString("yy-MM-dd hh:mm:ss"); - - if (ex != null) - { - 异常信息 = ex.Message; - 异常对象 = ex.Source; - 触发方法 = ex.TargetSite == null ? string.Empty : ex.TargetSite.ToString(); - 调用堆栈 = ex.StackTrace == null ? string.Empty : ex.StackTrace.Trim(); - } - if (message != null) - 备注信息 = message; - } - - /// 为了不引入json的dll,所以这里自己构造 - public override string? ToString() - { - var sb = new StringBuilder(); - sb.Append('{'); - sb.Append(Environment.NewLine); - sb.AppendLine($" \"{nameof(当前时间)}\": \"{当前时间}\""); - sb.AppendLine($" \"{nameof(备注信息)}\": \"{备注信息}\""); - sb.AppendLine($" \"{nameof(异常信息)}\": \"{异常信息}\""); - sb.AppendLine($" \"{nameof(异常对象)}\": \"{异常对象}\""); - sb.AppendLine($" \"{nameof(触发方法)}\": \"{触发方法}\""); - sb.AppendLine($" \"{nameof(调用堆栈)}\": \"{调用堆栈}\""); - sb.Append('}'); - return sb.ToString(); - } -} -#endregion - - -#if false // 最简单的实现 -public static class Log -{ - /// - /// 读写锁 - /// 当资源处于写入模式时,其他线程写入需要等待本次写入结束之后才能继续写入 - /// - static readonly ReaderWriterLockSlim _logWriteLock = new(); - - /// - /// 日志文件完整路径 - /// - static readonly string _logAddress; - - static Log() - { - // 微软回复:静态构造函数只会被调用一次, - // 并且在它执行完成之前,任何其它线程都不能创建这个类的实例或使用这个类的静态成员 - // https://blog.csdn.net/weixin_34204722/article/details/90095812 - var sb = new StringBuilder(); - sb.Append(Environment.CurrentDirectory); - sb.Append("\\ErrorLog"); - - // 新建文件夹 - var path = sb.ToString(); - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path) - .Attributes = FileAttributes.Normal; // 设置文件夹属性为普通 - } - - sb.Append('\\'); - sb.Append(DateTime.Now.ToString("yy-MM-dd")); - sb.Append(".log"); - _logAddress = sb.ToString(); - } - - - /// - /// 将异常打印到日志文件 - /// - /// 异常 - /// 备注 - /// DEBUG模式打印到vs输出窗口 - public static string? WriteLog(this Exception? ex, - string? remarks = null, - bool printDebugWindow = true) - { - try - { - _logWriteLock.EnterWriteLock();// 写模式锁定 读写锁 - - var logtxt = new LogTxt(ex, remarks); - // var logtxtJson = Newtonsoft.Json.JsonConvert.SerializeObject(logtxt, Formatting.Indented); - var logtxtJson = logtxt.ToString(); - - if (logtxtJson == null) - return string.Empty; - - // 把异常信息输出到文件 - var sw = new StreamWriter(_logAddress, true/*当天日志文件存在就追加,否则就创建*/); - sw.Write(logtxtJson); - sw.Flush(); - sw.Close(); - sw.Dispose(); - - if (printDebugWindow) - { - Debugx.Printl("错误日志: " + _logAddress); - Debug.Write(logtxtJson); - // Debugger.Break(); - // Debug.Assert(false, "终止进程"); - } - return logtxtJson; - } - finally - { - _logWriteLock.ExitWriteLock();// 解锁 读写锁 - } - } -} -#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/Utils.cs b/src/CAD/IFox.CAD.Shared/Runtime/Utils.cs deleted file mode 100644 index 28c47c2fbeb1dc9b11d9ce18694860bcd18dae7e..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Shared/Runtime/Utils.cs +++ /dev/null @@ -1,98 +0,0 @@ -namespace IFoxCAD.Cad; - -using System; - -public class DBTransHelper -{ - /* - * id = db.GetObjectId(false, handle, 0); - * 参数意义: db.GetObjectId(如果没有找到就创建,句柄号,标记..将来备用) - * 在vs的输出会一直抛出: - * 引发的异常:“Autodesk.AutoCAD.Runtime.Exception”(位于 AcdbMgd.dll 中) - * "eUnknownHandle" - * 这就是为什么慢的原因,所以直接运行就好了!而Debug还是需要用arx的API替代. - */ - - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("acdb17.dll", CallingConvention = CallingConvention.ThisCall/*08的调用约定 高版本是__cdecl*/, - EntryPoint = "?getAcDbObjectId@AcDbDatabase@@QAE?AW4ErrorStatus@Acad@@AAVAcDbObjectId@@_NABVAcDbHandle@@K@Z")] - extern static int getAcDbObjectId17x32(IntPtr db, out ObjectId id, [MarshalAs(UnmanagedType.U1)] bool createnew, ref Handle h, uint reserved); - - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("acdb17.dll", CallingConvention = CallingConvention.ThisCall/*08的调用约定 高版本是__cdecl*/, - EntryPoint = "?getAcDbObjectId@AcDbDatabase@@QEAA?AW4ErrorStatus@Acad@@AEAVAcDbObjectId@@_NAEBVAcDbHandle@@K@Z")] - extern static int getAcDbObjectId17x64(IntPtr db, out ObjectId id, [MarshalAs(UnmanagedType.U1)] bool createnew, ref Handle h, uint reserved); - - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("acdb18.dll", CallingConvention = CallingConvention.ThisCall/*08的调用约定 高版本是__cdecl*/, - EntryPoint = "?getAcDbObjectId@AcDbDatabase@@QAE?AW4ErrorStatus@Acad@@AAVAcDbObjectId@@_NABVAcDbHandle@@K@Z")] - extern static int getAcDbObjectId18x32(IntPtr db, out ObjectId id, [MarshalAs(UnmanagedType.U1)] bool createnew, ref Handle h, uint reserved); - - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("acdb18.dll", CallingConvention = CallingConvention.ThisCall/*08的调用约定 高版本是__cdecl*/, - EntryPoint = "?getAcDbObjectId@AcDbDatabase@@QEAA?AW4ErrorStatus@Acad@@AEAVAcDbObjectId@@_NAEBVAcDbHandle@@K@Z")] - extern static int getAcDbObjectId18x64(IntPtr db, out ObjectId id, [MarshalAs(UnmanagedType.U1)] bool createnew, ref Handle h, uint reserved); - - /// - /// 句柄转id,NET35(08~12)专用的 - /// - /// 数据库 - /// 句柄 - /// 返回的id - /// 不存在则创建 - /// 保留,用于未来 - /// 成功0,其他值都是错误.可以强转ErrorStatus - static int GetAcDbObjectId(IntPtr db, Handle handle, out ObjectId id, bool createIfNotFound = false, uint reserved = 0) - { - id = ObjectId.Null; - switch (Acap.Version.Major) - { - case 17: - { - if (IntPtr.Size == 4) - return getAcDbObjectId17x32(db, out id, createIfNotFound, ref handle, reserved); - else - return getAcDbObjectId17x64(db, out id, createIfNotFound, ref handle, reserved); - } - case 18: - { - if (IntPtr.Size == 4) - return getAcDbObjectId18x32(db, out id, createIfNotFound, ref handle, reserved); - else - return getAcDbObjectId18x64(db, out id, createIfNotFound, ref handle, reserved); - } - } - return -1; - } - - /// - /// 句柄转id - /// - /// 数据库 - /// 句柄 - /// id - public static ObjectId TryGetObjectId(Database db, Handle handle) - { -#if !NET35 - // 高版本直接利用 - var es = db.TryGetObjectId(handle, out ObjectId id); - // if (!es) -#else - var es = GetAcDbObjectId(db.UnmanagedObject, handle, out ObjectId id); - // if (ErrorStatus.OK != (ErrorStatus)es) -#endif - return id; - } - - // public static int GetCadFileVersion(string filename) - // { - // var bytes = File.ReadAllBytes(filename); - // var headstr = Encoding.Default.GetString(bytes)[0..6]; - // if (!headstr.StartsWith("AC")) return 0; - // var vernum = int.Parse(headstr.Replace("AC", "")); - // var a = Enum.Parse(typeof(DwgVersion), "AC1800"); - // Enum.TryParse() - // return vernum + 986; - - // } -} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Source/IFox.CAD.Source.csproj b/src/CAD/IFox.CAD.Source/IFox.CAD.Source.csproj deleted file mode 100644 index 262b59137da2e2735c93cdd5b13e78ec3d98f3ff..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.Source/IFox.CAD.Source.csproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - netstandard1.0 - true - $(AssemblyName) - $(Version) - true - - - - CS8021 - true - false - contentFiles - true - false - false - true - - - - - true - $(ContentTargetFolders)\cs\any\$(PackageId)\ - false - - - - true - - - - true - - - - - - - - - - - - - diff --git a/src/CAD/IFox.CAD.ZCAD/IFox.CAD.ZCAD.csproj b/src/CAD/IFox.CAD.ZCAD/IFox.CAD.ZCAD.csproj deleted file mode 100644 index e99b5ef40c1290871036477eefc774fa73580256..0000000000000000000000000000000000000000 --- a/src/CAD/IFox.CAD.ZCAD/IFox.CAD.ZCAD.csproj +++ /dev/null @@ -1,45 +0,0 @@ - - - - NET48 - - true - true - false - MSB3270 - - - - DEBUG - - - $(Configuration);zcad - - - - runtime - - - - - - True - - - - - - - - - - - - - - - - - - - diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadEntity.cs b/src/CADShared/Algorithms/QuadTree/QuadEntity.cs similarity index 100% rename from src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadEntity.cs rename to src/CADShared/Algorithms/QuadTree/QuadEntity.cs diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTree.cs b/src/CADShared/Algorithms/QuadTree/QuadTree.cs similarity index 97% rename from src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTree.cs rename to src/CADShared/Algorithms/QuadTree/QuadTree.cs index 538a6207d96679f78b1e3006bebe85dd372c26d6..4ef6568570dc8e090fbeee9a88af98e0b18b94a8 100644 --- a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTree.cs +++ b/src/CADShared/Algorithms/QuadTree/QuadTree.cs @@ -51,7 +51,7 @@ public class QuadTree where TEntity : QuadEntity public QuadTree(Rect rect) { _rootNode = new QuadTreeNode(rect, null, 0);// 初始化根节点 - _points = new(); + _points = []; } #endregion @@ -172,11 +172,11 @@ public List Query(Rect rect, QuadTreeSelectMode selectMode = QuadTreeSe { QuadTreeEvn.SelectMode = selectMode; - var results = new List(); + List results = []; // 选择图元 _rootNode.Query(rect, results); // 选择点 - var ptge = _points.GetEnumerator(); + using var ptge = _points.GetEnumerator(); switch (selectMode) { case QuadTreeSelectMode.IntersectsWith: @@ -190,12 +190,12 @@ public List Query(Rect rect, QuadTreeSelectMode selectMode = QuadTreeSe while (ptge.MoveNext()) { var ptEnt = ptge.Current; - if (rect._X <= ptEnt._X && ptEnt._X <= rect._Right) + if (ptEnt != null && rect._X <= ptEnt._X && ptEnt._X <= rect._Right) { if (rect._Y <= ptEnt._Y && ptEnt._Y <= rect.Top) results.Add(ptEnt); } - else if (ptEnt._X > rect._Right) + else if (ptEnt != null && ptEnt._X > rect._Right) break;// 超过后面范围就break,因为红黑树已经排序 } break; diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTreeEvn.cs b/src/CADShared/Algorithms/QuadTree/QuadTreeEvn.cs similarity index 100% rename from src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTreeEvn.cs rename to src/CADShared/Algorithms/QuadTree/QuadTreeEvn.cs diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTreeNode.cs b/src/CADShared/Algorithms/QuadTree/QuadTreeNode.cs similarity index 93% rename from src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTreeNode.cs rename to src/CADShared/Algorithms/QuadTree/QuadTreeNode.cs index 06bf47266e97a3c0074d6df09760770f028e59ed..a926bdab354ad7099cabe517972dafad6096428c 100644 --- a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTreeNode.cs +++ b/src/CADShared/Algorithms/QuadTree/QuadTreeNode.cs @@ -32,13 +32,13 @@ QuadTreeNode[] Nodes { get { - return new QuadTreeNode[] - { - RightTopTree!, + return + [ + RightTopTree!, LeftTopTree!, LeftBottomTree!, - RightBottomTree!, - }; + RightBottomTree! + ]; } } /// @@ -71,7 +71,7 @@ public void ContentsSubTree(List results) return; results.AddRange(Contents); var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) nodes[i]?.ContentsSubTree(results); } @@ -84,10 +84,10 @@ public int CountSubTree { if (Contents is null) return 0; - int count = Contents.Count; + var count = Contents.Count; var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) @@ -115,7 +115,7 @@ public QuadTreeNode(Rect box, QuadTreeNode? parent, int depth) Parent = parent; Depth = depth; - Contents = new(); + Contents = []; } #endregion @@ -137,7 +137,7 @@ public QuadTreeNode(Rect box, QuadTreeNode? parent, int depth) // 退出递归:4个节点都不完全包含 // 4个节点的上层 var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) @@ -219,7 +219,7 @@ public QuadTreeNode(Rect box, QuadTreeNode? parent, int depth) // 4个子节点开始递归 // 退出递归:4个节点都不完全包含,内容就是他们的父亲 var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) @@ -232,7 +232,7 @@ public QuadTreeNode(Rect box, QuadTreeNode? parent, int depth) // 为什么要用容器? // 相同包围盒或者四叉树分割线压着多个. - this.Contents.Add(ent); + Contents.Add(ent); return this; } @@ -268,7 +268,7 @@ static Rect[] RectSplit(Rect box) var lowerRight = new Rect(box._X + halfWidth, box._Y, box._Right, box._Top - halfHeight); // 依照象限顺序输出 - return new Rect[] { upperRight, upperLeft, lowerleft, lowerRight }; + return [upperRight, upperLeft, lowerleft, lowerRight]; } #endregion @@ -289,13 +289,13 @@ public bool Remove(TEntity easeEnt) if (Contents.Remove(easeEnt)) { if (CountSubTree == 0) - this.Clear(this); + Clear(this); return true; } // 2.递归子节点移除 var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) @@ -313,7 +313,7 @@ public bool Remove(TEntity easeEnt) void Clear(QuadTreeNode node) { var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) nodes[i]?.Clear(nodes[i]); node.Contents.Clear(); @@ -335,7 +335,7 @@ public void Remove(Rect queryArea) // 本节点内容移除 if (Contents is not null && Contents.Count > 0)// 从最上层的根节点开始进入 { - for (int i = Contents.Count - 1; i >= 0; i--) + for (var i = Contents.Count - 1; i >= 0; i--) { var ent = Contents[i]; // 移除之后,如果容器是0,那么这里不能直接 Contents=null, @@ -350,7 +350,7 @@ public void Remove(Rect queryArea) // 同插入一样 // 跳到指定节点再搜索这个节点下面的图元 var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) @@ -396,7 +396,7 @@ public void Query(Rect queryArea, List results) // 遍历子节点 var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) @@ -436,7 +436,7 @@ void GetCurrentContents(Rect queryArea, List results) // 遍历当前节点内容,加入方式取决于碰撞模式 if (QuadTreeEvn.SelectMode == QuadTreeSelectMode.IntersectsWith) { - for (int i = 0; i < Contents.Count; i++) + for (var i = 0; i < Contents.Count; i++) { var ent = Contents[i]; if (queryArea.IntersectsWith(ent)) @@ -445,7 +445,7 @@ void GetCurrentContents(Rect queryArea, List results) } else { - for (int i = 0; i < Contents.Count; i++) + for (var i = 0; i < Contents.Count; i++) { var ent = Contents[i]; if (queryArea.Contains(ent)) @@ -482,9 +482,9 @@ void GetCurrentContents(Rect queryArea, List results) // 再判断图元的与目标的距离,找到最小距离,即为最近 var minPt = new Point2d(queryAreaCenter.X - hw, queryAreaCenter.Y - hh); var maxPt = new Point2d(queryAreaCenter.X + hw, queryAreaCenter.Y + hh); - var ents = new List(); + List ents = []; Query(new Rect(minPt, maxPt), ents); - for (int i = 0; i < ents.Count; i++) + for (var i = 0; i < ents.Count; i++) { var ent = ents[i]; if (entDic.ContainsKey(ent)) @@ -521,7 +521,7 @@ void GetCurrentContents(Rect queryArea, List results) // 3.找到方向 findMode 拥有的节点,然后查找节点的内容 var queryNode = GetMinNode(queryArea); - bool whileFlag = true; + var whileFlag = true; // 同一个节点可能包含邻居,因为四叉树的加入是图元压线, // 那么就在这里搜就得了,用中心点决定空间位置 // 但是本空间的图元可能都比它矮,无法满足条件 @@ -608,7 +608,7 @@ void GetCurrentContents(Rect queryArea, List results) { TEntity? results = default; - var lst = new List(); + List lst = []; var qcent = queryArea.CenterPoint; switch (findMode) @@ -673,7 +673,7 @@ void GetCurrentContents(Rect queryArea, List results) QuadTreeNode GetMinNode(Rect queryArea) { var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) @@ -763,30 +763,32 @@ QuadTreeNode GetMinNode(Rect queryArea) #endregion #region 改 + /* /// /// 所有的点归类到最小包围它的空间 /// - // public void PointsToMinNode() - // { - // ForEach(node => - // { - // for (int i = 0; i < node.Contents.Count; i++) - // { - // var ent = node.Contents[i]; - // if (ent.IsPoint) - // { - // // 如果最小包含!=当前,就是没有放在最适合的位置 - // var queryNode = GetMinNode(ent); - // if (queryNode != node) - // { - // node.Remove(ent); - // queryNode.Contents.Add(ent); - // } - // } - // } - // return false; - // }); - // } + public void PointsToMinNode() + { + ForEach(node => + { + for (int i = 0; i < node.Contents.Count; i++) + { + var ent = node.Contents[i]; + if (ent.IsPoint) + { + // 如果最小包含!=当前,就是没有放在最适合的位置 + var queryNode = GetMinNode(ent); + if (queryNode != node) + { + node.Remove(ent); + queryNode.Contents.Add(ent); + } + } + } + return false; + }); + } + */ #endregion #region 方法 @@ -802,7 +804,7 @@ public bool ForEach(QuadTree.QTAction action) // 递归执行本节点的子节点 var nodes = Nodes; - for (int i = 0; i < nodes.Length; i++) + for (var i = 0; i < nodes.Length; i++) { var node = nodes[i]; if (node is null) diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTreeSelectMode.cs b/src/CADShared/Algorithms/QuadTree/QuadTreeSelectMode.cs similarity index 100% rename from src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/QuadTreeSelectMode.cs rename to src/CADShared/Algorithms/QuadTree/QuadTreeSelectMode.cs diff --git a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/Rect.cs b/src/CADShared/Algorithms/QuadTree/Rect.cs similarity index 84% rename from src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/Rect.cs rename to src/CADShared/Algorithms/QuadTree/Rect.cs index a4c219dab62d9f85e1b95cd2511eb6b8d2f66ddd..d771c19abe2e1b6bbfbc133d6bbecf0d068cbaf5 100644 --- a/src/CAD/IFox.CAD.Shared/Algorithms/QuadTree/Rect.cs +++ b/src/CADShared/Algorithms/QuadTree/Rect.cs @@ -1,6 +1,6 @@ -using System.Diagnostics; -using System.Runtime.CompilerServices; - +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Cad; /// @@ -17,7 +17,12 @@ public TolerancePoint2d(double tolerance = 1e-6) { _tolerance = tolerance; } - + /// + /// 比较 + /// + /// + /// + /// public bool Equals(Point2d a, Point2d b)// Point3d是struct不会为null { /*默认规则是==是0容差,Eq是有容差*/ @@ -32,7 +37,11 @@ public bool Equals(Point2d a, Point2d b)// Point3d是struct不会为null // (X86.CPU.FSQRT指令用的牛顿迭代法/软件层面可以使用快速平方根....我还以为CPU会采取快速平方根这样的取表操作) return a.IsEqualTo(b, new Tolerance(_tolerance, _tolerance)); } - + /// + /// 哈希 + /// + /// + /// public int GetHashCode(Point2d obj) { // 结构体直接返回 obj.GetHashCode(); Point3d ToleranceDistinct3d @@ -42,7 +51,9 @@ public int GetHashCode(Point2d obj) } } - +/// +/// 矩形范围类 +/// [Serializable] [StructLayout(LayoutKind.Sequential)] [DebuggerDisplay("{DebuggerDisplay,nq}")] @@ -53,7 +64,13 @@ public class Rect : IEquatable, IComparable private string DebuggerDisplay => ToString("f4"); #pragma warning disable CA2211 // 非常量字段应当不可见 + /// + /// 矩形容差 + /// public static TolerancePoint2d RectTolerance = new(1e-6); + /// + /// cad容差 + /// public static Tolerance CadTolerance = new(1e-6, 1e-6); #pragma warning restore CA2211 // 非常量字段应当不可见 @@ -68,15 +85,41 @@ public class Rect : IEquatable, IComparable #endregion #region 成员 + /// + /// X + /// public double X => _X; + /// + /// Y + /// public double Y => _Y; + /// + /// 左 + /// public double Left => _X; + /// + /// 下 + /// public double Bottom => _Y; + /// + /// 右 + /// public double Right => _Right; + /// + /// 上 + /// public double Top => _Top; - + /// + /// 宽 + /// public double Width => _Right - _X; + /// + /// 高 + /// public double Height => _Top - _Y; + /// + /// 面积 + /// public double Area { get @@ -85,9 +128,17 @@ public double Area return ar < 1e-10 ? 0 : ar; } } - + /// + /// 左下Min + /// public Point2d MinPoint => LeftLower; + /// + /// 右上Max + /// public Point2d MaxPoint => RightUpper; + /// + /// 中间 + /// public Point2d CenterPoint => Midst; /// @@ -143,6 +194,9 @@ public double Area #endregion #region 构造 + /// + /// + /// public Rect() { } @@ -188,18 +242,40 @@ public Rect(Point2d p1, Point2d p3, bool check = false) #endregion #region 重载运算符_比较 + /// + /// + /// + /// + /// public override bool Equals(object? obj) { - return this.Equals(obj as Rect); + return Equals(obj as Rect); } + /// + /// + /// + /// + /// public bool Equals(Rect? b) { - return this.Equals(b, 1e-6);/*默认规则是==是0容差,Eq是有容差*/ + return Equals(b, 1e-6);/*默认规则是==是0容差,Eq是有容差*/ } + /// + /// + /// + /// + /// + /// public static bool operator !=(Rect? a, Rect? b) { return !(a == b); } + /// + /// + /// + /// + /// + /// public static bool operator ==(Rect? a, Rect? b) { // 此处地方不允许使用==null,因为此处是定义 @@ -228,7 +304,10 @@ public bool Equals(Rect? b, double tolerance = 1e-6) Math.Abs(_Top - b._Top) < tolerance && Math.Abs(_Y - b._Y) < tolerance; } - + /// + /// + /// + /// public override int GetHashCode() { return (((int)_X ^ (int)_Y).GetHashCode() ^ (int)_Right).GetHashCode() ^ (int)_Top; @@ -236,10 +315,21 @@ public override int GetHashCode() #endregion #region 包含 + /// + /// + /// + /// + /// public bool Contains(Point2d Point2d) { return Contains(Point2d.X, Point2d.Y); } + /// + /// + /// + /// + /// + /// public bool Contains(double x, double y) { return _X <= x && x <= _Right && @@ -279,21 +369,27 @@ public Point2d[] GetCommonPoint(Rect other) { return ToPoints().Intersect(other.ToPoints(), RectTolerance).ToArray(); } - + /// + /// 转换为point2d数组 + /// + /// public Point2d[] ToPoints() { - Point2d a = MinPoint;// min + var a = MinPoint;// min Point2d b = new(_Right, _Y); - Point2d c = MaxPoint;// max + var c = MaxPoint;// max Point2d d = new(_X, _Top); - return new Point2d[] { a, b, c, d }; + return [a, b, c, d]; } - + /// + /// 转换为point2d元组 + /// + /// public (Point2d boxMin, Point2d boxRigthDown, Point2d boxMax, Point2d boxLeftUp) ToPoints4() { - Point2d a = MinPoint;// min + var a = MinPoint;// min Point2d b = new(_Right, _Y); - Point2d c = MaxPoint;// max + var c = MaxPoint;// max Point2d d = new(_X, _Top); return (a, b, c, d); } @@ -311,13 +407,13 @@ public Rect Expand(double d) /// 是否矩形(带角度) /// /// + /// /// public static bool IsRectAngle(List? ptList, double tolerance = 1e-8) { //if (ptList == null) // throw new ArgumentNullException(nameof(ptList)); - - ptList.NotNull(nameof(ptList)); + ArgumentNullException.ThrowIfNull(ptList); var pts = ptList.ToList(); /* * 消重,不这里设置,否则这不是一个正确的单元测试 @@ -372,7 +468,7 @@ public static bool IsRect(List? ptList, double tolerance = 1e-10) { //if (ptList == null) // throw new ArgumentNullException(nameof(ptList)); - ptList.NotNull(nameof(ptList)); + ArgumentNullException.ThrowIfNull(ptList); var pts = ptList.ToList(); if (ptList.Count == 5) { @@ -422,8 +518,8 @@ public static bool RectAnglePointOrder(List? pts) { //if (pts == null) // throw new ArgumentNullException(nameof(pts)); - pts.NotNull(nameof(pts)); - if (!Rect.IsRectAngle(pts)) + ArgumentNullException.ThrowIfNull(pts); + if (!IsRectAngle(pts)) return false; // 获取min和max点(非包围盒) @@ -436,7 +532,7 @@ public static bool RectAnglePointOrder(List? pts) pts.Clear(); // 排序这四个点,左下/右下/右上/左上 var node = link.Find(minPt); - for (int i = 0; i < 4; i++) + for (var i = 0; i < 4; i++) { pts.Add(node!.Value); node = node.Next; @@ -490,7 +586,7 @@ static bool CrossAclockwise(Point2d o, Point2d a, Point2d b) /// 多段线对象 public Entity ToPolyLine() { - var bv = new List(); + List bv = []; var pts = ToPoints(); Polyline pl = new(); pl.SetDatabaseDefaults(); @@ -520,16 +616,16 @@ public static void XCollision(List box, box = box.OrderBy(a => a._X).ToList(); // 遍历所有图元 - for (int i = 0; i < box.Count; i++) + for (var i = 0; i < box.Count; i++) { var oneRect = box[i]; if (firstProcessing(oneRect)) continue; - bool actionlast = true; + var actionlast = true; // 搜索范围要在 one 的头尾中间的部分 - for (int j = i + 1; j < box.Count; j++) + for (var j = i + 1; j < box.Count; j++) { var twoRect = box[j]; // x碰撞:矩形2的Left 在 矩形1[Left-Right]闭区间;穿过的话,也必然有自己的Left因此不需要处理 @@ -566,10 +662,18 @@ public static void XCollision(List box, // { // return new Rect(rect.Left, rect.Bottom, rect.Right, rect.Top); // } + /// + /// + /// + /// public static implicit operator Rect(System.Drawing.RectangleF rect) { return new Rect(rect.Left, rect.Bottom, rect.Right, rect.Top); } + /// + /// + /// + /// public static implicit operator Rect(System.Drawing.Rectangle rect) { return new Rect(rect.Left, rect.Bottom, rect.Right, rect.Top); @@ -577,14 +681,29 @@ public static implicit operator Rect(System.Drawing.Rectangle rect) #endif #region ToString + /// + /// + /// + /// public sealed override string ToString() { return ToString(null, null); } + /// + /// + /// + /// + /// public string ToString(IFormatProvider? provider) { return ToString(null, provider); } + /// + /// + /// + /// + /// + /// public string ToString(string? format = null, IFormatProvider? formatProvider = null) { return $"({_X.ToString(format, formatProvider)},{_Y.ToString(format, formatProvider)})," + @@ -597,7 +716,12 @@ public string ToString(string? format = null, IFormatProvider? formatProvider = } /*为了红黑树,加入这个*/ - public int CompareTo(Rect rect) + /// + /// + /// + /// + /// + public int CompareTo(Rect? rect) { if (rect == null) return -1; diff --git a/src/CADShared/Assoc/AssocPersSubentityIdPEEx.cs b/src/CADShared/Assoc/AssocPersSubentityIdPEEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..cc1cdfa338771f04973103cca4c68a874e23f26e --- /dev/null +++ b/src/CADShared/Assoc/AssocPersSubentityIdPEEx.cs @@ -0,0 +1,59 @@ +namespace IFoxCAD.Cad.Assoc; + +/// +/// 子对象关系Id扩展 +/// +public static class AssocPersSubentityIdPEEx +{ + private static readonly RXClass _acdbAssocPersSubentityIdPEClass = RXObject.GetClass(typeof(AssocPersSubentityIdPE)); + + /// + /// 获取实体的个性化子对象关系Id + /// + /// 要查询的实体 + /// 返回个性化子对象关系Id实例,如果不存在则返回null + public static AssocPersSubentityIdPE? GetPersSubentityIdPE(this Entity entity) + { + var intPtr = entity.QueryX(_acdbAssocPersSubentityIdPEClass); + return RXObject.Create(intPtr, false) as AssocPersSubentityIdPE; + } + + /// + /// 获取实体中所有指定类型的子对象Id + /// + /// 要查询的实体 + /// 子对象的类型 + /// 返回所有子对象Id的数组 + public static SubentityId[] GetAllSubentityIds(this Entity entity, SubentityType subentityType) + { + var assocPersSubentityIdPE = entity.GetPersSubentityIdPE(); + return assocPersSubentityIdPE is null + ? [] + : assocPersSubentityIdPE.GetAllSubentities(entity, subentityType); + } + + /// + /// 获取实体中所有指定类型的子对象 + /// + /// 要查询的实体 + /// 子对象的类型 + /// 返回所有子对象的列表 + public static List GetAllSubentities(this Entity entity, SubentityType subentityType) + { + var subentityIds = entity.GetAllSubentityIds(subentityType); + + List result = []; + foreach (var subentityId in subentityIds) + { + var fullSubentityPath = new FullSubentityPath([entity.ObjectId], subentityId); + // 这里会有get不到的情况 + // 比如一条line,获取edge能获取到有一个子边,但是实际是取不到的 + // 可能cad认为子边和自身一样没必要再返回 + if (entity.GetSubentity(fullSubentityPath) is not { } subentity) + continue; + result.Add(subentity); + } + + return result; + } +} \ No newline at end of file diff --git a/src/CADShared/Assoc/AssocUtils.cs b/src/CADShared/Assoc/AssocUtils.cs new file mode 100644 index 0000000000000000000000000000000000000000..c8c400185834c4b68949885419962c2a455d856a --- /dev/null +++ b/src/CADShared/Assoc/AssocUtils.cs @@ -0,0 +1,55 @@ +#if acad +using ErrorStatus = Autodesk.AutoCAD.Runtime.ErrorStatus; +#elif zcad +using ErrorStatus = ZwSoft.ZwCAD.Runtime.ErrorStatus; +#endif + + +namespace IFoxCAD.Cad.Assoc; + +/// +/// 关联动作辅助类 +/// +public static class AssocUtils +{ + /// + /// 创建关系动作并提交到数据库
+ /// 替代AssocActionBody.CreateActionAndActionBodyAndPostToDatabase();函数 + ///
+ /// actionBody的RXClass + /// 拥有者Id + /// 动作id + /// 动作bodyId + /// 错误信息 + public static ErrorStatus CreateActionAndActionBodyAndPostToDatabase(RXClass actionBodyClass, + ObjectId ownerId, out ObjectId actionId, out ObjectId actionBodyId) + { + actionId = actionBodyId = ObjectId.Null; + try + { + if (!actionBodyClass.IsDerivedFrom(RXObject.GetClass(typeof(AssocActionBody))) || + Activator.CreateInstance(actionBodyClass.GetRuntimeType()) is not AssocActionBody + actionBody) + return ErrorStatus.NotThatKindOfClass; + var db = ownerId.Database; + using var tr = new DBTrans(db); + var networkId = AssocNetwork.GetInstanceFromObject(ownerId, true, true, ""); + var network = (AssocNetwork)tr.GetObject(networkId, OpenMode.ForWrite); + actionBodyId = db.AddDBObject(actionBody); + tr.Transaction.AddNewlyCreatedDBObject(actionBody, true); + using var action = new AssocAction(); + action.ActionBody = actionBodyId; + actionId = db.AddDBObject(action); + network.AddAction(actionId, true); + return ErrorStatus.OK; + } + catch (AcException e) + { + return e.ErrorStatus; + } + catch (Exception) + { + return ErrorStatus.InternetUnknownError; + } + } +} \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/General/ArrayEx.cs b/src/CADShared/Basal/General/ArrayEx.cs similarity index 91% rename from src/Basal/IFox.Basal.Shared/General/ArrayEx.cs rename to src/CADShared/Basal/General/ArrayEx.cs index 5b0e2cdddec5fec8cab1cc773b75ee0104ba460d..36bf8e7f1c6c17de151fca3181abdfce7ccbe039 100644 --- a/src/Basal/IFox.Basal.Shared/General/ArrayEx.cs +++ b/src/CADShared/Basal/General/ArrayEx.cs @@ -40,14 +40,14 @@ public static T[] Combine2(this T[] a, T[] b) /// 传出参数2:数组结尾
/// 返回值比较结尾为就移除
/// - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static void Deduplication(List lst, Func func) { // 头和尾比较,满足条件移除尾巴 - for (int i = 0; i < lst.Count; i++) + for (var i = 0; i < lst.Count; i++) { var first = lst[i]; - for (int j = lst.Count - 1; j > i/*符号是 >= 而且是i*/; j--) + for (var j = lst.Count - 1; j > i/*符号是 >= 而且是i*/; j--) { var last = lst[j]; if (func(first, last)) diff --git a/src/Basal/IFox.Basal.Shared/General/DebugHelper.cs b/src/CADShared/Basal/General/DebugHelper.cs similarity index 66% rename from src/Basal/IFox.Basal.Shared/General/DebugHelper.cs rename to src/CADShared/Basal/General/DebugHelper.cs index 58ae2fc30a545fb22c9107bc66e166687d7f0d1e..cadff7efb9a72647b6bba87cd61b078ba6f7d13b 100644 --- a/src/Basal/IFox.Basal.Shared/General/DebugHelper.cs +++ b/src/CADShared/Basal/General/DebugHelper.cs @@ -1,12 +1,11 @@ -using System.Diagnostics; -using System.Threading; - -namespace IFoxCAD.Basal; - -public static class Debugx +namespace IFoxCAD.Basal; +/// +/// 调试工具 +/// +public static class DebugEx { /// - /// cad命令切换: Debugx + /// cad命令切换: DebugEx /// /// 打印信息 /// 打印时间 @@ -14,17 +13,17 @@ public static class Debugx public static void Printl(object message, bool time = true) { var flag = Environment.GetEnvironmentVariable("debugx", EnvironmentVariableTarget.User); - if (flag == null || flag == "0") + if (flag is null or "0") return; if (time) //message = $"{DateTime.Now.ToLongDateString() + DateTime.Now.TimeOfDay}\n" + - message = $"{DateTime.Now.TimeOfDay} ThreadId:{Thread.CurrentThread.ManagedThreadId}\n" + + message = $"{DateTime.Now.TimeOfDay} ThreadId:{Environment.CurrentManagedThreadId}\n" + $"\t\t{message}"; //System.Diagnostics.Debug.Indent(); #if DEBUG - System.Diagnostics.Debug.WriteLine(message); + Debug.WriteLine(message); #else System.Diagnostics.Trace.WriteLine(message); #endif diff --git a/src/Basal/IFox.Basal.Shared/General/EnumEx.cs b/src/CADShared/Basal/General/EnumEx.cs similarity index 60% rename from src/Basal/IFox.Basal.Shared/General/EnumEx.cs rename to src/CADShared/Basal/General/EnumEx.cs index 50ab654a6d915fe91971ff55d5f95a7a5978044d..0f761ce3577bc19cb0f52cbf6642fad16c2870cf 100644 --- a/src/Basal/IFox.Basal.Shared/General/EnumEx.cs +++ b/src/CADShared/Basal/General/EnumEx.cs @@ -1,8 +1,8 @@ namespace IFoxCAD.Basal; -using System.ComponentModel; -using System.Linq; - +/// +/// 枚举扩展 +/// public static class EnumEx { /// @@ -10,59 +10,56 @@ public static class EnumEx /// public static void CleanCache() { - _cache.Clear(); + Cache.Clear(); } // (类型完整名,描述组合) - static readonly Dictionary> _cache = new(); + private static readonly Dictionary> Cache = []; /// /// 打印枚举的特性注释内容 /// /// 枚举 + /// /// 注释内容 public static HashSet? GetAttribute(this Enum e, bool noDescrToString = true) where T : DescriptionAttribute { var eType = e.GetType(); - string eFullName = eType.FullName + "." + e.ToString(); + var eFullName = eType.FullName + "." + e; - if (_cache.ContainsKey(eFullName)) - return _cache[eFullName]; + if (Cache.TryGetValue(eFullName, out var attribute1)) + return attribute1; - var fieldInfo = eType.GetField(Enum.GetName(eType, e)); + var fieldInfo = eType.GetField(Enum.GetName(eType, e) ?? string.Empty); if (fieldInfo == null) return null!; // 注释存放的容器 - HashSet nodes = new(); + HashSet nodes = []; if (Attribute.GetCustomAttribute(fieldInfo, typeof(T)) is T attribute) { nodes.Add(attribute.Description); - _cache.Add(eFullName, nodes); + Cache.Add(eFullName, nodes); return nodes; } // 通常到这里的就是 ALL = A | B | C // 遍历所有的枚举,组合每个注释 - List enumHas = new(); + List enumHas = []; + enumHas.AddRange(Enum.GetValues(eType).Cast().Where(em => + (e.GetHashCode() & em.GetHashCode()) == em.GetHashCode() && e.GetHashCode() != em.GetHashCode())); // 遍历这个枚举类型,获取枚举按位包含的成员 - foreach (Enum em in Enum.GetValues(eType)) - if ((e.GetHashCode() & em.GetHashCode()) == em.GetHashCode() && - e.GetHashCode() != em.GetHashCode()) - enumHas.Add(em); // 采取的行为是:注释的行为是特殊的,就按照注释的,否则,遍历子元素提取注释 // 大的在前面才能判断是否按位包含后面的,后面的就是要移除的 - enumHas = enumHas.OrderByDescending(a => a.GetHashCode()).ToList(); - ArrayEx.Deduplication(enumHas, (a, b) => { - return (a.GetHashCode() & b.GetHashCode()) == b.GetHashCode(); - }); + enumHas = [.. enumHas.OrderByDescending(a => a.GetHashCode())]; + ArrayEx.Deduplication(enumHas, (a, b) => (a.GetHashCode() & b.GetHashCode()) == b.GetHashCode()); // 逆序仅仅为排序后处理,不一定和书写顺序一样,尤其是递归可能存在重复的元素 - for (int i = enumHas.Count - 1; i >= 0; i--) + for (var i = enumHas.Count - 1; i >= 0; i--) { var atts = GetAttribute(enumHas[i], noDescrToString);// 递归 if (atts == null) @@ -74,7 +71,7 @@ public static void CleanCache() if (nodes.Count == 0 && noDescrToString) nodes.Add(e.ToString()); - _cache.Add(eFullName, nodes); + Cache.Add(eFullName, nodes); return nodes; } @@ -84,15 +81,18 @@ public static void CleanCache() public static string? PrintNote(this Enum e, bool noDescToString = true) { var hash = GetAttribute(e, noDescToString); - if (hash != null) - return string.Join("|", hash.ToArray()); - return null; + return hash == null ? null : string.Join("|", [.. hash]); } - - // 不按位运算的情况下,直接获取比较快捷 - public static string GetDesc(this Enum e) + + /// + /// 获取枚举的描述内容 + /// + /// 不按位运算的情况下,直接获取比较快捷 + /// + /// + public static string GetDescription(this Enum e) { - return GetDesc(e.GetType(), e.ToString()); + return GetDescription(e.GetType(), e.ToString()); } /// @@ -101,13 +101,11 @@ public static string GetDesc(this Enum e) /// /// /// - public static string GetDesc(this Type type, string field) + public static string GetDescription(this Type type, string field) { var memberInfo = type.GetMember(field); var attributes = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); // 如果没有定义描述,就把当前枚举值的对应名称返回 - if (attributes is null || attributes.Length != 1) - return field; - return ((DescriptionAttribute)attributes.Single()).Description; + return attributes.Length != 1 ? field : ((DescriptionAttribute)attributes.Single()).Description; } } \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/General/LinqEx.cs b/src/CADShared/Basal/General/LinqEx.cs similarity index 69% rename from src/Basal/IFox.Basal.Shared/General/LinqEx.cs rename to src/CADShared/Basal/General/LinqEx.cs index 8112e63d87a23a94379b1591ecfbe87a636845cf..30036a163457105fc0093ca030f0f276f6f12a33 100644 --- a/src/Basal/IFox.Basal.Shared/General/LinqEx.cs +++ b/src/CADShared/Basal/General/LinqEx.cs @@ -18,21 +18,19 @@ public static class LinqEx public static TValue FindByMax(this IEnumerable source, Func func) where TKey : IComparable { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue value = itor.Current; - TKey key = func(value); + var value = itr.Current; + var key = func(value); - while (itor.MoveNext()) + while (itr.MoveNext()) { - TKey tkey = func(itor.Current); - if (tkey.CompareTo(key) > 0) - { - key = tkey; - value = itor.Current; - } + var tKey = func(itr.Current); + if (tKey.CompareTo(key) <= 0) continue; + key = tKey; + value = itr.Current; } return value; } @@ -49,21 +47,19 @@ public static TValue FindByMax(this IEnumerable source, Fu public static TValue FindByMax(this IEnumerable source, out TKey maxResult, Func func) where TKey : IComparable { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue value = itor.Current; - TKey key = func(value); + var value = itr.Current; + var key = func(value); - while (itor.MoveNext()) + while (itr.MoveNext()) { - TKey tkey = func(itor.Current); - if (tkey.CompareTo(key) > 0) - { - key = tkey; - value = itor.Current; - } + var tKey = func(itr.Current); + if (tKey.CompareTo(key) <= 0) continue; + key = tKey; + value = itr.Current; } maxResult = key; return value; @@ -78,16 +74,16 @@ public static TValue FindByMax(this IEnumerable source, ou /// 最大键值的对应值 public static TValue FindByMax(this IEnumerable source, Comparison comparison) { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue value = itor.Current; + var value = itr.Current; - while (itor.MoveNext()) + while (itr.MoveNext()) { - if (comparison(itor.Current, value) > 0) - value = itor.Current; + if (comparison(itr.Current, value) > 0) + value = itr.Current; } return value; } @@ -108,21 +104,19 @@ public static TValue FindByMax(this IEnumerable source, Comparis public static TValue FindByMin(this IEnumerable source, out TKey minKey, Func func) where TKey : IComparable { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue value = itor.Current; - TKey key = func(value); + var value = itr.Current; + var key = func(value); - while (itor.MoveNext()) + while (itr.MoveNext()) { - TKey tkey = func(itor.Current); - if (tkey.CompareTo(key) < 0) - { - key = tkey; - value = itor.Current; - } + var tKey = func(itr.Current); + if (tKey.CompareTo(key) >= 0) continue; + key = tKey; + value = itr.Current; } minKey = key; return value; @@ -139,21 +133,19 @@ public static TValue FindByMin(this IEnumerable source, ou public static TValue FindByMin(this IEnumerable source, Func func) where TKey : IComparable { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue value = itor.Current; - TKey key = func(value); + var value = itr.Current; + var key = func(value); - while (itor.MoveNext()) + while (itr.MoveNext()) { - TKey tkey = func(itor.Current); - if (tkey.CompareTo(key) < 0) - { - key = tkey; - value = itor.Current; - } + var tKey = func(itr.Current); + if (tKey.CompareTo(key) >= 0) continue; + key = tKey; + value = itr.Current; } return value; } @@ -167,16 +159,16 @@ public static TValue FindByMin(this IEnumerable source, Fu /// 最小键值的对应值 public static TValue FindByMin(this IEnumerable source, Comparison comparison) { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue value = itor.Current; + var value = itr.Current; - while (itor.MoveNext()) + while (itr.MoveNext()) { - if (comparison(itor.Current, value) < 0) - value = itor.Current; + if (comparison(itr.Current, value) < 0) + value = itr.Current; } return value; } @@ -196,28 +188,28 @@ public static TValue FindByMin(this IEnumerable source, Comparis public static TValue[] FindByExt(this IEnumerable source, Func func) where TKey : IComparable { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue[] values = new TValue[2]; - values[0] = values[1] = itor.Current; + var values = new TValue[2]; + values[0] = values[1] = itr.Current; - TKey[] keys = new TKey[2]; - keys[0] = keys[1] = func(itor.Current); + var keys = new TKey[2]; + keys[0] = keys[1] = func(itr.Current); - while (itor.MoveNext()) + while (itr.MoveNext()) { - TKey tkey = func(itor.Current); - if (tkey.CompareTo(keys[0]) < 0) + var tKey = func(itr.Current); + if (tKey.CompareTo(keys[0]) < 0) { - keys[0] = tkey; - values[0] = itor.Current; + keys[0] = tKey; + values[0] = itr.Current; } - else if (tkey.CompareTo(keys[1]) > 0) + else if (tKey.CompareTo(keys[1]) > 0) { - keys[1] = tkey; - values[1] = itor.Current; + keys[1] = tKey; + values[1] = itr.Current; } } return values; @@ -232,19 +224,19 @@ public static TValue[] FindByExt(this IEnumerable source, /// 最(小/大)键值的对应值 public static TValue[] FindByExt(this IEnumerable source, Comparison comparison) { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TValue[] values = new TValue[2]; - values[0] = values[1] = itor.Current; + var values = new TValue[2]; + values[0] = values[1] = itr.Current; - while (itor.MoveNext()) + while (itr.MoveNext()) { - if (comparison(itor.Current, values[0]) < 0) - values[0] = itor.Current; - else if (comparison(itor.Current, values[1]) > 0) - values[1] = itor.Current; + if (comparison(itr.Current, values[0]) < 0) + values[0] = itr.Current; + else if (comparison(itr.Current, values[1]) > 0) + values[1] = itr.Current; } return values; } @@ -260,20 +252,20 @@ public static TValue[] FindByExt(this IEnumerable source, Compar public static TKey[] FindExt(this IEnumerable source, Func func) where TKey : IComparable { - var itor = source.GetEnumerator(); - if (!itor.MoveNext()) + using var itr = source.GetEnumerator(); + if (!itr.MoveNext()) throw new ArgumentNullException(nameof(source), "对象为 null"); - TKey[] keys = new TKey[2]; - keys[0] = keys[1] = func(itor.Current); + var keys = new TKey[2]; + keys[0] = keys[1] = func(itr.Current); - while (itor.MoveNext()) + while (itr.MoveNext()) { - TKey tkey = func(itor.Current); - if (tkey.CompareTo(keys[0]) < 0) - keys[0] = tkey; - else if (tkey.CompareTo(keys[1]) > 0) - keys[1] = tkey; + var tKey = func(itr.Current); + if (tKey.CompareTo(keys[0]) < 0) + keys[0] = tKey; + else if (tKey.CompareTo(keys[1]) > 0) + keys[1] = tKey; } return keys; } @@ -296,9 +288,12 @@ internal SpecComparer(Comparison comp) } #region IComparer 成员 - public int Compare(T x, T y) + + public int Compare(T? x, T? y) { - return _comp(x, y); + if (x is not null && y is not null) + return _comp(x, y); + return 0; } #endregion IComparer 成员 } diff --git a/src/Basal/IFox.Basal.Shared/General/LoopList.cs b/src/CADShared/Basal/General/LoopList.cs similarity index 89% rename from src/Basal/IFox.Basal.Shared/General/LoopList.cs rename to src/CADShared/Basal/General/LoopList.cs index 243ced664120ae5260e54db6e3080aa113e3cc60..78355d5045db767d696188fdbbcc59a73e8016c8 100644 --- a/src/Basal/IFox.Basal.Shared/General/LoopList.cs +++ b/src/CADShared/Basal/General/LoopList.cs @@ -35,6 +35,7 @@ public class LoopListNode /// 环链表节点构造函数 /// /// 节点值 + /// 环链表 public LoopListNode(T value, LoopList ts) { Value = value; @@ -104,10 +105,10 @@ public LoopList() { } /// 环链表构造函数 ///
/// 节点迭代器 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public LoopList(IEnumerable values) { - var ge = values.GetEnumerator(); + using var ge = values.GetEnumerator(); while (ge.MoveNext()) Add(ge.Current); } @@ -149,7 +150,7 @@ public void Reverse() if (first is null) return; var last = Last; - for (int i = 0; i < Count / 2; i++) + for (var i = 0; i < Count / 2; i++) { Swap(first!, last!); first = first!.Next; @@ -176,7 +177,7 @@ void ForEach(Func, bool> action) var node = First; if (node is null) return; - for (int i = 0; i < Count; i++) + for (var i = 0; i < Count; i++) { if (action(node!)) break; @@ -193,7 +194,7 @@ public void For(Func, bool> action) var node = First; if (node is null) return; - for (int i = 0; i < Count; i++) + for (var i = 0; i < Count; i++) { if (action(i, node!)) break; @@ -210,7 +211,7 @@ public void For(Func, bool> action) /// public bool Contains(LoopListNode node) { - return node is not null && node.List == this; + return node.List == this; } /// @@ -220,14 +221,11 @@ public bool Contains(LoopListNode node) /// public bool Contains(T value) { - bool result = false; + var result = false; ForEach(node => { - if (node.Value!.Equals(value)) - { - result = true; - return true; - } - return false; + if (!node.Value!.Equals(value)) return false; + result = true; + return true; }); return result; } @@ -235,7 +233,7 @@ public bool Contains(T value) /// /// 查找第一个出现的节点 /// - /// + /// /// public LoopListNode? Find(T value) { @@ -284,11 +282,11 @@ public bool Contains(T value) /// public IEnumerable>? Finds(T value) { - LoopListNode? node = First; + var node = First; if (node is null) return null; - List> result = new(); + List> result = []; var c = EqualityComparer.Default; if (value is not null) { @@ -390,7 +388,7 @@ public LoopListNode Add(T value) /// /// /// - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public LoopListNode AddLast(T value) { return Add(value); @@ -400,10 +398,10 @@ public LoopListNode AddLast(T value) /// 容器内容全部加入到末尾 ///
/// - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public void AddRange(IEnumerable list) { - var ge = list.GetEnumerator(); + using var ge = list.GetEnumerator(); while (ge.MoveNext()) Add(ge.Current); } @@ -419,13 +417,13 @@ public LoopListNode AddBefore(LoopListNode node, T value) if (node == First) return AddFirst(value); - var tnode = new LoopListNode(value, this); - node.Previous!.Next = tnode; - tnode.Previous = node.Previous; - node.Previous = tnode; - tnode.Next = node; + var tNode = new LoopListNode(value, this); + node.Previous!.Next = tNode; + tNode.Previous = node.Previous; + node.Previous = tNode; + tNode.Next = node; Count++; - return tnode; + return tNode; } /// @@ -436,13 +434,13 @@ public LoopListNode AddBefore(LoopListNode node, T value) /// public LoopListNode AddAfter(LoopListNode node, T value) { - var tnode = new LoopListNode(value, this); - node.Next!.Previous = tnode; - tnode.Next = node.Next; - node.Next = tnode; - tnode.Previous = node; + var tNode = new LoopListNode(value, this); + node.Next!.Previous = tNode; + tNode.Next = node.Next; + node.Next = tNode; + tNode.Previous = node; Count++; - return tnode; + return tNode; } #endregion @@ -524,9 +522,10 @@ public bool Remove(T value) if (lst is null) return false; - var ge = lst!.GetEnumerator(); + using var ge = lst.GetEnumerator(); while (ge.MoveNext()) - InternalRemove(ge.Current); + if (ge.Current != null) + InternalRemove(ge.Current); return true; } @@ -564,8 +563,8 @@ public void LinkTo(LoopListNode from, LoopListNode to) if (from != to && Contains(from) && Contains(to)) { LoopListNode node = from.Next!; - bool isFirstChanged = false; - int number = 0; + var isFirstChanged = false; + var number = 0; while (node != to) { @@ -633,11 +632,11 @@ public void LinkTo(LoopListNode from, LoopListNode to, int number, bool is /// /// /// - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public IEnumerable> GetNodes(LoopListNode from) { var node = from; - for (int i = 0; i < Count; i++) + for (var i = 0; i < Count; i++) { yield return node!; node = node!.Next; @@ -648,11 +647,11 @@ public IEnumerable> GetNodes(LoopListNode from) /// 获取节点的查询器 ///
/// - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public IEnumerable> GetNodes() { LoopListNode node = First!; - for (int i = 0; i < Count; i++) + for (var i = 0; i < Count; i++) { yield return node!; node = node.Next!; @@ -663,23 +662,23 @@ public IEnumerable> GetNodes() /// 获取节点值的查询器 /// /// - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public IEnumerator GetEnumerator() { LoopListNode node = First!; - for (int i = 0; i < Count; i++) + for (var i = 0; i < Count; i++) { yield return node!.Value; node = node.Next!; } } - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); #region IEnumerable 成员 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); #endregion IEnumerable 成员 @@ -704,7 +703,7 @@ string IFormattable.ToString(string? format, IFormatProvider? formatProvider) /// public override string ToString() { - return ToString(null, null); + return ToString(null); } /// @@ -715,13 +714,11 @@ public string ToString(string? format, IFormatProvider? formatProvider = null) { var s = new StringBuilder(); s.Append($"Count = {Count};"); - if (format is null) - { - s.Append("{ "); - foreach (T value in this) - s.Append($"{value} "); - s.Append(" }"); - } + if (format is not null) return s.ToString(); + s.Append("{ "); + foreach (var value in this) + s.Append($"{value} "); + s.Append(" }"); return s.ToString(); } #endregion diff --git a/src/CADShared/Basal/General/LoopState.cs b/src/CADShared/Basal/General/LoopState.cs new file mode 100644 index 0000000000000000000000000000000000000000..1367e869331c96486e80daa02e89e22d81ff57b9 --- /dev/null +++ b/src/CADShared/Basal/General/LoopState.cs @@ -0,0 +1,71 @@ +// ReSharper disable InconsistentNaming +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 +namespace IFoxCAD.Basal; + +#line hidden // 调试的时候跳过它 +/// +/// 控制循环结束 +/// +public class LoopState +{ + private const int PlsNone = 0; + private const int PlsExceptional = 1; + private const int PlsBroken = 2; + private const int PlsStopped = 4; + private const int PlsCanceled = 8; + + private volatile int _flag = PlsNone; + + public bool IsRun => _flag == PlsNone; + public bool IsExceptional => (_flag & PlsExceptional) == PlsExceptional; + public bool IsBreak => (_flag & PlsBroken) == PlsBroken; + public bool IsStop => (_flag & PlsStopped) == PlsStopped; + public bool IsCancel => (_flag & PlsCanceled) == PlsCanceled; + + public void Exceptional() + { + if ((_flag & PlsExceptional) != PlsExceptional) + _flag |= PlsExceptional; + } + public void Break() => _flag = PlsBroken; + public void Stop() => _flag = PlsStopped; + public void Cancel() => _flag = PlsCanceled; + public void Reset() => _flag = PlsNone; +} +#line default + +/// +/// 控制程序流程 +/// +public class ProState +{ + private const int PlsNone = 0; // 初始化(构造就立马运行,将导致构造函数中也被检测,这是浪费性能及挖坑给自己的) + private const int PlsRun = 1; // 运行 + private const int PlsBroken = 2; + private const int PlsStopped = 4; + private const int PlsCanceled = 8; + private const int PlsExceptional = 16; // 异常 用于附加状态 + + private volatile int _flag = PlsNone; + + public bool IsNone => _flag == PlsNone; + public bool IsRun => (_flag & PlsRun) == PlsRun; + public bool IsBreak => (_flag & PlsBroken) == PlsBroken; + public bool IsStop => (_flag & PlsStopped) == PlsStopped; + public bool IsCancel => (_flag & PlsCanceled) == PlsCanceled; + public bool IsExceptional => (_flag & PlsExceptional) == PlsExceptional; + + public void Exceptional() + { + if ((_flag & PlsExceptional) != PlsExceptional) + _flag |= PlsExceptional; + } + public void Break() => _flag = PlsBroken; + public void Stop() => _flag = PlsStopped; + public void Cancel() => _flag = PlsCanceled; + public void Start() => _flag = PlsRun; + public void None() => _flag = PlsNone; +} +#line default + +#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 \ No newline at end of file diff --git a/src/CADShared/Basal/Nullable/ArgumentNullEx.cs b/src/CADShared/Basal/Nullable/ArgumentNullEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..517cd14c8a7658d4c277fa82539de35f42b15ba3 --- /dev/null +++ b/src/CADShared/Basal/Nullable/ArgumentNullEx.cs @@ -0,0 +1,28 @@ + +#if !NET8_0_OR_GREATER +namespace IFoxCAD.Basal; + +/// +/// 参数null检查类 +/// +public static class ArgumentNullEx +{ + /// + /// 检查参数是否为 null + /// + /// 参数 + /// 参数名字 + public static void ThrowIfNull([NotNull] object? argument, + [CallerArgumentExpression(nameof(argument))] + string? paramName = null) + { + if (argument is null) + { + Throw(paramName); + } + } + + [DoesNotReturn] + private static void Throw(string? paramName) => throw new ArgumentNullException(paramName); +} +#endif \ No newline at end of file diff --git a/src/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs b/src/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs new file mode 100644 index 0000000000000000000000000000000000000000..505d5ee5e07b9c01f80abc5accca7da62b51be2b --- /dev/null +++ b/src/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs @@ -0,0 +1,25 @@ + +#if !NET8_0_OR_GREATER +namespace System.Runtime.CompilerServices; +/// +/// 指示参数将为另一个参数传递的表达式捕获为字符串。 +/// +[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] +internal sealed class CallerArgumentExpressionAttribute : Attribute +{ + /// + /// 初始化 CallerArgumentExpressionAttribute 类的新实例。 + /// + /// 参数名 + public CallerArgumentExpressionAttribute(string parameterName) + { + ParameterName = parameterName; + } + + /// + /// 获取其表达式应捕获为字符串的参数的名称。 + /// + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public string ParameterName { get; } +} +#endif \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/WindowsAPI/Enums.cs b/src/CADShared/Basal/Win/Enums.cs similarity index 99% rename from src/Basal/IFox.Basal.Shared/WindowsAPI/Enums.cs rename to src/CADShared/Basal/Win/Enums.cs index ed76fd07940514ca3ca50af663aa30bf9862495f..059f92ce810232a42a44bf9e94eaf0ebe16831a3 100644 --- a/src/Basal/IFox.Basal.Shared/WindowsAPI/Enums.cs +++ b/src/CADShared/Basal/Win/Enums.cs @@ -1,4 +1,5 @@ -#if true +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 +#if true namespace IFoxCAD.Basal; // https://blog.csdn.net/qq_43812868/article/details/108587936 @@ -1068,4 +1069,5 @@ public enum GetWindowCmd : uint /// GW_ENABLEDPOPUP = 6 } -#endif \ No newline at end of file +#endif +#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 diff --git a/src/CADShared/Basal/Win/PInvokeUser32.cs b/src/CADShared/Basal/Win/PInvokeUser32.cs new file mode 100644 index 0000000000000000000000000000000000000000..ef4dd5d8fad75f0491fd948b1efa315750aa85b3 --- /dev/null +++ b/src/CADShared/Basal/Win/PInvokeUser32.cs @@ -0,0 +1,316 @@ +namespace IFoxCAD.Basal; + +/// +/// PInvokeUser32 +/// +public static class PInvokeUser32 +{ + #region Win32 + + /// + /// 查找窗口 + /// + /// 类名 + /// 窗口名 + /// 窗口句柄 + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + /// + /// 发送指定消息给一个或多个接收对象,常用于窗口或控件的消息处理 + /// + /// 目标窗口的句柄如果为0,表示发送给所有顶级窗口 + /// 要发送的消息标识符 + /// 附加的消息特定信息,通常用于传递额外的参数 + /// 附加的消息特定信息,通常用于传递额外的参数 + /// 返回值取决于发送的消息类型,通常表示操作的结果或状态 + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); + + #region user32 + + /// + /// 获取窗口客户区的大小,客户区为窗口中除标题栏,菜单栏之外的地方 + /// + /// + /// + /// + [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetClientRect")] + public static extern bool GetClientRect(IntPtr hwnd, out WindowsAPI.IntRect lpRect); + + /// + /// 查找主线程
+ /// 代替
+ /// 托管线程和他们不一样: + /// System.Threading.Thread.CurrentThread.ManagedThreadId + /// + ///
+ /// 主窗口 + /// 进程ID + /// 线程ID + [DllImport("user32.dll", SetLastError = true)] + public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); + + /// + /// 设置焦点 + /// + /// + /// + [DllImport("user32.dll")] + public static extern IntPtr SetFocus(IntPtr hWnd); + + /// + /// 获取当前窗口 + /// + /// 当前窗口标识符 + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + /// + /// 将一个消息的组成部分合成一个消息并放入对应线程消息队列的方法 + /// + /// 控件句柄 + /// 消息是什么键盘按键、鼠标点击还是其他 + /// + /// + /// + [DllImport("user32.dll")] + public static extern bool PostMessage(IntPtr hhwnd, int msg, IntPtr wparam, IntPtr lparam); + + /// + /// 发送击键 + /// + /// + /// + /// + /// + [DllImport("user32.dll", EntryPoint = "keybd_event")] + public static extern void KeybdEvent(byte bVk, byte bScan, int dwFlags, int dwExtraInfo); + + /// + /// 获取窗口文字的长度 + /// + /// 窗口标识符 + /// 文字长度 + [DllImport("user32.dll")] + public static extern int GetWindowTextLength(IntPtr hWnd); + + /// + /// 获取窗口的标题 + /// + /// 窗口标识符 + /// 窗口文字 + /// 文字长度 + /// + [DllImport("User32.dll", CharSet = CharSet.Auto)] + public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int nMaxCount); + + // [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + // internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + + /// + /// 获取某个线程的输入法布局 + /// + /// 线程ID + /// 布局码 + [DllImport("user32.dll")] + public static extern int GetKeyboardLayout(int threadId); + + /// + /// 获取按键的当前状态 + /// + /// 按键虚拟代码 + /// 表示没按下>0;按下<0 + [DllImport("user32.dll")] + public static extern short GetKeyState(int nVirtualKey); + + /// + /// 检索指定窗口所属的类的名称 + /// + /// 窗口标识符 + /// 存储窗口类名称的字符串缓冲区 + /// 缓冲区的最大字符数 + /// 如果函数成功,返回值是窗口类名的长度,不包括终止的空字符如果窗口没有类名,返回值为零如果函数失败,返回值为零,并且 GetLastError 返回值提供扩展错误信息 + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + + /// + /// 检索由指定窗口拥有的下一个窗口的句柄 + /// + /// 要获取其拥有的下一个窗口的句柄的窗口 + /// 指定要获取的窗口的类型 + /// 如果函数成功,返回值是指定窗口拥有的下一个窗口的句柄如果没有更多窗口,返回值为null + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); + + /// + /// 检索指定窗口的子窗口链表中的第一个窗口 + /// + /// 要获取其第一个子窗口的父窗口句柄 + /// 如果函数成功,返回值是子窗口的句柄如果没有子窗口,返回值为null + [DllImport("user32.DLL", CharSet = CharSet.Unicode, + CallingConvention = CallingConvention.StdCall, SetLastError = true)] + public static extern IntPtr GetTopWindow(IntPtr hWnd); + + /// + /// 获取线程对应的窗体信息 + /// + /// 线程 + /// + /// + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui); + + /// + /// 获取线程对应的窗体信息 + /// + [StructLayout(LayoutKind.Sequential)] + public struct GuiThreadInfo + { + /// + /// 结构体的大小 + /// + public int cbSize; + + /// + /// 状态标志 + /// + public int flags; + + /// + /// 当前激活的窗口句柄 + /// + public IntPtr hwndActive; + + /// + /// 当前焦点的窗口句柄 + /// + public IntPtr hwndFocus; + + /// + /// 当前捕获的窗口句柄 + /// + public IntPtr hwndCapture; + + /// + /// 当前菜单所有者的窗口句柄 + /// + public IntPtr hwndMenuOwner; + + /// + /// 当前正在移动或改变大小的窗口句柄 + /// + public IntPtr hwndMoveSize; + + /// + /// 当前插入符号的窗口句柄 + /// + public IntPtr hwndCaret; + + /// + /// 插入符号的位置和大小 + /// + public System.Drawing.Rectangle rcCaret; + + /// + /// 创建GuiThreadInfo实例 + /// + /// 窗口线程的进程ID + /// GuiThreadInfo实例 + public static GuiThreadInfo Create(uint windowThreadProcessId) + { + if (windowThreadProcessId == 0) + throw new System.ArgumentNullException(nameof(windowThreadProcessId)); + + GuiThreadInfo gti = new(); + gti.cbSize = Marshal.SizeOf(gti); + GetGUIThreadInfo(windowThreadProcessId, ref gti); + return gti; + } + } + + /// + /// 获取当前焦点的窗口句柄 + /// + /// 窗口句柄 + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetFocus(); + + /// + /// 发送消息到指定窗口 + /// + /// 窗口句柄 + /// 消息 + /// 附加参数 + /// 附加参数 + /// 消息处理结果 + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam); + + /// + /// 获取指定窗口的父窗口句柄 + /// + /// 窗口句柄 + /// 父窗口句柄 + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetParent(IntPtr hWnd); + + /// + /// 将虚拟键代码和扫描码转换为ASCII字符 + /// + /// 虚拟键代码 + /// 扫描码 + /// 键盘状态 + /// 转换后的字符 + /// 状态标志 + /// 转换的字符数 + [DllImport("user32.dll")] + public static extern int ToAscii(int uVirtKey, int uScancode, byte[] lpdKeyState, + byte[] lpwTransKey, int fuState); + + /// + /// 获取当前激活的窗口句柄 + /// + /// 窗口句柄 + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetActiveWindow(); + + /// + /// 获取窗口对应的线程和进程ID + /// + /// 窗口句柄 + /// 进程ID + /// 线程ID + [DllImport("user32.dll", SetLastError = true)] + public static extern long GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId); + + /// + /// 检查窗口是否最小化 + /// + /// 窗口句柄 + /// 是否最小化 + [DllImport("user32.dll")] + public static extern bool IsIconic(int hWnd); + + /// + /// 检查窗口是否启用 + /// + /// 窗口句柄 + /// 是否启用 + [DllImport("user32.dll")] + public static extern bool IsWindowEnabled(IntPtr hWnd); + + #endregion + + #endregion +} + +internal class WmMessage +{ + #region Message + + public const uint Close = 0x0010; + + #endregion +} \ No newline at end of file diff --git a/src/CADShared/Basal/Win/SystemEx.cs b/src/CADShared/Basal/Win/SystemEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..50d93db6fdc5958ea1e6b1009033b9f5f1ddb203 --- /dev/null +++ b/src/CADShared/Basal/Win/SystemEx.cs @@ -0,0 +1,28 @@ +namespace IFoxCAD.Basal; + +/// +/// 系统扩展 +/// +public class SystemEx +{ + /// + /// 关闭进程 + /// + /// 进程名 + /// 成功返回true + public static bool CloseProc(string procName) + { + var result = false; + + foreach (var thisProc in Process.GetProcesses()) + { + var tempName = thisProc.ProcessName; + if (tempName != procName) + continue; + thisProc.Kill(); //当发送关闭窗口命令无效时强行结束进程 + result = true; + } + + return result; + } +} \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/WindowsAPI/WindowsAPI.cs b/src/CADShared/Basal/Win/WindowsAPI.cs similarity index 64% rename from src/Basal/IFox.Basal.Shared/WindowsAPI/WindowsAPI.cs rename to src/CADShared/Basal/Win/WindowsAPI.cs index 6f8ac91489655ed2c03be1ad55c1f77ac364fe1c..5b12ae2cc22560fc476fb352a8a9a4eddb6c1593 100644 --- a/src/Basal/IFox.Basal.Shared/WindowsAPI/WindowsAPI.cs +++ b/src/CADShared/Basal/Win/WindowsAPI.cs @@ -1,9 +1,14 @@ -#define Marshal - +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 +#define Marshal +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Basal; + public partial class WindowsAPI { #region kernel32 + // https://blog.csdn.net/haelang/article/details/45147121 [DllImport("kernel32.dll")] public extern static uint GetLastError(); @@ -12,7 +17,7 @@ public partial class WindowsAPI public static extern long GetHandleInformation(long hObject, ref long lpdwFlags); [DllImport("kernel32.dll")] - public static extern IntPtr GetModuleHandle(string ModuleName); + public static extern IntPtr GetModuleHandle(string moduleName); [DllImport("kernel32.dll")] public static extern int GetCurrentThreadId(); @@ -32,14 +37,15 @@ public partial class WindowsAPI /// /// [DllImport("kernel32.dll", SetLastError = true)] - static extern IntPtr GlobalLock(IntPtr hMem); + private static extern IntPtr GlobalLock(IntPtr hMem); + /// /// 解锁内存 /// /// /// [DllImport("kernel32.dll", SetLastError = true)] - static extern bool GlobalUnlock(IntPtr hMem); + private static extern bool GlobalUnlock(IntPtr hMem); #if !Marshal /* const int GMEM_MOVEABLE = 0x0002; @@ -77,12 +83,12 @@ public partial class WindowsAPI /// 锁定数据对象指针 /// 返回锁定的内存片段指针,锁定期间执行任务 /// 是否锁定成功 - /// + /// public static bool GlobalLockTask(IntPtr data, Action task) { //if (task == null) // throw new ArgumentNullException(nameof(task)); - task.NotNull(nameof(task)); + ArgumentNullException.ThrowIfNull(task); if (data == IntPtr.Zero) return false; @@ -96,7 +102,11 @@ public static bool GlobalLockTask(IntPtr data, Action task) return false; task.Invoke(ptr); } - finally { GlobalUnlock(data); } + finally + { + GlobalUnlock(data); + } + return true; } @@ -116,13 +126,13 @@ public static bool GlobalLockTask(IntPtr data, Action task) // 安全写法效率太低了 // 分配结构体大小的内存空间 - IntPtr structPtr = Marshal.AllocHGlobal(typeSize); + var structPtr = Marshal.AllocHGlobal(typeSize); // 将byte数组拷到分配好的内存空间 Marshal.Copy(bytes, 0, structPtr, typeSize); // 将内存空间转换为目标结构体; // 转类型的时候会拷贝一次,看它们地址验证 &result != &structPtr - var result = (T)Marshal.PtrToStructure(structPtr, structType); + var result = (T)Marshal.PtrToStructure(structPtr, structType)!; // 释放内存空间 Marshal.FreeHGlobal(structPtr); @@ -137,7 +147,7 @@ public static bool GlobalLockTask(IntPtr data, Action task) [MethodImpl] public static T? BytesToStruct(byte[] bytes) { - T? result = default; + T? result; unsafe { // 安全指针方法 @@ -148,6 +158,7 @@ public static bool GlobalLockTask(IntPtr data, Action task) result = (T?)Marshal.PtrToStructure(new IntPtr(pB), typeof(T)); } } + return result; } @@ -157,7 +168,7 @@ public static bool GlobalLockTask(IntPtr data, Action task) /// /// 要转换的结构体 [MethodImpl] - public static byte[] StructToBytes(T structObj) where T : unmanaged/*非托管的T从来不为空*/ + public static byte[] StructToBytes(T structObj) where T : unmanaged /*非托管的T从来不为空*/ { // 得到结构体的大小 var typeSize = Marshal.SizeOf(structObj); @@ -224,12 +235,17 @@ public static void StructToPtr(T structObj, } } #endif + #endregion } -public partial class WindowsAPI +/// +/// 系统Api +/// +public static partial class WindowsAPI { #region imm32 + /// /// 获取输入法的虚拟键码 /// @@ -237,6 +253,7 @@ public partial class WindowsAPI /// [DllImport("imm32.dll")] public static extern IntPtr ImmGetVirtualKey(IntPtr hWnd); + /// /// 获取输入法状态 /// @@ -254,6 +271,7 @@ public partial class WindowsAPI /// [DllImport("imm32.dll")] public static extern IntPtr ImmGetContext(IntPtr hwnd); + /// /// 设置输入法的当前状态 /// @@ -262,6 +280,7 @@ public partial class WindowsAPI /// [DllImport("imm32.dll")] public static extern bool ImmSetOpenStatus(IntPtr hwnd, bool fOpen); + /// /// 输入法打开状态 /// @@ -269,191 +288,26 @@ public partial class WindowsAPI /// 非0打开,0关闭;(true中文,false英文) [DllImport("imm32.dll")] public static extern bool ImmGetOpenStatus(IntPtr hwnd); + #endregion } public partial class WindowsAPI { - #region user32 - - /// - /// 获取窗口客户区的大小,客户区为窗口中除标题栏,菜单栏之外的地方 - /// - /// - /// - /// - [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetClientRect")] - public static extern bool GetClientRect(IntPtr hwnd, out IntRect lpRect); - - /// - /// 查找主线程
- /// 代替
- /// 托管线程和他们不一样: - ///
- /// 主窗口 - /// 进程ID - /// 线程ID - [DllImport("user32.dll", SetLastError = true)] - public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); - - /// - /// 设置焦点 - /// - /// - /// - [DllImport("user32.dll")] - public static extern IntPtr SetFocus(IntPtr hWnd); - - /// - /// 获取当前窗口 - /// - /// 当前窗口标识符 - [DllImport("user32.dll")] - public static extern IntPtr GetForegroundWindow(); - /// - /// 将一个消息的组成部分合成一个消息并放入对应线程消息队列的方法 - /// - /// 控件句柄 - /// 消息是什么。键盘按键、鼠标点击还是其他 - /// - /// - /// - [DllImport("user32.dll")] - public static extern bool PostMessage(IntPtr hhwnd, int msg, IntPtr wparam, IntPtr lparam); - /// - /// 发送击键 - /// - /// - /// - /// - /// - [DllImport("user32.dll", EntryPoint = "keybd_event")] - public static extern void KeybdEvent(byte bVk, byte bScan, int dwFlags, int dwExtraInfo); - /// - /// 获取窗口文字的长度 - /// - /// 窗口标识符 - /// 文字长度 - [DllImport("user32.dll")] - public static extern int GetWindowTextLength(IntPtr hWnd); - /// - /// 获取窗口的标题 - /// - /// 窗口标识符 - /// 窗口文字 - /// 文字长度 - /// - [DllImport("User32.dll", CharSet = CharSet.Auto)] - public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int nMaxCount); - - // [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - // internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); - - - /// - /// 获取某个线程的输入法布局 - /// - /// 线程ID - /// 布局码 - [DllImport("user32.dll")] - public static extern int GetKeyboardLayout(int threadid); - - - /// - /// 获取按键的当前状态 - /// - /// 按键虚拟代码 - /// 表示没按下>0;按下<0 - [DllImport("user32.dll")] - public static extern short GetKeyState(int nVirtKey); - /// - /// 检索指定窗口所属的类的名称。 - /// - /// 窗口标识符 - /// - /// - /// - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); - - [DllImport("user32.DLL", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)] - public static extern IntPtr GetTopWindow(IntPtr hWnd); - - - /// - /// 获取线程对应的窗体信息 - /// - /// 线程 - /// - /// - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetGUIThreadInfo(uint idThread, ref GuiThreadInfo lpgui); - - /// - /// 获取线程对应的窗体信息 - /// - [StructLayout(LayoutKind.Sequential)] - public struct GuiThreadInfo - { - public int cbSize; - public int flags; - public IntPtr hwndActive; - public IntPtr hwndFocus; - public IntPtr hwndCapture; - public IntPtr hwndMenuOwner; - public IntPtr hwndMoveSize; - public IntPtr hwndCaret; - public System.Drawing.Rectangle rcCaret; - - public static GuiThreadInfo Create(uint windowThreadProcessId) - { - if (windowThreadProcessId == 0) - throw new ArgumentNullException(nameof(windowThreadProcessId)); - - GuiThreadInfo gti = new(); - gti.cbSize = Marshal.SizeOf(gti); - GetGUIThreadInfo(windowThreadProcessId, ref gti); - return gti; - } - } - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr GetFocus(); - - [DllImport("user32.dll")] - public static extern IntPtr SendMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr GetParent(IntPtr hWnd); - - [DllImport("user32.dll")] - public static extern int ToAscii(int uVirtKey, int uScancode, byte[] lpdKeyState, byte[] lpwTransKey, int fuState); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr GetActiveWindow(); - - [DllImport("user32.dll", SetLastError = true)] - public static extern long GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId); + #region 键盘钩子 - [DllImport("user32.dll", SetLastError = true)] - public static extern bool IsIconic(int hWnd); + public delegate IntPtr CallBack(int nCode, int wParam, IntPtr lParam); [DllImport("user32.dll")] - public static extern bool IsWindowEnabled(IntPtr hWnd); - #endregion + public static extern IntPtr SetWindowsHookEx(HookType idHook, CallBack lpfn, IntPtr hmod, + int dwThreadId); - #region 键盘钩子 - public delegate IntPtr CallBack(int nCode, int wParam, IntPtr lParam); - [DllImport("user32.dll")] - public static extern IntPtr SetWindowsHookEx(HookType idHook, CallBack lpfn, IntPtr hmod, int dwThreadId); [DllImport("user32.dll")] public static extern IntPtr UnhookWindowsHookEx(IntPtr hHook); + [DllImport("user32.dll")] public static extern IntPtr CallNextHookEx(IntPtr hHook, int ncode, int wParam, IntPtr lParam); + /// /// Hook键盘数据结构 /// @@ -464,21 +318,23 @@ public static GuiThreadInfo Create(uint windowThreadProcessId) [StructLayout(LayoutKind.Sequential)] public struct KeyboardHookStruct { - public int VkCode; // 键码,该代码必须有一个价值的范围1至254 - public int ScanCode; // 指定的硬件扫描码的关键 - public int Flags; // 键标志 - public int Time; // 指定的时间戳记的这个讯息 - public int DwExtraInfo; // 指定额外信息相关的信息 + public int VkCode; // 键码,该代码必须有一个价值的范围1至254 + public int ScanCode; // 指定的硬件扫描码的关键 + public int Flags; // 键标志 + public int Time; // 指定的时间戳记的这个讯息 + public int DwExtraInfo; // 指定额外信息相关的信息 public static KeyboardHookStruct Create(IntPtr lParam) { - return (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); + return (KeyboardHookStruct)(Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)) ?? throw new InvalidOperationException()); } + public void ToPtr(IntPtr lParam) { Marshal.StructureToPtr(this, lParam, true); } } + /// /// 注册表增加低级钩子超时处理,防止系统不允许, /// 否则:偶发性出现 键盘钩子不能用了,而且退出时产生 1404 错误 @@ -488,14 +344,26 @@ public static void CheckLowLevelHooksTimeout(int setLowLevel = 25000) { const string llh = "LowLevelHooksTimeout"; using var registryKey = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", true); - if ((int)registryKey.GetValue(llh, 0) < setLowLevel) + if (registryKey is not null && (int)registryKey.GetValue(llh, 0) < setLowLevel) + { registryKey.SetValue(llh, setLowLevel, RegistryValueKind.DWord); + } } + #endregion } public partial class WindowsAPI { + /// + /// 关闭窗口 + /// + /// + public static void CloseWindow(IntPtr hWnd) + { + PInvokeUser32.SendMessage(hWnd, WmMessage.Close, IntPtr.Zero, IntPtr.Zero); + } + [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hwnd, ref IntRect lpRect); @@ -507,12 +375,13 @@ public partial class WindowsAPI public struct IntRect { [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string DebuggerDisplay => $"(Left:{_Left},Top:{_Top},Right:{_Right},Bottom:{_Bottom})"; + private string DebuggerDisplay => + $"(Left:{_Left},Top:{_Top},Right:{_Right},Bottom:{_Bottom})"; - int _Left; - int _Top; - int _Right; - int _Bottom; + private int _Left; + private int _Top; + private int _Right; + private int _Bottom; public int Left => _Left; public int Top => _Top; public int Right => _Right; @@ -528,32 +397,34 @@ public IntRect(int left, int top, int right, int bottom) _Bottom = bottom; } - static readonly IntRect _Zero = new(0, 0, 0, 0); + private static readonly IntRect _Zero = new(0, 0, 0, 0); public static IntRect Zero => _Zero; public override string ToString() => $"({_Left},{_Top},{_Right},{_Bottom})"; #region 重载运算符_比较 + public bool Equals(IntRect other) { - return - _Left == other._Left && - _Top == other._Top && - _Right == other._Right && - _Bottom == other._Bottom; + return _Left == other._Left && _Top == other._Top && _Right == other._Right && + _Bottom == other._Bottom; } + public static bool operator !=(IntRect a, IntRect b) { return !(a == b); } + public static bool operator ==(IntRect a, IntRect b) { return a.Equals(b); } - public override bool Equals(object obj) + + public override bool Equals(object? obj) { return obj is IntRect d && Equals(d); } + public override int GetHashCode() { return ((_Left, _Top).GetHashCode(), _Right).GetHashCode() ^ _Bottom.GetHashCode(); @@ -563,6 +434,7 @@ public IntRect Clone() { return (IntRect)MemberwiseClone(); } + #endregion } @@ -575,6 +447,7 @@ public struct IntSize { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string DebuggerDisplay => $"(Hight:{Hight},Width:{Width})"; + public int Hight; public int Width; @@ -583,6 +456,7 @@ public IntSize(int cx, int cy) Hight = cx; Width = cy; } + public override string ToString() => $"({Hight},{Width})"; } @@ -607,6 +481,7 @@ public Point3D(double x, double y, double z) Y = y; Z = z; } + //public static implicit operator Point3D(Point3d pt) //{ // return new Point3D(pt.X, pt.Y, pt.Z); @@ -619,7 +494,7 @@ public Point3D(double x, double y, double z) public static Point3D Create(IntPtr lParam) { - return (Point3D)Marshal.PtrToStructure(lParam, typeof(Point3D)); + return (Point3D)(Marshal.PtrToStructure(lParam, typeof(Point3D)) ?? throw new InvalidOperationException()); } public void ToPtr(IntPtr lParam) @@ -627,31 +502,35 @@ public void ToPtr(IntPtr lParam) Marshal.StructureToPtr(this, lParam, true); } - #region 重载运算符_比较 + public bool Equals(Point3D other) { - return - X == other.X && - Y == other.Y && - Z == other.Z; + return X == other.X && Y == other.Y && Z == other.Z; } + public static bool operator !=(Point3D a, Point3D b) { return !(a == b); } + public static bool operator ==(Point3D a, Point3D b) { return a.Equals(b); } - public override bool Equals(object obj) + + public override bool Equals(object? obj) { return obj is Point3D d && Equals(d); } + public override int GetHashCode() { return (X, Y).GetHashCode() ^ Z.GetHashCode(); } + #endregion } -} \ No newline at end of file +} + +#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/IFox.CAD.Shared.projitems b/src/CADShared/CADShared.projitems similarity index 53% rename from src/CAD/IFox.CAD.Shared/IFox.CAD.Shared.projitems rename to src/CADShared/CADShared.projitems index 9983528568bd0c0ac645a23bd4eb1d32225a25d7..bd2680bb41c0b68586a48989e293db477bac9462 100644 --- a/src/CAD/IFox.CAD.Shared/IFox.CAD.Shared.projitems +++ b/src/CADShared/CADShared.projitems @@ -1,91 +1,110 @@  - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) true - 20f254f7-aee5-42ae-a9b3-149bbdc7397f + 00D9188F-646C-4E1A-AD53-5F6C0754346F - IFox.CAD.Shared + CADShared - - - - - + + + + + + + + + + + + + + + + - - - + + + - + + + + + - - - - - - - + + + + + + + + + - - + + + + + + + - + + + + - - - - - - - + + + + + + + + + + + + + + - + - - - - - - - + - - - - - - - - - - + + + - + diff --git a/src/CADShared/CADShared.shproj b/src/CADShared/CADShared.shproj new file mode 100644 index 0000000000000000000000000000000000000000..d138ef06162f8acb0f7aaf1dc39c17c2695465de --- /dev/null +++ b/src/CADShared/CADShared.shproj @@ -0,0 +1,12 @@ + + + + {5178502E-9A78-4588-B849-33ED439976B2} + + + + + + + diff --git a/src/CADShared/CADShared.shproj.DotSettings b/src/CADShared/CADShared.shproj.DotSettings new file mode 100644 index 0000000000000000000000000000000000000000..959e91883114bcf0f38d092e358db271a2499cfe --- /dev/null +++ b/src/CADShared/CADShared.shproj.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file diff --git a/src/CADShared/Constant/DllFileNames.cs b/src/CADShared/Constant/DllFileNames.cs new file mode 100644 index 0000000000000000000000000000000000000000..81384e06220a4ca968b725d611da2e47c735b9b4 --- /dev/null +++ b/src/CADShared/Constant/DllFileNames.cs @@ -0,0 +1,8 @@ +namespace IFoxCAD.Cad; + +internal static class DllFileNames +{ +#if zcad + public const string ZwCadExe = "zwcad.exe"; +#endif +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/BaseEx.cs b/src/CADShared/ExtensionMethod/BaseEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..51766f32cb8293c96b760b288f2107178da9aba1 --- /dev/null +++ b/src/CADShared/ExtensionMethod/BaseEx.cs @@ -0,0 +1,17 @@ +namespace IFoxCAD.Cad; + +/// +/// 基础扩展 +/// +public static class BaseEx +{ + /// + /// 判断图层名是否合法 + /// + /// 图层名 + /// 是则返回true + public static bool IsLegalLayerName(this string layerName) + { + return !string.IsNullOrWhiteSpace(layerName) && SymbolUtilityServices.RepairSymbolName(layerName, true) == layerName; + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/BulgeVertexWidth.cs b/src/CADShared/ExtensionMethod/BulgeVertexWidth.cs similarity index 86% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/BulgeVertexWidth.cs rename to src/CADShared/ExtensionMethod/BulgeVertexWidth.cs index 1f9e08d9d4758a1128add30d674d7314d7b156e9..4303fd330aa1844c18f554902ddad2214bcd09be 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/BulgeVertexWidth.cs +++ b/src/CADShared/ExtensionMethod/BulgeVertexWidth.cs @@ -26,21 +26,25 @@ public class BulgeVertexWidth /// 尾宽 /// public double EndWidth; - + /// + /// 顶点 + /// public Point2d Vertex => new(X, Y); - + /// + /// 默认构造 + /// public BulgeVertexWidth() { } /// /// 多段线的顶点,凸度,头宽,尾宽 /// - public BulgeVertexWidth(double vertex_X, double vertex_Y, + public BulgeVertexWidth(double vertexX, double vertexY, double bulge = 0, double startWidth = 0, double endWidth = 0) { - X = vertex_X; - Y = vertex_Y; + X = vertexX; + Y = vertexY; Bulge = bulge; StartWidth = startWidth; EndWidth = endWidth; @@ -77,7 +81,10 @@ public BulgeVertexWidth(Polyline pl, int index) StartWidth = pl.GetStartWidthAt(index); EndWidth = pl.GetEndWidthAt(index); } - + /// + /// 转换为 BulgeVertex + /// + /// public BulgeVertex ToBulgeVertex() { return new BulgeVertex(Vertex, Bulge); diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/CollectionEx.cs b/src/CADShared/ExtensionMethod/CollectionEx.cs similarity index 63% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/CollectionEx.cs rename to src/CADShared/ExtensionMethod/CollectionEx.cs index acd120a24ecd01bf4636097749cc76227f41a602..61415d32d88a4c1c05fd5e50f269ab9c86326620 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/CollectionEx.cs +++ b/src/CADShared/ExtensionMethod/CollectionEx.cs @@ -1,8 +1,4 @@ -using System.ComponentModel; -using System.Xml.Linq; -using static System.Windows.Forms.AxHost; - -namespace IFoxCAD.Cad; +namespace IFoxCAD.Cad; /// /// 集合扩展类 @@ -14,23 +10,26 @@ public static class CollectionEx /// /// 对象id的迭代器 /// 对象id集合,记得释放 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static ObjectIdCollection ToCollection(this IEnumerable ids) { - return new ObjectIdCollection(ids.ToArray()); + var objectIds = ids as ObjectId[] ?? ids.ToArray(); + // new ObjectIdCollection时填长度为0的数组会报错 + return objectIds.Length == 0 ? new ObjectIdCollection() : new ObjectIdCollection(objectIds); } + /// /// 实体迭代器转换为集合 /// /// 对象类型 /// 实体对象的迭代器 /// 实体集合,记得释放 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static DBObjectCollection ToCollection(this IEnumerable objs) where T : DBObject { DBObjectCollection objCol = new(); - foreach (T obj in objs) + foreach (var obj in objs) objCol.Add(obj); return objCol; } @@ -40,18 +39,29 @@ public static DBObjectCollection ToCollection(this IEnumerable objs) where /// /// double 数值迭代器 /// 数值集合,它没有Dispose - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static DoubleCollection ToCollection(this IEnumerable doubles) { return new DoubleCollection(doubles.ToArray()); } + /// + /// double 数值迭代器转换为 double 数值集合 + /// + /// double 数值迭代器 + /// 数值集合,它没有Dispose + [DebuggerStepThrough] + public static IntegerCollection ToCollection(this IEnumerable ints) + { + return new IntegerCollection(ints.ToArray()); + } + /// /// 二维点迭代器转换为二维点集合 /// /// 二维点迭代器 /// 二维点集合,!acad记得释放 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static Point2dCollection ToCollection(this IEnumerable pts) { return new Point2dCollection(pts.ToArray()); @@ -62,7 +72,7 @@ public static Point2dCollection ToCollection(this IEnumerable pts) /// /// 三维点迭代器 /// 三维点集合,记得释放 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static Point3dCollection ToCollection(this IEnumerable pts) { return new Point3dCollection(pts.ToArray()); @@ -73,7 +83,7 @@ public static Point3dCollection ToCollection(this IEnumerable pts) /// /// 对象id集合 /// 对象id列表 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static List ToList(this ObjectIdCollection ids) { return ids.Cast().ToList(); @@ -86,7 +96,7 @@ public static List ToList(this ObjectIdCollection ids) /// 集合值的类型 /// 集合 /// 委托 - [System.Diagnostics.DebuggerStepThrough] //[DebuggerHidden] 两个特性差不多 + [DebuggerStepThrough] public static void ForEach(this IEnumerable source, Action action) { // 这里不要嵌套调用ForEach委托, @@ -101,13 +111,30 @@ public static void ForEach(this IEnumerable source, Action action) action.Invoke(element); } + /// + /// 遍历集合,执行委托 + /// + /// 集合值的类型 + /// 集合 + /// 委托 + [DebuggerStepThrough] + public static void ForEach(this IEnumerable source, Action action) + { + var i = 0; + foreach (var element in source) + { + action.Invoke(i, element); + i++; + } + } + /// /// 遍历集合,执行委托(允许循环中断) /// /// 集合值的类型 /// 集合 /// 委托 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static void ForEach(this IEnumerable source, Action action) { // 这里不要嵌套调用ForEach委托, @@ -118,7 +145,7 @@ public static void ForEach(this IEnumerable source, Action a // action.Invoke(a, b); // }); - LoopState state = new();/*这种方式比Action改Func更友好*/ + LoopState state = new(); /*这种方式比Action改Func更友好*/ foreach (var element in source) { action.Invoke(element, state); @@ -133,11 +160,11 @@ public static void ForEach(this IEnumerable source, Action a /// 集合值的类型 /// 集合 /// 委托 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static void ForEach(this IEnumerable source, Action action) { - int i = 0; - LoopState state = new();/*这种方式比Action改Func更友好*/ + var i = 0; + LoopState state = new(); /*这种方式比Action改Func更友好*/ foreach (var element in source) { action.Invoke(element, state, i); @@ -149,11 +176,26 @@ public static void ForEach(this IEnumerable source, Action + /// 关键字名字 + /// public enum KeywordName { - GlobalName, - LocalName, - DisplayName, + /// + /// 全局名字 + /// + GLOBAL, + + /// + /// 本地名字 + /// + LOCAL, + + /// + /// 显示名字 + /// + DISPLAY, } /// @@ -163,59 +205,54 @@ public enum KeywordName /// 关键字 /// 关键字容器字段名 /// true含有 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static bool Contains(this KeywordCollection collection, string name, - KeywordName keywordName = KeywordName.GlobalName) + KeywordName keywordName = KeywordName.GLOBAL) { - bool contains = false; + var contains = false; switch (keywordName) { - case KeywordName.GlobalName: - for (int i = 0; i < collection.Count; i++) - { -#if gcad - var item = collection.get_Item(i); -#else - var item = collection[i]; -#endif - if (item.GlobalName == name) + case KeywordName.GLOBAL: + for (var i = 0; i < collection.Count; i++) { - contains = true; - break; + var item = collection[i]; + + if (item.GlobalName == name) + { + contains = true; + break; + } } - } - break; - case KeywordName.LocalName: - for (int i = 0; i < collection.Count; i++) - { -#if gcad - var item = collection.get_Item(i); -#else - var item = collection[i]; -#endif - if (item.LocalName == name) + + break; + case KeywordName.LOCAL: + for (var i = 0; i < collection.Count; i++) { - contains = true; - break; + var item = collection[i]; + + if (item.LocalName == name) + { + contains = true; + break; + } } - } - break; - case KeywordName.DisplayName: - for (int i = 0; i < collection.Count; i++) - { -#if gcad - var item = collection.get_Item(i); -#else - var item = collection[i]; -#endif - if (item.DisplayName == name) + + break; + case KeywordName.DISPLAY: + for (var i = 0; i < collection.Count; i++) { - contains = true; - break; + var item = collection[i]; + + if (item.DisplayName == name) + { + contains = true; + break; + } } - } - break; + + break; } + return contains; } @@ -225,35 +262,35 @@ public static bool Contains(this KeywordCollection collection, string name, /// /// /// - [System.Diagnostics.DebuggerStepThrough] - public static Dictionary GetDict(this KeywordCollection collection) + [DebuggerStepThrough] + public static Dictionary ToDictionary(this KeywordCollection collection) { Dictionary map = new(); - for (int i = 0; i < collection.Count; i++) + for (var i = 0; i < collection.Count; i++) { -#if gcad - var item = collection.get_Item(i); -#else var item = collection[i]; -#endif + map.Add(item.GlobalName, item.DisplayName); } + return map; } + #endregion #region IdMapping + /// /// 旧块名 /// - /// + /// /// - [System.Diagnostics.DebuggerStepThrough] - public static List GetKeys(this IdMapping idmap) + [DebuggerStepThrough] + public static List GetKeys(this IdMapping idMapping) { - List ids = new(); - foreach (IdPair item in idmap) + List ids = []; + foreach (IdPair item in idMapping) ids.Add(item.Key); return ids; } @@ -261,14 +298,17 @@ public static List GetKeys(this IdMapping idmap) /// /// 新块名 /// - /// + /// /// - [System.Diagnostics.DebuggerStepThrough] - public static List GetValues(this IdMapping idmap) + [DebuggerStepThrough] + public static List GetValues(this IdMapping idMapping) { - List ids = new(); - foreach (IdPair item in idmap) + List ids = []; + foreach (IdPair item in idMapping) + { ids.Add(item.Value); + } + return ids; } @@ -277,13 +317,17 @@ public static List GetValues(this IdMapping idmap) /// /// /// - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static Dictionary ToDictionary(this IdMapping mapping) { var keyValuePairs = new Dictionary(); foreach (IdPair item in mapping) + { keyValuePairs.Add(item.Key, item.Value); + } + return keyValuePairs; } + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/DBDictionaryEx.cs b/src/CADShared/ExtensionMethod/DBDictionaryEx.cs similarity index 60% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/DBDictionaryEx.cs rename to src/CADShared/ExtensionMethod/DBDictionaryEx.cs index e099a936bce6cb4f6b257cee201460ae987483d7..829b1ae9b5751da28ddb9335b6e18a956fe994e4 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/DBDictionaryEx.cs +++ b/src/CADShared/ExtensionMethod/DBDictionaryEx.cs @@ -5,42 +5,63 @@ /// public static class DBDictionaryEx { + #region Get Set + /// /// 获取字典里的全部对象 /// /// 对象类型的泛型 /// 字典 - /// 事务 /// 对象迭代器 - [System.Diagnostics.DebuggerStepThrough] - public static IEnumerable GetAllObjects(this DBDictionary dict, DBTrans? trans = null) where T : DBObject + [DebuggerStepThrough] + public static IEnumerable GetAllObjects(this DBDictionary dict) where T : DBObject { - trans ??= DBTrans.Top; - foreach (DBDictionaryEntry e in dict) + var tr = DBTrans.GetTopTransaction(dict.Database); + foreach (var e in dict) { - var ent = trans.GetObject(e.Value); - if (ent is not null) - yield return ent; + if (tr.GetObject(e.Value) is T tObj) + yield return tObj; } } /// /// 获取字典内指定key的对象 /// - /// 对象类型的泛型 /// 字典 - /// 事务 /// 指定的键值 /// T 类型的对象 - public static T? GetAt(this DBDictionary dict, string key, DBTrans? trans = null) where T : DBObject + public static DBObject? GetData(this DBDictionary dict, string key) { - trans ??= DBTrans.Top; + var tr = DBTrans.GetTopTransaction(dict.Database); if (dict.Contains(key)) { - ObjectId id = dict.GetAt(key); + var id = dict.GetAt(key); if (!id.IsNull) - return trans.GetObject(id); + return tr.GetObject(id); } + + return null; + } + + /// + /// 获取字典内指定key的对象 + /// + /// 对象类型的泛型 + /// 字典 + /// key + /// T类型的对象 + public static T? GetData(this DBDictionary dict, string key) where T : DBObject + { + var tr = DBTrans.GetTopTransaction(dict.Database); + if (dict.Contains(key)) + { + var id = dict.GetAt(key); + if (!id.IsNull) + { + return tr.GetObject(id); + } + } + return null; } @@ -49,19 +70,33 @@ public static IEnumerable GetAllObjects(this DBDictionary dict, DBTrans? t /// /// 对象类型 /// 字典 - /// 事务 /// 键 /// 值 - public static void SetAt(this DBDictionary dict, string key, T newValue, Transaction? trans = null) where T : DBObject + /// 字典项目的id + public static ObjectId SetData(this DBDictionary dict, string key, T newValue) where T : DBObject { - trans ??= DBTrans.Top.Transaction; + var tr = DBTrans.GetTopTransaction(dict.Database); + using (dict.ForWrite()) { - dict.SetAt(key, newValue); - trans.AddNewlyCreatedDBObject(newValue, true); + if (dict.Contains(key)) + { + var oldValue = dict.GetData(key)!; + using (oldValue.ForWrite()) + { + oldValue.Erase(); + dict.Remove(key); + } + } + + var id = dict.SetAt(key, newValue); + tr.AddNewlyCreatedDBObject(newValue, true); + return id; } } + #endregion + #region XRecord /// @@ -70,12 +105,10 @@ public static void SetAt(this DBDictionary dict, string key, T newValue, Tran /// 字典 /// 键值 /// 扩展数据 + // ReSharper disable once ReturnTypeCanBeNotNullable public static XRecordDataList? GetXRecord(this DBDictionary dict, string key) { - var rec = dict.GetAt(key); - if (rec is null) - return null; - return rec.Data; + return dict.GetData(key) is Xrecord { Data: not null } xr ? xr.Data : null; } /// @@ -84,33 +117,39 @@ public static void SetAt(this DBDictionary dict, string key, T newValue, Tran /// 扩展数据 /// 字典 /// 键值 - public static void SetXRecord(this DBDictionary dict, string key, XRecordDataList rb) + /// 字典项的Id + public static ObjectId SetXRecord(this DBDictionary dict, string key, XRecordDataList rb) { // DxfCode.300 字符串可以写 Data // DxfCode.1004 内存流不给写 Data,只能去写 XData - using Xrecord newValue = new() { Data = rb }; - dict.SetAt(key, newValue); + Xrecord newValue = new(); + newValue.Data = rb; + return dict.SetData(key, newValue); } + #endregion /// /// 获取扩展字典 /// /// 对象 - /// 事务 + /// 打开模式 /// 扩展字典对象 - public static DBDictionary? GetXDictionary(this DBObject obj, DBTrans? trans = null) + public static DBDictionary GetXDictionary(this DBObject obj, OpenMode openMode = OpenMode.ForRead) { - trans ??= DBTrans.Top; - ObjectId id = obj.ExtensionDictionary; + var tr = DBTrans.GetTopTransaction(obj.Database); + var id = obj.ExtensionDictionary; if (id.IsNull) { using (obj.ForWrite()) + { obj.CreateExtensionDictionary(); + } id = obj.ExtensionDictionary; } - return id.GetObject(trans: trans); + + return (DBDictionary)tr.GetObject(id, openMode); } #region 数据表 @@ -127,22 +166,24 @@ public static DataTable CreateDataTable(Dictionary colTypes, o foreach (var t in colTypes) table.AppendColumn(t.Value, t.Key); - var ncol = colTypes.Count; - var types = new CellType[ncol]; + var nCol = colTypes.Count; + var types = new CellType[nCol]; colTypes.Values.CopyTo(types, 0); - var nrow = content.GetLength(0); - for (int i = 0; i < nrow; i++) + var nRow = content.GetLength(0); + for (var i = 0; i < nRow; i++) { DataCellCollection row = new(); - for (int j = 0; j < ncol; j++) + for (var j = 0; j < nCol; j++) { var cell = new DataCell(); cell.SetValue(types[j], content[i, j]); row.Add(cell); } + table.AppendRow(row, true); } + return table; } @@ -157,121 +198,109 @@ public static void SetValue(this DataCell cell, CellType type, object value) switch (type) { case CellType.Bool: - cell.SetBool((bool)value); - break; + cell.SetBool((bool)value); + break; case CellType.CharPtr: - cell.SetString((string)value); - break; + cell.SetString((string)value); + break; case CellType.Integer: - cell.SetInteger((int)value); - break; + cell.SetInteger((int)value); + break; case CellType.Double: - cell.SetDouble((double)value); - break; + cell.SetDouble((double)value); + break; case CellType.ObjectId: - cell.SetObjectId((ObjectId)value); - break; + cell.SetObjectId((ObjectId)value); + break; case CellType.Point: - cell.SetPoint((Point3d)value); - break; + cell.SetPoint((Point3d)value); + break; case CellType.Vector: - cell.SetVector((Vector3d)value); - break; + cell.SetVector((Vector3d)value); + break; case CellType.HardOwnerId: - cell.SetHardOwnershipId((ObjectId)value); - break; + cell.SetHardOwnershipId((ObjectId)value); + break; case CellType.HardPtrId: - cell.SetHardPointerId((ObjectId)value); - break; + cell.SetHardPointerId((ObjectId)value); + break; case CellType.SoftOwnerId: - cell.SetSoftOwnershipId((ObjectId)value); - break; + cell.SetSoftOwnershipId((ObjectId)value); + break; case CellType.SoftPtrId: - cell.SetSoftPointerId((ObjectId)value); - break; + cell.SetSoftPointerId((ObjectId)value); + break; } } + #endregion #region 子字典 + /// /// 获取子字典 /// /// 根字典 - /// 事务 /// 是否创建子字典 /// 键值列表 /// 字典 - public static DBDictionary? GetSubDictionary(this DBDictionary dict, - bool createSubDictionary, - IEnumerable dictNames, - DBTrans? trans = null) + public static DBDictionary? GetSubDictionary(this DBDictionary dict, bool createSubDictionary, + IEnumerable dictNames) { - DBDictionary? newdict = null; - trans ??= DBTrans.Top; + DBDictionary? newDict = null; + if (createSubDictionary) { using (dict.ForWrite()) dict.TreatElementsAsHard = true; - foreach (string name in dictNames) + foreach (var name in dictNames) { if (dict.Contains(name)) { - newdict = dict.GetAt(name, trans); + newDict = dict.GetData(name) as DBDictionary; } else { DBDictionary subDict = new(); - dict.SetAt(name, subDict, trans); - newdict = subDict; - newdict.TreatElementsAsHard = true; + dict.SetData(name, subDict); + newDict = subDict; + newDict.TreatElementsAsHard = true; } } } else { - foreach (string name in dictNames) + foreach (var name in dictNames) { if (dict.Contains(name)) - newdict = dict.GetAt(name, trans); + newDict = dict.GetData(name); else return null; } } - return newdict; - } - - ///// - ///// 获取对象扩展字典的子字典 - ///// - ///// 对象 - ///// 事务 - ///// 是否创建子字典 - ///// 键值列表 - ///// 字典 - // public static DBDictionary GetSubDictionary(this DBObject obj, bool createSubDictionary, params string[] dictNames) - // { - // return obj.GetXDictionary().GetSubDictionary(createSubDictionary, dictNames); - // } + return newDict; + } #endregion #region 组字典 + /// /// 添加编组 /// + /// 字典 /// 组名 /// 实体Id集合 /// 编组Id @@ -285,7 +314,8 @@ public static ObjectId AddGroup(this DBDictionary dict, string name, ObjectIdCol Group g = new(); g.Append(ids); dict.SetAt(name, g); - DBTrans.Top.Transaction.AddNewlyCreatedDBObject(g, true); + var tr = DBTrans.GetTopTransaction(dict.Database); + tr.AddNewlyCreatedDBObject(g, true); return g.ObjectId; } } @@ -293,6 +323,7 @@ public static ObjectId AddGroup(this DBDictionary dict, string name, ObjectIdCol /// /// 添加编组 /// + /// 字典 /// 组名 /// 实体Id集合 /// 编组Id @@ -301,7 +332,7 @@ public static ObjectId AddGroup(this DBDictionary dict, string name, IEnumerable if (dict.Contains(name)) return ObjectId.Null; - using ObjectIdCollection idc = new(ids.ToArray());//需要using吗? 暂无测试 + using ObjectIdCollection idc = new(ids.ToArray()); //需要using吗? 暂无测试 return dict.AddGroup(name, idc); } @@ -309,13 +340,13 @@ public static ObjectId AddGroup(this DBDictionary dict, string name, IEnumerable /// /// 按选择条件获取编组集合 /// + /// 字典 /// 选择条件,过滤函数 /// g.NumEntities < 2);]]> /// 编组集合 public static IEnumerable GetGroups(this DBDictionary dict, Func func) { - return dict.GetAllObjects() - .Where(func); + return dict.GetAllObjects().Where(func); } /// @@ -325,10 +356,8 @@ public static IEnumerable GetGroups(this DBDictionary dict, Func编组集合 public static IEnumerable GetGroups(this Entity ent) { - return ent.GetPersistentReactorIds() - .Cast() - .Select(id => id.GetObject()) - .OfType(); + return ent.GetPersistentReactorIds().Cast().Select(id => id.GetObject()) + .OfType(); } /// @@ -338,36 +367,46 @@ public static IEnumerable GetGroups(this Entity ent) public static List RemoveNullGroup(this DBDictionary dict) { var groups = dict.GetGroups(g => g.NumEntities < 2); - List names = new(); - foreach (Group g in groups) + List names = []; + foreach (var g in groups) { names.Add(g.Name); using (g.ForWrite()) + { g.Erase(); + } } + return names; } /// /// 移除所有空组 /// + /// /// 过滤条件,过滤要删除的组名的规则函数 - /// RemoveNullGroup(g => g.StartsWith("hah")) + /// + /// g.StartsWith("hah"));]]> + /// /// 被移除编组的名称集合 public static List RemoveNullGroup(this DBDictionary dict, Func func) { var groups = dict.GetGroups(g => g.NumEntities < 2); - List names = new(); - foreach (Group g in groups) + List names = []; + foreach (var g in groups) { if (func(g.Name)) { names.Add(g.Name); using (g.ForWrite()) + { g.Erase(); + } } } + return names; } + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/DBObjectEx.cs b/src/CADShared/ExtensionMethod/DBObjectEx.cs similarity index 59% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/DBObjectEx.cs rename to src/CADShared/ExtensionMethod/DBObjectEx.cs index 9733d949f1495bf0f4b704da285824f30f50e305..9d1f9ab31e48075112197153808a938deaa0f92c 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/DBObjectEx.cs +++ b/src/CADShared/ExtensionMethod/DBObjectEx.cs @@ -1,13 +1,33 @@ -using System.Linq; - -namespace IFoxCAD.Cad; +namespace IFoxCAD.Cad; /// /// 实体对象扩展类 /// public static class DBObjectEx { + #region Linq + + /// + /// 删除数据库对象 + /// + /// 数据库对象列表 + public static void Erase(this IEnumerable dBObjects) + { + foreach (var dbo in dBObjects) + { + if (dbo.IsNewObject || dbo.IsErased) + continue; + using (dbo.ForWrite()) + { + dbo.Erase(); + } + } + } + + #endregion + #region Xdata扩展 + /// /// 删除扩展数据 /// @@ -16,22 +36,22 @@ public static class DBObjectEx /// 要删除数据的组码 public static void RemoveXData(this DBObject obj, string appName, DxfCode dxfCode) { - if (obj.XData == null) + if (obj.XData is null) return; XDataList data = obj.XData; - // 测试命令 addxdata removexdata // 移除指定App的扩展 - var indexs = data.GetXdataAppIndex(appName, new DxfCode[] { dxfCode }); - if (indexs.Count == 0) + var indexes = data.GetXdataAppIndex(appName, [dxfCode]); + if (indexes.Count == 0) return; - for (int i = indexs.Count - 1; i >= 0; i--) - data.RemoveAt(indexs[i]); + for (var i = indexes.Count - 1; i >= 0; i--) + data.RemoveAt(indexes[i]); using (obj.ForWrite()) obj.XData = data; } + /// /// 删除扩展数据 /// @@ -39,16 +59,24 @@ public static void RemoveXData(this DBObject obj, string appName, DxfCode dxfCod /// 应用程序名称 public static void RemoveXData(this DBObject obj, string appName) { - if (obj.XData == null) + if (obj.GetXDataForApplication(appName) is null) return; - foreach (var data in obj.XData) - { - // 直接赋值进去等于清空名称 - using var rb = new ResultBuffer(); - rb.Add(new((int)DxfCode.ExtendedDataRegAppName, appName)); - using (obj.ForWrite()) - obj.XData = rb; - } + + // 直接赋值进去等于清空名称 + using (obj.ForWrite()) + obj.XData = new XDataList { { 1001, appName } }; + } + + /// + /// 克隆对象 + /// + /// 对象类型 + /// 对象 + /// 克隆后的对象 + /// + public static T CloneEx(this T obj) where T : ICloneable + { + return obj.Clone() is T tObj ? tObj : throw new ArgumentException(nameof(CloneEx) + "克隆出错"); } /// @@ -57,48 +85,51 @@ public static void RemoveXData(this DBObject obj, string appName) /// 对象实例 /// 应用程序名称 /// 要修改数据的组码 - /// 新的数据 - public static void ChangeXData(this DBObject obj, string appName, DxfCode dxfCode, object newvalue) + /// 新的数据 + public static void ChangeXData(this DBObject obj, string appName, DxfCode dxfCode, + object newValue) { - if (obj.XData == null) + if (obj.XData is null) return; XDataList data = obj.XData; - var indexs = data.GetXdataAppIndex(appName, new DxfCode[] { dxfCode }); - if (indexs.Count == 0) + var indexes = data.GetXdataAppIndex(appName, [dxfCode]); + if (indexes.Count == 0) return; - for (int i = indexs.Count - 1; i >= 0; i--) - data[indexs[i]] = new TypedValue((short)dxfCode, newvalue); + for (var i = indexes.Count - 1; i >= 0; i--) + data[indexes[i]] = new TypedValue((short)dxfCode, newValue); using (obj.ForWrite()) obj.XData = data; } + #endregion #region 读写模式切换 #line hidden // 调试的时候跳过它 /// - /// 实体自动管理读写函数 + /// 实体自动管理读写函数,此函数性能比using模式低一倍 /// /// 实体类型 /// 实体对象 /// 操作委托 public static void ForWrite(this T obj, Action action) where T : DBObject { - var _isNotifyEnabled = obj.IsNotifyEnabled; - var _isWriteEnabled = obj.IsWriteEnabled; - if (_isNotifyEnabled) + var isNotifyEnabled = obj.IsNotifyEnabled; + var isWriteEnabled = obj.IsWriteEnabled; + if (isNotifyEnabled) obj.UpgradeFromNotify(); - else if (!_isWriteEnabled) + else if (!isWriteEnabled) obj.UpgradeOpen(); + // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract action?.Invoke(obj); - if (_isNotifyEnabled) - obj.DowngradeToNotify(_isWriteEnabled); - else if (!_isWriteEnabled) + if (isNotifyEnabled) + obj.DowngradeToNotify(isWriteEnabled); + else if (!isWriteEnabled) obj.DowngradeOpen(); } @@ -149,5 +180,6 @@ public void Dispose() #endregion IDisposable 成员 } #line default + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/DBTransEx.cs b/src/CADShared/ExtensionMethod/DBTransEx.cs similarity index 86% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/DBTransEx.cs rename to src/CADShared/ExtensionMethod/DBTransEx.cs index fdd4e91ced58800d71fb95a71df1055170ec92bd..f28d4513e80329b2aa8dcc9bdb3497460192fb81 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/DBTransEx.cs +++ b/src/CADShared/ExtensionMethod/DBTransEx.cs @@ -3,6 +3,9 @@ namespace IFoxCAD.Cad; #if lack_test +/// +/// 事务类扩展 +/// public static class DBTransEx { /* @@ -10,7 +13,7 @@ public static class DBTransEx * db.Purge(ids)是获取未硬引用(无引用?)的对象,也就可以删除的. * 0x02 * 如果一个图元引用一个图层, - * 假设这个图元是可以删除的(实际上它可能来自于词典记录的id) => 那么它被 db.Purge(ids) 识别, + * 假设这个图元是可以删除的(实际上它可能来自词典记录的id) => 那么它被 db.Purge(ids) 识别, * 但是这个图层因为有硬引用,所以不被 db.Purge(ids) 识别, * 只能删除图元之后,循环第二次再通过 db.Purge(ids) 获取图层id. * 0x03 @@ -37,11 +40,13 @@ public static void Purge(this DBTrans tr, SymModes sym = SymModes.All, bool excl if (!excludeXref) GetAllIds(tr, tr.BlockTable, ids, excludeXref); else - tr.BlockTable.ForEach(tabRec => { + tr.BlockTable.ForEach(tabRec => + { if (!tabRec.IsFromExternalReference) ids.Add(tabRec.Id); }, checkIdOk: true); } + if ((sym & SymModes.DimStyleTable) == SymModes.DimStyleTable) GetAllIds(tr, tr.DimStyleTable, ids, excludeXref); if ((sym & SymModes.LayerTable) == SymModes.LayerTable) @@ -67,18 +72,16 @@ public static void Purge(this DBTrans tr, SymModes sym = SymModes.All, bool excl id.Erase(); } - static void GetAllIds(DBTrans tr, - SymbolTable symbolTable, - ObjectIdCollection ids, - bool excludeXref = true) - where TTable : SymbolTable - where TRecord : SymbolTableRecord, new() + private static void GetAllIds(DBTrans tr, SymbolTable symbolTable, + ObjectIdCollection ids, bool excludeXref = true) where TTable : SymbolTable + where TRecord : SymbolTableRecord, new() { if (!excludeXref) symbolTable.ForEach(id => ids.Add(id)); else { - symbolTable.ForEach(id => { + symbolTable.ForEach(id => + { var tabRec = tr.GetObject(id); if (tabRec == null) return; diff --git a/src/CADShared/ExtensionMethod/DatabaseEx.cs b/src/CADShared/ExtensionMethod/DatabaseEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..a2cd7113123f44f2492cf59e27440db8e6fff11d --- /dev/null +++ b/src/CADShared/ExtensionMethod/DatabaseEx.cs @@ -0,0 +1,224 @@ +namespace IFoxCAD.Cad; + +/// +/// 数据库扩展函数 +/// +public static class DatabaseEx +{ +#if zcad + + /// + /// 审查 + /// + /// 数据库 + /// 修复错误 + /// 输出 + public static void Audit(this Database db, bool fixError, bool cmdEcho) + { + ZcedAudit(db.UnmanagedObject, fixError, cmdEcho); + } + + [DllImport(DllFileNames.ZwCadExe, + EntryPoint = "?zcedAudit@@YA?AW4ErrorStatus@Zcad@@PEAVZcDbDatabase@@_N1@Z", + CallingConvention = CallingConvention.Cdecl)] + private static extern int ZcedAudit(IntPtr pDatabase, + [MarshalAs(UnmanagedType.I1)] bool fixErrors, [MarshalAs(UnmanagedType.I1)] bool cmdEcho); + +#endif + + /// + /// 打开切换活动数据库 + /// + /// 当前数据库 + /// 切换数据库对象 + public static SwitchDatabase SwitchDatabase(this Database db) => new(db); + + /// + /// 保存文件 + /// + /// 数据库 + /// 文件版本 + public static void SaveDwgFile(this Database db, DwgVersion version = DwgVersion.AC1800) + { + db.SaveFile(version); + } + + /// + /// 保存文件
+ ///
+ /// 数据库 + /// 默认2004dwg;若保存dxf则需要在路径输入扩展名 + /// 为true时候无效,将变为自动识别环境变量 + /// 另存为文件,前台将调用时它将无效,将变为弹出面板 + /// 保存路径失败的提示 + public static void SaveFile(this Database db, DwgVersion version = DwgVersion.AC1800, + bool automatic = true, string? saveAsFile = null, bool echoes = true) + { + // 遍历当前所有文档,文档必然是前台的 + Document? doc = null; + foreach (Document docItem in Acaop.DocumentManager) + { + if (docItem.Database.Filename == db.Filename) + { + doc = docItem; + break; + } + } + + // 前台开图,使用命令保存;不需要切换文档 + if (doc != null) + { + // 无法把 给这个面板 + doc.SendStringToExecute(saveAsFile == null ? "_qSave\n" : $"_SaveAs\n", false, true, + true); + return; + } + + // 后台开图,用数据库保存 + string? fileMsg; + var creatFlag = false; + if (string.IsNullOrWhiteSpace(saveAsFile)) + { + fileMsg = db.Filename; + saveAsFile = fileMsg; + //creatFlag = true; + } + else + { + fileMsg = saveAsFile; + + // 路径失败也保存到桌面 + var path = Path.GetDirectoryName(saveAsFile); + if (string.IsNullOrWhiteSpace(path)) + { + creatFlag = true; + } + else if (!Directory.Exists(path)) + { + try + { + Directory.CreateDirectory(path); + } + catch + { + creatFlag = true; + } + } + + // 文件名缺失时 + if (!creatFlag && string.IsNullOrWhiteSpace(Path.GetFileName(saveAsFile))) + creatFlag = true; + } + + if (saveAsFile != null) + { + var fileNameWith = Path.GetFileNameWithoutExtension(saveAsFile); + if (string.IsNullOrWhiteSpace(fileNameWith)) + creatFlag = true; + } + else + { + creatFlag = true; + } + + if (creatFlag) + { + var (error, file) = db.GetOrCreateSaveAsFile(); + if (echoes && error) + System.Windows.Forms.MessageBox.Show($@"错误参数: +{fileMsg} + +它将保存: +{file}", "错误的文件路径"); + saveAsFile = file; + } + + if (Path.GetExtension(saveAsFile)!.ToLower().Contains("dxf")) + { + // dxf用任何版本号都会报错 +#if acad || gcad + db.DxfOut(saveAsFile, 7, true); +#endif +#if zcad // 中望这里没有测试 + db.DxfOut(saveAsFile, 7, version); +#endif + return; + } + + if (automatic) + version = Env.GetDefaultDwgVersion(); + + // dwg需要版本号,而dxf不用,dwg用dxf版本号会报错 + // 若扩展名和版本号冲突,按照扩展名为准 + if (version.IsDxfVersion()) + version = DwgVersion.Current; + db.SaveAs(saveAsFile, version); + } + + /// + /// 获取文件名,无效的话就制造 + /// + /// + private static (bool error, string path) GetOrCreateSaveAsFile(this Database db) + { + var file = db.Filename; + if (!string.IsNullOrWhiteSpace(file)) + return (false, file); + + // 为了防止用户输入了错误的路径造成无法保存, + // 所以此处将进行保存到桌面, + // 而不是弹出警告就结束 + // 防止前台关闭了所有文档导致没有Editor,所以使用 MessageBox 发送警告 + var fileName = Path.GetFileNameWithoutExtension(file); + var fileExt = Path.GetExtension(file); + if (string.IsNullOrWhiteSpace(fileName)) + // ReSharper disable once StringLiteralTypo + fileName = DateTime.Now.ToString("--yyMMdd--hhmmssffff"); + if (string.IsNullOrWhiteSpace(fileExt)) + fileExt = ".dwg"; + + // 构造函数(fileName)用了不存在的路径进行后台打开,就会出现此问题 + // 测试命令 FileNotExist + var dir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + + "\\后台保存出错的文件\\"; + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + file = dir + fileName + fileExt; + while (File.Exists(file)) + { + // ReSharper disable once StringLiteralTypo + var time = DateTime.Now.ToString("--yyMMdd--hhmmssffff"); + file = dir + fileName + time + fileExt; + Thread.Sleep(100); + } + + return (true, file); + } +} + +/// +/// 自动切换活动数据库 +/// +public class SwitchDatabase : IDisposable +{ + private readonly Database _db; + + /// + /// 切换活动数据库 + /// + /// 当前数据库 + public SwitchDatabase(Database database) + { + _db = HostApplicationServices.WorkingDatabase; + HostApplicationServices.WorkingDatabase = database; + } + + /// + /// 恢复活动数据库为默认 + /// + public void Dispose() + { + HostApplicationServices.WorkingDatabase = _db; + GC.SuppressFinalize(this); + } +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/DocumentLockManager.cs b/src/CADShared/ExtensionMethod/DocumentLockManager.cs new file mode 100644 index 0000000000000000000000000000000000000000..60040655b4ab3be49bc5db9d038ca5517a43ff5e --- /dev/null +++ b/src/CADShared/ExtensionMethod/DocumentLockManager.cs @@ -0,0 +1,59 @@ +namespace IFoxCAD.Cad; + +/// +/// 文档锁管理器,用于管理文档的锁定和解锁。 +/// +public sealed class DocumentLockManager : IDisposable +{ + /// + /// 用于存储文档锁的实例,如果文档未锁定则为null。 + /// + private readonly DocumentLock? _documentLock; + + /// + /// 初始化DocumentLockManager实例。 + /// + /// 需要进行锁定管理的文档。 + internal DocumentLockManager(Document doc) + { + // 如果文档未锁定,则尝试锁定文档,否则不创建锁实例。 + _documentLock = doc.LockMode(false) == DocumentLockMode.NotLocked ? doc.LockDocument() : null; + } + + /// + /// 表示当前实例是否已被释放。 + /// + public bool IsDisposed { get; private set; } + + /// + /// 释放当前实例持有的资源。 + /// + public void Dispose() + { + // 如果资源已经被释放,则不再次释放。 + if (IsDisposed) + return; + // 释放文档锁资源,如果存在的话。 + _documentLock?.Dispose(); + + // 标记当前实例为已释放状态。 + IsDisposed = true; + } +} + +/// +/// 提供Document类型的扩展方法来方便创建DocumentLockManager实例。 +/// +public static class DocumentLockManagerExtension +{ + /// + /// 安全锁定文档,返回一个新的DocumentLockManager实例。 + /// + /// 需要进行锁定的文档。 + /// DocumentLockManager实例,用于管理文档锁。 + public static DocumentLockManager SecurelyLock(this Document doc) + { + // 创建并返回DocumentLockManager实例。 + return new DocumentLockManager(doc); + } +} diff --git a/src/CADShared/ExtensionMethod/DwgMark.cs b/src/CADShared/ExtensionMethod/DwgMark.cs new file mode 100644 index 0000000000000000000000000000000000000000..501da985663edaa07ff440e0d038b0bf5cef57ec --- /dev/null +++ b/src/CADShared/ExtensionMethod/DwgMark.cs @@ -0,0 +1,70 @@ +namespace IFoxCAD.Cad; + +/// +/// 为dwg文件添加标记 +/// +public static class DwgMark +{ + private const int kFreeSpace = 0x15; + private const int kFreeSpaceDefault = 0x00; + + /// + /// 为dwg文件添加标识 + /// + /// DWG文件 + /// ASCII标识字节0X00~0X7F + /// 非dwg文件会报错,给定bite超界限也报错 + public static void AddMark(FileInfo file, int bite) + { + if (file.Extension.ToLower() != ".dwg") + { + throw new ArgumentException("必须是dwg文件!"); + } + + if (bite > 0x7F || bite < 0x00) + { + throw new ArgumentException("字符必须在ASCII范围!"); + } + + using var bw = new BinaryWriter(File.Open(file.FullName, FileMode.Open)); + bw.BaseStream.Position = kFreeSpace; //文件头第21个字节 + bw.Write(bite); //写入数据,仅一个字节 + } + + /// + /// 将dwg文件标记恢复为默认值 + /// + /// 文件 + /// 非dwg文件会报错 + public static void RemoveMark(FileInfo file) + { + if (file.Extension.ToLower() != ".dwg") + { + throw new ArgumentException("必须是dwg文件!"); + } + + using var bw = new BinaryWriter(File.Open(file.FullName, FileMode.Open)); + bw.BaseStream.Position = kFreeSpace; //文件头第21个字节 + bw.Write(kFreeSpaceDefault); //写入数据,仅一个字节 + } + + /// + /// 获取设置的dwg文件标记 + /// + /// 文件 + /// + /// 非dwg文件会报错 + public static int GetMark(FileInfo file) + { + if (file.Extension.ToLower() != ".dwg") + { + throw new ArgumentException("必须是dwg文件!"); + } + + using var fs = File.OpenRead(file.FullName); + fs.Seek(kFreeSpace, SeekOrigin.Begin); + var mark = new byte[1]; + _ = fs.Read(mark, 0, mark.Length); + return mark[0]; + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/EditorEx.cs b/src/CADShared/ExtensionMethod/EditorEx.cs similarity index 67% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/EditorEx.cs rename to src/CADShared/ExtensionMethod/EditorEx.cs index d432bf33e86a6d4b932b5132aa27d7efcacb5f87..bd18a46727efd99b88e8a97e03e10449c61e54bd 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/EditorEx.cs +++ b/src/CADShared/ExtensionMethod/EditorEx.cs @@ -1,4 +1,5 @@ -using IFoxCAD.Com; +using ArgumentNullException = System.ArgumentNullException; +// ReSharper disable MemberCanBePrivate.Global namespace IFoxCAD.Cad; @@ -8,6 +9,7 @@ namespace IFoxCAD.Cad; public static class EditorEx { #region 选择集 + /// /// 选择穿过一个点的对象 /// @@ -16,9 +18,9 @@ public static class EditorEx /// 过滤器 /// 选择集结果类 public static PromptSelectionResult SelectAtPoint(this Editor editor, Point3d point, - SelectionFilter? filter = default) + SelectionFilter? filter = null) { - return editor.SelectCrossingWindow(point, point, filter); + return editor.SelectCrossingWindow(point, point, filter?? new SelectionFilter([])); } /// @@ -31,25 +33,17 @@ public static SelectionSet SelectByLineWeight(this Editor editor, LineWeight lin { OpFilter filter = new OpEqual(370, lineWeight); - var lays = - DBTrans.Top.LayerTable - .GetRecords() + var lays = DBTrans.Top.LayerTable.GetRecords() .Where(ltr => ltr.LineWeight == lineWeight) .Select(ltr => ltr.Name) .ToArray(); if (lays.Length > 0) { - filter = - new OpOr - { - filter, - new OpAnd - { - { 8, string.Join(",", lays) }, - { 370, LineWeight.ByLayer } - } - }; + filter = new OpOr + { + filter, new OpAnd { { 8, string.Join(",", lays) }, { 370, LineWeight.ByLayer } } + }; } var res = editor.SelectAll(filter); @@ -63,16 +57,16 @@ public static SelectionSet SelectByLineWeight(this Editor editor, LineWeight lin /// 模式 /// 过滤器 /// 消息 - /// 关键字和回调函数 + /// + /// 关键字和回调函数 + /// 不用使用下列关键字 "Window/Last/Crossing/BOX/ALL/Fence/WPolygon/CPolygon/Group/Add/Remove/Multiple/Previous/Undo/AUto/Single" + /// /// - public static PromptSelectionResult SSGet(this Editor editor, - string? mode = null, - SelectionFilter? filter = null, - string[]? messages = null, - Dictionary? keywords = null) + public static PromptSelectionResult SSGet(this Editor editor, string? mode = null, + SelectionFilter? filter = null, (string add, string remove)? messages = null, + Dictionary? keywords = null) { PromptSelectionOptions pso = new(); - PromptSelectionResult ss; if (mode is not null) { mode = mode.ToUpper(); @@ -87,10 +81,11 @@ public static PromptSelectionResult SSGet(this Editor editor, pso.AllowSubSelections = mode.Contains("-A"); pso.ForceSubSelections = mode.Contains("-F"); } + if (messages is not null) { - pso.MessageForAdding = messages[0]; - pso.MessageForRemoval = messages[1]; + pso.MessageForAdding = messages.Value.add; + pso.MessageForRemoval = messages.Value.remove; } if (keywords is not null) @@ -99,28 +94,25 @@ public static PromptSelectionResult SSGet(this Editor editor, pso.Keywords.Add(keyword); if (pso.MessageForRemoval is null) pso.MessageForAdding = "选择对象"; - pso.MessageForAdding += $"[{string.Join(" / ", keywords.Keys.ToArray())}]"; - pso.KeywordInput += (s, e) => { - if (keywords.ContainsKey(e.Input)) - keywords[e.Input].Invoke(); + + var str = keywords.Keys.Select(key => + { + keywords.TryGetValue(key, out (string, Action) value); + return $"{value.Item1}({key})"; + }); + + pso.MessageForAdding += $" [{string.Join("/", str)}]"; + pso.KeywordInput += (_, e) => + { + if (keywords.TryGetValue(e.Input, out var value)) + value.Item2.Invoke(); }; } - try - { - if (filter is not null) - ss = editor.GetSelection(pso, filter); - else - ss = editor.GetSelection(pso); - } - catch (Exception) - { - //editor.WriteMessage($"\nKey is {e.Message}"); - throw; - } + + var ss = filter is not null ? editor.GetSelection(pso, filter) : editor.GetSelection(pso); return ss; } - /* * // 定义选择集选项 * var pso = new PromptSelectionOptions @@ -158,13 +150,12 @@ public static PromptSelectionResult SSGet(this Editor editor, /// /// 选择集配置 /// 关键字,回调委托 - /// public static void SsgetAddKeys(this PromptSelectionOptions pso, Dictionary dicActions) { Dictionary tmp = new(); // 后缀名的|号切割,移除掉,组合成新的加入tmp - for (int i = dicActions.Count - 1; i >= 0; i--) + for (var i = dicActions.Count - 1; i >= 0; i--) { var pair = dicActions.ElementAt(i); var key = pair.Key; @@ -172,19 +163,18 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, if (keySp.Length < 2) continue; - for (int j = 0; j < keySp.Length; j++) + foreach (var item in keySp) { - var item = keySp[j]; // 防止多个后缀通过|符越过词典约束同名 // 后缀(key)含有,而且Action(value)不同,就把Action(value)累加到后面. - if (dicActions.ContainsKey(item)) + if (dicActions.TryGetValue(item, out var value)) { if (dicActions[item] != dicActions[key]) dicActions[item] += dicActions[key]; } - else - tmp.Add(item, dicActions[key]); + else if (value != null) tmp.Add(item, value); } + dicActions.Remove(key); } @@ -192,12 +182,12 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, dicActions.Add(item.Key, item.Value); // 去除关键字重复的,把重复的执行动作移动到前面 - for (int i = 0; i < dicActions.Count; i++) + for (var i = 0; i < dicActions.Count; i++) { var pair1 = dicActions.ElementAt(i); var key1 = pair1.Key; - for (int j = dicActions.Count - 1; j > i; j--) + for (var j = dicActions.Count - 1; j > i; j--) { var pair2 = dicActions.ElementAt(j); var key2 = pair2.Key; @@ -213,10 +203,10 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, foreach (var item in dicActions) { - var keySplitS = item.Key.Split(new string[] { ",", "|" }, StringSplitOptions.RemoveEmptyEntries); - for (int i = 0; i < keySplitS.Length; i += 2) + var keySplitS = item.Key.Split([",", "|"], StringSplitOptions.RemoveEmptyEntries); + for (var i = 0; i < keySplitS.Length; i += 2) pso.Keywords.Add(keySplitS[i], keySplitS[i], - keySplitS[i + 1] + "(" + keySplitS[i] + ")"); + keySplitS[i + 1] + "(" + keySplitS[i] + ")"); } // 回调的时候我想用Dict的O(1)索引, @@ -231,16 +221,9 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, // 从选择集命令中显示关键字 pso.MessageForAdding = keyWords.GetDisplayString(true); // 关键字回调事件 ssget关键字 - pso.KeywordInput += (sender, e) => { - dicActions[e.Input].Invoke(); - }; + pso.KeywordInput += (_, e) => { dicActions[e.Input].Invoke(); }; } - - - - - // #region 即时选择样板 // /// // /// 即时选择,框选更新关键字 @@ -252,7 +235,6 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, // Env.Editor.SelectionAdded += SelectTest_SelectionAdded; // // 初始化坐标系 // Env.Editor.CurrentUserCoordinateSystem = Matrix3d.Identity; - // // 创建过滤器 // var sf = new OpEqual(0, "arc"); // var pso = new PromptSelectionOptions @@ -270,8 +252,6 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, // // 用户选择 // var psr = Env.Editor.GetSelection(pso, sf); // // 处理代码 - - // } // catch (Exception ex)// 捕获关键字 // { @@ -335,6 +315,7 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, // throw new ArgumentException("XuError"); // } // #endregion + #endregion #region Info @@ -362,7 +343,7 @@ public static void StreamMessage(string message) else InfoMessageBox(message); } - catch (System.Exception ex) + catch (Exception ex) { Message(ex); } @@ -372,18 +353,17 @@ public static void StreamMessage(string message) /// 异常信息对话框 /// /// 异常 - public static void Message(System.Exception ex) + public static void Message(Exception ex) { try { - System.Windows.Forms.MessageBox.Show( - ex.ToString(), - "Error", + System.Windows.Forms.MessageBox.Show(ex.ToString(), "Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error); } catch { + // ignored } } @@ -396,13 +376,11 @@ public static void InfoMessageBox(string caption, string message) { try { - System.Windows.Forms.MessageBox.Show( - message, - caption, + System.Windows.Forms.MessageBox.Show(message, caption, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); } - catch (System.Exception ex) + catch (Exception ex) { Message(ex); } @@ -447,11 +425,9 @@ public static void WriteMessage(string message) try { if (Acceptable()) - Acap.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n" + message); - else - return; + Acaop.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n" + message); } - catch (System.Exception ex) + catch (Exception ex) { Message(ex); } @@ -473,9 +449,9 @@ public static void WriteMessage(string format, params object[] args) /// 有,没有 public static bool HasEditor() { - return Acap.DocumentManager.MdiActiveDocument is not null - && Acap.DocumentManager.Count != 0 - && Acap.DocumentManager.MdiActiveDocument.Editor is not null; + return Acaop.DocumentManager.MdiActiveDocument is not null && + Acaop.DocumentManager.Count != 0 && + Acaop.DocumentManager.MdiActiveDocument.Editor is not null; } /// @@ -484,8 +460,7 @@ public static bool HasEditor() /// 可以打印,不可以打印 public static bool Acceptable() { - return HasEditor() - && !Acap.DocumentManager.MdiActiveDocument.Editor.IsDragging; + return HasEditor() && !Acaop.DocumentManager.MdiActiveDocument.Editor.IsDragging; } #endregion Info @@ -500,28 +475,26 @@ public static bool Acceptable() /// public static List GetLines(IEnumerable pnts, bool isClosed) { - var itor = pnts.GetEnumerator(); - if (!itor.MoveNext()) - return new List(); + using var enumerator = pnts.GetEnumerator(); + if (!enumerator.MoveNext()) + return []; - List values = new(); + List values = []; - TypedValue tvFirst = new((int)LispDataType.Point2d, itor.Current); - TypedValue tv1; - TypedValue tv2 = tvFirst; + TypedValue first = new((int)LispDataType.Point2d, enumerator.Current); + var last = first; - while (itor.MoveNext()) + while (enumerator.MoveNext()) { - tv1 = tv2; - tv2 = new TypedValue((int)LispDataType.Point2d, itor.Current); - values.Add(tv1); - values.Add(tv2); + values.Add(last); + last = new TypedValue((int)LispDataType.Point2d, enumerator.Current); + values.Add(last); } if (isClosed) { - values.Add(tv2); - values.Add(tvFirst); + values.Add(last); + values.Add(first); } return values; @@ -534,12 +507,12 @@ public static List GetLines(IEnumerable pnts, bool isClosed /// 点表 /// 颜色码 /// 是否闭合, 为闭合, 为不闭合 - public static void DrawVectors(this Editor editor, IEnumerable pnts, short colorIndex, bool isClosed) + public static void DrawVectors(this Editor editor, IEnumerable pnts, short colorIndex, + bool isClosed) { - var rlst = - new LispList { { LispDataType.Int16, colorIndex } }; + var rlst = new LispList { { LispDataType.Int16, colorIndex } }; rlst.AddRange(GetLines(pnts, isClosed)); - editor.DrawVectors(rlst, editor.CurrentUserCoordinateSystem); + editor.DrawVectors(new(rlst.ToArray()), Matrix3d.Identity); } /// @@ -561,28 +534,26 @@ public static void DrawVectors(this Editor editor, IEnumerable pnts, sh /// 颜色码 /// 半径 /// 多边形边的个数 - public static void DrawCircles(this Editor editor, IEnumerable pnts, short colorIndex, double radius, int numEdges) + public static void DrawCircles(this Editor editor, IEnumerable pnts, short colorIndex, + double radius, int numEdges) { - var rlst = - new LispList { { LispDataType.Int16, colorIndex } }; + var rlst = new LispList { { LispDataType.Int16, colorIndex } }; - foreach (Point2d pnt in pnts) + foreach (var pnt in pnts) { - Vector2d vec = Vector2d.XAxis * radius; - double angle = Math.PI * 2 / numEdges; + var vec = Vector2d.XAxis * radius; + var angle = Math.PI * 2 / numEdges; - List tpnts = new() - { - pnt + vec - }; - for (int i = 1; i < numEdges; i++) + List tpnts = [pnt + vec]; + for (var i = 1; i < numEdges; i++) { tpnts.Add(pnt + vec.RotateBy(angle * i)); } rlst.AddRange(GetLines(tpnts, true)); } - editor.DrawVectors(rlst, editor.CurrentUserCoordinateSystem); + + editor.DrawVectors(new(rlst.ToArray()), editor.CurrentUserCoordinateSystem); } /// @@ -593,21 +564,66 @@ public static void DrawCircles(this Editor editor, IEnumerable pnts, sh /// 颜色码 /// 半径 /// 多边形边的个数 - public static void DrawCircle(this Editor editor, Point2d pnt, short colorIndex, double radius, int numEdges) + public static void DrawCircle(this Editor editor, Point2d pnt, short colorIndex, double radius, + int numEdges) { - Vector2d vec = Vector2d.XAxis * radius; - double angle = Math.PI * 2 / numEdges; + var vec = Vector2d.XAxis * radius; + var angle = Math.PI * 2 / numEdges; - List pnts = new() - { - pnt + vec - }; - for (int i = 1; i < numEdges; i++) + List pnts = [pnt + vec]; + for (var i = 1; i < numEdges; i++) pnts.Add(pnt + vec.RotateBy(angle * i)); editor.DrawVectors(pnts, colorIndex, true); } + /// + /// 根据点表绘制矢量线段(每两点为一条线段的起始点和终止点) + /// + /// 用户交互对象 + /// 点表 + /// CAD颜色索引;默认:1为红色 + /// 是否高亮显示;为高亮显示,默认:为不高亮显示 + public static void DrawLineVectors(this Editor editor, IEnumerable points, + int colorIndex = 1, bool drawHighlighted = false) + { + using var itor = points.GetEnumerator(); + while (itor.MoveNext()) + { + var endPoint1 = itor.Current; + if (!itor.MoveNext()) + return; + var endPoint2 = itor.Current; + editor.DrawVector(endPoint1, endPoint2, colorIndex, drawHighlighted); + } + } + + /// + /// 根据点表绘制首尾相连的矢量 + /// + /// 用户交互对象 + /// 点表 + /// CAD颜色索引;默认:1为红色 + /// 是否闭合; 为闭合,默认: 为不闭合 + /// 是否高亮显示;为高亮显示,默认:为不高亮显示 + public static void DrawEndToEndVectors(this Editor editor, IEnumerable points, + int colorIndex = 1, bool isClose = false, bool drawHighlighted = false) + { + using var itor = points.GetEnumerator(); + if (!itor.MoveNext()) + return; + Point3d endPoint1 = itor.Current, endPoint2 = new(), firstEndPoint = endPoint1; + while (itor.MoveNext()) + { + endPoint2 = itor.Current; + editor.DrawVector(endPoint1, endPoint2, colorIndex, drawHighlighted); + endPoint1 = endPoint2; + } + + if (isClose) + editor.DrawVector(endPoint2, firstEndPoint, colorIndex, drawHighlighted); + } + #endregion #region 矩阵 @@ -633,15 +649,14 @@ public static Matrix3d GetMatrixFromWcsToUcs(this Editor editor) } /// - /// 获取MDCS(模型空间)到WCS的矩阵 + /// 获取MDcs(模型空间)到WCS的矩阵 /// /// 命令行对象 /// 变换矩阵 public static Matrix3d GetMatrixFromMDcsToWcs(this Editor editor) { - Matrix3d mat; - using ViewTableRecord vtr = editor.GetCurrentView(); - mat = Matrix3d.PlaneToWorld(vtr.ViewDirection); + using var vtr = editor.GetCurrentView(); + var mat = Matrix3d.PlaneToWorld(vtr.ViewDirection); mat = Matrix3d.Displacement(vtr.Target - Point3d.Origin) * mat; return Matrix3d.Rotation(-vtr.ViewTwist, vtr.ViewDirection, vtr.Target) * mat; } @@ -666,8 +681,9 @@ public static Matrix3d GetMatrixFromMDcsToPDcs(this Editor editor) if ((short)Env.GetVar("TILEMODE") == 1) throw new ArgumentException("TILEMODE == 1..Espace papier uniquement"); - Matrix3d mat = Matrix3d.Identity; - using DBTrans tr = new(); + var mat = Matrix3d.Identity; + //using DBTrans tr = new(); + var tr = DBTrans.GetTopTransaction(editor.Document.Database); var vp = tr.GetObject(editor.CurrentViewportObjectId); if (vp == null) return mat; @@ -685,6 +701,7 @@ public static Matrix3d GetMatrixFromMDcsToPDcs(this Editor editor) throw new Exception("Aucun fenêtre active...ErrorStatus.InvalidInput"); } } + if (vp == null) return mat; @@ -712,85 +729,38 @@ public static Matrix3d GetMatrixFromPDcsToMDcs(this Editor editor) /// 源坐标系 /// 目标坐标系 /// 变换矩阵 - public static Matrix3d GetMatrix(this Editor editor, CoordinateSystemCode from, CoordinateSystemCode to) + public static Matrix3d GetMatrix(this Editor editor, CoordinateSystemCode from, + CoordinateSystemCode to) { -#if ac2009 - switch (from) - { - case CoordinateSystemCode.Wcs: - switch (to) - { - case CoordinateSystemCode.Ucs: - return editor.GetMatrixFromWcsToUcs(); - - case CoordinateSystemCode.MDcs: - return editor.GetMatrixFromMDcsToWcs(); - - case CoordinateSystemCode.PDcs: - throw new Exception("To be used only with DCS...ErrorStatus.InvalidInput"); - } - break; - case CoordinateSystemCode.Ucs: - switch (to) - { - case CoordinateSystemCode.Wcs: - return editor.GetMatrixFromUcsToWcs(); - - case CoordinateSystemCode.MDcs: - return editor.GetMatrixFromUcsToWcs() * editor.GetMatrixFromWcsToMDcs(); - - case CoordinateSystemCode.PDcs: - throw new Exception("To be used only with DCS... ErrorStatus.InvalidInput"); - } - break; - case CoordinateSystemCode.MDcs: - switch (to) - { - case CoordinateSystemCode.Wcs: - return editor.GetMatrixFromMDcsToWcs(); - - case CoordinateSystemCode.Ucs: - return editor.GetMatrixFromMDcsToWcs() * editor.GetMatrixFromWcsToUcs(); - - case CoordinateSystemCode.PDcs: - return editor.GetMatrixFromMDcsToPDcs(); - } - break; - case CoordinateSystemCode.PDcs: - switch (to) - { - case CoordinateSystemCode.Wcs: - throw new Exception("To be used only with DCS... ErrorStatus.InvalidInput"); - case CoordinateSystemCode.Ucs: - throw new Exception("To be used only with DCS... ErrorStatus.InvalidInput"); - case CoordinateSystemCode.MDcs: - return editor.GetMatrixFromPDcsToMDcs(); - } - break; - } - return Matrix3d.Identity; -#else return (from, to) switch { (CoordinateSystemCode.Wcs, CoordinateSystemCode.Ucs) => editor.GetMatrixFromWcsToUcs(), - (CoordinateSystemCode.Wcs, CoordinateSystemCode.MDcs) => editor.GetMatrixFromWcsToMDcs(), + (CoordinateSystemCode.Wcs, CoordinateSystemCode.MDcs) => + editor.GetMatrixFromWcsToMDcs(), (CoordinateSystemCode.Ucs, CoordinateSystemCode.Wcs) => editor.GetMatrixFromUcsToWcs(), - (CoordinateSystemCode.Ucs, CoordinateSystemCode.MDcs) => editor.GetMatrixFromUcsToWcs() * editor.GetMatrixFromWcsToMDcs(), - (CoordinateSystemCode.MDcs, CoordinateSystemCode.Wcs) => editor.GetMatrixFromMDcsToWcs(), - (CoordinateSystemCode.MDcs, CoordinateSystemCode.Ucs) => editor.GetMatrixFromMDcsToWcs() * editor.GetMatrixFromWcsToUcs(), - (CoordinateSystemCode.MDcs, CoordinateSystemCode.PDcs) => editor.GetMatrixFromMDcsToPDcs(), - (CoordinateSystemCode.PDcs, CoordinateSystemCode.MDcs) => editor.GetMatrixFromPDcsToMDcs(), + (CoordinateSystemCode.Ucs, CoordinateSystemCode.MDcs) => + editor.GetMatrixFromUcsToWcs() * editor.GetMatrixFromWcsToMDcs(), + (CoordinateSystemCode.MDcs, CoordinateSystemCode.Wcs) => + editor.GetMatrixFromMDcsToWcs(), + (CoordinateSystemCode.MDcs, CoordinateSystemCode.Ucs) => + editor.GetMatrixFromMDcsToWcs() * editor.GetMatrixFromWcsToUcs(), + (CoordinateSystemCode.MDcs, CoordinateSystemCode.PDcs) => + editor.GetMatrixFromMDcsToPDcs(), + (CoordinateSystemCode.PDcs, CoordinateSystemCode.MDcs) => + editor.GetMatrixFromPDcsToMDcs(), (CoordinateSystemCode.PDcs, CoordinateSystemCode.Wcs or CoordinateSystemCode.Ucs) - or (CoordinateSystemCode.Wcs or CoordinateSystemCode.Ucs, CoordinateSystemCode.PDcs) => throw new Exception("To be used only with DCS...ErrorStatus.InvalidInput"), + or (CoordinateSystemCode.Wcs or CoordinateSystemCode.Ucs, CoordinateSystemCode.PDcs) + => throw new Exception("To be used only with DCS...ErrorStatus.InvalidInput"), (_, _) => Matrix3d.Identity }; -#endif } #endregion #region 缩放 + // todo 暂时先屏蔽这个又臭又长的代码,待搞明白为什么都这么写之后再说 +#if false /// /// 缩放窗口范围 /// @@ -833,33 +803,55 @@ public static void ZoomWindow(this Editor ed, Point3d minPoint, Point3d maxPoint .Convert2d(Curve2dEx._planeCache); ed.SetCurrentView(vtr); - ed.Regen(); + //ed.Regen(); } +#endif /// /// 缩放窗口范围 /// /// 命令行对象 /// 窗口范围点 - public static void ZoomWindow(this Editor ed, Extents3d ext) + /// 偏移距离 + public static void ZoomWindow(this Editor ed, Extents3d ext, double offsetDist = 0) { - ZoomWindow(ed, ext.MinPoint, ext.MaxPoint); + using var view = ed.GetCurrentView().CloneEx(); + var mt = Matrix3d.WorldToPlane(view.ViewDirection) * + Matrix3d.Displacement(Point3d.Origin - view.Target) * + Matrix3d.Rotation(view.ViewTwist, view.ViewDirection, view.Target); + ext.TransformBy(mt); + var width = ext.MaxPoint.X - ext.MinPoint.X + offsetDist * 2; + var height = ext.MaxPoint.Y - ext.MinPoint.Y + offsetDist * 2; + var ratio = view.Width / view.Height; + if (width / height < ratio) + { + view.Height = height; + view.Width = height * ratio; + } + else + { + view.Height = width / ratio; + view.Width = width; + } + + view.CenterPoint = ext.MinPoint.GetMidPointTo(ext.MaxPoint).Point2d(); + ed.SetCurrentView(view); } /// /// 按范围缩放 /// /// 命令行对象 - /// 中心点 + /// 中心点 /// 窗口宽 /// 窗口高 - public static void Zoom(this Editor ed, Point3d CenPt, double width, double height) + public static void Zoom(this Editor ed, Point3d cenPt, double width, double height) { - using ViewTableRecord view = ed.GetCurrentView(); - view.Width = width; - view.Height = height; - view.CenterPoint = new Point2d(CenPt.X, CenPt.Y); - ed.SetCurrentView(view);// 更新当前视图 + using var vtr = ed.GetCurrentView(); + vtr.Width = width; + vtr.Height = height; + vtr.CenterPoint = cenPt.TransformBy(ed.GetMatrixFromWcsToMDcs()).Point2d(); + ed.SetCurrentView(vtr); // 更新当前视图 } /// @@ -869,18 +861,15 @@ public static void Zoom(this Editor ed, Point3d CenPt, double width, double heig /// 第一点 /// 对角点 /// 偏移距离 - public static void ZoomWindow(this Editor ed, Point3d lpt, Point3d rpt, double offsetDist = 0.00) + public static void ZoomWindow(this Editor ed, Point3d lpt, Point3d rpt, + double offsetDist = 0.00) { - Extents3d extents = new(); - extents.AddPoint(lpt); - extents.AddPoint(rpt); - rpt = extents.MaxPoint + new Vector3d(offsetDist, offsetDist, 0); - lpt = extents.MinPoint - new Vector3d(offsetDist, offsetDist, 0); - Vector3d ver = rpt - lpt; - ed.Zoom(lpt + ver / 2, ver.X, ver.Y); + Extents3d ext = new(); + ext.AddPoint(lpt); + ext.AddPoint(rpt); + ed.ZoomWindow(ext, offsetDist); } - /// /// 获取有效的数据库范围 /// @@ -889,7 +878,7 @@ public static void ZoomWindow(this Editor ed, Point3d lpt, Point3d rpt, double o /// public static Extents3d? GetValidExtents3d(this Database db, double extention = 1e-6) { - db.UpdateExt(true);// 更新当前模型空间的范围 + db.UpdateExt(true); // 更新当前模型空间的范围 var ve = new Vector3d(extention, extention, extention); // 数据库没有图元的时候,min是大,max是小,导致新建出错 // 数据如下: @@ -910,7 +899,7 @@ public static void ZoomWindow(this Editor ed, Point3d lpt, Point3d rpt, double o /// 偏移距离 public static void ZoomExtents(this Editor ed, double offsetDist = 0.00) { - Database db = ed.Document.Database; + var db = ed.Document.Database; // db.UpdateExt(true); // GetValidExtents3d内提供了 var dbExtent = db.GetValidExtents3d(); if (dbExtent == null) @@ -927,7 +916,7 @@ public static void ZoomExtents(this Editor ed, double offsetDist = 0.00) /// 偏移距离 public static void ZoomObject(this Editor ed, Entity ent, double offsetDist = 0.00) { - Extents3d ext = ent.GeometricExtents; + var ext = ent.GeometricExtents; ed.ZoomWindow(ext.MinPoint, ext.MaxPoint, offsetDist); } @@ -939,16 +928,12 @@ public static void ZoomObject(this Editor ed, Entity ent, double offsetDist = 0. /// 获取Point /// /// 命令行对象 - /// 提示信息 - /// 提示使用的基点 - /// - public static PromptPointResult GetPoint(this Editor ed, string Message, Point3d BasePoint) + /// 提示信息 + /// 提示使用的基点 + /// 交互结果 + public static PromptPointResult GetPoint(this Editor ed, string message, Point3d basePoint) { - PromptPointOptions ptOp = new(Message) - { - BasePoint = BasePoint, - UseBasePoint = true - }; + PromptPointOptions ptOp = new(message) { BasePoint = basePoint, UseBasePoint = true, AllowNone = true }; return ed.GetPoint(ptOp); } @@ -956,15 +941,13 @@ public static PromptPointResult GetPoint(this Editor ed, string Message, Point3d /// 获取double值 /// /// 命令行对象 - /// 提示信息 - /// double默认值 - /// - public static PromptDoubleResult GetDouble(this Editor ed, string Message, double DefaultValue = 1.0) + /// 提示信息 + /// double默认值 + /// 交互结果 + public static PromptDoubleResult GetDouble(this Editor ed, string message, + double defaultValue = 1.0) { - PromptDoubleOptions douOp = new(Message) - { - DefaultValue = DefaultValue - }; + PromptDoubleOptions douOp = new(message) { DefaultValue = defaultValue, AllowNone = true }; return ed.GetDouble(douOp); } @@ -972,15 +955,13 @@ public static PromptDoubleResult GetDouble(this Editor ed, string Message, doubl /// 获取int值 /// /// 命令行对象 - /// 提示信息 - /// double默认值 - /// - public static PromptIntegerResult GetInteger(this Editor ed, string Message, int DefaultValue = 1) + /// 提示信息 + /// 默认值 + /// 交互结果 + public static PromptIntegerResult GetInteger(this Editor ed, string message, + int defaultValue = 1) { - PromptIntegerOptions douOp = new(Message) - { - DefaultValue = DefaultValue - }; + PromptIntegerOptions douOp = new(message) { DefaultValue = defaultValue, AllowNone = true }; return ed.GetInteger(douOp); } @@ -988,52 +969,53 @@ public static PromptIntegerResult GetInteger(this Editor ed, string Message, int /// 获取string值 /// /// 命令行对象 - /// 提示信息 - /// string默认值 + /// 提示信息 + /// string默认值 /// - public static PromptResult GetString(this Editor ed, string Message, string DefaultValue = "") + public static PromptResult GetString(this Editor ed, string message, string defaultValue = "") { - PromptStringOptions strOp = new(Message) - { - DefaultValue = DefaultValue - }; + PromptStringOptions strOp = new(message) + { DefaultValue = defaultValue, UseDefaultValue = !string.IsNullOrWhiteSpace(defaultValue) }; return ed.GetString(strOp); } #endregion #region 执行lisp -#if NET35 - [DllImport("acad.exe", -#else - [DllImport("accore.dll", -#endif - CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedInvoke")] - static extern int AcedInvoke(IntPtr args, out IntPtr result); -#if NET35 - [DllImport("acad.exe", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "?acedEvaluateLisp@@YAHPB_WAAPAUresbuf@@@Z")] -#else + [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "acedInvoke")] + private static extern int AcedInvoke(IntPtr args, out IntPtr result); + // 高版本此接口不能使用lisp(command "xx"),但是可以直接在自动运行接口上 [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedEvaluateLisp@@YAHPEB_WAEAPEAUresbuf@@@Z")] -#endif - [System.Security.SuppressUnmanagedCodeSecurity]// 初始化默认值 - static extern int AcedEvaluateLisp(string lispLine, out IntPtr result); + [System.Security.SuppressUnmanagedCodeSecurity] // 初始化默认值 + private static extern int AcedEvaluateLisp(string lispLine, out IntPtr result); -#if NET35 - [DllImport("acad.exe", -#else - [DllImport("accore.dll", -#endif - CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ads_queueexpr")] - static extern int Ads_queueexpr(string strExpr); + [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "ads_queueexpr")] + private static extern int Ads_queueexpr(string strExpr); + /// + /// 执行lisp的方式枚举 + /// + [Flags] public enum RunLispFlag : byte { + /// + /// AdsQueueexpr + /// AdsQueueexpr = 1, + + /// + /// AcedEvaluateLisp + /// AcedEvaluateLisp = 2, + + /// + /// SendStringToExecute + /// SendStringToExecute = 4, } @@ -1062,32 +1044,38 @@ public enum RunLispFlag : byte /// lisp语句 /// 运行方式 /// 缓冲结果,返回值 - public static ResultBuffer? RunLisp(this Editor ed, string lispCode, RunLispFlag flag = RunLispFlag.AdsQueueexpr) + public static ResultBuffer? RunLisp(this Editor ed, string lispCode, + RunLispFlag flag = RunLispFlag.AdsQueueexpr) { if ((flag & RunLispFlag.AdsQueueexpr) == RunLispFlag.AdsQueueexpr) { // 这个在08/12发送lisp不会出错,但是发送bo命令出错了. - // 0x01 设置 CommandFlags.Session 可以同步, + // 0x01 设置RunLispFlag特性为RunLispFlag.AcedEvaluateLisp即可同步执行 // 0x02 自执行发送lisp都是异步,用来发送 含有(command)的lisp的 _ = Ads_queueexpr(lispCode + "\n"); } + if ((flag & RunLispFlag.AcedEvaluateLisp) == RunLispFlag.AcedEvaluateLisp) { - _ = AcedEvaluateLisp(lispCode, out IntPtr rb); + _ = AcedEvaluateLisp(lispCode, out var rb); if (rb != IntPtr.Zero) return (ResultBuffer)DisposableWrapper.Create(typeof(ResultBuffer), rb, true); } + if ((flag & RunLispFlag.SendStringToExecute) == RunLispFlag.SendStringToExecute) { - var dm = Acap.DocumentManager; + var dm = Acaop.DocumentManager; var doc = dm.MdiActiveDocument; doc?.SendStringToExecute(lispCode + "\n", false, false, false); } + return null; } + #endregion #region Export + /// /// 输出WMF
/// 此函数不适用于后台 @@ -1096,75 +1084,113 @@ public enum RunLispFlag : byte /// 保存文件 /// 选择集的对象,为null时候手选 /// 是否清空选择集 - /// - public static void ComExportWMF(this Editor editor, string saveFile, - ObjectId[]? ids = null, bool wmfSetDel = false) + /// + public static void ComExportWMF(this Editor editor, string saveFile, ObjectId[]? ids = null, + bool wmfSetDel = false) { - if (string.IsNullOrEmpty(saveFile)) + if (string.IsNullOrWhiteSpace(saveFile)) throw new ArgumentNullException(nameof(saveFile)); if (File.Exists(saveFile)) throw new FileFormatException("文件重复:" + saveFile); - var dm = Acap.DocumentManager; + var dm = Acaop.DocumentManager; if (dm.Count == 0) return; // 剔除后缀 - int dot = saveFile.LastIndexOf('.'); - if (dot != -1) - { - // 因为文件名可以有.所以后缀点必须是最后\的后面 - int s = saveFile.LastIndexOf('\\'); - if (s < dot) - saveFile = saveFile.Substring(0, dot); - } - + saveFile = Path.Combine(Path.GetDirectoryName(saveFile) ?? string.Empty, + Path.GetFileNameWithoutExtension(saveFile)); // ActiveSelectionSet: // 第一次执行会触发选择,再次重复命令执行的时候,它会无法再选择(即使清空选择集). // 因此此处netAPI进行选择,它就能读取当前选择集缓冲区的对象 if (ids == null || ids.Length == 0) { - var psr = editor.SelectImplied();// 预选 + var psr = editor.SelectImplied(); // 预选 if (psr.Status != PromptStatus.OK) - psr = editor.GetSelection();// 手选 + psr = editor.GetSelection(); // 手选 if (psr.Status != PromptStatus.OK) return; ids = psr.Value.GetObjectIds(); } + editor.SetImpliedSelection(ids); #if zcad - var com = Acap.ZcadApplication; + dynamic com = Acap.ZcadApplication; #else - var com = Acap.AcadApplication; + dynamic com = Acap.AcadApplication; #endif - var doc = com.GetProperty("ActiveDocument"); - var wmfSet = doc.GetProperty("ActiveSelectionSet"); - + var doc = com.ActiveDocument; + var wmfSet = doc.ActiveSelectionSet; // TODO 20221007 导出wmf的bug // cad21 先net选择,再进行,此处再选择一次? // cad21 调试期间无法选择性粘贴? - var exp = doc.Invoke("Export", saveFile, "wmf", wmfSet); // JPGOUT,PNGOUT + doc.Export(saveFile, "wmf", wmfSet); if (wmfSetDel) - wmfSet.Invoke("Delete"); + wmfSet.Delete(); } + #endregion + #region JigEx + /// - /// 可以发送透明命令的状态
- /// 福萝卜:这个应该是修正ribbon里输入丢焦点的问题,低版本可以不要 + /// jig前的准备工作,使图元暗显 ///
- /// - /// - public static bool IsQuiescentForTransparentCommand(this Editor ed) + /// 命令栏 + /// 实体(已存在数据库中) + public static void PrepareForJig(this Editor ed, params Entity[] ents) { -#if NET35 - //if (ed.IsQuiescent) - //{ - //} - return true; -#else - return ed.IsQuiescentForTransparentCommand; -#endif + ed.PrepareForJig(ents.ToList()); } + + /// + /// jig前的准备工作,使图元暗显 + /// + /// 命令栏 + /// 实体(已存在数据库中) + public static void PrepareForJig(this Editor ed, IEnumerable ents) + { + var dic = new Dictionary(); + foreach (var ent in ents) + { + if (ent.IsNewObject) + continue; + dic.Add(ent, ent.Color); + using (ent.ForWrite()) + { + ent.ColorIndex = 250; + ent.Draw(); + } + } + + ed.Redraw(); + foreach (var kvp in dic) + { + var ent = kvp.Key; + using (ent.ForWrite()) + { + kvp.Key.Color = kvp.Value; + } + } + } + + #endregion + + #region Extension + + /// + /// 获取CAD鼠标当前位置坐标 + /// + /// 命令栏 + /// 坐标(可能为null) + public static Point3d? GetCurrentMouthPoint(this Editor ed) + { + return ed.RunLisp("(grread T)", RunLispFlag.AcedEvaluateLisp) + ?.AsArray() + .FirstOrDefault(tv => tv.TypeCode == 5009) + .Value as Point3d?; + } + + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/ArcEx.cs b/src/CADShared/ExtensionMethod/Entity/ArcEx.cs similarity index 78% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/ArcEx.cs rename to src/CADShared/ExtensionMethod/Entity/ArcEx.cs index f3ef9508c736ad81171e8e0847202b20fb3d9d6e..49922f4b293ff6e14a33721fe0f57daf26206b58 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/ArcEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/ArcEx.cs @@ -27,6 +27,7 @@ public static Arc CreateArcSCE(Point3d startPoint, Point3d centerPoint, Point3d arc.EndAngle = endVector.Angle; return arc; } + /// /// 三点法创建圆弧(二维) /// @@ -40,11 +41,8 @@ public static Arc CreateArc(Point3d startPoint, Point3d pointOnArc, Point3d endP CircularArc3d geArc = new(startPoint, pointOnArc, endPoint); // 将几何类圆弧对象的圆心和半径赋值给圆弧 #if !gcad -#if NET35 - return (Arc)geArc.ToCurve(); -#else + return (Arc)Curve.CreateFromGeCurve(geArc); -#endif #else return (Arc)geArc.ToCurve(); #endif @@ -69,5 +67,22 @@ public static Arc CreateArc(Point3d startPoint, Point3d centerPoint, double angl return arc; } + /// + /// 圆弧转为多段线 + /// + /// 圆弧 + /// 多段线 + public static Polyline ToPolyline(this Arc arc) + { + var plane = new Plane(arc.Center, arc.Normal); + var pl = new Polyline(); + pl.Normal = arc.Normal; + pl.AddVertexAt(0, arc.StartPoint.Convert2d(plane), Math.Tan(arc.TotalAngle * 0.25), 0, 0); + pl.AddVertexAt(1, arc.EndPoint.Convert2d(plane), 0, 0, 0); + pl.TransformBy(Matrix3d.Displacement(pl.StartPoint.GetVectorTo(arc.StartPoint))); + pl.SetPropertiesFrom(arc); + return pl; + } + #endregion } \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Entity/AttributeDefinitionEx.cs b/src/CADShared/ExtensionMethod/Entity/AttributeDefinitionEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..e60e18156bbec61a889d1a7231a2e0cc91a8c42a --- /dev/null +++ b/src/CADShared/ExtensionMethod/Entity/AttributeDefinitionEx.cs @@ -0,0 +1,22 @@ +namespace IFoxCAD.Cad; + +/// +/// 属性文字扩展 +/// +public static class AttributeDefinitionEx +{ + /// + /// 设置属性为多行文字,并通过委托设置多行文字的属性 + /// + /// 属性对象 + /// 设置多行文字的委托 + public static void SetMTextAttribute(this AttributeDefinition attr, Action action) + { + attr.IsMTextAttributeDefinition = true; + var mt = attr.MTextAttributeDefinition; + action(mt); + attr.MTextAttributeDefinition = mt; + attr.UpdateMTextAttributeDefinition(); + } + +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs b/src/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..cdeda3235a45a8008fbae8c737731395491d4793 --- /dev/null +++ b/src/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs @@ -0,0 +1,397 @@ +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; + +/// +/// 块参照扩展类 +/// +public static class BlockReferenceEx +{ + #region 裁剪块参照 + + private const string kFilterDictName = "ACAD_FILTER"; + private const string kSpatialName = "SPATIAL"; + + /// + /// 裁剪块参照 + /// + /// 块参照 + /// 裁剪多边形点表 + public static void XClip(this BlockReference brf, IEnumerable pt3ds) + { + var mat = brf.BlockTransform.Inverse(); + var pts = pt3ds.Select(p => p.TransformBy(mat).Point2d()).ToCollection(); + SpatialFilterDefinition sfd = new(pts, Vector3d.ZAxis, 0.0, double.PositiveInfinity, + double.NegativeInfinity, true); + using SpatialFilter sf = new(); + sf.Definition = sfd; + var dict = brf.GetXDictionary().GetSubDictionary(true, [kFilterDictName])!; + dict.SetData(kSpatialName, sf); + } + + /// + /// 裁剪块参照 + /// + /// 块参照 + /// 第一角点 + /// 第二角点 + public static void XClip(this BlockReference brf, Point3d pt1, Point3d pt2) + { + var mat = brf.BlockTransform.Inverse(); + pt1 = pt1.TransformBy(mat); + pt2 = pt2.TransformBy(mat); + Point2dCollection pts = + [ + new Point2d(Math.Min(pt1.X, pt2.X), Math.Min(pt1.Y, pt2.Y)), + new Point2d(Math.Max(pt1.X, pt2.X), Math.Max(pt1.Y, pt2.Y)) + ]; + using SpatialFilter sf = new(); + sf.Definition = new(pts, Vector3d.ZAxis, 0.0, double.PositiveInfinity, + double.NegativeInfinity, true); + var dict = brf.GetXDictionary().GetSubDictionary(true, [kFilterDictName])!; + dict.SetData(kSpatialName, sf); +#if !acad + pts.Dispose(); +#endif + } + + #endregion + + #region 属性 + + /// + /// 更新动态块参数值 + /// + public static bool ChangeBlockProperty(this BlockReference blockReference, + Dictionary propertyNameValues) + { + if (!blockReference.IsDynamicBlock) + return false; + using (blockReference.ForWrite()) + { + foreach (DynamicBlockReferenceProperty item in blockReference + .DynamicBlockReferencePropertyCollection) + { + if (propertyNameValues.TryGetValue(item.PropertyName, out var value)) + { + item.Value = item.PropertyTypeCode switch + { + 1 => Convert.ToDouble(value), + 2 => Convert.ToInt32(value), + 3 => Convert.ToInt16(value), + 4 => Convert.ToInt16(value), + 5 => Convert.ToString(value), + 13 => Convert.ToInt64(value), + _ => value, + }; + } + } + } + + return true; + } + + /// + /// 更新动态块参数值 + /// + public static bool ChangeBlockProperty(this BlockReference blockReference, string propName, + object value) + { + if (!blockReference.IsDynamicBlock) + return false; + using (blockReference.ForWrite()) + { + foreach (DynamicBlockReferenceProperty item in blockReference + .DynamicBlockReferencePropertyCollection) + { + if (item.PropertyName != propName) + continue; + item.Value = item.PropertyTypeCode switch + { + 1 => Convert.ToDouble(value), + 2 => Convert.ToInt32(value), + 3 => Convert.ToInt16(value), + 4 => Convert.ToInt16(value), + 5 => Convert.ToString(value), + 13 => Convert.ToInt64(value), + _ => value, + }; + break; + } + } + + return true; + } + + /// + /// 更新属性块的属性值 + /// + public static void ChangeBlockAttribute(this BlockReference blockReference, + Dictionary propertyNameValues) + { + var tr = DBTrans.GetTopTransaction(blockReference.Database); + foreach (var item in blockReference.AttributeCollection) + { + AttributeReference att; + if (item is ObjectId id) + { + // 通常情况下返回的都是 ObjectId + att = (AttributeReference)tr.GetObject(id); + } + else + { + // 某些情况下,比如你exploded炸开块后的子块块参照是没有在数据库里的,这时候返回的结果就是 AttributeReference + att = (AttributeReference)item; + } + + using (att.ForWrite()) + { + if (propertyNameValues.TryGetValue(att.Tag, out var value)) + { + att.TextString = value; + att.AdjustAlignment(blockReference.Database); + } + } + } + } + + /// + /// 获取普通块参照的属性集合 + /// + /// 普通块参照 + /// 属性集合 + public static IEnumerable GetAttributes(this BlockReference owner) + { + if (owner.Database != null) + { + var trans = DBTrans.GetTopTransaction(owner.Database); + foreach (ObjectId id in owner.AttributeCollection) + yield return (AttributeReference)trans.GetObject(id); + } + else + { + foreach (AttributeReference att in owner.AttributeCollection) + yield return att; + } + } + + #endregion + + /// + /// 获取块表记录 + /// + /// 块参照 + /// 块表记录 + public static BlockTableRecord GetBlockTableRecord(this BlockReference brf) + { + return (BlockTableRecord)brf.BlockTableRecord.GetObject(OpenMode.ForRead); + } + + /// + /// 获取块的有效名字 + /// + /// 块参照 + /// 名字 + public static string GetBlockName(this BlockReference blk) + { + ArgumentNullException.ThrowIfNull(blk); + if (blk.IsDynamicBlock) + { + var btrId = blk.DynamicBlockTableRecord; + var tr = btrId.Database.TransactionManager.TopTransaction; + ArgumentNullException.ThrowIfNull(tr); + var btr = (BlockTableRecord)tr.GetObject(btrId); + return btr.Name; + } + + return blk.Name; + } + + /// + /// 获取嵌套块的位置(wcs) + /// + /// 父块 + /// 子块名 + /// 子块的位置 + /// + public static Point3d? GetNestedBlockPosition(this BlockReference parentBlockRef, + string nestedBlockName) + { + var tr = DBTrans.GetTopTransaction(parentBlockRef.Database); + var btr = tr.GetObject(parentBlockRef.BlockTableRecord); + if (btr == null) + return null; + foreach (var id in btr) + { + if (id.ObjectClass.Name == "AcDbBlockReference") + { + var nestedBlockRef = tr.GetObject(id); + if (nestedBlockRef?.Name == nestedBlockName) + { + return nestedBlockRef.Position.TransformBy(parentBlockRef.BlockTransform); + } + } + } + + return null; + } + + /// + /// 遍历块内 + /// + /// + /// + [DebuggerStepThrough] + public static void ForEach(this BlockReference brf, Action action) + { + ArgumentNullException.ThrowIfNull(action); + var tr = DBTrans.GetTopTransaction(brf.Database); + if (tr.GetObject(brf.BlockTableRecord) is BlockTableRecord btr) + { + btr.ForEach(action); + } + } + + /// + /// 遍历块内 + /// + /// + /// + /// + [DebuggerStepThrough] + public static void ForEach(this BlockReference brf, Action action) + { + ArgumentNullException.ThrowIfNull(action); + var tr = DBTrans.GetTopTransaction(brf.Database); + if (tr.GetObject(brf.BlockTableRecord) is BlockTableRecord btr) + { + btr.ForEach(action); + } + } + + /// + /// 遍历块内 + /// + /// + /// + /// + [DebuggerStepThrough] + public static void ForEach(this BlockReference brf, Action action) + { + ArgumentNullException.ThrowIfNull(action); + var tr = DBTrans.GetTopTransaction(brf.Database); + if (tr.GetObject(brf.BlockTableRecord) is BlockTableRecord btr) + { + btr.ForEach(action); + } + } + + /// + /// 遍历嵌套块中块图元 + /// + /// 块参照 + /// 委托 + /// 事务 + public static void NestedForEach(this Entity blockReference, Action action, + DBTrans? tr = null) + { + tr ??= DBTrans.GetTop(blockReference.IsNewObject ? Env.Database : blockReference.Database); + var queue = new Queue<(Entity, Matrix3d)>(); + queue.Enqueue((blockReference, Matrix3d.Identity)); + while (queue.Any()) + { + var (ent, mt) = queue.Dequeue(); + action?.Invoke(ent, mt); + if (ent is BlockReference brfTemp) + { + var mtNext = mt * brfTemp.BlockTransform; + tr.BlockTable.Change(brfTemp.BlockTableRecord, btr => + { + foreach (var id in btr) + { + if (tr.GetObject(id) is Entity entNext) + { + queue.Enqueue((entNext, mtNext)); + } + } + }); + } + } + } + + /// + /// 获取块可见性信息 + /// + /// 块参照 + /// 可见性信息 + public static BlockVisibilityInfo GetVisibilityInfo(this BlockReference blockReference) + { + var info = new BlockVisibilityInfo(); + if (blockReference.IsDynamicBlock) + { + var btr = (BlockTableRecord)blockReference.DynamicBlockTableRecord.GetObject(); + info = btr.GetVisibilityInfo(); + } + + return info; + } + + /// + /// 获取块可见性信息 + /// + /// 块表记录 + /// 可见性信息 + public static BlockVisibilityInfo GetVisibilityInfo(this BlockTableRecord btr) + { + var info = new BlockVisibilityInfo(); + if (btr.IsDynamicBlock && btr.ExtensionDictionary.IsOk()) + { + var dict = btr.GetXDictionary(); + if (dict.Contains("ACAD_ENHANCEDBLOCK")) + { + var idEnhancedBlock = dict.GetAt("ACAD_ENHANCEDBLOCK"); + var enhancedBlockTypedValues = Env.EntGet(idEnhancedBlock); + var parm = enhancedBlockTypedValues.FirstOrDefault(e => + e.TypeCode == 360 && e.Value is ObjectId id && id.IsOk() && + id.ObjectClass.DxfName == "BLOCKVISIBILITYPARAMETER") + .Value; + if (parm is ObjectId parmId) + { + info.Has = true; + var parmTypedValues = Env.EntGet(parmId); + info.PropertyName = parmTypedValues.FirstOrDefault(e => e.TypeCode == 301) + .Value?.ToString() ?? ""; + info.AllowedValues = parmTypedValues.Where(e => e.TypeCode == 303) + .Select(e => e.Value?.ToString() ?? "") + .Where(e => !string.IsNullOrWhiteSpace(e)) + .ToList(); + } + } + } + + return info; + } +} + +/// +/// 块可见性信息 +/// +public class BlockVisibilityInfo +{ + /// + /// 有无可见性 + /// + public bool Has { get; set; } + + /// + /// 属性名 + /// + public string PropertyName { get; set; } = ""; + + /// + /// 允许值 + /// + public List AllowedValues { get; set; } = []; +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Entity/BoundingInfo.cs b/src/CADShared/ExtensionMethod/Entity/BoundingInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..be90241426ca82d3c795ce24e66c4996e588115f --- /dev/null +++ b/src/CADShared/ExtensionMethod/Entity/BoundingInfo.cs @@ -0,0 +1,193 @@ +namespace IFoxCAD.Cad; + +/// +/// 和尚777 重构 +/// 包围盒信息 +/// +public struct BoundingInfo +{ + #region 成员 + + /// + /// MinPoint.X + /// + public double MinX { get; private set; } + + /// + /// MinPoint.Y + /// + public double MinY { get; private set; } + + /// + /// MinPoint.Z + /// + public double MinZ { get; private set; } + + /// + /// MaxPoint.X + /// + public double MaxX { get; private set; } + + /// + /// MaxPoint.Y + /// + public double MaxY { get; private set; } + + /// + /// MaxPoint.Z + /// + public double MaxZ { get; private set; } + + #region 包围盒9位码坐标 + + /* + * 包围盒9位码坐标 + * P7---------------P8----------------P9 + * | | | + * | | | + * | | | + * P4---------------P5----------------P6 + * | | | + * | | | + * | | | + * P1---------------P2----------------P3 + */ + /// + /// MinPoint 左下点 P1 + /// + public readonly Point3d BottomLeft => new(MinX, MinY, MinZ); + + /// + /// P2 + /// + public readonly Point3d BottomCenter => BottomLeft.GetMidPointTo(BottomRight); + + /// + /// P3 + /// + public readonly Point3d BottomRight => new(MaxX, MinY, MinZ); + + /// + /// P4 + /// + public readonly Point3d MidLeft => BottomLeft.GetMidPointTo(TopLeft); + + /// + /// P5 + /// + public readonly Point3d MidCenter => BottomLeft.GetMidPointTo(TopRight); + + /// + /// P6 + /// + public readonly Point3d MidRight => BottomRight.GetMidPointTo(TopRight); + + /// + /// P7 + /// + public readonly Point3d TopLeft => new(MinX, MaxY, MinZ); + + /// + /// P8 + /// + public readonly Point3d TopCenter => TopLeft.GetMidPointTo(TopRight); + + /// + /// MaxPoint 右上点 P9 + /// + public readonly Point3d TopRight => new(MaxX, MaxY, MaxZ); + + // public Point3d Min => new(MinX, MinY, MinZ); + + // public Point3d Max => new(MaxX, MaxY, MaxZ); + + #endregion + + /// + /// 高 + /// + public readonly double Height => Math.Abs(MaxY - MinY); + + /// + /// 宽 + /// + public readonly double Width => Math.Abs(MaxX - MinX); + + /// + /// 面积 + /// + public readonly double Area => Height * Width; + + /// + /// 3D包围盒 + /// + public Extents3d Extents3d { get; } + + /// + /// 2D包围盒 + /// + public readonly Extents2d Extents2d => new(MinX, MinY, MaxX, MaxY); + + #endregion + + #region 构造 + + /// + /// 包围盒信息3D构造 + /// + /// 包围盒 + public BoundingInfo(Extents3d ext) + { + MinX = ext.MinPoint.X; + MinY = ext.MinPoint.Y; + MinZ = ext.MinPoint.Z; + MaxX = ext.MaxPoint.X; + MaxY = ext.MaxPoint.Y; + MaxZ = ext.MaxPoint.Z; + Extents3d = ext; + } + + /// + /// 包围盒信息2D构造 + /// + /// 包围盒 + public BoundingInfo(Extents2d ext) + { + MinX = ext.MinPoint.X; + MinY = ext.MinPoint.Y; + MinZ = 0; + MaxX = ext.MaxPoint.X; + MaxY = ext.MaxPoint.Y; + MaxZ = 0; + var pt1 = new Point3d(MinX, MinY, 0); + var pt9 = new Point3d(MaxX, MaxY, 0); + Extents3d = new Extents3d(pt1, pt9); + } + + #endregion + + /// + /// 重写ToString + /// + /// 返回MinPoint,MaxPoint坐标 + public override string ToString() + { + return Extents3d.ToString(); + } + + /// + /// 移动包围盒 + /// + /// 基点 + /// 目标点 + public void Move(Point3d pt1, Point3d pt2) + { + var ve = pt1 - pt2; + MinX -= ve.X; + MinY -= ve.Y; + MinZ -= ve.Z; + MaxX -= ve.X; + MaxY -= ve.Y; + MaxZ -= ve.Z; + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/CircleEx.cs b/src/CADShared/ExtensionMethod/Entity/CircleEx.cs similarity index 84% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/CircleEx.cs rename to src/CADShared/ExtensionMethod/Entity/CircleEx.cs index 4488f3a5d62545be2f8b25739d968c3edb9dec93..d0fba8ac4064b4f4956fbbcdceb0aae7982dc184 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/CircleEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/CircleEx.cs @@ -5,7 +5,6 @@ ///
public static class CircleEx { - /// /// 两点创建圆(两点中点为圆心) /// @@ -31,10 +30,10 @@ public static Circle CreateCircle(Point3d startPoint, Point3d endPoint) public static Circle? CreateCircle(Point3d pt1, Point3d pt2, Point3d pt3) { // 先判断三点是否共线,得到pt1点指向pt2、pt2点的矢量 - Vector3d va = pt1.GetVectorTo(pt2); - Vector3d vb = pt1.GetVectorTo(pt3); + var va = pt2 - pt1; + var vb = pt3 - pt2; // 如两矢量夹角为0或180度(π弧度),则三点共线. - if (va.GetAngleTo(vb) == 0 | va.GetAngleTo(vb) == Math.PI) + if (va.GetAngleTo(vb) == 0 | va.GetAngleTo(vb).Equals(Math.PI)) return null; // 创建一个几何类的圆弧对象 @@ -51,9 +50,8 @@ public static Circle CreateCircle(Point3d startPoint, Point3d endPoint) /// 法向量的Y /// 法向量的Z /// - public static Circle? CreateCircle(Point3d center, double radius, double vex = 0, double vey = 0, double vez = 1) + public static Circle CreateCircle(Point3d center, double radius, double vex = 0, double vey = 0, double vez = 1) { - return new Circle(center, new Vector3d(vex, vey, vez), radius);// 平面法向量XY方向 + return new Circle(center, new Vector3d(vex, vey, vez), radius); // 平面法向量XY方向 } - } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/CurveEx.cs b/src/CADShared/ExtensionMethod/Entity/CurveEx.cs similarity index 48% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/CurveEx.cs rename to src/CADShared/ExtensionMethod/Entity/CurveEx.cs index bfca634af56a45f77ea2c10de9f2b389c60bcb06..0df06cde18045f47e8e36283ceba1ba07b32737f 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/CurveEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/CurveEx.cs @@ -1,4 +1,8 @@ +// ReSharper disable ForCanBeConvertedToForeach +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Cad; @@ -17,7 +21,7 @@ public static double GetLength(this Curve curve) return curve.GetDistanceAtParameter(curve.EndParam); } - /// + /*/// /// 获取分割曲线集合 /// /// 曲线 @@ -27,12 +31,9 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable(); - } + ArgumentNullEx.ThrowIfNull(pars); + return curve.GetSplitCurves(new DoubleCollection(pars.ToArray())).Cast(); + }*/ /// /// 获取分割曲线集合 @@ -46,20 +47,19 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable /// /// 打断后曲线的集合 - public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable pars, bool isOrder = false) + public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable pars, + bool isOrder = false) { //if (pars is null) // throw new ArgumentNullException(nameof(pars)); - pars.NotNull(nameof(pars)); + ArgumentNullException.ThrowIfNull(pars); if (isOrder) pars = pars.OrderBy(x => x); - return - curve - .GetSplitCurves(new DoubleCollection(pars.ToArray())) - .Cast(); + return curve.GetSplitCurves(new DoubleCollection(pars.ToArray())).Cast(); } + /* /// /// 获取分割曲线集合 /// @@ -70,10 +70,10 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable(); - } + }*/ /// /// 获取分割曲线集合 @@ -87,13 +87,15 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable /// /// 打断后曲线的集合 - public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable points, bool isOrder = false) + public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable points, + bool isOrder = false) { //if (points is null) // throw new ArgumentNullException(nameof(points)); - points.NotNull(nameof(points)); + ArgumentNullException.ThrowIfNull(points); if (isOrder) - points = points.OrderBy(point => { + points = points.OrderBy(point => + { var pt = curve.GetClosestPointTo(point, false); return curve.GetParameterAtPoint(pt); }); @@ -102,44 +104,6 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable(); } - /// - /// 获取曲线集所围成的封闭区域的曲线集,注意此函数不能处理平行边(两个点及两条线组成的闭合环) - /// - /// 曲线集合 - /// 所有的闭合环的曲线集合 - public static IEnumerable GetAllCycle(this IEnumerable curves) - { - curves.NotNull(nameof(curves)); - - // 新建图 - var graph = new Graph(); - foreach (var curve in curves) - { -#if !gcad -#if NET35 - graph.AddEdge(curve.ToCurve3d()!); -#else - graph.AddEdge(curve.GetGeCurve()); -#endif -#else - graph.AddEdge(curve.ToCurve3d()!); -#endif - } - // 新建 dfs - var dfs = new DepthFirst(); - // 查询全部的 闭合环 - dfs.FindAll(graph); - // 遍历闭合环的列表,将每个闭合环转换为实体曲线 - var res = new List(); - foreach (var item in dfs.Curve3ds) - { - var curve = graph.GetCurves(item.ToList()).ToArray(); - var comcur = new CompositeCurve3d(curve).ToCurve(); - if (comcur is not null) - res.Add(comcur); - } - return res; - } /// /// 曲线打断 /// @@ -147,37 +111,39 @@ public static IEnumerable GetAllCycle(this IEnumerable curves) /// 打断后的曲线列表 public static List BreakCurve(this List curves) { - curves.NotNull(nameof(curves)); + ArgumentNullException.ThrowIfNull(curves); + + var tol = new Tolerance(0.01, 0.01); - var geCurves = new List(); // 存储曲线转换后的复合曲线 - var paramss = new List>(); // 存储每个曲线的交点参数值 + List geCurves = []; // 存储曲线转换后的复合曲线 + List> paramsList = []; // 存储每个曲线的交点参数值 - for (int i = 0; i < curves.Count; i++) + for (var i = 0; i < curves.Count; i++) { var cc3d = curves[i].ToCompositeCurve3d(); if (cc3d is not null) { geCurves.Add(cc3d); - paramss.Add(new List()); + paramsList.Add([]); } } - // var oldCurves = new List(); - var newCurves = new List(); + // List oldCurves = []; + List newCurves = []; var cci3d = new CurveCurveIntersector3d(); - for (int i = 0; i < curves.Count; i++) + for (var i = 0; i < curves.Count; i++) { var gc1 = geCurves[i]; - var pars1 = paramss[i]; // 引用 - for (int j = i; j < curves.Count; j++) + var pars1 = paramsList[i]; // 引用 + for (var j = i; j < curves.Count; j++) { var gc2 = geCurves[j]; - var pars2 = paramss[j]; // 引用 + var pars2 = paramsList[j]; // 引用 - cci3d.Set(gc1, gc2, Vector3d.ZAxis); + cci3d.Set(gc1, gc2, Vector3d.ZAxis, tol); - for (int k = 0; k < cci3d.NumberOfIntersectionPoints; k++) + for (var k = 0; k < cci3d.NumberOfIntersectionPoints; k++) { var pars = cci3d.GetIntersectionParameters(k); pars1.Add(pars[0]); // 引用修改会同步到源对象 @@ -207,6 +173,294 @@ public static List BreakCurve(this List curves) return newCurves; } + /// + /// 在z法向量平面打断曲线 + /// + /// 曲线列表 + /// 打断后的曲线列表 + /// 传入的曲线列表错误 + public static List BreakCurveOnZPlane(this List curves) + { + if (curves is null) + throw new System.ArgumentNullException(nameof(curves)); + var zPlane = new Plane(Point3d.Origin, Vector3d.ZAxis); + var curvesTemp = curves.Select(c => c.GetProjectedCurve(zPlane, Vector3d.ZAxis)).ToList(); + List geCurves = []; // 存储曲线转换后的复合曲线 + List> paramsList = []; // 存储每个曲线的交点参数值 + + for (var i = 0; i < curvesTemp.Count; i++) + { + paramsList.Add([]); + var cc3d = curvesTemp[i].ToCompositeCurve3d(); + if (cc3d is not null) + { + geCurves.Add(cc3d); + } + } + + List newCurves = []; + var cci3d = new CurveCurveIntersector3d(); + + for (var i = 0; i < curvesTemp.Count; i++) + { + var gc1 = geCurves[i]; + var pars1 = paramsList[i]; // 引用 + for (var j = i; j < curvesTemp.Count; j++) + { + var gc2 = geCurves[j]; + var pars2 = paramsList[j]; // 引用 + + cci3d.Set(gc1, gc2, Vector3d.ZAxis); + + for (var k = 0; k < cci3d.NumberOfIntersectionPoints; k++) + { + var pars = cci3d.GetIntersectionParameters(k); + pars1.Add(pars[0]); // 引用修改会同步到源对象 + pars2.Add(pars[1]); // 引用修改会同步到源对象 + } + } + + var curNow = curvesTemp[i]; + var length = curNow.GetLength(); + var np = pars1.Where(p => p >= 0 && p <= length) + .Select(curNow.GetParameterAtDistance) + .Where(p => + !(Math.Abs(p - curNow.StartParam) < 1e-6 || + Math.Abs(p - curNow.EndParam) < 1e-6)) + .ToList(); + if (np.Count > 0) + { + var splitCurs = curNow.GetSplitCurves(np, true).ToList(); + if (splitCurs.Count > 1) + { + newCurves.AddRange(splitCurs); + } + else + { + newCurves.Add(curNow.CloneEx()); + } + } + else + { + newCurves.Add(curNow.CloneEx()); + } + } + + return newCurves; + } +#if !gcad + /// + /// 打段曲线2维By四叉树 + /// + /// 目前对xLine,ray的支持存在错误 + /// 需要更多的测试 + /// + /// + /// 曲线列表 + /// 容差 + /// 打断后的曲线列表 + public static List BreakCurve2dByQuadTree(this List sourceCurveList, + double tol = 1e-6) + { + //var tolerance = new Tolerance(tol, tol); + var zPlane = new Plane(Point3d.Origin, Vector3d.ZAxis); + var curves = sourceCurveList.Select(c => c.GetOrthoProjectedCurve(zPlane)).ToList(); + List geCurves = []; + List xLines = []; + var minX = double.MaxValue; + var minY = double.MaxValue; + var maxX = double.MinValue; + var maxY = double.MinValue; + // 遍历每条曲线,计算出四叉树对象,加到四叉树曲线对象列表和四叉树容器中 + for (var i = 0; i < curves.Count; i++) + { + var curTemp = curves[i]; + if (curTemp is Ray || curTemp is Xline) + { + xLines.Add(curTemp); + } + else + { + var cc3d = curTemp.ToCompositeCurve3d(); + if (cc3d is not null) + { + var e3d = curTemp.GeometricExtents; + var rect = new Rect(e3d.MinPoint.Point2d(), e3d.MaxPoint.Point2d()); + var cit = new BreakCurveInfo(rect, curTemp, cc3d); + if (rect.Left < minX) minX = rect.Left; + if (rect.Right > maxX) maxX = rect.Right; + if (rect.Bottom < minY) minY = rect.Bottom; + if (rect.Top > maxY) maxY = rect.Top; + geCurves.Add(cit); + } + } + } + + // 建四叉树容器 + var maxBox = new Rect(minX - 10, minY - 10, maxX + 10, maxY + 10); + xLines.ForEach(xl => + { + var cc3d = new CompositeCurve3d([xl.GetGeCurve()]); + var bci = new BreakCurveInfo(maxBox, xl, cc3d); + geCurves.Add(bci); + }); + List newCurves = []; + var quadTree = new QuadTree(maxBox); + foreach (var bci in geCurves) + { + quadTree.Insert(bci); + } + + var cci3d = new CurveCurveIntersector3d(); + + foreach (var gc1 in geCurves) + { + var parsList = new HashSet(); + var cts = quadTree.Query(new Rect(gc1.Left - tol, gc1.Bottom - tol, gc1.Right + tol, + gc1.Top + tol)); + cts.Remove(gc1); + foreach (var gc2 in cts) + { + cci3d.Set(gc1.Cc3d, gc2.Cc3d, Vector3d.ZAxis, Tolerance.Global); + for (var k = 0; k < cci3d.NumberOfIntersectionPoints; k++) + { + var pars = cci3d.GetIntersectionParameters(k); + parsList.Add(pars[0]); + } + + if (!gc2.Curve.Closed) + { + var cpt1 = gc1.Cc3d.GetClosestPointTo(gc2.Cc3d.StartPoint); + var cpt2 = gc1.Cc3d.GetClosestPointTo(gc2.Cc3d.EndPoint); + if (cpt1.Point.Distance2dTo(gc2.Cc3d.StartPoint) < tol && + cpt1.Point.Distance2dTo(gc1.Cc3d.StartPoint) >= tol) + { + parsList.Add(cpt1.Parameter); + } + + if (cpt2.Point.Distance2dTo(gc2.Cc3d.EndPoint) < tol && + cpt2.Point.Distance2dTo(gc1.Cc3d.EndPoint) >= tol) + { + parsList.Add(cpt2.Parameter); + } + } + } + + if (gc1.Curve is Polyline || gc1.Curve is Spline) + { + cci3d.Set(gc1.Cc3d, gc1.Cc3d, Vector3d.ZAxis); + for (var k = 0; k < cci3d.NumberOfIntersectionPoints; k++) + { + var pars = cci3d.GetIntersectionParameters(k); + if (Math.Abs(pars[0] - pars[1]) < 1e-6) + continue; + parsList.Add(pars[0]); + parsList.Add(pars[1]); + } + } + + var parsNew = parsList.OrderBy(d => d).ToList(); + + var cur = gc1.Curve; + if (parsNew.Count > 0) + { + var c3ds = gc1.Cc3d.GetSplitCurves(parsNew); + if (c3ds is not null && c3ds.Count > 1) + { + if (cur is Arc || (cur is Ellipse { Closed: false })) + { + foreach (var c3d in c3ds) + { + var c3dCur = Curve.CreateFromGeCurve(c3d); + + if (c3dCur is null || c3dCur.Closed || c3dCur is Circle || + c3dCur.GetLength() < tol) + continue; + c3dCur.SetPropertiesFrom(cur); + newCurves.Add(c3dCur); + } + + continue; + } + + foreach (var c3d in c3ds) + { + var c3dCur = Curve.CreateFromGeCurve(c3d); + if (c3dCur is not null) + { + c3dCur.SetPropertiesFrom(cur); + newCurves.Add(c3dCur); + } + } + } + else + { + newCurves.Add(cur.CloneEx()); + } + } + else + { + newCurves.Add(cur.CloneEx()); + } + } + + return newCurves; + } + + private class BreakCurveInfo : QuadEntity + { + // ReSharper disable once UnusedAutoPropertyAccessor.Local + public Rect Rect { get; } + public Curve Curve { get; } + public CompositeCurve3d Cc3d { get; } + + public BreakCurveInfo(Rect rect, Curve curve, CompositeCurve3d cc3d) : base(rect) + { + Curve = curve; + Cc3d = cc3d; + Rect = rect; + } + } +#endif + /// + /// 获取非等比转换的曲线(旋转投影法) + /// + /// 转换前的曲线 + /// 基点 + /// x方向比例 + /// y方向比例 + /// 转换后的曲线 + public static Curve GetScaleCurve(this Curve cur, Point3d pt, double x, double y) + { + // 先做个z平面 + using var zPlane = new Plane(pt, Vector3d.ZAxis); + // 克隆一个,防止修改到原来的 + using var cur2 = cur.CloneEx(); + + // 因为旋转投影后只能比原来小,所以遇到先放大 + while (Math.Abs(x) > 1 || Math.Abs(y) > 1) + { + cur2.TransformBy(Matrix3d.Scaling(2, pt)); + x /= 2; + y /= 2; + } + + // 旋转投影 + var xA = Math.Acos(x); + cur2.TransformBy(Matrix3d.Rotation(xA, Vector3d.YAxis, pt)); + + using var cur3 = cur2.GetOrthoProjectedCurve(zPlane); + + // 再次旋转投影 + var yA = Math.Acos(y); + cur3.TransformBy(Matrix3d.Rotation(yA, Vector3d.XAxis, pt)); + var cur4 = cur3.GetOrthoProjectedCurve(zPlane); + + //设置属性 + cur4.SetPropertiesFrom(cur); + return cur4; + } + // 转换DBCurve为GeCurved #region Curve @@ -241,15 +495,15 @@ public static List BreakCurve(this List curves) { return curve switch { - Line li => new CompositeCurve3d(new Curve3d[] { ToCurve3d(li) }), - Circle ci => new CompositeCurve3d(new Curve3d[] { ToCurve3d(ci) }), - Arc arc => new CompositeCurve3d(new Curve3d[] { ToCurve3d(arc) }), - Ellipse el => new CompositeCurve3d(new Curve3d[] { ToCurve3d(el) }), - Polyline pl => new CompositeCurve3d(new Curve3d[] { ToCurve3d(pl) }), - - Polyline2d pl2 => new CompositeCurve3d(new Curve3d[] { ToCurve3d(pl2)! }), - Polyline3d pl3 => new CompositeCurve3d(new Curve3d[] { ToCurve3d(pl3) }), - Spline sp => new CompositeCurve3d(new Curve3d[] { ToCurve3d(sp) }), + Line li => new CompositeCurve3d([ToCurve3d(li)]), + Circle ci => new CompositeCurve3d([ToCurve3d(ci)]), + Arc arc => new CompositeCurve3d([ToCurve3d(arc)]), + Ellipse el => new CompositeCurve3d([ToCurve3d(el)]), + Polyline pl => new CompositeCurve3d([ToCurve3d(pl)]), + + Polyline2d pl2 => new CompositeCurve3d([ToCurve3d(pl2)!]), + Polyline3d pl3 => new CompositeCurve3d([ToCurve3d(pl3)]), + Spline sp => new CompositeCurve3d([ToCurve3d(sp)]), _ => null }; } @@ -308,11 +562,7 @@ public static NurbCurve3d ToNurbCurve3d(this Line line) /// ge圆弧曲线 public static CircularArc3d ToCurve3d(this Circle cir) { - return - new CircularArc3d( - cir.Center, - cir.Normal, - cir.Radius); + return new CircularArc3d(cir.Center, cir.Normal, cir.Radius); } /// @@ -348,15 +598,8 @@ public static CircularArc3d ToCurve3d(this Arc arc) { Plane plane = new(arc.Center, arc.Normal); - return - new CircularArc3d( - arc.Center, - arc.Normal, - plane.GetCoordinateSystem().Xaxis, - arc.Radius, - arc.StartAngle, - arc.EndAngle - ); + return new CircularArc3d(arc.Center, arc.Normal, plane.GetCoordinateSystem().Xaxis, + arc.Radius, arc.StartAngle, arc.EndAngle); } /// @@ -390,15 +633,8 @@ public static NurbCurve3d ToNurbCurve3d(this Arc arc) /// 三维ge椭圆曲线 public static EllipticalArc3d ToCurve3d(this Ellipse ell) { - return - new EllipticalArc3d( - ell.Center, - ell.MajorAxis.GetNormal(), - ell.MinorAxis.GetNormal(), - ell.MajorRadius, - ell.MinorRadius, - ell.StartParam, - ell.EndParam); + return new EllipticalArc3d(ell.Center, ell.MajorAxis.GetNormal(), ell.MinorAxis.GetNormal(), + ell.MajorRadius, ell.MinorRadius, ell.StartParam, ell.EndParam); } /// @@ -423,38 +659,27 @@ public static NurbCurve3d ToNurbCurve3d(this Ellipse ell) public static NurbCurve3d ToCurve3d(this Spline spl) { NurbCurve3d nc3d; - NurbsData ndata = spl.NurbsData; - KnotCollection knots = new(); - foreach (Double knot in ndata.GetKnots()) - knots.Add(knot); + var nData = spl.NurbsData; + KnotCollection knots = [.. nData.GetKnots()]; - if (ndata.Rational) + if (nData.Rational) { - nc3d = - new NurbCurve3d( - ndata.Degree, - knots, - ndata.GetControlPoints(), - ndata.GetWeights(), - ndata.Periodic); + nc3d = new NurbCurve3d(nData.Degree, knots, nData.GetControlPoints(), + nData.GetWeights(), nData.Periodic); } else { - nc3d = - new NurbCurve3d( - ndata.Degree, - knots, - ndata.GetControlPoints(), - ndata.Periodic); + nc3d = new NurbCurve3d(nData.Degree, knots, nData.GetControlPoints(), nData.Periodic); } if (spl.HasFitData) { - var fdata = spl.FitData; + var fData = spl.FitData; var vec = new Vector3d(); - if (fdata.TangentsExist && (fdata.StartTangent != vec || fdata.EndTangent != vec)) - nc3d.SetFitData(fdata.GetFitPoints(), fdata.StartTangent, fdata.EndTangent); + if (fData.TangentsExist && (fData.StartTangent != vec || fData.EndTangent != vec)) + nc3d.SetFitData(fData.GetFitPoints(), fData.StartTangent, fData.EndTangent); } + return nc3d; } @@ -473,12 +698,12 @@ public static NurbCurve3d ToCurve3d(this Spline spl) { case Poly2dType.SimplePoly: case Poly2dType.FitCurvePoly: - Polyline pl = new(); - pl.SetDatabaseDefaults(); - pl.ConvertFrom(pl2d, false); - return ToCurve3d(pl); + Polyline pl = new(); + pl.SetDatabaseDefaults(); + pl.ConvertFrom(pl2d, false); + return ToCurve3d(pl); default: - return ToNurbCurve3d(pl2d); + return ToNurbCurve3d(pl2d); } // Polyline pl = new Polyline(); @@ -497,13 +722,13 @@ public static NurbCurve3d ToCurve3d(this Spline spl) { case Poly2dType.SimplePoly: case Poly2dType.FitCurvePoly: - Polyline pl = new(); - pl.SetDatabaseDefaults(); - pl.ConvertFrom(pl2d, false); - return ToNurbCurve3d(pl); + Polyline pl = new(); + pl.SetDatabaseDefaults(); + pl.ConvertFrom(pl2d, false); + return ToNurbCurve3d(pl); default: - return ToCurve3d(pl2d.Spline); + return ToCurve3d(pl2d.Spline); } } @@ -514,10 +739,10 @@ public static NurbCurve3d ToCurve3d(this Spline spl) /// 三维ge多段线 public static PolylineCurve3d ToPolylineCurve3d(this Polyline2d pl) { - using Point3dCollection pnts = new(); + using Point3dCollection p3dc = new(); foreach (Vertex2d ver in pl) - pnts.Add(ver.Position); - return new PolylineCurve3d(pnts); + p3dc.Add(ver.Position); + return new PolylineCurve3d(p3dc); } #endregion Polyline2d @@ -555,14 +780,14 @@ public static NurbCurve3d ToNurbCurve3d(this Polyline3d pl3d) /// 三维ge多段线 public static PolylineCurve3d ToPolylineCurve3d(this Polyline3d pl) { - using Point3dCollection pnts = new(); + using Point3dCollection p3dc = new(); foreach (ObjectId id in pl) { - var ver = id.GetObject(OpenMode.ForRead); - if (ver != null) - pnts.Add(ver.Position); + if (id.GetObject(OpenMode.ForRead) is PolylineVertex3d ver) + p3dc.Add(ver.Position); } - return new PolylineCurve3d(pnts); + + return new PolylineCurve3d(p3dc); } #endregion Polyline3d @@ -576,25 +801,23 @@ public static PolylineCurve3d ToPolylineCurve3d(this Polyline3d pl) /// 复合曲线对象 public static CompositeCurve3d ToCurve3d(this Polyline pl) { - List c3ds = new(); + List c3ds = []; - for (int i = 0; i < pl.NumberOfVertices; i++) + for (var i = 0; i < pl.NumberOfVertices; i++) { switch (pl.GetSegmentType(i)) { case SegmentType.Line: - c3ds.Add(pl.GetLineSegmentAt(i)); - break; + c3ds.Add(pl.GetLineSegmentAt(i)); + break; case SegmentType.Arc: - c3ds.Add(pl.GetArcSegmentAt(i)); - break; - - default: - break; + c3ds.Add(pl.GetArcSegmentAt(i)); + break; } } - return new CompositeCurve3d(c3ds.ToArray()); + + return new CompositeCurve3d([.. c3ds]); } /// @@ -605,27 +828,26 @@ public static CompositeCurve3d ToCurve3d(this Polyline pl) public static NurbCurve3d? ToNurbCurve3d(this Polyline pl) { NurbCurve3d? nc3d = null; - for (int i = 0; i < pl.NumberOfVertices; i++) + for (var i = 0; i < pl.NumberOfVertices; i++) { - NurbCurve3d? nc3dtemp = null; + NurbCurve3d? nc3dTemp = null; switch (pl.GetSegmentType(i)) { case SegmentType.Line: - nc3dtemp = new NurbCurve3d(pl.GetLineSegmentAt(i)); - break; + nc3dTemp = new NurbCurve3d(pl.GetLineSegmentAt(i)); + break; case SegmentType.Arc: - nc3dtemp = pl.GetArcSegmentAt(i).ToNurbCurve3d(); - break; - - default: - break; + nc3dTemp = pl.GetArcSegmentAt(i).ToNurbCurve3d(); + break; } + if (nc3d is null) - nc3d = nc3dtemp; - else if (nc3dtemp is not null) - nc3d.JoinWith(nc3dtemp); + nc3d = nc3dTemp; + else if (nc3dTemp is not null) + nc3d.JoinWith(nc3dTemp); } + return nc3d; } @@ -639,19 +861,18 @@ public static CompositeCurve3d ToCurve3d(this Polyline pl) public static void ChamferAt(this Polyline polyline, int index, double radius, bool isFillet) { if (index < 1 || index > polyline.NumberOfVertices - 2) - throw new System.Exception("错误的索引号"); + throw new Exception("错误的索引号"); if (SegmentType.Line != polyline.GetSegmentType(index - 1) || SegmentType.Line != polyline.GetSegmentType(index)) - throw new System.Exception("非直线段不能倒角"); + throw new Exception("非直线段不能倒角"); // 获取当前索引号的前后两段直线,并组合为Ge复合曲线 Curve3d[] c3ds = - new Curve3d[] - { - polyline.GetLineSegmentAt(index - 1), - polyline.GetLineSegmentAt(index) - }; + [ + polyline.GetLineSegmentAt(index - 1), + polyline.GetLineSegmentAt(index) + ]; CompositeCurve3d cc3d = new(c3ds); // 试倒直角 @@ -659,28 +880,18 @@ public static void ChamferAt(this Polyline polyline, int index, double radius, b // 1、=3时倒角方向正确 // 2、=2时倒角方向相反 // 3、=0或为直线时失败 - c3ds = - cc3d.GetTrimmedOffset - ( - radius, - Vector3d.ZAxis, - OffsetCurveExtensionType.Chamfer - ); + c3ds = cc3d.GetTrimmedOffset(radius, Vector3d.ZAxis, OffsetCurveExtensionType.Chamfer); if (c3ds.Length > 0 && c3ds[0] is CompositeCurve3d) { - var newcc3d = c3ds[0] as CompositeCurve3d; - c3ds = newcc3d!.GetCurves(); + var newCc3d = c3ds[0] as CompositeCurve3d; + c3ds = newCc3d!.GetCurves(); if (c3ds.Length == 3) { - c3ds = cc3d.GetTrimmedOffset - ( - -radius, - Vector3d.ZAxis, - OffsetCurveExtensionType.Chamfer - ); + c3ds = cc3d.GetTrimmedOffset(-radius, Vector3d.ZAxis, + OffsetCurveExtensionType.Chamfer); if (c3ds.Length == 0 || c3ds[0] is LineSegment3d) - throw new System.Exception("倒角半径过大"); + throw new Exception("倒角半径过大"); } else if (c3ds.Length == 2) { @@ -689,29 +900,16 @@ public static void ChamferAt(this Polyline polyline, int index, double radius, b } else { - throw new System.Exception("倒角半径过大"); + throw new Exception("倒角半径过大"); } // GetTrimmedOffset会生成倒角+偏移,故先反方向倒角,再倒回 - c3ds = cc3d.GetTrimmedOffset - ( - -radius, - Vector3d.ZAxis, - OffsetCurveExtensionType.Extend - ); - OffsetCurveExtensionType type = - isFillet ? - OffsetCurveExtensionType.Fillet : OffsetCurveExtensionType.Chamfer; - c3ds = c3ds[0].GetTrimmedOffset - ( - radius, - Vector3d.ZAxis, - type - ); + c3ds = cc3d.GetTrimmedOffset(-radius, Vector3d.ZAxis, OffsetCurveExtensionType.Extend); + var type = isFillet ? OffsetCurveExtensionType.Fillet : OffsetCurveExtensionType.Chamfer; + c3ds = c3ds[0].GetTrimmedOffset(radius, Vector3d.ZAxis, type); // 将结果Ge曲线转为Db曲线,并将相关的数值反映到原曲线 - var plTemp = c3ds[0].ToCurve() as Polyline; - if (plTemp is null) + if (c3ds[0].ToCurve() is not Polyline plTemp) return; polyline.RemoveVertexAt(index); polyline.AddVertexAt(index, plTemp.GetPoint2dAt(1), plTemp.GetBulgeAt(1), 0, 0); diff --git a/src/CADShared/ExtensionMethod/Entity/DBTextEx.cs b/src/CADShared/ExtensionMethod/Entity/DBTextEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..0b198f8a39237ce4dd42ec032ae8e5fe72b0cea6 --- /dev/null +++ b/src/CADShared/ExtensionMethod/Entity/DBTextEx.cs @@ -0,0 +1,60 @@ +namespace IFoxCAD.Cad; + +/// +/// 单行文字扩展类 +/// +public static class DBTextEx +{ + /// + /// 创建单行文字 + /// + /// 插入点 + /// 文本内容 + /// 文字高度 + /// 对齐方式 + /// 文字所在的数据库 + /// 文字属性设置委托 + /// 文字对象 + /// + public static DBText CreateDBText(Point3d position, string text, double height, + AttachmentPoint justify = AttachmentPoint.BaseLeft, Database? database = null, + Action? action = null) + { + if (string.IsNullOrEmpty(text)) + throw new ArgumentNullException(nameof(text), "创建文字无内容"); + + var workingDatabase = database ?? HostApplicationServices.WorkingDatabase; + using var _ = new SwitchDatabase(workingDatabase); + + var acText = new DBText(); + acText.SetDatabaseDefaults(workingDatabase); + + acText.Height = height; + acText.TextString = text; + acText.Position = position; // 插入点(一定要先设置) + + acText.Justify = justify; // 使他们对齐 + + action?.Invoke(acText); + + if (!acText.IsDefaultAlignment) + acText.AlignmentPoint = position; + + acText.AdjustAlignment(workingDatabase); + + return acText; + } + + /// + /// 更正单行文字的镜像属性 + /// + /// 单行文字 + public static void ValidateMirror(this DBText txt) + { + if (!txt.Database.Mirrtext) + { + txt.IsMirroredInX = false; + txt.IsMirroredInY = false; + } + } +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Entity/EntityBoundingInfo.cs b/src/CADShared/ExtensionMethod/Entity/EntityBoundingInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..854f9cc4abf9d6ce133975f5aef77bdbe0e9c796 --- /dev/null +++ b/src/CADShared/ExtensionMethod/Entity/EntityBoundingInfo.cs @@ -0,0 +1,251 @@ +namespace IFoxCAD.Cad; + +/// +/// 获取实体包围盒信息方法 +/// +internal static class EntityBoundingInfo +{ + /// + /// 获取包围盒信息 + /// + /// 包围盒 + /// 包围盒信息 + public static BoundingInfo? GetBoundingInfo(this Extents3d ext) + { + return new(ext); + } + + /// + /// 获取多行文本的正交包围盒 + /// + /// 多行文本 + /// 包围盒 + static Extents3d GetMTextBox(MText mText) + { + var ext = new Extents3d(); + foreach (var p in GetMTextBoxCorners(mText)) + { + ext.AddPoint(p); + } + + return ext; + } + + /// + /// 获取块的包围盒 + /// + /// 实体 + /// + /// + static void GetBlockBox(this Entity en, ref Extents3d ext, ref Matrix3d mat) + { + if (en is BlockReference block) + { + var matins = mat * block.BlockTransform; + if (block.BlockTableRecord.GetObject() is BlockTableRecord btr) + foreach (var id in btr) + { + if (id.GetObject() is Entity ent1) + { + if (ent1.Visible != true) + continue; + if (ent1 is AttributeDefinition att) + { + if (!att.Constant || att.Invisible) + continue; + } + + GetBlockBox(ent1, ref ext, ref matins); + } + } + + if (block.AttributeCollection.Count > 0) + { + foreach (var att in block.GetAttributes()) + { + if (!att.Invisible && att.Visible) + GetBlockBox(att, ref ext, ref mat); + } + } + } + else + { + if (mat.IsUniscaledOrtho()) + { + using (var ent1 = en.GetTransformedCopy(mat)) + { + if (ext.IsEmptyExt()) + { + //var e = ent1.GetEntityBox(); + var e = GetEntityBoxEx(ent1); + if (e.HasValue) + ext = e.Value; + } + else + { + //var e = ent1.GetEntityBox(); + var e = GetEntityBoxEx(ent1); + if (e.HasValue) + ext.AddExtents(e.Value); + } + } + } + else + { + //var e = en.GetEntityBox(); + var e = GetEntityBoxEx(en); + if (e.HasValue) + { + var entext = e.Value; + entext.TransformBy(mat); + if (ext.IsEmptyExt()) + ext = entext; + else + ext.AddExtents(entext); + } + + return; + } + } + + return; + } + + /// + /// 获取多行文字最小包围盒4点坐标 + /// + /// 多行文本 + /// 最小包围盒4点坐标 + public static Point3d[] GetMTextBoxCorners(MText mtext) + { + var width = mtext.ActualWidth; + var height = mtext.ActualHeight; + Point3d point1, point2; + switch (mtext.Attachment) + { + case AttachmentPoint.TopLeft: + default: + point1 = new Point3d(0.0, -height, 0.0); + point2 = new Point3d(width, 0.0, 0.0); + break; + case AttachmentPoint.TopCenter: + point1 = new Point3d(-width * 0.5, -height, 0.0); + point2 = new Point3d(width * 0.5, 0.0, 0.0); + break; + case AttachmentPoint.TopRight: + point1 = new Point3d(-width, -height, 0.0); + point2 = new Point3d(0.0, 0.0, 0.0); + break; + case AttachmentPoint.MiddleLeft: + point1 = new Point3d(0.0, -height * 0.5, 0.0); + point2 = new Point3d(width, height * 0.5, 0.0); + break; + case AttachmentPoint.MiddleCenter: + point1 = new Point3d(-width * 0.5, -height * 0.5, 0.0); + point2 = new Point3d(width * 0.5, height * 0.5, 0.0); + break; + case AttachmentPoint.MiddleRight: + point1 = new Point3d(-width, -height * 0.5, 0.0); + point2 = new Point3d(0.0, height * 0.5, 0.0); + break; + case AttachmentPoint.BottomLeft: + point1 = new Point3d(0.0, 0.0, 0.0); + point2 = new Point3d(width, height, 0.0); + break; + case AttachmentPoint.BottomCenter: + point1 = new Point3d(-width * 0.5, 0.0, 0.0); + point2 = new Point3d(width * 0.5, height, 0.0); + break; + case AttachmentPoint.BottomRight: + point1 = new Point3d(-width, 0.0, 0.0); + point2 = new Point3d(0.0, height, 0.0); + break; + } + + var xform = Matrix3d.Displacement(mtext.Location.GetAsVector()) * + Matrix3d.Rotation(mtext.Rotation, mtext.Normal, Point3d.Origin) * + Matrix3d.PlaneToWorld(new Plane(Point3d.Origin, mtext.Normal)); + + return + [ + point1.TransformBy(xform), + new Point3d(point2.X, point1.Y, 0.0).TransformBy(xform), + point2.TransformBy(xform), + new Point3d(point1.X, point2.Y, 0.0).TransformBy(xform) + ]; + } + + /// + /// 获取实体包围盒 + /// + /// 实体 + /// 包围盒 + public static Extents3d? GetEntityBoxEx(Entity ent) + { + Extents3d? ext = null; + switch (ent) + { + case Spline spl: + ext = spl.ToPolyline().GeometricExtents; + break; + case MText mtext: + ext = GetMTextBox(mtext); + break; + case Table table: + if (table.IsNewObject) + table.GenerateLayout(); + table.RecomputeTableBlock(true); + ext = table.GeometricExtents; + break; + case Dimension dim: + if (dim.IsNewObject) + dim.GenerateLayout(); // 新new的实体生成布局,即可获取包围盒 + dim.RecomputeDimensionBlock(true); + ext = dim.GeometricExtents; + break; + case BlockReference block: + Extents3d blockExt = default; + var mat = Matrix3d.Identity; + block!.GetBlockBox(ref blockExt, ref mat); + if (!blockExt.IsEmptyExt()) + ext = blockExt; + break; + // 和尚_2024-10-26 + case Hatch hatch: + var hc = new HatchConverter(hatch); + hc.GetBoundarysData(); + var extTmp = new Extents3d(); + foreach (var curve in hc.CreateBoundary()) + { + extTmp.AddExtents(GetEntityBoxEx(curve)!.Value); + curve.Dispose(); + } + + ext = extTmp; + break; + default: + if (ent.Bounds.HasValue) + ext = ent.GeometricExtents; + break; + } + + if (ext != null) + //实体不是点时,pass + if (ent is not DBPoint && ext.Value.MinPoint.IsEqualTo(ext.Value.MaxPoint)) + return null; + return ext; + } + + /// + /// 判断包围盒是否有效 + /// + /// 包围盒 + /// + static bool IsEmptyExt(this Extents3d ext) + { + if (ext.MinPoint.DistanceTo(ext.MaxPoint) < Tolerance.Global.EqualPoint) + return true; + else + return false; + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/EntityEx.cs b/src/CADShared/ExtensionMethod/Entity/EntityEx.cs similarity index 61% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/EntityEx.cs rename to src/CADShared/ExtensionMethod/Entity/EntityEx.cs index 65f7ee4c674fadac8e3ebecc36a74a6fabde9183..1f505418f0d11d02f7295ce88caa2a75b6dd33e3 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/EntityEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/EntityEx.cs @@ -1,13 +1,10 @@ namespace IFoxCAD.Cad; - /// /// 实体图元扩展类 /// public static class EntityEx { - - #region 实体线性变换 /// @@ -18,7 +15,20 @@ public static class EntityEx /// 目标点 public static void Move(this Entity ent, Point3d from, Point3d to) { - ent.TransformBy(Matrix3d.Displacement(to - from)); + Move(ent, to - from); + } + + /// + /// 移动实体 + /// + /// 实体 + /// 向量 + public static void Move(this Entity ent, Vector3d vector) + { + using (ent.ForWrite()) + { + ent.TransformBy(Matrix3d.Displacement(vector)); + } } /// @@ -29,7 +39,10 @@ public static void Move(this Entity ent, Point3d from, Point3d to) /// 缩放比例 public static void Scale(this Entity ent, Point3d center, double scaleValue) { - ent.TransformBy(Matrix3d.Scaling(scaleValue, center)); + using (ent.ForWrite()) + { + ent.TransformBy(Matrix3d.Scaling(scaleValue, center)); + } } /// @@ -41,7 +54,10 @@ public static void Scale(this Entity ent, Point3d center, double scaleValue) /// 旋转平面的法向矢量 public static void Rotation(this Entity ent, Point3d center, double angle, Vector3d normal) { - ent.TransformBy(Matrix3d.Rotation(angle, normal, center)); + using (ent.ForWrite()) + { + ent.TransformBy(Matrix3d.Rotation(angle, normal, center)); + } } /// @@ -52,7 +68,10 @@ public static void Rotation(this Entity ent, Point3d center, double angle, Vecto /// 转角,弧度制,正数为顺时针 public static void Rotation(this Entity ent, Point3d center, double angle) { - ent.TransformBy(Matrix3d.Rotation(angle, Vector3d.ZAxis.TransformBy(ent.Ecs), center)); + using (ent.ForWrite()) + { + ent.TransformBy(Matrix3d.Rotation(angle, Vector3d.ZAxis.TransformBy(ent.Ecs), center)); + } } /// @@ -63,7 +82,11 @@ public static void Rotation(this Entity ent, Point3d center, double angle) /// 对称轴终点 public static void Mirror(this Entity ent, Point3d startPoint, Point3d endPoint) { - ent.TransformBy(Matrix3d.Mirroring(new Line3d(startPoint, endPoint))); + using (ent.ForWrite()) + { + using var line3d = new Line3d(startPoint, endPoint); + ent.TransformBy(Matrix3d.Mirroring(line3d)); + } } /// @@ -73,7 +96,10 @@ public static void Mirror(this Entity ent, Point3d startPoint, Point3d endPoint) /// 对称平面 public static void Mirror(this Entity ent, Plane plane) { - ent.TransformBy(Matrix3d.Mirroring(plane)); + using (ent.ForWrite()) + { + ent.TransformBy(Matrix3d.Mirroring(plane)); + } } /// @@ -83,12 +109,16 @@ public static void Mirror(this Entity ent, Plane plane) /// 对称点 public static void Mirror(this Entity ent, Point3d basePoint) { - ent.TransformBy(Matrix3d.Mirroring(basePoint)); + using (ent.ForWrite()) + { + ent.TransformBy(Matrix3d.Mirroring(basePoint)); + } } #endregion #region 实体范围 + /// /// 获取实体集合的范围 /// @@ -99,25 +129,36 @@ public static Extents3d GetExtents(this IEnumerable ents) var ext = new Extents3d(); foreach (var item in ents) { - ext.AddExtents(item.GeometricExtents); + var e = item.GetBoundingBoxEx(); + if (e.HasValue) + ext.AddExtents(e.Value.Extents3d); } + return ext; } + #endregion - /// /// 获取图元包围盒 /// /// /// 包围盒信息 - /// 异常: - /// 会将包围盒类型记录到所属路径中,以此查询 - public static BoundingInfo GetBoundingBoxEx(this Entity ent) + public static BoundingInfo? GetBoundingBoxEx(this Entity ent) { - return EntityBoundingInfo.GetBoundingInfo(ent); + return EntityBoundingInfo.GetEntityBoxEx(ent)?.GetBoundingInfo(); } - + /// + /// 获取拉伸点 + /// + /// 实体 + /// 点集 + public static List GetStretchPoints(this Entity ent) + { + using var p3dc = new Point3dCollection(); + ent.GetStretchPoints(p3dc); + return p3dc.Cast().ToList(); + } } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/MTextEx.cs b/src/CADShared/ExtensionMethod/Entity/MTextEx.cs similarity index 39% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/MTextEx.cs rename to src/CADShared/ExtensionMethod/Entity/MTextEx.cs index fd39bac75dd60fb93c7d42403a53a3fb505bc6a0..52c85a97c627360d2b00e06f6e05fae4a733e465 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Entity/MTextEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/MTextEx.cs @@ -1,10 +1,43 @@ -namespace IFoxCAD.Cad; +using ArgumentNullException = System.ArgumentNullException; + +namespace IFoxCAD.Cad; /// /// 多行文字扩展类 /// public static class MTextEx { + /// + /// 创建多行文字 + /// + /// 插入点 + /// 文本内容 + /// 文字高度 + /// 文字所在的数据库 + /// 文字属性设置委托 + /// 文字对象id + /// + public static MText CreateMText(Point3d position, string text, double height, Database? database = null, + Action? action = null) + { + if (string.IsNullOrEmpty(text)) + throw new ArgumentNullException(nameof(text), "创建文字无内容"); + + var db = database ?? DBTrans.Top.Database; + using var _ = new SwitchDatabase(db); + + var mText = new MText(); + + mText.SetDatabaseDefaults(db); + + mText.TextHeight = height; // 高度 + mText.Contents = text; // 内容 + mText.Location = position; // 插入点 + + action?.Invoke(mText); + + return mText; + } /// /// 炸散多行文字 @@ -18,11 +51,10 @@ public static class MTextEx /// 回调函数处理的结果 /// /// - public static void ExplodeFragments(this MText mt, T obj, Func mTextFragmentCallback) + public static void ExplodeFragments(this MText mt, T obj, + Func mTextFragmentCallback) { - mt.ExplodeFragments( - (f, o) => - mTextFragmentCallback(f, (T)o), obj); + mt.ExplodeFragments((f, o) => mTextFragmentCallback(f, (T)o), obj); } /// @@ -32,14 +64,12 @@ public static void ExplodeFragments(this MText mt, T obj, Func文本 public static string GetUnFormatString(this MText mt) { - List strs = new(); - mt.ExplodeFragments( - strs, - (f, o) => { - o.Add(f.Text); - return MTextFragmentCallbackStatus.Continue; - }); + List strs = []; + mt.ExplodeFragments(strs, (f, o) => + { + o.Add(f.Text); + return MTextFragmentCallbackStatus.Continue; + }); return string.Join("", strs.ToArray()); } - } \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Entity/PolylineEx.cs b/src/CADShared/ExtensionMethod/Entity/PolylineEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..25a034a6d74445767a18afe4d73c284063b3106d --- /dev/null +++ b/src/CADShared/ExtensionMethod/Entity/PolylineEx.cs @@ -0,0 +1,163 @@ +namespace IFoxCAD.Cad; + +/// +/// 多段线扩展类 +/// +public static class PolylineEx +{ + #region 获取多段线端点 + + /// + /// 获取二维多段线的端点坐标 + /// + /// 二维多段线 + /// 端点坐标集合 + public static IEnumerable GetPoints(this Polyline2d pl2d) + { + var tr = DBTrans.GetTopTransaction(pl2d.Database); + foreach (ObjectId id in pl2d) + { + if (tr.GetObject(id) is Vertex2d vertex) + { + yield return vertex.Position; + } + } + } + + /// + /// 获取三维多段线的端点坐标 + /// + /// 三维多段线 + /// 端点坐标集合 + public static IEnumerable GetPoints(this Polyline3d pl3d) + { + var tr = DBTrans.GetTopTransaction(pl3d.Database); + foreach (ObjectId id in pl3d) + { + if (tr.GetObject(id) is PolylineVertex3d vertex) + yield return vertex.Position; + } + } + + /// + /// 获取多段线的端点坐标 + /// + /// 多段线 + /// 端点坐标集合 + public static List GetPoints(this Polyline pl) + { + return + Enumerable + .Range(0, pl.NumberOfVertices) + .Select(pl.GetPoint3dAt) + .ToList(); + } + + #endregion + + #region 创建多段线 + + /// + /// 根据点集创建多段线
+ /// 此多段线无默认全局宽度0,无圆弧段 + ///
+ /// 点集 + /// 多段线属性设置委托 + /// 多段线对象 + public static Polyline CreatePolyline(this IEnumerable points, Action? action = null) + { + Polyline pl = new(); + pl.SetDatabaseDefaults(); + points.ForEach((index, pt) => { pl.AddVertexAt(index, pt.Point2d(), 0, 0, 0); }); + action?.Invoke(pl); + return pl; + } + + /// + /// 根据点集创建多段线 + /// + /// 端点表,利用元组(Point3d pt, double bulge, double startWidth, double endWidth) + /// 轻多段线属性设置委托 + /// 轻多段线对象 + public static Polyline CreatePolyline( + this IEnumerable<(Point3d pt, double bulge, double startWidth, double endWidth)> pts, + Action? action = null) + { + Polyline pl = new(); + pl.SetDatabaseDefaults(); + + pts.ForEach((index, vertex) => + { + pl.AddVertexAt(index, vertex.pt.Point2d(), vertex.bulge, vertex.startWidth, vertex.endWidth); + }); + action?.Invoke(pl); + return pl; + } + + /// + /// 根据Extents3d创建多段线
+ /// 此多段线无默认全局宽度0,无圆弧段,标高为0 + ///
+ /// Extents3d + /// 多段线属性设置委托 + /// 多段线对象 + public static Polyline CreatePolyline(this Extents3d points, Action? action = null) + { + List pts = + [ + points.MinPoint.Point2d(), + new(points.MinPoint.X, points.MaxPoint.Y), + points.MaxPoint.Point2d(), + new(points.MaxPoint.X, points.MinPoint.Y) + ]; + + Polyline pl = new() { Closed = true }; + pl.SetDatabaseDefaults(); + pts.ForEach((index, pt) => { pl.AddVertexAt(index, pt, 0, 0, 0); }); + action?.Invoke(pl); + return pl; + } + + + /// + /// 点表生成多段线 + /// + /// 点表 + /// 线宽 + /// 是否闭合 + /// Polyline + public static Polyline ToPolyline(this IEnumerable pointList, double plineWidth = 0, bool closed = false) + { + var pl = new Polyline(); + var enumerable = pointList.ToList(); + for (var i = 0; i < enumerable.Count; i++) + { + pl.AddVertexAt(i, enumerable.ElementAt(i), 0, plineWidth, plineWidth); + } + + pl.Closed = closed; + return pl; + } + + /// + /// 点表生成多段线 + /// + /// 点表 + /// 线宽 + /// 是否闭合 + /// Polyline + public static Polyline ToPolyline(this IEnumerable pointList, double plineWidth = 0, bool closed = false) + { + var pl = new Polyline(); + var enumerable = pointList.ToList(); + for (var i = 0; i < enumerable.Count; i++) + { + pl.AddVertexAt(i, enumerable.ElementAt(i).Point2d(), 0, plineWidth, plineWidth); + } + + pl.Closed = closed; + return pl; + } + + #endregion +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Entity/RegionEx.cs b/src/CADShared/ExtensionMethod/Entity/RegionEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..c8323058d0fa820247ae2c6828d57f362d67fdad --- /dev/null +++ b/src/CADShared/ExtensionMethod/Entity/RegionEx.cs @@ -0,0 +1,75 @@ +#if acad +using Autodesk.AutoCAD.BoundaryRepresentation; + +#elif zcad +using ZwSoft.ZwCAD.BoundaryRepresentation; +#endif +namespace IFoxCAD.Cad; + +/// +/// 面域扩展 +/// +public static class RegionEx +{ + /// + /// 面域转曲线 + /// + /// 面域 + /// 曲线集合 + public static IEnumerable ToCurves(this Region region) + { + if (region.IsNull) + yield break; + using var brep = new Brep(region); + var loops = brep.Complexes.SelectMany(complex => complex.Shells) + .SelectMany(shell => shell.Faces) + .SelectMany(face => face.Loops); + foreach (var loop in loops) + { + var curves3d = loop.Edges.Select(edge => ((ExternalCurve3d)edge.Curve).NativeCurve) + .ToList(); + var cur = Curve.CreateFromGeCurve(1 < curves3d.Count + ? new CompositeCurve3d(curves3d.ToOrderedArray()) + : curves3d.First()); + + foreach (var curve3d in curves3d) + { + curve3d.Dispose(); + } + + cur.SetPropertiesFrom(region); + yield return cur; + } + } + + /// + /// 按首尾相连对曲线集合进行排序 + /// + /// + /// 曲线列表 + /// 当不能首尾相连时会抛出此异常 + private static Curve3d[] ToOrderedArray(this IEnumerable source) + { + var tol = new Tolerance(0.001, 0.001); + var list = source.ToList(); + var count = list.Count; + var array = new Curve3d[count]; + var i = 0; + array[0] = list[0]; + list.RemoveAt(0); + while (i < count - 1) + { + var pt = array[i++].EndPoint; + int index; + if ((index = list.FindIndex(c => c.StartPoint.IsEqualTo(pt, tol))) != -1) + array[i] = list[index]; + else if ((index = list.FindIndex(c => c.EndPoint.IsEqualTo(pt, tol))) != -1) + array[i] = list[index].GetReverseParameterCurve(); + else + throw new ArgumentException("非连续曲线."); + list.RemoveAt(index); + } + + return array; + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Enums.cs b/src/CADShared/ExtensionMethod/Enums.cs similarity index 83% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Enums.cs rename to src/CADShared/ExtensionMethod/Enums.cs index d100ded9fb2ff4a5bc0a15ebee691f1cf15e1e7b..87f02c374237b4e5e0a9b86c62e5cdb21544822b 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Enums.cs +++ b/src/CADShared/ExtensionMethod/Enums.cs @@ -37,7 +37,10 @@ public enum XrefModes : byte ///
Bind, } - +/// +/// 符号表模式 +/// +[Flags] public enum SymModes : ushort { /// @@ -65,6 +68,9 @@ public enum SymModes : ushort /// 线型表 /// LinetypeTable = 32, + /// + /// 图层|字体|标注|线型|应用 + /// Option1 = LayerTable | TextStyleTable | DimStyleTable | LinetypeTable | RegAppTable, /// @@ -79,9 +85,14 @@ public enum SymModes : ushort /// 视口表 /// ViewportTable = 256, + /// + /// 坐标|视口|视图 + /// Option2 = UcsTable | ViewTable | ViewportTable, - // 全部 + /// + /// 全部 + /// All = BlockTable | Option1 | Option2 } @@ -158,17 +169,34 @@ public enum PointOnRegionType } - +/// +/// ttf字体枚举 +/// public enum FontTTF { + /// + /// 宋体 + /// [Description("宋体.ttf")] 宋体, + /// + /// 仿宋 + /// [Description("simfang.ttf")] 仿宋, + /// + /// 仿宋GB2312 + /// [Description("FSGB2312.ttf")] 仿宋GB2312, + /// + /// Arial + /// [Description("Arial.ttf")] Arial, + /// + /// Romans + /// [Description("Romans")] Romans } \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/ErrorInfoEx.cs b/src/CADShared/ExtensionMethod/ErrorInfoEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..9462d79201f2628644330fb9ef3f68c8c2a25b49 --- /dev/null +++ b/src/CADShared/ExtensionMethod/ErrorInfoEx.cs @@ -0,0 +1,421 @@ +namespace IFoxCAD.Cad; + +/// +/// CAD错误大全 +/// +public static class ErrorInfoEx +{ + /// + /// 打印CAD错误信息到命令行 + /// 使用方法: + /// try + /// { + /// //你的代码 + /// } + /// catch (AcException acex) { acex.AcErrorInfo(); } + /// catch (Exception) { throw; } + /// + /// + /// AcException + internal static void AcErrorInfo(this AcException acex) + { + var infoStr = acex.Message switch + { + "eAlreadyInDb" => "已经在数据库中了", + "eAmbiguousInput" => "模糊不清的输入", + "eAmbiguousOutput" => "模糊不清的输出", + "eAnonymousEntry" => "多重入口", + "eBrokenHandle" => "损坏的句柄", + "eBufferTooSmall" => "缓冲区太小", + "eContainerNotEmpty" => "容器不为空", + "eDeletedEntry" => "已经删除的函数入口", + "eDuplicateDxfField" => "DXF字段重复", + "eDuplicateIndex" => "重复的索引", + "eDuplicateKey" => "重复的关键字", + "eEndOfFile" => "文件结束", + "eEndOfObject" => "对象结束", + "eEntityInInactiveLayout" => "实体不在活动布局上", + "eHandleExists" => "句柄已存在", + "eHandleInUse" => "句柄被占用", + "eIllegalEntityType" => "非法的实体类型", + "eIllegalReplacement" => "非法的替代者", + "eInvalidAdsName" => "无效的ADS名称", + "eInvalidBlockName" => "不合理的块名称", + "eInvalidDwgVersion" => "不合理的DWG版本", + "eInvalidDxfCode" => "不合理的DXF编码", + "eInvalidExtents" => "无效的空间范围", + "eInvalidIndex" => "无效的索引", + "eInvalidInput" => "无效的输入", + "eInvalidKey" => "无效的关键字", + "eInvalidOpenState" => "无效的打开状态", + "eInvalidSymbolTableName" => "无效的符号名称", + "eIsReading" => "正在读取", + "eIsWriting" => "正在写入", + "eKeyNotFound" => "关键字未找到", + "eMissingDxfField" => "DXF字段缺失", + "eNegativeValueNotAllowed" => "不允许输入负数", + "eNotApplicable" => "不合适的", + "eNotImplementedYet" => "尚未实现", + "eNotOpenForRead" => "不是只读打开", + "eNotOpenForWrite" => "不是可写打开", + "eNotThatKindOfClass" => "类型不匹配", + "eNullBlockName" => "块名称为空", + "eNullEntityPointer" => "实体指针为空", + "eNullHandle" => "空句柄", + "eNullObjectId" => "对象ID为空", + "eNullObjectPointer" => "对象指针为空", + "eObjectToBeDeleted" => "对象即将被删除", + "eOk" => "正确", + "eOutOfDisk" => "硬盘容量不足", + "eOutOfMemory" => "内存不足", + "eUnknownHandle" => "未知句柄", + "eWrongDatabase" => "错误的数据库", + "eWrongObjectType" => "错误的类型", + "eInvalidResBuf" => "不合理的ResBuf", + "eBadDxfSequence" => "不正确的DXF顺序", + "eFilerError" => "文件错误", + "eVertexAfterFace" => "顶点在面后面", + "eInvalidFaceVertexIndex" => "不合理的面顶点顺序", + "eInvalidMeshVertexIndex" => "不合理的mesh顺序", + "eOtherObjectsBusy" => "其它对象忙", + "eMustFirstAddBlockToDb" => "必须先把块加入到数据库", + "eCannotNestBlockDefs" => "不可以嵌套块定义", + "eDwgRecoveredOK" => "修复DWG完成", + "eDwgNotRecoverable" => "无法修复DWG", + "eDxfPartiallyRead" => "DXF部分读取", + "eDxfReadAborted" => "读取DXF终止", + "eDxbPartiallyRead" => "DXB部分读取", + "eDwgCRCDoesNotMatch" => "DWG文件的CRC不匹配", + "eDwgSentinelDoesNotMatch" => "DWG文件的校验不匹配", + "eDwgObjectImproperlyRead" => "DWG文件错误读取", + "eNoInputFiler" => "没有找到输入过滤", + "eDwgNeedsAFullSave" => "DWG需要完全保存", + "eDxbReadAborted" => "DXB读取终止", + "eFileLockedByACAD" => "文件被ACAD锁定", + "eFileAccessErr" => "无法读取文件", + "eFileSystemErr" => "文件系统错误", + "eFileInternalErr" => "文件内部错误", + "eFileTooManyOpen" => "文件被打开太多次", + "eFileNotFound" => "未找到文件", + "eDwkLockFileFound" => "找到DWG锁定文件", + "eWasErased" => "对象被删除", + "ePermanentlyErased" => "对象被永久删除", + "eWasOpenForRead" => "对象只读打开", + "eWasOpenForWrite" => "对象可写打开", + "eWasOpenForUndo" => "对象撤销打开", + "eWasNotifying" => "对象被通知", + "eWasOpenForNotify" => "对象通知打开", + "eOnLockedLayer" => "对象在锁定图层上", + "eMustOpenThruOwner" => "必须经过所有者打开", + "eSubentitiesStillOpen" => "子对象依然打开着", + "eAtMaxReaders" => "超过最大打开次数", + "eIsWriteProtected" => "对象被写保护", + "eIsXRefObject" => "对象是XRef", + "eNotAnEntity" => "对象不是实体", + "eHadMultipleReaders" => "被多重打开", + "eDuplicateRecordName" => "重复的记录名称", + "eXRefDependent" => "依赖于XREF", + "eSelfReference" => "引用自身", + "eMissingSymbolTable" => "丢失符号化表", + "eMissingSymbolTableRec" => "丢失符号化记录", + "eWasNotOpenForWrite" => "不是可写打开", + "eCloseWasNotifying" => "对象关闭,正在执行通知", + "eCloseModifyAborted" => "对象关闭,修改被取消", + "eClosePartialFailure" => "对象关闭,部分操作未成功", + "eCloseFailObjectDamaged" => "对象被损坏,关闭失败", + "eCannotBeErasedByCaller" => "对象不可以被当前呼叫者删除", + "eCannotBeResurrected" => "不可以复活", + "eWasNotErased" => "对象未删除", + "eInsertAfter" => "在后面插入", + "eFixedAllErrors" => "修复了所有错误", + "eLeftErrorsUnfixed" => "剩下一些错误未修复", + "eUnrecoverableErrors" => "不可恢复的错误", + "eNoDatabase" => "没有数据库", + "eXdataSizeExceeded" => "扩展数据长度太大", + "eRegappIdNotFound" => "没有找到扩展数据注册ID", + "eRepeatEntity" => "重复实体", + "eRecordNotInTable" => "表中未找到记录", + "eIteratorDone" => "迭代器完成", + "eNullIterator" => "空的迭代器", + "eNotInBlock" => "不在块中", + "eOwnerNotInDatabase" => "所有者不在数据库中", + "eOwnerNotOpenForRead" => "所有者不是只读打开", + "eOwnerNotOpenForWrite" => "所有者不是可写打开", + "eExplodeBeforeTransform" => "在变换之前就被炸开了", + "eCannotScaleNonUniformly" => "不可以不同比例缩放", + "eNotInDatabase" => "不在数据库中", + "eNotCurrentDatabase" => "不是当前数据库", + "eIsAnEntity" => "是一个实体", + "eCannotChangeActiveViewport" => "不可以改变活动视口", + "eNotInPaperspace" => "不在图纸空间中", + "eCommandWasInProgress" => "正在执行命令", + "eGeneralModelingFailure" => "创建模型失败", + "eOutOfRange" => "超出范围", + "eNonCoplanarGeometry" => "没有平面几何对象", + "eDegenerateGeometry" => "退化的几何对象", + "eInvalidAxis" => "无效的轴线", + "ePointNotOnEntity" => "点不在实体上", + "eSingularPoint" => "单一的点", + "eInvalidOffset" => "无效的偏移", + "eNonPlanarEntity" => "没有平面的实体", + "eCannotExplodeEntity" => "不可分解的实体", + "eStringTooLong" => "字符串太短", + "eInvalidSymTableFlag" => "无效的符号化表标志", + "eUndefinedLineType" => "没有定义的线型", + "eInvalidTextStyle" => "无效的字体样式", + "eTooFewLineTypeElements" => "太少的线型要素", + "eTooManyLineTypeElements" => "太多的线型要素", + "eExcessiveItemCount" => "过多的项目", + "eIgnoredLinetypeRedef" => "忽略线型定义描述", + "eBadUCS" => "不好的用户坐标系", + "eBadPaperspaceView" => "不好的图纸空间视图", + "eSomeInputDataLeftUnread" => "一些输入数据未被读取", + "eNoInternalSpace" => "不是内部空间", + "eInvalidDimStyle" => "无效的标注样式", + "eInvalidLayer" => "无效的图层", + "eUserBreak" => "用户打断", + "eDwgNeedsRecovery" => "DWG文件需要修复", + "eDeleteEntity" => "删除实体", + "eInvalidFix" => "无效的方位", + "eFSMError" => "FSM错误", + "eBadLayerName" => "不好的图层名称", + "eLayerGroupCodeMissing" => "图层分组编码丢失", + "eBadColorIndex" => "不好的颜色索引号", + "eBadLinetypeName" => "不好的线型名称", + "eBadLinetypeScale" => "不好的线型缩放比例", + "eBadVisibilityValue" => "不好的可见性值", + "eProperClassSeparatorExpected" => "本身类未找到预期的分割符号(?)", + "eBadLineWeightValue" => "不好的线宽值", + "eBadColor" => "不好的颜色", + "ePagerError" => "页面错误", + "eOutOfPagerMemory" => "页面内存不足", + "ePagerWriteError" => "页面不可写", + "eWasNotForwarding" => "不是促进(?)", + "eInvalidIdMap" => "无效的ID字典", + "eInvalidOwnerObject" => "无效的所有者", + "eOwnerNotSet" => "未设置所有者", + "eWrongSubentityType" => "错误的子对象类型", + "eTooManyVertices" => "太多节点", + "eTooFewVertices" => "太少节点", + "eNoActiveTransactions" => "不活动的事务", + "eNotTopTransaction" => "不是最顶层的事务", + "eTransactionOpenWhileCommandEnded" => "在命令结束的时候打开(/开始)事务", + "eInProcessOfCommitting" => "在提交事务的过程中", + "eNotNewlyCreated" => "不是新创建的", + "eLongTransReferenceError" => "长事务引用错误", + "eNoWorkSet" => "没有工作集", + "eAlreadyInGroup" => "已经在组中了", + "eNotInGroup" => "不在组中", + "eInvalidREFIID" => "无效的REFIID", + "eInvalidNormal" => "无效的标准", + "eInvalidStyle" => "无效的样式", + "eCannotRestoreFromAcisFile" => "不可以从Acis(?)文件中恢复", + "eMakeMeProxy" => "自我代理", + "eNLSFileNotAvailable" => "无效的NLS文件", + "eNotAllowedForThisProxy" => "不允许这个代理", + "eNotSupportedInDwgApi" => "在Dwg Api中不支持", + "ePolyWidthLost" => "多段线宽度丢失", + "eNullExtents" => "空的空间范围", + "eExplodeAgain" => "再一次分解", + "eBadDwgHeader" => "坏的DWG文件头", + "eLockViolation" => "锁定妨碍当前操作", + "eLockConflict" => "锁定冲突", + "eDatabaseObjectsOpen" => "数据库对象打开", + "eLockChangeInProgress" => "锁定改变中", + "eVetoed" => "禁止", + "eNoDocument" => "没有文档", + "eNotFromThisDocument" => "不是从这个文档", + "eLISPActive" => "LISP活动", + "eTargetDocNotQuiescent" => "目标文档活动中", + "eDocumentSwitchDisabled" => "禁止文档转换", + "eInvalidContext" => "无效的上下文环境", + "eCreateFailed" => "创建失败", + "eCreateInvalidName" => "创建无效名称", + "eSetFailed" => "设置失败", + "eDelDoesNotExist" => "删除对象不存在", + "eDelIsModelSpace" => "删除模型空间", + "eDelLastLayout" => "删除最后一个布局", + "eDelUnableToSetCurrent" => "删除后无法设置当前对象", + "eDelUnableToFind" => "没有找到删除对象", + "eRenameDoesNotExist" => "重命名对象不存在", + "eRenameIsModelSpace" => "不可以重命令模型空间", + "eRenameInvalidLayoutName" => "重命名无效的布局名称", + "eRenameLayoutAlreadyExists" => "重命名布局名称已存在", + "eRenameInvalidName" => "重命名无效名称", + "eCopyDoesNotExist" => "拷贝不存在", + "eCopyIsModelSpace" => "拷贝是模型空间", + "eCopyFailed" => "拷贝失败", + "eCopyInvalidName" => "拷贝无效名称", + "eCopyNameExists" => "拷贝名称存在", + "eProfileDoesNotExist" => "配置名称不存在", + "eInvalidFileExtension" => "无效的文件后缀名成", + "eInvalidProfileName" => "无效的配置文件名称", + "eFileExists" => "文件存在", + "eProfileIsInUse" => "配置文件存在", + "eCantOpenFile" => "打开文件失败", + "eNoFileName" => "没有文件名称", + "eRegistryAccessError" => "读取注册表错误", + "eRegistryCreateError" => "创建注册表项错误", + "eBadDxfFile" => "坏的DXF文件", + "eUnknownDxfFileFormat" => "未知的DXF文件格式", + "eMissingDxfSection" => "丢失DXF分段", + "eInvalidDxfSectionName" => "无效的DXF分段名称", + "eNotDxfHeaderGroupCode" => "无效的DXF组码", + "eUndefinedDxfGroupCode" => "没有定义DXF组码", + "eNotInitializedYet" => "没有初始化", + "eInvalidDxf2dPoint" => "无效的DXF二维点", + "eInvalidDxf3dPoint" => "无效的DXD三维点", + "eBadlyNestedAppData" => "坏的嵌套应用程序数据", + "eIncompleteBlockDefinition" => "不完整的块定义", + "eIncompleteComplexObject" => "不完整的合成(?复杂)对象", + "eBlockDefInEntitySection" => "块定义在实体段中", + "eNoBlockBegin" => "没有块开始", + "eDuplicateLayerName" => "重复的图层名称", + "eBadPlotStyleName" => "不好的打印样式名称", + "eDuplicateBlockName" => "重复的块名称", + "eBadPlotStyleType" => "不好的打印样式类型", + "eBadPlotStyleNameHandle" => "不好的打印样式名称句柄", + "eUndefineShapeName" => "没有定义形状名称", + "eDuplicateBlockDefinition" => "重复的块定义", + "eMissingBlockName" => "丢失了块名称", + "eBinaryDataSizeExceeded" => "二进制数据长度太长", + "eObjectIsReferenced" => "对象被引用", + "eNoThumbnailBitmap" => "没有缩略图", + "eGuidNoAddress" => "未找到GUID地址", + "eMustBe0to2" => "必须是0到2", + "eMustBe0to3" => "必须是0到3", + "eMustBe0to4" => "必须是0到4", + "eMustBe0to5" => "必须是0到5", + "eMustBe0to8" => "必须是0到8", + "eMustBe1to8" => "必须是1到8", + "eMustBe1to15" => "必须是1到15", + "eMustBePositive" => "必须为正数", + "eMustBeNonNegative" => "必须为非负数", + "eMustBeNonZero" => "不可以等于0", + "eMustBe1to6" => "必须是1到6", + "eNoPlotStyleTranslationTable" => "没有打印样式事务表(?)", + "ePlotStyleInColorDependentMode" => "打印样式依赖颜色", + "eMaxLayouts" => "最大布局数量", + "eNoClassId" => "没有类ID", + "eUndoOperationNotAvailable" => "撤销操作无效", + "eUndoNoGroupBegin" => "撤销操作没有组开始", + "eHatchTooDense" => "填充太密集", + "eOpenFileCancelled" => "打开文件取消", + "eNotHandled" => "没有处理", + "eMakeMeProxyAndResurrect" => "将自己变成代理然后复活", + "eFileMissingSections" => "文件丢失分段", + "eRepeatedDwgRead" => "重复的读取DWG文件", + "eWrongCellType" => "错误的单元格类型", + "eCannotChangeColumnType" => "不可以改变列类型", + "eRowsMustMatchColumns" => "行必须匹配列", + "eFileSharingViolation" => "文件共享妨碍", + "eUnsupportedFileFormat" => "不支持的文件格式", + "eObsoleteFileFormat" => "废弃的文件格式", + "eDwgShareDemandLoad" => "DWG共享要求加载(?)", + "eDwgShareReadAccess" => "DWG共享读取", + "eDwgShareWriteAccess" => "DWG共享写入", + "eLoadFailed" => "加载失败", + "eDeviceNotFound" => "驱动未找到", + "eNoCurrentConfig" => "没有当前配置", + "eNullPtr" => "空指针", + "eNoLayout" => "没有布局", + "eIncompatiblePlotSettings" => "不兼容的打印设置", + "eNonePlotDevice" => "没有打印驱动", + "eNoMatchingMedia" => "没有匹配的打印尺寸", + "eInvalidView" => "无效的视图", + "eInvalidWindowArea" => "无效的窗口范围", + "eInvalidPlotArea" => "无效的打印范围", + "eCustomSizeNotPossible" => "用户输入的打印尺寸不可能存在", + "ePageCancelled" => "纸张取消", + "ePlotCancelled" => "打印取消", + "eInvalidEngineState" => "无效的引擎状态", + "ePlotAlreadyStarted" => "已经开始在打印了", + "eNoErrorHandler" => "没有错误处理", + "eInvalidPlotInfo" => "无效的打印信息", + "eNumberOfCopiesNotSupported" => "不支持打印份数", + "eLayoutNotCurrent" => "不是当前布局", + "eGraphicsNotGenerated" => "绘图对象创建失败(?)", + "eCannotPlotToFile" => "不可以打印到文件", + "eMustPlotToFile" => "必须打印到文件", + "eNotMultiPageCapable" => "不支持多种纸张", + "eBackgroundPlotInProgress" => "正在后台打印", + "eSubSelectionSetEmpty" => "子选择集被设置为空", + "eInvalidObjectId" => "无效的对象ID或者对象ID不在当前数据库", + "eInvalidXrefObjectId" => "无效的XREF对象ID或者XREF对象ID不在当前数据库", + "eNoViewAssociation" => "未找到对应的视图对象", + "eNoLabelBlock" => "视口未找到关联的块", + "eUnableToSetViewAssociation" => "设置视图关联视口失败", + "eUnableToGetViewAssociation" => "无法找到关联的视图", + "eUnableToSetLabelBlock" => "无法设置关联的块", + "eUnableToGetLabelBlock" => "无法获取关联的块", + "eUnableToRemoveAssociation" => "无法移除视口关联对象", + "eUnableToSyncModelView" => "无法同步视口和模型空间视图", + "eSecInitializationFailure" => "SEC(?)初始化错误", + "eSecErrorReadingFile" => "SEC(?)读取文件错误", + "eSecErrorWritingFile" => "SEC(?)写入文件错误", + "eSecInvalidDigitalID" => "SEC(?)无效的数字ID", + "eSecErrorGeneratingTimestamp" => "SEC(?)创建时间戳错误", + "eSecErrorComputingSignature" => "SEC(?)电子签名错误", + "eSecErrorWritingSignature" => "SEC(?)写入签名错误", + "eSecErrorEncryptingData" => "SEC(?)加密数据错误", + "eSecErrorCipherNotSupported" => "SEC(?)不支持的密码", + "eSecErrorDecryptingData" => "SEC(?)解密数据错误", + "eInetBase" => "网络错误", + "eInetOk" => "网络正常", + "eInetInCache" => "在缓冲区中", + "eInetFileNotFound" => "网络文件不存在", + "eInetBadPath" => "不好的网络路径", + "eInetTooManyOpenFiles" => "打开太多网络文件", + "eInetFileAccessDenied" => "打开网络文件被拒绝", + "eInetInvalidFileHandle" => "无效的网络文件句柄", + "eInetDirectoryFull" => "网络文件夹目录已满", + "eInetHardwareError" => "网络硬件错误", + "eInetSharingViolation" => "违反网络共享", + "eInetDiskFull" => "网络硬盘满了", + "eInetFileGenericError" => "网络文件创建错误", + "eInetValidURL" => "无效的URL地址", + "eInetNotAnURL" => "不是URL地址", + "eInetNoWinInet" => "没有WinInet(?)", + "eInetOldWinInet" => "旧的WinInet(?)", + "eInetNoAcadInet" => "无法连接ACAD网站", + "eInetNotImplemented" => "无法应用网络", + "eInetProtocolNotSupported" => "网络协议不支持", + "eInetCreateInternetSessionFailed" => "创建网络会话失败", + "eInetInternetSessionConnectFailed" => "连接网络会话失败", + "eInetInternetSessionOpenFailed" => "打开网络会话失败", + "eInetInvalidAccessType" => "无效的网络接收类型", + "eInetFileOpenFailed" => "打开网络文件失败", + "eInetHttpOpenRequestFailed" => "打开HTTP协议失败", + "eInetUserCancelledTransfer" => "用户取消了网络传输", + "eInetHttpBadRequest" => "不合理的网络请求", + "eInetHttpAccessDenied" => "HTTP协议拒绝", + "eInetHttpPaymentRequired" => "HTTP协议要求付费", + "eInetHttpRequestForbidden" => "禁止HTTP请求", + "eInetHttpObjectNotFound" => "HTTP对象未找到", + "eInetHttpBadMethod" => "不合理的HTTP请求方法", + "eInetHttpNoAcceptableResponse" => "不接受的HTTP回复", + "eInetHttpProxyAuthorizationRequired" => "要求HTTP代理授权", + "eInetHttpTimedOut" => "HTTP超时", + "eInetHttpConflict" => "HTTP冲突", + "eInetHttpResourceGone" => "网络资源被用光", + "eInetHttpLengthRequired" => "HTTP请求长度是必须的", + "eInetHttpPreconditionFailure" => "HTTP预处理失败", + "eInetHttpRequestTooLarge" => "HTTP请求太大", + "eInetHttpUriTooLong" => "URL地址太长", + "eInetHttpUnsupportedMedia" => "HTTP不支持的媒体", + "eInetHttpServerError" => "HTTP服务器错误", + "eInetHttpNotSupported" => "HTTP不支持", + "eInetHttpBadGateway" => "HTTP网关错误", + "eInetHttpServiceUnavailable" => "HTTP服务当前不可用", + "eInetHttpGatewayTimeout" => "HTTP网关超时", + "eInetHttpVersionNotSupported" => "HTTP版本不支持", + "eInetInternetError" => "HTTP网络错误", + "eInetGenericException" => "HTTP常规异常", + "eInetUnknownError" => "HTTP未知错误", + "eAlreadyActive" => "已经是活动的了", + "eAlreadyInactive" => "已经是不活动的了", + _ => acex.Message, + }; + Acaop.ShowAlertDialog($"{acex.Message}:{infoStr}"); + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DwgFiler.cs b/src/CADShared/ExtensionMethod/Filter/DwgFiler.cs similarity index 69% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DwgFiler.cs rename to src/CADShared/ExtensionMethod/Filter/DwgFiler.cs index 6820f375a806e362159ba830d8c7abbfd9f38e4c..dfb0ec93200a9e0ba244e46147788ae16e7f004b 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Filer/DwgFiler.cs +++ b/src/CADShared/ExtensionMethod/Filter/DwgFiler.cs @@ -1,4 +1,11 @@ -namespace IFoxCAD.Cad; +// ReSharper disable InconsistentNaming + +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 + +#if acad +using ErrorStatus = Autodesk.AutoCAD.Runtime.ErrorStatus; + +namespace IFoxCAD.Cad; /* Arx自定义实体类,加 读函数(assertReadEnabled)和写函数(assertWriteEnabled) @@ -7,136 +14,108 @@ [Serializable] 设置类 可以序列化 [Newtonsoft.Json.JsonIgnore] 设置成员 不可序列化 */ - -#if NewtonsoftJson -[JsonConverter(typeof(ObjectIdConverter))] -#endif +// DYH 2025-01-21 取消序列化相关代码,因为无法打上json转换器,不想让ifox再多引一个json包 +// 如有此类需求自己继承并实现即可 +// #if false +// [JsonConverter(typeof(ObjectIdConverter))] +// #endif [Serializable] -public class DwgFiler : Cad_DwgFiler +public class IFoxDwgFiler : DwgFiler { -#if NET35 - public int m_Position; -#else - public long m_Position; -#endif + public IFoxDwgFiler(FilerType filerType = FilerType.CopyFiler) + { + m_FilerType = filerType; + } + + public long m_Position = 0; public FilerType m_FilerType; - public Cad_ErrorStatus m_FilerStatus; - public List AddressList; - public int AddressListPt = 0; - public List BinaryChunkList; - public int BinaryChunkListPt = 0; - public List BooleanList; - public int BooleanListPt = 0; - public List ByteList; - public int ByteListPt = 0; - public List BytesList; - public int BytesListPt = 0; - public List DoubleList; - public int DoubleListPt = 0; - public List HandleList; - public int HandleListPt = 0; + public ErrorStatus m_FilerStatus = ErrorStatus.OK; + public List AddressList = new(); + public int AddressListPt; + public List BinaryChunkList = new(); + public int BinaryChunkListPt; + public List BooleanList = new(); + public int BooleanListPt; + public List ByteList = new(); + public int ByteListPt; + public List BytesList = new(); + public int BytesListPt; + public List DoubleList = new(); + public int DoubleListPt; + public List HandleList = new(); + + public int HandleListPt; + //[NonSerialized] //[ScriptIgnore] - public List HardOwnershipIdList; - public int HardOwnershipIdListPt = 0; + public List HardOwnershipIdList = new(); + + public int HardOwnershipIdListPt; + //[NonSerialized] //[ScriptIgnore] - public List HardPointerIdList; - public int HardPointerIdListPt = 0; - public List Int16List; - public int Int16ListPt = 0; - public List Int32List; - public int Int32ListPt = 0; -#if !NET35 - public List Int64List; - public int Int64ListPt = 0; -#endif - public List Point2dList; - public int Point2dListPt = 0; - public List Point3dList; - public int Point3dListPt = 0; - public List Scale3dList; - public int Scale3dListPt = 0; + public List HardPointerIdList = new(); + public int HardPointerIdListPt; + public List Int16List = new(); + public int Int16ListPt; + public List Int32List = new(); + public int Int32ListPt; + + public List Int64List = new(); + public int Int64ListPt; + + public List Point2dList = new(); + public int Point2dListPt; + public List Point3dList = new(); + public int Point3dListPt; + public List Scale3dList = new(); + + public int Scale3dListPt; + //[NonSerialized] //[ScriptIgnore] - public List SoftOwnershipIdList; - public int SoftOwnershipIdListPt = 0; + public List SoftOwnershipIdList = new(); + + public int SoftOwnershipIdListPt; + //[NonSerialized] //[ScriptIgnore] - public List SoftPointerIdList; - public int SoftPointerIdListPt = 0; - public List StringList; - public int StringListPt = 0; - public List Uint16List; - public int uint16ListPt = 0; - public List Uint32List; - public int uint32ListPt = 0; -#if !NET35 - public List Uint64List; - public int uint64ListPt = 0; -#endif - public List Vector2dList; - public int Vector2dListPt = 0; - public List Vector3dList; - public int Vector3dListPt = 0; - - public DwgFiler() - { - m_Position = 0; - m_FilerType = FilerType.CopyFiler; - m_FilerStatus = Cad_ErrorStatus.OK; - AddressList = new(); - BinaryChunkList = new(); - BooleanList = new(); - ByteList = new(); - BytesList = new(); - DoubleList = new(); - HandleList = new(); - HardOwnershipIdList = new(); - HardPointerIdList = new(); - Int16List = new(); - Int32List = new(); -#if !NET35 - Int64List = new(); -#endif - Point2dList = new(); - Point3dList = new(); - Scale3dList = new(); - SoftOwnershipIdList = new(); - SoftPointerIdList = new(); - StringList = new(); - Uint16List = new(); - Uint32List = new(); -#if !NET35 - Uint64List = new(); -#endif - Vector2dList = new(); - Vector3dList = new(); - } + public List SoftPointerIdList = new(); + public int SoftPointerIdListPt; + public List StringList = new(); + public int StringListPt; + public List Uint16List = new(); + public int uint16ListPt; + public List Uint32List = new(); + public int uint32ListPt; + + public List Uint64List = new(); + public int uint64ListPt; + + public List Vector2dList = new(); + public int Vector2dListPt; + public List Vector3dList = new(); + public int Vector3dListPt; -#if NET35 - public override int Position => m_Position; -#else public override long Position => m_Position; -#endif public override FilerType FilerType => m_FilerType; - public override Cad_ErrorStatus FilerStatus + public override ErrorStatus FilerStatus { - get { return m_FilerStatus; } - set { m_FilerStatus = value; } + get => m_FilerStatus; + set => m_FilerStatus = value; } public override IntPtr ReadAddress() { - if (AddressList.Count == 0) - return new(); + if (AddressListPt >= AddressList.Count) + return IntPtr.Zero; return AddressList[AddressListPt++]; } public override byte[]? ReadBinaryChunk() { - if (BinaryChunkList.Count == 0) + if (BinaryChunkListPt >= BinaryChunkList.Count) return null; return BinaryChunkList[BinaryChunkListPt++]; } @@ -205,14 +184,12 @@ public override int ReadInt32() return Int32List[Int32ListPt++]; } -#if !NET35 public override long ReadInt64() { if (Int64List.Count == 0) return 0; return Int64List[Int64ListPt++]; } -#endif public override Point2d ReadPoint2d() { @@ -251,7 +228,7 @@ public override ObjectId ReadSoftPointerId() public override string? ReadString() { - if (StringList.Count == 0) + if (StringListPt >= StringList.Count) return null; return StringList[StringListPt++]; } @@ -270,14 +247,12 @@ public override uint ReadUInt32() return Uint32List[uint32ListPt++]; } -#if !NET35 public override ulong ReadUInt64() { if (Uint64List.Count == 0) return 0; return Uint64List[uint64ListPt++]; } -#endif public override Vector2d ReadVector2d() { @@ -317,10 +292,10 @@ public override void ResetFilerStatus() Int16ListPt = 0; Int32List.Clear(); Int32ListPt = 0; -#if !NET35 + Int64List.Clear(); Int64ListPt = 0; -#endif + Point2dList.Clear(); Point2dListPt = 0; Point3dList.Clear(); @@ -337,10 +312,10 @@ public override void ResetFilerStatus() uint16ListPt = 0; Uint32List.Clear(); uint32ListPt = 0; -#if !NET35 + Uint64List.Clear(); uint64ListPt = 0; -#endif + Vector2dList.Clear(); Vector2dListPt = 0; Vector3dList.Clear(); @@ -362,16 +337,10 @@ public override void Seek(long offset, int method) #endif #if acad || gcad - public override void Seek( -#if NET35 - int -#else - long -#endif - offset, int method) + public override void Seek(long offset, int method) { var ed = Acap.DocumentManager.MdiActiveDocument.Editor; - ed.WriteMessage(MethodInfo.GetCurrentMethod().Name + " = " + " \n "); + ed.WriteMessage(MethodInfo.GetCurrentMethod()!.Name + " = " + " \n "); } #endif @@ -430,12 +399,11 @@ public override void WriteInt32(int value) Int32List.Add(value); } -#if !NET35 public override void WriteInt64(long value) { Int64List.Add(value); } -#endif + public override void WritePoint2d(Point2d value) { Point2dList.Add(value); @@ -476,12 +444,10 @@ public override void WriteUInt32(uint value) Uint32List.Add(value); } -#if !NET35 public override void WriteUInt64(ulong value) { Uint64List.Add(value); } -#endif public override void WriteVector2d(Vector2d value) { @@ -493,14 +459,16 @@ public override void WriteVector3d(Vector3d value) Vector3dList.Add(value); } - public override string ToString() - { -#if NewtonsoftJson - return JsonConvert.SerializeObject(this, Formatting.Indented); -#else - JavaScriptSerializer serializer = new(); - serializer.RegisterConverters(new[] { new ObjectIdConverter() }); - return serializer.Serialize(this); -#endif - } -} \ No newline at end of file + // public override string ToString() + // { +// #if NewtonsoftJson +// return JsonConvert.SerializeObject(this, Formatting.Indented); +// #else +// JavaScriptSerializer serializer = new(); +// serializer.RegisterConverters(new[] { new ObjectIdConverter() }); +// return serializer.Serialize(this); +// #endif + // } +} + +#endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Curve2dEx.cs b/src/CADShared/ExtensionMethod/Geomerty/Curve2dEx.cs similarity index 83% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Curve2dEx.cs rename to src/CADShared/ExtensionMethod/Geomerty/Curve2dEx.cs index 07db654fee2c9e43e61fae75d40249070a5e0f3b..251969df7b0a1007ccd7d937e67c3801c57047fd 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Curve2dEx.cs +++ b/src/CADShared/ExtensionMethod/Geomerty/Curve2dEx.cs @@ -1,11 +1,13 @@ -namespace IFoxCAD.Cad; +// ReSharper disable SuggestVarOrType_SimpleTypes + +namespace IFoxCAD.Cad; /// /// 二维解析类曲线转换为二维实体曲线扩展类 /// public static class Curve2dEx { - internal static readonly Plane _planeCache = new(); + private static readonly Plane _planeCache = new(); #region Curve2d @@ -92,18 +94,18 @@ public static Circle ToCircle(this CircularArc2d c2d) /// 圆弧 public static Arc ToArc(this CircularArc2d a2d) { - double startangle, endangle; - double refangle = a2d.ReferenceVector.Angle; + double startAngle, endAngle; + var refAngle = a2d.ReferenceVector.Angle; if (a2d.IsClockWise) { - startangle = -a2d.EndAngle - refangle; - endangle = -a2d.StartAngle - refangle; + startAngle = -a2d.EndAngle + refAngle; + endAngle = -a2d.StartAngle + refAngle; } else { - startangle = a2d.StartAngle + refangle; - endangle = a2d.EndAngle + refangle; + startAngle = a2d.StartAngle + refAngle; + endAngle = a2d.EndAngle + refAngle; } return @@ -111,8 +113,8 @@ public static Arc ToArc(this CircularArc2d a2d) new Point3d(_planeCache, a2d.Center), Vector3d.ZAxis, a2d.Radius, - startangle, - endangle); + startAngle, + endAngle); } #endregion CircularArc2d @@ -141,12 +143,12 @@ public static Ellipse ToCurve(this EllipticalArc2d ea2d, Matrix3d mat) public static Ellipse ToCurve(this EllipticalArc2d ea2d) { Ellipse ell = new( - new Point3d(_planeCache, ea2d.Center), - Vector3d.ZAxis, - new Vector3d(_planeCache, ea2d.MajorAxis) * ea2d.MajorRadius, - ea2d.MinorRadius / ea2d.MajorRadius, - 0, - Math.PI * 2); + new Point3d(_planeCache, ea2d.Center), + Vector3d.ZAxis, + new Vector3d(_planeCache, ea2d.MajorAxis) * ea2d.MajorRadius, + ea2d.MinorRadius / ea2d.MajorRadius, + 0, + Math.PI * 2); if (!ea2d.IsClosed()) { if (ea2d.IsClockWise) @@ -160,6 +162,7 @@ public static Ellipse ToCurve(this EllipticalArc2d ea2d) ell.EndAngle = ell.GetAngleAtParameter(ea2d.EndAngle); } } + return ell; } @@ -246,9 +249,9 @@ public static Line ToCurve(this LineSegment2d ls2d) #region NurbCurve2d /// - /// 将二维解析类BURB曲线转换为实体类样条曲线,并进行矩阵变换 + /// 将二维解析类NURB曲线转换为实体类样条曲线,并进行矩阵变换 /// - /// 二维解析类BURB曲线 + /// 二维解析类NURB曲线 /// 变换矩阵 /// 实体类样条曲线 public static Spline ToCurve(this NurbCurve2d nc2d, Matrix3d mat) @@ -259,37 +262,37 @@ public static Spline ToCurve(this NurbCurve2d nc2d, Matrix3d mat) } /// - /// 将二维解析类BURB曲线转换为实体类样条曲线 + /// 将二维解析类NURB曲线转换为实体类样条曲线 /// - /// 二维解析类BURB曲线 + /// 二维解析类NURB曲线 /// 实体类样条曲线 public static Spline ToCurve(this NurbCurve2d nc2d) { - using Point3dCollection ctlpnts = new(); - for (int i = 0; i < nc2d.NumControlPoints; i++) - ctlpnts.Add(new Point3d(_planeCache, nc2d.GetControlPointAt(i))); + using Point3dCollection ctlPts = new(); + for (var i = 0; i < nc2d.NumControlPoints; i++) + ctlPts.Add(new Point3d(_planeCache, nc2d.GetControlPointAt(i))); DoubleCollection knots = new(); - for (int i = 0; i < nc2d.Knots.Count; i++) + for (var i = 0; i < nc2d.Knots.Count; i++) knots.Add(nc2d.Knots[i]); DoubleCollection weights = new(); - for (int i = 0; i < nc2d.NumWeights; i++) + for (var i = 0; i < nc2d.NumWeights; i++) weights.Add(nc2d.GetWeightAt(i)); - NurbCurve2dData ncdata = nc2d.DefinitionData; + NurbCurve2dData nurbCurve2dData = nc2d.DefinitionData; return new Spline( - ncdata.Degree, - ncdata.Rational, + nurbCurve2dData.Degree, + nurbCurve2dData.Rational, nc2d.IsClosed(), - ncdata.Periodic, - ctlpnts, + nurbCurve2dData.Periodic, + ctlPts, knots, weights, 0, - nc2d.Knots.Tolerance); + nc2d.Knots.Tolerance) { Type = SplineType.FitPoints }; } #endregion NurbCurve2d diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Curve3dEx.cs b/src/CADShared/ExtensionMethod/Geomerty/Curve3dEx.cs similarity index 73% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/Curve3dEx.cs rename to src/CADShared/ExtensionMethod/Geomerty/Curve3dEx.cs index c12275b2a5c98ae72a13b00c4b2590be063f33f1..d3d6139f978c173ed970462f2632e98def4adb8c 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/Curve3dEx.cs +++ b/src/CADShared/ExtensionMethod/Geomerty/Curve3dEx.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +// ReSharper disable SuggestVarOrType_SimpleTypes namespace IFoxCAD.Cad; @@ -26,12 +26,13 @@ public static bool IsEqualPoint(this Tolerance tol, double d1, double d2) /// 获取三维解析类曲线(自交曲线)的交点参数 ///
/// 三维解析类曲线 + /// 是否排序 /// 曲线参数的列表 public static List GetParamsAtIntersectionPoints(this Curve3d c3d, bool sort = true) { CurveCurveIntersector3d cci = new(c3d, c3d, Vector3d.ZAxis); - List pars = new(); - for (int i = 0; i < cci.NumberOfIntersectionPoints; i++) + List pars = []; + for (var i = 0; i < cci.NumberOfIntersectionPoints; i++) pars.AddRange(cci.GetIntersectionParameters(i)); if (sort) pars.Sort(); @@ -48,8 +49,8 @@ public static List GetParamsAtIntersectionPoints(this Curve3d c3d, bool public static Curve3d GetSubCurve(this Curve3d curve, double from, double to) { Interval inter = curve.GetInterval(); - bool atStart = Tolerance.Global.IsEqualPoint(inter.LowerBound, from); - bool atEnd = Tolerance.Global.IsEqualPoint(inter.UpperBound, to); + var atStart = Tolerance.Global.IsEqualPoint(inter.LowerBound, from); + var atEnd = Tolerance.Global.IsEqualPoint(inter.UpperBound, to); if (atStart && atEnd) return (Curve3d)curve.Clone(); if (curve is NurbCurve3d) @@ -62,24 +63,20 @@ public static Curve3d GetSubCurve(this Curve3d curve, double from, double to) clone.HardTrimByParams(from, to); return clone; } - else - { - clone.HardTrimByParams(inter.LowerBound, to); - clone.HardTrimByParams(from, to); - return clone; - } - } - else - { - NurbCurve3d clone1 = (NurbCurve3d)curve.Clone(); - clone1.HardTrimByParams(from, inter.UpperBound); - NurbCurve3d clone2 = (NurbCurve3d)curve.Clone(); - clone2.HardTrimByParams(inter.LowerBound, to); - clone1.JoinWith(clone2); - return clone1; + + clone.HardTrimByParams(inter.LowerBound, to); + clone.HardTrimByParams(from, to); + return clone; } + + NurbCurve3d clone1 = (NurbCurve3d)curve.Clone(); + clone1.HardTrimByParams(from, inter.UpperBound); + NurbCurve3d clone2 = (NurbCurve3d)curve.Clone(); + clone2.HardTrimByParams(inter.LowerBound, to); + clone1.JoinWith(clone2); + return clone1; } - else + { Curve3d clone = (Curve3d)curve.Clone(); clone.SetInterval(new Interval(from, to, Tolerance.Global.EqualPoint)); @@ -149,16 +146,18 @@ public static bool IsCircular(this Curve3d curve) /// 三维复合曲线 /// 曲线参数列表 /// 三维复合曲线列表 - public static List? GetSplitCurves(this CompositeCurve3d c3d, List pars) + public static List? GetSplitCurves(this CompositeCurve3d c3d, + List pars) { // 曲线参数剔除重复的 if (pars.Count > 0) { pars.Sort(); - for (int i = pars.Count - 1; i > 0; i--) + for (var i = pars.Count - 1; i > 0; i--) if (Tolerance.Global.IsEqualPoint(pars[i], pars[i - 1])) pars.RemoveAt(i); } + if (pars.Count == 0) return null; @@ -188,6 +187,7 @@ public static bool IsCircular(this Curve3d curve) { pars[^1] = inter.UpperBound; } + // 加入第一点以支持反向打断 pars.Add(pars[0]); } @@ -204,9 +204,9 @@ public static bool IsCircular(this Curve3d curve) pars.Add(inter.UpperBound); } - List curves = new(); - List cc3ds = new(); - for (int i = 0; i < pars.Count - 1; i++) + List curves = []; + List cc3ds = []; + for (var i = 0; i < pars.Count - 1; i++) { cc3ds.Clear(); // 复合曲线参数转换到包含曲线参数 @@ -215,27 +215,20 @@ public static bool IsCircular(this Curve3d curve) if (cp1.SegmentIndex == cp2.SegmentIndex) { cc3ds.Add( - c3ds[cp1.SegmentIndex].GetSubCurve( - cp1.LocalParameter, - cp2.LocalParameter)); + c3ds[cp1.SegmentIndex].GetSubCurve(cp1.LocalParameter, cp2.LocalParameter)); } else { inter = c3ds[cp1.SegmentIndex].GetInterval(); - cc3ds.Add( - c3ds[cp1.SegmentIndex].GetSubCurve( - cp1.LocalParameter, - inter.UpperBound)); + cc3ds.Add(c3ds[cp1.SegmentIndex].GetSubCurve(cp1.LocalParameter, inter.UpperBound)); - for (int j = cp1.SegmentIndex + 1; j < cp2.SegmentIndex; j++) + for (var j = cp1.SegmentIndex + 1; j < cp2.SegmentIndex; j++) cc3ds.Add((Curve3d)c3ds[j].Clone()); inter = c3ds[cp2.SegmentIndex].GetInterval(); - cc3ds.Add( - c3ds[cp2.SegmentIndex].GetSubCurve( - inter.LowerBound, - cp2.LocalParameter)); + cc3ds.Add(c3ds[cp2.SegmentIndex].GetSubCurve(inter.LowerBound, cp2.LocalParameter)); } + curves.Add(new(cc3ds.ToArray())); } @@ -264,21 +257,20 @@ public static bool IsCircular(this Curve3d curve) if (cs.Length == 1) return ToCurve(cs[0]); - bool hasNurb = false; + var hasNurb = false; - for (int i = 0; i < cs.Length; i++) + foreach (var c in cs) { - var c = cs[i]; - if (c is NurbCurve3d || c is EllipticalArc3d) - { - hasNurb = true; - break; - } + if (c is not (NurbCurve3d or EllipticalArc3d)) + continue; + hasNurb = true; + break; } + if (hasNurb) { var nc3d = cs[0].ToNurbCurve3d(); - for (int i = 1; i < cs.Length; i++) + for (var i = 1; i < cs.Length; i++) nc3d?.JoinWith(cs[i].ToNurbCurve3d()); return nc3d?.ToCurve(); } @@ -298,24 +290,26 @@ public static Polyline ToPolyline(this CompositeCurve3d cc3d) pl.Elevation = cc3d.StartPoint[2]; Plane plane = pl.GetPlane(); - Point2d endver = Point2d.Origin; - int i = 0; + Point2d endVer = Point2d.Origin; + var i = 0; foreach (Curve3d c3d in cc3d.GetCurves()) { if (c3d is CircularArc3d ca3d) { - double b = Math.Tan(0.25 * (ca3d.EndAngle - ca3d.StartAngle)) * ca3d.Normal[2]; + var b = Math.Tan(0.25 * (ca3d.EndAngle - ca3d.StartAngle)) * ca3d.Normal[2]; pl.AddVertexAt(i, c3d.StartPoint.Convert2d(plane), b, 0, 0); - endver = c3d.EndPoint.Convert2d(plane); + endVer = c3d.EndPoint.Convert2d(plane); } else { pl.AddVertexAt(i, c3d.StartPoint.Convert2d(plane), 0, 0, 0); - endver = c3d.EndPoint.Convert2d(plane); + endVer = c3d.EndPoint.Convert2d(plane); } + i++; } - pl.AddVertexAt(i, endver, 0, 0, 0); + + pl.AddVertexAt(i, endVer, 0, 0, 0); return pl; } @@ -330,12 +324,11 @@ public static Polyline ToPolyline(this CompositeCurve3d cc3d) /// 实体类构造线 public static Xline ToCurve(this Line3d line3d) { - return - new Xline - { - BasePoint = line3d.PointOnLine, - SecondPoint = line3d.PointOnLine + line3d.Direction - }; + return new Xline + { + BasePoint = line3d.PointOnLine, + SecondPoint = line3d.PointOnLine + line3d.Direction + }; } /// @@ -345,14 +338,11 @@ public static Xline ToCurve(this Line3d line3d) /// 起点参数 /// 终点参数 /// 三维解析类线段 - public static LineSegment3d ToLineSegment3d(this Line3d line3d, double fromParameter, double toParameter) + public static LineSegment3d ToLineSegment3d(this Line3d line3d, double fromParameter, + double toParameter) { - return - new LineSegment3d - ( - line3d.EvaluatePoint(fromParameter), - line3d.EvaluatePoint(toParameter) - ); + return new LineSegment3d(line3d.EvaluatePoint(fromParameter), + line3d.EvaluatePoint(toParameter)); } #endregion Line3d @@ -384,10 +374,8 @@ public static Curve ToCurve(this CircularArc3d ca3d) { return ToCircle(ca3d); } - else - { - return ToArc(ca3d); - } + + return ToArc(ca3d); } /// @@ -406,8 +394,9 @@ public static Circle ToCircle(this CircularArc3d ca3d) => public static Arc ToArc(this CircularArc3d ca3d) { // 必须新建,而不能直接使用GetPlane()获取 - double angle = ca3d.ReferenceVector.AngleOnPlane(new Plane(ca3d.Center, ca3d.Normal)); - return new Arc(ca3d.Center, ca3d.Normal, ca3d.Radius, ca3d.StartAngle + angle, ca3d.EndAngle + angle); + var angle = ca3d.ReferenceVector.AngleOnPlane(new Plane(ca3d.Center, ca3d.Normal)); + return new Arc(ca3d.Center, ca3d.Normal, ca3d.Radius, ca3d.StartAngle + angle, + ca3d.EndAngle + angle); } /// @@ -417,19 +406,12 @@ public static Arc ToArc(this CircularArc3d ca3d) /// 三维解析类椭圆弧 public static EllipticalArc3d ToEllipticalArc3d(this CircularArc3d ca3d) { - Vector3d zaxis = ca3d.Normal; - Vector3d xaxis = ca3d.ReferenceVector; - Vector3d yaxis = zaxis.CrossProduct(xaxis); - - return - new EllipticalArc3d( - ca3d.Center, - xaxis, - yaxis, - ca3d.Radius, - ca3d.Radius, - ca3d.StartAngle, - ca3d.EndAngle); + Vector3d zAxis = ca3d.Normal; + Vector3d xAxis = ca3d.ReferenceVector; + Vector3d yAxis = zAxis.CrossProduct(xAxis); + + return new EllipticalArc3d(ca3d.Center, xAxis, yAxis, ca3d.Radius, ca3d.Radius, + ca3d.StartAngle, ca3d.EndAngle); } /// @@ -455,20 +437,15 @@ public static NurbCurve3d ToNurbCurve3d(this CircularArc3d ca3d) /// 实体类椭圆弧 public static Ellipse ToCurve(this EllipticalArc3d ea3d) { - Ellipse ell = - new( - ea3d.Center, - ea3d.Normal, - ea3d.MajorAxis * ea3d.MajorRadius, - ea3d.MinorRadius / ea3d.MajorRadius, - 0, - Math.PI * 2); + Ellipse ell = new(ea3d.Center, ea3d.Normal, ea3d.MajorAxis * ea3d.MajorRadius, + ea3d.MinorRadius / ea3d.MajorRadius, 0, Math.PI * 2); // Ge椭圆角度就是Db椭圆的参数 if (!ea3d.IsClosed()) { ell.StartAngle = ell.GetAngleAtParameter(ea3d.StartAngle); ell.EndAngle = ell.GetAngleAtParameter(ea3d.EndAngle); } + return ell; } @@ -486,22 +463,15 @@ public static Spline ToCurve(this NurbCurve3d nc3d) Spline spl; if (nc3d.HasFitData) { - NurbCurve3dFitData fdata = nc3d.FitData; - if (fdata.TangentsExist) + NurbCurve3dFitData fData = nc3d.FitData; + if (fData.TangentsExist) { - spl = new Spline( - fdata.FitPoints, - fdata.StartTangent, - fdata.EndTangent, - nc3d.Order, - fdata.FitTolerance.EqualPoint); + spl = new Spline(fData.FitPoints, fData.StartTangent, fData.EndTangent, nc3d.Order, + fData.FitTolerance.EqualPoint); } else { - spl = new Spline( - fdata.FitPoints, - nc3d.Order, - fdata.FitTolerance.EqualPoint); + spl = new Spline(fData.FitPoints, nc3d.Order, fData.FitTolerance.EqualPoint); } } else @@ -510,19 +480,14 @@ public static Spline ToCurve(this NurbCurve3d nc3d) foreach (double knot in nc3d.Knots) knots.Add(knot); - NurbCurve3dData ncdata = nc3d.DefinitionData; - - spl = new Spline( - ncdata.Degree, - ncdata.Rational, - nc3d.IsClosed(), - ncdata.Periodic, - ncdata.ControlPoints, - knots, - ncdata.Weights, - Tolerance.Global.EqualPoint, - ncdata.Knots.Tolerance); + NurbCurve3dData nurbCurve3dData = nc3d.DefinitionData; + + spl = new Spline(nurbCurve3dData.Degree, nurbCurve3dData.Rational, nc3d.IsClosed(), + nurbCurve3dData.Periodic, nurbCurve3dData.ControlPoints, knots, + nurbCurve3dData.Weights, Tolerance.Global.EqualPoint, + nurbCurve3dData.Knots.Tolerance); } + return spl; } @@ -537,19 +502,20 @@ public static Spline ToCurve(this NurbCurve3d nc3d) /// 实体类三维多段线 public static Polyline3d ToCurve(this PolylineCurve3d pl3d) { - using Point3dCollection pnts = new(); + using Point3dCollection pt3dCollection = new(); - for (int i = 0; i < pl3d.NumberOfControlPoints; i++) - pnts.Add(pl3d.ControlPointAt(i)); + for (var i = 0; i < pl3d.NumberOfControlPoints; i++) + pt3dCollection.Add(pl3d.ControlPointAt(i)); - bool closed = false; - int n = pnts.Count - 1; - if (pnts[0] == pnts[n]) + var closed = false; + var n = pt3dCollection.Count - 1; + if (pt3dCollection[0] == pt3dCollection[n]) { - pnts.RemoveAt(n); + pt3dCollection.RemoveAt(n); closed = true; } - return new Polyline3d(Poly3dType.SimplePoly, pnts, closed); + + return new Polyline3d(Poly3dType.SimplePoly, pt3dCollection, closed); } #endregion PolylineCurve3d diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/GeometryEx.cs b/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs similarity index 61% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/GeometryEx.cs rename to src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs index 58e9da30362db999f44a37c97423491dd950ce82..d21d81851a17cacd5de05a4987a4e8f995937525 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/GeometryEx.cs +++ b/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs @@ -1,3 +1,7 @@ +#if a2024 +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; using System.Drawing; @@ -17,46 +21,84 @@ public static class GeometryEx /// 点与多边形的关系 public static PointOnRegionType PointOnRegion(this IEnumerable pts, Point2d pt) { - // 遍历点集并生成首尾连接的多边形 - var ptlst = new LoopList(pts); - if (ptlst.Count < 3) + var ptList = pts.ToList(); + if (ptList.Count < 3) + return PointOnRegionType.Error; + if (ptList[0] == ptList[^1]) + { + ptList.RemoveAt(ptList.Count - 1); + } + + if (ptList.Count < 3) return PointOnRegionType.Error; - var ls2ds = new List(); - foreach (var node in ptlst.GetNodes()) +#if !zcad + List ls2ds = []; + for (var i = 0; i < ptList.Count - 1; i++) { - ls2ds.Add(new LineSegment2d(node.Value, node.Next!.Value)); + ls2ds.Add(new LineSegment2d(ptList[i], ptList[i + 1])); + } + + ls2ds.Add(new LineSegment2d(ptList[^1], ptList[0])); + using var cc2d = new CompositeCurve2d(ls2ds.ToArray()); + + // 释放资源 + foreach (var curve2d in ls2ds) + { + using (curve2d) + { + } } - var cc2d = new CompositeCurve2d(ls2ds.ToArray()); // 在多边形上? if (cc2d.IsOn(pt)) return PointOnRegionType.On; - // 在最小包围矩形外? var bb2d = cc2d.BoundBlock; if (!bb2d.Contains(pt)) return PointOnRegionType.Outside; - - // - bool flag = false; - foreach (var node in ptlst.GetNodes()) +#endif + + #region 旧版疑似有问题的代码 + + // // + // var flag = false; + // foreach (var node in ptlst.GetNodes()) + // { + // var pt1 = node.Value; + // var pt2 = node.Next!.Value; + // if (pt.Y < pt1.Y && pt.Y < pt2.Y) + // continue; + // if (pt1.X < pt.X && pt2.X < pt.X) + // continue; + // var vec = pt2 - pt1; + // var t = (pt.X - pt1.X) / vec.X; + // var y = t * vec.Y + pt1.Y; + // if (y < pt.Y && t >= 0 && t <= 1) + // flag = !flag; + // } + // return + // flag ? + // PointOnRegionType.Inside : PointOnRegionType.Outside; + + #endregion + + var flag = false; + var j = ptList.Count - 1; + for (var i = 0; i < ptList.Count; i++) { - var pt1 = node.Value; - var pt2 = node.Next!.Value; - if (pt.Y < pt1.Y && pt.Y < pt2.Y) - continue; - if (pt1.X < pt.X && pt2.X < pt.X) - continue; - Vector2d vec = pt2 - pt1; - double t = (pt.X - pt1.X) / vec.X; - double y = t * vec.Y + pt1.Y; - if (y < pt.Y && t >= 0 && t <= 1) - flag = !flag; + var pi = ptList[i]; + var pj = ptList[j]; + if ((pi.Y < pt.Y && pj.Y >= pt.Y || pj.Y < pt.Y && pi.Y >= pt.Y) && + (pi.X <= pt.X || pj.X <= pt.X)) + { + flag ^= pi.X + (pt.Y - pi.Y) / (pj.Y - pi.Y) * (pj.X - pi.X) < pt.X; + } + + j = i; } - return - flag ? - PointOnRegionType.Inside : PointOnRegionType.Outside; + + return flag ? PointOnRegionType.Inside : PointOnRegionType.Outside; } /// @@ -67,46 +109,60 @@ public static PointOnRegionType PointOnRegion(this IEnumerable pts, Poi /// 点与多边形的关系 public static PointOnRegionType PointOnRegion(this IEnumerable pts, Point3d pt) { - // 遍历点集并生成首尾连接的多边形 - var ptlst = new LoopList(pts); - if (ptlst.First!.Value == ptlst.Last!.Value) - ptlst.RemoveLast(); - if (ptlst.Count < 3) + var ptList = pts.ToList(); + if (ptList.Count < 3) return PointOnRegionType.Error; + if (ptList[0] == ptList[^1]) + { + ptList.RemoveAt(ptList.Count - 1); + } + + if (ptList.Count < 3) + return PointOnRegionType.Error; + + List ls3ds = []; + for (var i = 0; i < ptList.Count - 1; i++) + { + ls3ds.Add(new LineSegment3d(ptList[i], ptList[i + 1])); + } - var ls3ds = new List(); - foreach (var node in ptlst.GetNodes()) - ls3ds.Add(new LineSegment3d(node.Value, node.Next!.Value)); - var cc3d = new CompositeCurve3d(ls3ds.ToArray()); + ls3ds.Add(new LineSegment3d(ptList[^1], ptList[0])); + using var cc3d = new CompositeCurve3d(ls3ds.ToArray()); + + // 释放资源 + foreach (var curve3d in ls3ds) + { + using (curve3d) + { + } + } // 在多边形上? if (cc3d.IsOn(pt)) return PointOnRegionType.On; // 在最小包围矩形外? - var bb2d = cc3d.BoundBlock; - if (!bb2d.Contains(pt)) + var bb3d = cc3d.BoundBlock; + if (!bb3d.Contains(pt)) return PointOnRegionType.Outside; - // - bool flag = false; - foreach (var node in ptlst.GetNodes()) + + var flag = false; + var j = ptList.Count - 1; + for (var i = 0; i < ptList.Count; i++) { - var pt1 = node.Value; - var pt2 = node.Next!.Value; - if (pt.Y < pt1.Y && pt.Y < pt2.Y) - continue; - if (pt1.X < pt.X && pt2.X < pt.X) - continue; - Vector3d vec = pt2 - pt1; - double t = (pt.X - pt1.X) / vec.X; - double y = t * vec.Y + pt1.Y; - if (y < pt.Y && t >= 0 && t <= 1) - flag = !flag; + var pi = ptList[i]; + var pj = ptList[j]; + if ((pi.Y < pt.Y && pj.Y >= pt.Y || pj.Y < pt.Y && pi.Y >= pt.Y) && + (pi.X <= pt.X || pj.X <= pt.X)) + { + flag ^= pi.X + (pt.Y - pi.Y) / (pj.Y - pi.Y) * (pj.X - pi.X) < pt.X; + } + + j = i; } - return - flag ? - PointOnRegionType.Inside : PointOnRegionType.Outside; + + return flag ? PointOnRegionType.Inside : PointOnRegionType.Outside; } /// @@ -118,13 +174,8 @@ public static PointOnRegionType PointOnRegion(this IEnumerable pts, Poi /// 解析类圆对象 public static CircularArc2d GetMinCircle(Point2d pt1, Point2d pt2, out LoopList ptlst) { - ptlst = new LoopList { pt1, pt2 }; - return - new CircularArc2d - ( - (pt1 + pt2.GetAsVector()) / 2, - pt1.GetDistanceTo(pt2) / 2 - ); + ptlst = [pt1, pt2]; + return new CircularArc2d((pt1 + pt2.GetAsVector()) / 2, pt1.GetDistanceTo(pt2) / 2); } /// @@ -135,21 +186,17 @@ public static CircularArc2d GetMinCircle(Point2d pt1, Point2d pt2, out LoopList< /// 基准点 /// 输出圆上的点 /// 解析类圆对象 - public static CircularArc2d GetMinCircle(Point2d pt1, Point2d pt2, Point2d pt3, out LoopList ptlst) + public static CircularArc2d GetMinCircle(Point2d pt1, Point2d pt2, Point2d pt3, + out LoopList ptlst) { - ptlst = new LoopList { pt1, pt2, pt3 }; + ptlst = [pt1, pt2, pt3]; // 遍历各点与下一点的向量长度,找到距离最大的两个点 - LoopListNode maxNode = - ptlst.GetNodes().FindByMax - ( - out double maxLength, - node => node.Value.GetDistanceTo(node.Next!.Value) - ); + var maxNode = ptlst.GetNodes() + .FindByMax(out _, node => node.Value.GetDistanceTo(node.Next!.Value)); // 以两点做最小包围圆 - CircularArc2d ca2d = - GetMinCircle(maxNode.Value, maxNode.Next!.Value, out LoopList tptlst); + var ca2d = GetMinCircle(maxNode.Value, maxNode.Next!.Value, out var tptlst); // 如果另一点属于该圆 if (ca2d.IsIn(maxNode.Previous!.Value)) @@ -158,9 +205,10 @@ public static CircularArc2d GetMinCircle(Point2d pt1, Point2d pt2, Point2d pt3, ptlst = tptlst; return ca2d; } + // 否则按三点做圆 // ptlst.SetFirst(maxNode); - ptlst = new LoopList { maxNode.Value, maxNode.Next.Value, maxNode.Previous.Value }; + ptlst = [maxNode.Value, maxNode.Next.Value, maxNode.Previous.Value]; ca2d = new CircularArc2d(pt1, pt2, pt3); ca2d.SetAngles(0, Math.PI * 2); return ca2d; @@ -175,7 +223,8 @@ public static CircularArc2d GetMinCircle(Point2d pt1, Point2d pt2, Point2d pt3, /// 基准点 /// 输出圆上的点 /// 解析类圆对象 - public static CircularArc2d? GetMinCircle(Point2d pt1, Point2d pt2, Point2d pt3, Point2d pt4, out LoopList? ptlst) + public static CircularArc2d? GetMinCircle(Point2d pt1, Point2d pt2, Point2d pt3, Point2d pt4, + out LoopList? ptlst) { var iniptlst = new LoopList() { pt1, pt2, pt3, pt4 }; ptlst = null; @@ -187,7 +236,8 @@ public static CircularArc2d GetMinCircle(Point2d pt1, Point2d pt2, Point2d pt3, // 获取各组合下三点的最小包围圆 var secondNode = firstNode.Next; var thirdNode = secondNode!.Next; - var tca2d = GetMinCircle(firstNode.Value, secondNode.Value, thirdNode!.Value, out LoopList tptlst); + var tca2d = GetMinCircle(firstNode.Value, secondNode.Value, thirdNode!.Value, + out var tptlst); // 如果另一点属于该圆,并且半径小于当前值就把它做为候选解 if (!tca2d.IsIn(firstNode.Previous!.Value)) @@ -214,6 +264,7 @@ private static double CalArea(Point2d ptBase, Point2d pt1, Point2d pt2) { return (pt2 - ptBase).DotProduct((pt1 - ptBase).GetPerpendicularVector()) * 0.5; } + /// /// 计算三点围成的三角形的真实面积 /// @@ -290,16 +341,16 @@ public static OrientationType IsClockWise(Vector2d vecBase, Vector2d vec) /// 有向面积 private static double CalArea(IEnumerable pnts) { - var itor = pnts.GetEnumerator(); + using var itor = pnts.GetEnumerator(); if (!itor.MoveNext()) - throw new ArgumentNullException(nameof(pnts)); + throw new System.ArgumentNullException(nameof(pnts)); var start = itor.Current; - Point2d p1, p2 = start; + var p2 = start; double area = 0; while (itor.MoveNext()) { - p1 = p2; + var p1 = p2; p2 = itor.Current; area += (p1.X * p2.Y - p2.X * p1.Y); } @@ -307,6 +358,7 @@ private static double CalArea(IEnumerable pnts) area = (area + (p2.X * start.Y - start.X * p2.Y)) / 2.0; return area; } + /// /// 计算点集的真实面积 /// @@ -344,21 +396,18 @@ public static OrientationType IsClockWise(this IEnumerable pnts) switch (pnts.Count) { case 0: - ptlst = null; - return null; + ptlst = null; + return null; case 1: - ptlst = new LoopList { pnts[0] }; - return new CircularArc2d(pnts[0], 0); + ptlst = [pnts[0]]; + return new CircularArc2d(pnts[0], 0); - case 2: - return GetMinCircle(pnts[0], pnts[1], out ptlst); + case 2: return GetMinCircle(pnts[0], pnts[1], out ptlst); - case 3: - return GetMinCircle(pnts[0], pnts[1], pnts[2], out ptlst); + case 3: return GetMinCircle(pnts[0], pnts[1], pnts[2], out ptlst); - case 4: - return GetMinCircle(pnts[0], pnts[1], pnts[2], pnts[3], out ptlst); + case 4: return GetMinCircle(pnts[0], pnts[1], pnts[2], pnts[3], out ptlst); } // 按前三点计算最小包围圆 @@ -384,10 +433,9 @@ public static OrientationType IsClockWise(this IEnumerable pnts) { // 第三点取另两点中距离圆心较远的点 // 按算法中描述的任选其中一点的话,还是无法收敛...... - tpnts[2] = - tpnts.Except(ptlst) - .FindByMax(pnt => ca2d!.Center.GetDistanceTo(pnt)); + tpnts[2] = tpnts.Except(ptlst).FindByMax(pnt => ca2d!.Center.GetDistanceTo(pnt)); } + tpnts[0] = ptlst.First!.Value; tpnts[1] = ptlst.First.Next!.Value; @@ -401,6 +449,18 @@ public static OrientationType IsClockWise(this IEnumerable pnts) return ca2d; } + /// + /// 叉积,二维叉乘计算 + /// + /// 原点 + /// oa向量 + /// ob向量,此为判断点 + /// 返回值有正负,表示绕原点四象限的位置变换,也就是有向面积 + private static double Cross(Point2d o, Point2d a, Point2d b) + { + return (a.X - o.X) * (b.Y - o.Y) - (a.Y - o.Y) * (b.X - o.X); + } + /// /// 获取点集的凸包 /// @@ -408,36 +468,33 @@ public static OrientationType IsClockWise(this IEnumerable pnts) /// 凸包 public static List? ConvexHull(this List points) { - if (points is null) - return null; - - if (points.Count <= 1) - return points; + if (points.Count < 3) return null; - int n = points.Count, k = 0; - List H = new(new Point2d[2 * n]); + //坐标排序 + points = points.OrderBy(p => p.X).ThenBy(p => p.Y).ToList(); - points.Sort((a, b) => - a.X == b.X ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X)); + var hullPts = new List(); - // Build lower hull - for (int i = 0; i < n; ++i) - { - while (k >= 2 && IsClockWise(H[k - 2], H[k - 1], points[i]) == OrientationType.CounterClockWise) - k--; - H[k++] = points[i]; + //构建下凸包 + foreach (var pt in points) { + while (hullPts.Count >= 2 && Cross(hullPts[^2], hullPts[^1], pt) <= 0) + hullPts.RemoveAt(hullPts.Count - 1); + hullPts.Add(pt); } - // Build upper hull - for (int i = n - 2, t = k + 1; i >= 0; i--) - { - while (k >= t && IsClockWise(H[k - 2], H[k - 1], points[i]) == OrientationType.CounterClockWise) - k--; - H[k++] = points[i]; + //构建上凸包 + var lowerHullCount = hullPts.Count + 1; + for (var i = points.Count - 2; i >= 0; i--) { + while (hullPts.Count >= lowerHullCount && Cross(hullPts[^2], hullPts[^1], points[i]) <= 0) + hullPts.RemoveAt(hullPts.Count - 1); + hullPts.Add(points[i]); } - return H.Take(k - 1).ToList(); - } + //移除与起点重复的尾点 + hullPts.RemoveAt(hullPts.Count - 1); + + return hullPts.Count >= 3 ? hullPts : null; + } #endregion PointList @@ -492,7 +549,8 @@ public static Vector3d Wcs2Ucs(this Vector3d vec) /// 源坐标系 /// 目标坐标系 /// 变换后的点 - public static Point3d Trans(this Point3d point, CoordinateSystemCode from, CoordinateSystemCode to) + public static Point3d Trans(this Point3d point, CoordinateSystemCode from, + CoordinateSystemCode to) { return Env.Editor.GetMatrix(from, to) * point; } @@ -504,7 +562,8 @@ public static Point3d Trans(this Point3d point, CoordinateSystemCode from, Coord /// 源坐标系 /// 目标坐标系 /// 变换后的向量 - public static Vector3d Trans(this Vector3d vec, CoordinateSystemCode from, CoordinateSystemCode to) + public static Vector3d Trans(this Vector3d vec, CoordinateSystemCode from, + CoordinateSystemCode to) { return vec.TransformBy(Env.Editor.GetMatrix(from, to)); } @@ -517,11 +576,8 @@ public static Vector3d Trans(this Vector3d vec, CoordinateSystemCode from, Coord /// 变换后的点 public static Point3d Wcs2Dcs(this Point3d point, bool atPaperSpace) { - return - Trans( - point, - CoordinateSystemCode.Wcs, atPaperSpace ? CoordinateSystemCode.PDcs : CoordinateSystemCode.MDcs - ); + return Trans(point, CoordinateSystemCode.Wcs, + atPaperSpace ? CoordinateSystemCode.PDcs : CoordinateSystemCode.MDcs); } /// @@ -532,16 +588,12 @@ public static Point3d Wcs2Dcs(this Point3d point, bool atPaperSpace) /// 变换后的向量 public static Vector3d Wcs2Dcs(this Vector3d vec, bool atPaperSpace) { - return - Trans( - vec, - CoordinateSystemCode.Wcs, atPaperSpace ? CoordinateSystemCode.PDcs : CoordinateSystemCode.MDcs - ); + return Trans(vec, CoordinateSystemCode.Wcs, + atPaperSpace ? CoordinateSystemCode.PDcs : CoordinateSystemCode.MDcs); } #endregion Ucs - /// /// 返回不等比例变换矩阵 /// @@ -552,7 +604,7 @@ public static Vector3d Wcs2Dcs(this Vector3d vec, bool atPaperSpace) /// 三维矩阵 public static Matrix3d GetScaleMatrix(this Point3d point, double x, double y, double z) { - double[] matdata = new double[16]; + var matdata = new double[16]; matdata[0] = x; matdata[3] = point.X * (1 - x); matdata[5] = y; @@ -570,102 +622,119 @@ public static Matrix3d GetScaleMatrix(this Point3d point, double x, double y, do /// 尺寸对象 public static Size GetSize(this Extents3d ext) { - int width = (int)Math.Floor(ext.MaxPoint.X - ext.MinPoint.X); - int height = (int)Math.Ceiling(ext.MaxPoint.Y - ext.MinPoint.Y); + var width = (int)Math.Floor(ext.MaxPoint.X - ext.MinPoint.X); + var height = (int)Math.Ceiling(ext.MaxPoint.Y - ext.MinPoint.Y); return new(width, height); } /// - /// 将三维点转换为二维点 + /// 重绘 /// - /// 三维点 - /// 二维点 - public static Point2d Point2d(this Point3d pt) + /// 图形界面几何 + /// 可绘制的对象列表 + public static void Draw(this Geometry geometry, IEnumerable drawables) { - return new(pt.X, pt.Y); + drawables.ForEach(d => geometry.Draw(d)); } + /// - /// 将三维点集转换为二维点集 + /// 重绘 /// - /// 三维点集 - /// 二维点集 - public static IEnumerable Point2d(this IEnumerable pts) + /// 图形界面几何 + /// 可绘制的对象列表 + public static void Draw(this Geometry geometry, params Drawable[] drawables) { - return pts.Select(pt => pt.Point2d()); + drawables.ForEach(d => geometry.Draw(d)); } +} + +/// +/// 向量扩展类 +/// +public static class VectorEx +{ /// - /// 将二维点转换为三维点 + /// 转换为2d向量 /// - /// 二维点 - /// Z值 - /// 三维点 - public static Point3d Point3d(this Point2d pt, double z = 0) + /// 3d向量 + /// 2d向量 + public static Vector2d Convert2d(this Vector3d vector3d) { - return new(pt.X, pt.Y, z); + return new Vector2d(vector3d.X, vector3d.Y); } /// - /// 获取两个点之间的中点 + /// 转换为3d向量 /// - /// 第一点 - /// 第二点 - /// 返回两个点之间的中点 - public static Point3d GetMidPointTo(this Point3d pt1, Point3d pt2) + /// 2d向量 + /// z值 + /// 3d向量 + public static Vector3d Convert3d(this Vector2d vector2d, double z = 0) { - return new(pt1.X * 0.5 + pt2.X * 0.5, - pt1.Y * 0.5 + pt2.Y * 0.5, - pt1.Z * 0.5 + pt2.Z * 0.5); + return new Vector3d(vector2d.X, vector2d.Y, z); } /// - /// 获取两个点之间的中点 + /// 2d叉乘 /// - /// 第一点 - /// 第二点 - /// 返回两个点之间的中点 - public static Point2d GetMidPointTo(this Point2d pt1, Point2d pt2) + /// 向量a + /// 向量b + /// 叉乘值 + public static double Cross2d(this Vector3d a, Vector3d b) { - // (pt1 + pt2) / 2; // 溢出风险 - return new(pt1.X * 0.5 + pt2.X * 0.5, - pt1.Y * 0.5 + pt2.Y * 0.5); + return a.X * b.Y - b.X * a.Y; } /// - /// 根据世界坐标计算用户坐标 + /// 2d叉乘 /// - /// 基点世界坐标 - /// 基点用户坐标 - /// 目标世界坐标 - /// 坐标网旋转角,按x轴正向逆时针弧度 - /// 目标用户坐标 - public static Point3d TransPoint(this Point3d basePt, Point3d userPt, Point3d transPt, double ang) + /// 向量a + /// 向量b + /// 叉乘值 + public static double Cross2d(this Vector2d a, Vector2d b) { - Matrix3d transMat = Matrix3d.Displacement(userPt - basePt); - Matrix3d roMat = Matrix3d.Rotation(-ang, Vector3d.ZAxis, userPt); - return transPt.TransformBy(roMat * transMat); + return a.X * b.Y - b.X * a.Y; } + /// - /// 计算指定距离和角度的点 + /// 向量Z值归零 /// - /// 本函数仅适用于x-y平面 - /// 基点 - /// 角度,x轴正向逆时针弧度 - /// 距离 - /// 目标点 - public static Point3d Polar(this Point3d pt, double ang, double len) + /// 向量 + /// + public static Vector3d Z20(this Vector3d vector3d) { - return pt + Vector3d.XAxis.RotateBy(ang, Vector3d.ZAxis) * len; + return new Vector3d(vector3d.X, vector3d.Y, 0); } + /// - /// 计算指定距离和角度的点 + /// 向量在平面上的弧度 /// - /// 本函数仅适用于x-y平面 - /// 基点 - /// 角度,x轴正向逆时针弧度 - /// 距离 - /// 目标点 - public static Point2d Polar(this Point2d pt, double ang, double len) + /// 向量 + /// 平面 + /// 弧度 + public static double AngleOnPlane(this Vector3d vector, Plane? plane = null) { - return pt + Vector2d.XAxis.RotateBy(ang) * len; + return vector.AngleOnPlane(plane ?? PlaneEx.Z); } +} + +/// +/// 平面 +/// +public static class PlaneEx +{ + /// + /// X + /// + public static readonly Plane X = new(Point3d.Origin, Vector3d.XAxis); + + /// + /// Y + /// + public static readonly Plane Y = new(Point3d.Origin, Vector3d.YAxis); + + /// + /// Z + /// + public static readonly Plane Z = new(Point3d.Origin, Vector3d.ZAxis); } \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Geomerty/PointEx.cs b/src/CADShared/ExtensionMethod/Geomerty/PointEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..2a89e17409135e7fa89f6dd7e496cb484bc62bc5 --- /dev/null +++ b/src/CADShared/ExtensionMethod/Geomerty/PointEx.cs @@ -0,0 +1,355 @@ +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; + +/// +/// 点 +/// +public static class PointEx +{ + /// + /// 获取点的hash字符串,同时可以作为pt的字符串表示 + /// + /// 点 + /// 指示计算几维坐标的标志,1为计算x,2为计算x,y,其他为计算x,y,z + /// 保留的小数位数 + /// hash字符串 + public static string GetHashString(this Point3d pt, int xyz = 3, int decimalRetain = 6) + { + var de = $"f{decimalRetain}"; + return xyz switch + { + 1 => $"({pt.X.ToString(de)})", + 2 => $"({pt.X.ToString(de)},{pt.Y.ToString(de)})", + _ => $"({pt.X.ToString(de)},{pt.Y.ToString(de)},{pt.Z.ToString(de)})" + }; + } + + // 为了频繁触发所以弄个缓存 + private static Plane? _planeCache; + + /// + /// 两点计算弧度范围0到2Pi + /// + /// 起点 + /// 终点 + /// 方向 + /// 弧度值 + public static double GetAngle(this Point3d startPoint, Point3d endPoint, Vector3d? direction = null) + { + if (direction != null) + _planeCache = new Plane(new Point3d(), direction.Value); + if (_planeCache == null) + _planeCache = new Plane(new Point3d(), Vector3d.ZAxis); + return startPoint.GetVectorTo(endPoint).AngleOnPlane(_planeCache); + } + + /// + /// 两点计算弧度范围0到2Pi + /// + /// 起点 + /// 终点 + /// 弧度值 + public static double GetAngle(this Point2d startPoint, Point2d endPoint) + { + return startPoint.GetVectorTo(endPoint).Angle; + } + + /// + /// 获取中点 + /// + /// + /// + /// + public static Point2d GetMidPointTo(this Point2d a, Point2d b) + { + // (p1 + p2) / 2; // 溢出风险 + return new Point2d(a.X * 0.5 + b.X * 0.5, + a.Y * 0.5 + b.Y * 0.5); + } + + /// + /// 获取两个点之间的中点 + /// + /// 第一点 + /// 第二点 + /// 返回两个点之间的中点 + public static Point3d GetMidPointTo(this Point3d pt1, Point3d pt2) + { + return new(pt1.X * 0.5 + pt2.X * 0.5, + pt1.Y * 0.5 + pt2.Y * 0.5, + pt1.Z * 0.5 + pt2.Z * 0.5); + } + + /// + /// Z值归零 + /// + /// 点 + /// 新点 + public static Point3d Z20(this Point3d point) + { + return new Point3d(point.X, point.Y, 0); + } + + /// + /// 将三维点转换为二维点 + /// + /// 三维点 + /// 二维点 + public static Point2d Point2d(this Point3d pt) + { + return new(pt.X, pt.Y); + } + + /// + /// 将三维点集转换为二维点集 + /// + /// 三维点集 + /// 二维点集 + public static IEnumerable Point2d(this IEnumerable pts) + { + return pts.Select(pt => pt.Point2d()); + } + + /// + /// 将二维点转换为三维点 + /// + /// 二维点 + /// Z值 + /// 三维点 + public static Point3d Point3d(this Point2d pt, double z = 0) + { + return new(pt.X, pt.Y, z); + } + + /// + /// 投影到指定Z值 + /// + /// 点 + /// 新z值 + /// 投影后的坐标 + public static Point3d OrthoProject(this Point3d pt, double z) + { + return new Point3d(pt.X, pt.Y, z); + } + + /// + /// 根据世界坐标计算用户坐标 + /// + /// 基点世界坐标 + /// 基点用户坐标 + /// 目标世界坐标 + /// 坐标网旋转角,按x轴正向逆时针弧度 + /// 目标用户坐标 + public static Point3d TransPoint(this Point3d basePt, Point3d userPt, Point3d transPt, double ang) + { + var transMat = Matrix3d.Displacement(userPt - basePt); + var roMat = Matrix3d.Rotation(-ang, Vector3d.ZAxis, userPt); + return transPt.TransformBy(roMat * transMat); + } + + /// + /// 计算指定距离和角度的点 + /// + /// 本函数仅适用于x-y平面 + /// 基点 + /// 角度,x轴正向逆时针弧度 + /// 距离 + /// 目标点 + public static Point3d Polar(this Point3d pt, double ang, double len) + { + return pt + Vector3d.XAxis.RotateBy(ang, Vector3d.ZAxis) * len; + } + + /// + /// 计算指定距离和角度的点 + /// + /// 本函数仅适用于x-y平面 + /// 基点 + /// 角度,x轴正向逆时针弧度 + /// 距离 + /// 目标点 + public static Point2d Polar(this Point2d pt, double ang, double len) + { + return pt + Vector2d.XAxis.RotateBy(ang) * len; + } + + /// http://www.lee-mac.com/bulgeconversion.html + /// + /// 求凸度,判断三点是否一条直线上 + /// + /// 圆弧起点 + /// 圆弧腰点 + /// 圆弧尾点 + /// 容差 + /// 逆时针为正,顺时针为负 + public static double GetArcBulge(this Point2d arc1, Point2d arc2, Point2d arc3, double tol = 1e-10) + { + var dStartAngle = arc2.GetAngle(arc1); + var dEndAngle = arc2.GetAngle(arc3); + // 求的P1P2与P1P3夹角 + var talAngle = (Math.PI - dStartAngle + dEndAngle) / 2; + // 凸度==拱高/半弦长==拱高比值/半弦长比值 + // 有了比值就不需要拿到拱高值和半弦长值了,因为接下来是相除得凸度 + var bulge = Math.Sin(talAngle) / Math.Cos(talAngle); + + switch (bulge) + { + // 处理精度 + case > 0.9999 and < 1.0001: + bulge = 1; + break; + case < -0.9999 and > -1.0001: + bulge = -1; + break; + default: + { + if (Math.Abs(bulge) < tol) + bulge = 0; + break; + } + } + + return bulge; + } + + /// + /// 求两点在Z平面的距离 + /// + /// 点1 + /// 点2 + /// 距离 + public static double Distance2dTo(this Point3d pt1, Point3d pt2) + { + return new Vector2d(pt2.X - pt1.X, pt2.Y - pt1.Y).Length; + } + + #region 首尾相连 + + /// + /// 首尾相连 + /// + [DebuggerStepThrough] + public static void End2End(this Point2dCollection ptCollection) + { + ArgumentNullException.ThrowIfNull(ptCollection); + + if (ptCollection.Count == 0 || ptCollection[0].Equals(ptCollection[^1])) // 首尾相同直接返回 + return; + + // 首尾不同,去加一个到最后 + var lst = new Point2d[ptCollection.Count + 1]; + for (var i = 0; i < ptCollection.Count; i++) + lst[i] = ptCollection[i]; + lst[^1] = lst[0]; + + ptCollection.Clear(); + ptCollection.AddRange(lst); + } + + /// + /// 首尾相连 + /// + [DebuggerStepThrough] + public static void End2End(this Point3dCollection ptCollection) + { + ArgumentNullException.ThrowIfNull(ptCollection); + if (ptCollection.Count == 0 || ptCollection[0].Equals(ptCollection[^1])) // 首尾相同直接返回 + return; + + // 首尾不同,去加一个到最后 + var lst = new Point3d[ptCollection.Count + 1]; + for (var i = 0; i < ptCollection.Count; i++) + lst[i] = ptCollection[i]; + lst[^1] = lst[0]; + + ptCollection.Clear(); + foreach (var t in lst) + ptCollection.Add(t); + } + + #endregion + + #region 包围盒 + + /// + /// 获取矩形4个3d角点(左下起,正方向) + /// + /// 包围盒 + /// z轴坐标 + /// 点表 + public static List GetRecPoint3ds(this Extents3d extents3d, double z = 0) + { + var xMin = extents3d.MinPoint.X; + var xMax = extents3d.MaxPoint.X; + var yMin = extents3d.MinPoint.Y; + var yMax = extents3d.MaxPoint.Y; + var pt1 = new Point3d(xMin, yMin, z); + var pt2 = new Point3d(xMax, yMin, z); + var pt3 = new Point3d(xMax, yMax, z); + var pt4 = new Point3d(xMin, yMax, z); + return [pt1, pt2, pt3, pt4]; + } + + /// + /// 获取矩形4个2d角点(左下起,正方向) + /// + /// 包围盒 + /// 点表 + public static List GetRecPoint2ds(this Extents3d extents3d) + { + var xMin = extents3d.MinPoint.X; + var xMax = extents3d.MaxPoint.X; + var yMin = extents3d.MinPoint.Y; + var yMax = extents3d.MaxPoint.Y; + var pt1 = new Point2d(xMin, yMin); + var pt2 = new Point2d(xMax, yMin); + var pt3 = new Point2d(xMax, yMax); + var pt4 = new Point2d(xMin, yMax); + return [pt1, pt2, pt3, pt4]; + } + + /// + /// 获取矩形4个角3d点(左下起,正方向) + /// + /// 角1 + /// 角2 + /// z轴坐标 + /// 点表 + public static List GetRecPoint3ds(this Point3d corner1, Point3d corner2, double z = 0) + { + var xMin = Math.Min(corner1.X, corner2.X); + var xMax = Math.Max(corner1.X, corner2.X); + var yMin = Math.Min(corner1.Y, corner2.Y); + var yMax = Math.Max(corner1.Y, corner2.Y); + var pt1 = new Point3d(xMin, yMin, z); + var pt2 = new Point3d(xMax, yMin, z); + var pt3 = new Point3d(xMax, yMax, z); + var pt4 = new Point3d(xMin, yMax, z); + return [pt1, pt2, pt3, pt4]; + } + + /// + /// 获取矩形4个角3d点(左下起,正方向) + /// + /// 角1 + /// 角2 + /// z轴坐标 + /// 点表 + public static List GetRecPoint2ds(this Point2d corner1, Point2d corner2, double z = 0) + { + var xMin = Math.Min(corner1.X, corner2.X); + var xMax = Math.Max(corner1.X, corner2.X); + var yMin = Math.Min(corner1.Y, corner2.Y); + var yMax = Math.Max(corner1.Y, corner2.Y); + var pt1 = new Point2d(xMin, yMin); + var pt2 = new Point2d(xMax, yMin); + var pt3 = new Point2d(xMax, yMax); + var pt4 = new Point2d(xMin, yMax); + return [pt1, pt2, pt3, pt4]; + } + + #endregion +} \ No newline at end of file diff --git "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchConverter.cs" b/src/CADShared/ExtensionMethod/Hatch/HatchConverter.cs similarity index 68% rename from "src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchConverter.cs" rename to src/CADShared/ExtensionMethod/Hatch/HatchConverter.cs index 9f549dfbdd830ce036611a01241732bb0874e00a..eb17ddd55da15c25aecacec9eeab4502c262698c 100644 --- "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchConverter.cs" +++ b/src/CADShared/ExtensionMethod/Hatch/HatchConverter.cs @@ -1,7 +1,12 @@ -namespace IFoxCAD.Cad; +// ReSharper disable CompareOfFloatsByEqualityOperator +// ReSharper disable ForCanBeConvertedToForeach +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; -using System.Data; using PointV = Point2d; /// @@ -10,13 +15,14 @@ public class HatchConverter { #region 辅助类 + /// /// 生成圆形数据 /// class CircleData { - public PointV Center; - public double Radius; + public readonly PointV Center; + public readonly double Radius; /// /// 生成圆形数据 @@ -25,7 +31,7 @@ class CircleData /// 对称点2 public CircleData(PointV symmetryAxisPoint1, PointV symmetryAxisPoint2) { - Center = symmetryAxisPoint1.GetCenter(symmetryAxisPoint2); + Center = symmetryAxisPoint1.GetMidPointTo(symmetryAxisPoint2); Radius = symmetryAxisPoint1.GetDistanceTo(symmetryAxisPoint2) * 0.5; } } @@ -35,23 +41,25 @@ public CircleData(PointV symmetryAxisPoint1, PointV symmetryAxisPoint2) /// class HatchConverterData { - public List PolyLineData; - public List CircleData; - public List SplineData; + public readonly List PolyLineData; + public readonly List CircleConverterData; + public readonly List SplineData; /// /// 填充转换器的数据 /// public HatchConverterData() { - PolyLineData = new(); - CircleData = new(); - SplineData = new(); + PolyLineData = []; + CircleConverterData = []; + SplineData = []; } } + #endregion #region 成员 + /// /// 外部只能调用id,否则跨事务造成错误 /// @@ -64,23 +72,27 @@ public ObjectId OldHatchId return _oldHatch.ObjectId; } } + readonly Hatch? _oldHatch; readonly List _hcDatas; + /// /// 填充边界id(生成的/已存在反应器的直接提取) /// - public List BoundaryIds; + public readonly List BoundaryIds; + #endregion #region 构造 + /// /// 填充边界转换器 /// HatchConverter() { - _hcDatas = new(); - BoundaryIds = new(); + _hcDatas = []; + BoundaryIds = []; } /// @@ -104,8 +116,8 @@ public HatchConverter(Hatch hatch) : this() if (BoundaryIds.Count == 0) { throw new ArgumentException("关联的填充边界被删除后没有清理反应器,请调用:" + - "\n hatch.RemoveAssociatedObjectIds()" + - "\n hatch.Associative = false"); + "\n hatch.RemoveAssociatedObjectIds()" + + "\n hatch.Associative = false"); } } } @@ -116,10 +128,11 @@ public HatchConverter(Hatch hatch) : this() /// public void GetBoundarysData() { - _oldHatch?.ForEach(loop => { + _oldHatch?.ForEach(loop => + { HatchConverterData hcData = new(); - bool isCurve2d = true; + var isCurve2d = true; if (loop.IsPolyline) { // 边界是多段线 @@ -128,13 +141,13 @@ public void GetBoundarysData() } else { - if (loop.Curves.Count == 2)// 1是不可能的,大于2的是曲线 + if (loop.Curves.Count == 2) // 1是不可能的,大于2的是曲线 { // 边界是曲线,过滤可能是圆形的情况 var cir = TwoArcFormOneCircle(loop); if (cir is not null) { - hcData.CircleData.Add(cir); + hcData.CircleConverterData.Add(cir); isCurve2d = false; } } @@ -147,9 +160,11 @@ public void GetBoundarysData() _hcDatas.Add(hcData); }); } + #endregion #region 方法 + /// /// 多段线处理 /// @@ -163,8 +178,8 @@ static void HatchLoopIsPolyline(HatchLoop loop, HatchConverterData hcData) //if (hcData is null) // throw new ArgumentNullException(nameof(hcData)); - loop.NotNull(nameof(loop)); - hcData.NotNull(nameof(hcData)); + ArgumentNullException.ThrowIfNull(loop); + ArgumentNullException.ThrowIfNull(hcData); // 判断为圆形: @@ -173,13 +188,13 @@ static void HatchLoopIsPolyline(HatchLoop loop, HatchConverterData hcData) if (loop.Polyline.Count == 3 && loop.Polyline[0].Bulge == 1 && loop.Polyline[1].Bulge == 1 || loop.Polyline.Count == 3 && loop.Polyline[0].Bulge == -1 && loop.Polyline[1].Bulge == -1) { - hcData.CircleData.Add(new CircleData(loop.Polyline[0].Vertex, loop.Polyline[1].Vertex)); + hcData.CircleConverterData.Add(new CircleData(loop.Polyline[0].Vertex, loop.Polyline[1].Vertex)); } else { // 遍历多段线信息 var bvc = loop.Polyline; - for (int i = 0; i < bvc.Count; i++) + for (var i = 0; i < bvc.Count; i++) hcData.PolyLineData.Add(new BulgeVertexWidth(bvc[i])); } } @@ -194,11 +209,11 @@ static void HatchLoopIsPolyline(HatchLoop loop, HatchConverterData hcData) //if (loop is null) // throw new ArgumentNullException(nameof(loop)); - loop.NotNull(nameof(loop)); + ArgumentNullException.ThrowIfNull(loop); if (loop.Curves.Count != 2) - throw new ArgumentException( - "边界非多段线,而且点数!=2,点数为:" + nameof(loop.Curves.Count) + ";两个矩形交集的时候会出现此情况."); + throw new ArgumentException("边界非多段线,而且点数!=2,点数为:" + nameof(loop.Curves.Count) + + ";两个矩形交集的时候会出现此情况."); CircleData? circular = null; @@ -207,14 +222,14 @@ static void HatchLoopIsPolyline(HatchLoop loop, HatchConverterData hcData) // 边界为曲线,数量为2,可能是两个半圆曲线,如果是,就加入圆形数据中 // 第一段 - var getCurves1Pts = loop.Curves[0].GetSamplePoints(3); // 曲线取样点分两份(3点) - var mid1Pt = getCurves1Pts[1]; // 腰点 - double bulge1 = loop.Curves[0].StartPoint.GetArcBulge(mid1Pt, loop.Curves[0].EndPoint); + var getCurves1Pts = loop.Curves[0].GetSamplePoints(3); // 曲线取样点分两份(3点) + var mid1Pt = getCurves1Pts[1]; // 腰点 + var bulge1 = loop.Curves[0].StartPoint.GetArcBulge(mid1Pt, loop.Curves[0].EndPoint); // 第二段 var getCurves2Pts = loop.Curves[1].GetSamplePoints(3); var mid2Pt = getCurves2Pts[1]; - double bulge2 = loop.Curves[1].StartPoint.GetArcBulge(mid2Pt, loop.Curves[1].EndPoint); + var bulge2 = loop.Curves[1].StartPoint.GetArcBulge(mid2Pt, loop.Curves[1].EndPoint); // 第一段上弧&&第二段反弧 || 第一段反弧&&第二段上弧 if (bulge1 == -1 && bulge2 == -1 || bulge1 == 1 && bulge2 == 1) @@ -231,7 +246,7 @@ static void HatchLoopIsPolyline(HatchLoop loop, HatchConverterData hcData) static void HatchLoopIsCurve2d(HatchLoop loop, HatchConverterData hcData) { // 取每一段曲线,曲线可能是直线来的,但是圆弧会按照顶点来分段 - int curveIsClosed = 0; + var curveIsClosed = 0; // 遍历边界的多个子段 foreach (Curve2d curve in loop.Curves) @@ -247,21 +262,21 @@ static void HatchLoopIsCurve2d(HatchLoop loop, HatchConverterData hcData) var pts = curve.GetSamplePoints(3); var midPt = pts[1]; - if (curve.StartPoint.IsEqualTo(curve.EndPoint, new Tolerance(1e-6, 1e-6)))// 首尾相同,就是圆形 + if (curve.StartPoint.IsEqualTo(curve.EndPoint, new Tolerance(1e-6, 1e-6))) // 首尾相同,就是圆形 { // 判断为圆形: // 获取起点,然后采样三点,中间就是对称点(直径点) - hcData.CircleData.Add(new CircleData(curve.StartPoint, midPt)); + hcData.CircleConverterData.Add(new CircleData(curve.StartPoint, midPt)); continue; } // 判断为多段线,圆弧: - double bulge = curve.StartPoint.GetArcBulge(midPt, curve.EndPoint); + var bulge = curve.StartPoint.GetArcBulge(midPt, curve.EndPoint); hcData.PolyLineData.Add(new BulgeVertexWidth(curve.StartPoint, bulge)); // 末尾点,不闭合的情况下就要获取这个 if (curveIsClosed == loop.Curves.Count) - hcData.PolyLineData.Add(new BulgeVertexWidth(curve.EndPoint, 0)); + hcData.PolyLineData.Add(new BulgeVertexWidth(curve.EndPoint)); } } @@ -269,9 +284,10 @@ static void HatchLoopIsCurve2d(HatchLoop loop, HatchConverterData hcData) /// 创建边界图元 /// /// 返回图元 + [Obsolete("使用带返回值的CreateBoundary替代")] public void CreateBoundary(List outEnts) { - for (int i = 0; i < _hcDatas.Count; i++) + for (var i = 0; i < _hcDatas.Count; i++) { var data = _hcDatas[i]; @@ -280,37 +296,81 @@ public void CreateBoundary(List outEnts) { Polyline pl = new(); pl.SetDatabaseDefaults(); - for (int j = 0; j < data.PolyLineData.Count; j++) + for (var j = 0; j < data.PolyLineData.Count; j++) { - pl.AddVertexAt(j, - data.PolyLineData[j].Vertex, - data.PolyLineData[j].Bulge, - data.PolyLineData[j].StartWidth, - data.PolyLineData[j].EndWidth); + pl.AddVertexAt(j, data.PolyLineData[j].Vertex, data.PolyLineData[j].Bulge, + data.PolyLineData[j].StartWidth, data.PolyLineData[j].EndWidth); } + outEnts.Add(pl); } // 生成边界:圆 - data.CircleData.ForEach(item => { + data.CircleConverterData.ForEach(item => + { outEnts.Add(new Circle(item.Center.Point3d(), Vector3d.ZAxis, item.Radius)); }); // 生成边界:样条曲线 - data.SplineData.ForEach(item => { - outEnts.Add(item.ToCurve()); - }); + data.SplineData.ForEach(item => { outEnts.Add(item.ToCurve()); }); } if (_oldHatch is not null) { - outEnts.ForEach(ent => { + outEnts.ForEach(ent => + { ent.Color = _oldHatch.Color; ent.Layer = _oldHatch.Layer; }); } } + /// + /// 创建边界 + /// + /// + public List CreateBoundary() + { + var outEnts = new List(); + for (var i = 0; i < _hcDatas.Count; i++) + { + var data = _hcDatas[i]; + + // 生成边界:多段线 + if (data.PolyLineData.Count > 0) + { + Polyline pl = new(); + pl.SetDatabaseDefaults(); + for (var j = 0; j < data.PolyLineData.Count; j++) + { + pl.AddVertexAt(j, data.PolyLineData[j].Vertex, data.PolyLineData[j].Bulge, + data.PolyLineData[j].StartWidth, data.PolyLineData[j].EndWidth); + } + + outEnts.Add(pl); + } + + // 生成边界:圆 + data.CircleConverterData.ForEach(item => + { + outEnts.Add(new Circle(item.Center.Point3d(), Vector3d.ZAxis, item.Radius)); + }); + + // 生成边界:样条曲线 + data.SplineData.ForEach(item => { outEnts.Add(item.ToCurve()); }); + } + + if (_oldHatch is not null) + { + outEnts.ForEach(ent => + { + ent.Color = _oldHatch.Color; + ent.Layer = _oldHatch.Layer; + }); + } + + return outEnts; + } /// /// 创建边界图元和新填充到当前空间 @@ -320,15 +380,10 @@ public void CreateBoundary(List outEnts) /// 是否创建填充,false则只创建边界 /// 新填充id,边界在获取 public ObjectId CreateBoundarysAndHatchToMsPs(BlockTableRecord btrOfAddEntitySpace, - bool boundaryAssociative = true, - bool createHatchFlag = true, - Transaction? trans = null) + bool boundaryAssociative = true, bool createHatchFlag = true) { - List boEnts = new(); - CreateBoundary(boEnts); - boEnts.ForEach(ent => { - BoundaryIds.Add(btrOfAddEntitySpace.AddEntity(ent)); - }); + var boEnts = CreateBoundary(); + boEnts.ForEach(ent => { BoundaryIds.Add(btrOfAddEntitySpace.AddEntity(ent)); }); if (!createHatchFlag) return ObjectId.Null; @@ -341,21 +396,21 @@ public ObjectId CreateBoundarysAndHatchToMsPs(BlockTableRecord btrOfAddEntitySpa * 那么它的平移后的基点在哪里呢? */ - using ObjectIdCollection idc = new(new ObjectId[] { OldHatchId }); + using ObjectIdCollection idc = new([OldHatchId]); using IdMapping map = new(); btrOfAddEntitySpace.DeepCloneEx(idc, map); var newHatchId = map.GetValues()[0]; - trans ??= DBTrans.Top.Transaction; + var tr = DBTrans.GetTopTransaction(btrOfAddEntitySpace.Database); - bool openErased = false; - bool openLockedLayer = false; - var hatchEnt = trans.GetObject(newHatchId, OpenMode.ForWrite, - openErased, openLockedLayer) as Hatch; + var openErased = false; + var openLockedLayer = false; + var hatchEnt = tr.GetObject(newHatchId, OpenMode.ForWrite, openErased, openLockedLayer); if (hatchEnt != null) { ResetBoundary(hatchEnt, boundaryAssociative); hatchEnt.DowngradeOpen(); } + return newHatchId; } @@ -385,18 +440,17 @@ void ResetBoundary(Hatch hatch, bool boundaryAssociative = true) hatch.Associative = boundaryAssociative; using ObjectIdCollection obIds = new(); - for (int i = 0; i < BoundaryIds.Count; i++) + for (var i = 0; i < BoundaryIds.Count; i++) { obIds.Clear(); obIds.Add(BoundaryIds[i]); // 要先添加最外面的边界 - if (i == 0) - hatch.AppendLoop(HatchLoopTypes.Outermost, obIds); - else - hatch.AppendLoop(HatchLoopTypes.Default, obIds); + hatch.AppendLoop(i == 0 ? HatchLoopTypes.Outermost : HatchLoopTypes.Default, obIds); } + // 计算填充并显示 hatch.EvaluateHatch(true); } + #endregion } \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Hatch/HatchDialog.cs b/src/CADShared/ExtensionMethod/Hatch/HatchDialog.cs new file mode 100644 index 0000000000000000000000000000000000000000..7c71d3f8776f8489787e03f5344a0f083f961142 --- /dev/null +++ b/src/CADShared/ExtensionMethod/Hatch/HatchDialog.cs @@ -0,0 +1,52 @@ +#if acad + +namespace IFoxCAD.Cad; + +/// +/// 填充图案选择对话框
+/// 只是为了保持和其他Cad内置Dialog的使用一致性,并非真正的Dialog +///
+public class HatchDialog +{ + /// + /// 构造函数 + /// + public HatchDialog(string? name = null, bool showCustom = true) + { + // 默认填充图案名称为当前名称 + Name = name ?? SystemVariableManager.HPName; + ShowCustom = showCustom; + } + + /// + /// 填充图案名称 + /// + public string Name { get; set; } + + /// + /// 显示自定义图案 + /// + public bool ShowCustom { get; set; } + + /// + /// 模态显示图案选择对话框 + /// + /// 成功返回true + public bool ShowDialog() + { + var dr = ShowHatchPaletteDialog(Name, ShowCustom, out var newPattern); + if (dr) + { + Name = Marshal.PtrToStringAuto(newPattern) ?? ""; + } + + return dr; + } + + [DllImport("acad.exe", CharSet = CharSet.Auto, + EntryPoint = "?acedHatchPalletteDialog@@YA_NPEB_W_NAEAPEA_W@Z")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool ShowHatchPaletteDialog(string currentPattern, + [MarshalAs(UnmanagedType.Bool)] bool showCustom, out IntPtr newPattern); +} +#endif \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/Hatch/HatchEx.cs b/src/CADShared/ExtensionMethod/Hatch/HatchEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..5d6ccd09c35c2c5a22d95bd379fcdbb754155c5b --- /dev/null +++ b/src/CADShared/ExtensionMethod/Hatch/HatchEx.cs @@ -0,0 +1,365 @@ +// ReSharper disable CompareOfFloatsByEqualityOperator + +namespace IFoxCAD.Cad; + +/// +/// 充填扩展类 +/// +public static class HatchEx +{ + /// + /// 遍历填充每条边 + /// + /// + /// + public static void ForEach(this Hatch hatch, Action action) + { + for (var i = 0; i < hatch.NumberOfLoops; i++) + action.Invoke(hatch.GetLoopAt(i)); + } + + /// + /// 提取已存在的关联边界(一个边界环里所有的对象 id 组成一个 ObjectIdCollection) + /// + /// + /// + /// + public static List? GetAssociatedBoundaryIds(this Hatch hatch) + { + // if (!hatch.Id.IsOk()) + // throw new ArgumentException("填充未加入或不存在于数据库"); + + if (!hatch.Associative) + return null; + + var listObjIdColl = new List(); + + for (var i = 0; i < hatch.NumberOfLoops; i++) + { + var assIds = hatch.GetAssociatedObjectIdsAt(i); + if (assIds != null) + { + var objIds = new ObjectIdCollection(); + foreach (ObjectId id in assIds) + { + if (id.IsOk()) + objIds.Add(id); + } + + if (objIds.Count == 0) + { + throw new ArgumentException("关联的填充边界被删除后没有清理反应器,请调用:" + + "\n hatch.RemoveAssociatedObjectIds()" + + "\n hatch.Associative = false"); + } + + listObjIdColl.Add(objIds); + } + } + + return listObjIdColl; + } + + /// + /// 创建边界(仅创建于内存中,未加入数据库) + /// + /// + /// 边界环列表(一个边界环里所有的对象组成一个 DBObjectCollection) + public static List CreateBoundarys(this Hatch hatch) + { + // if (!hatch.Id.IsOk()) + // throw new ArgumentException("填充未加入或不存在于数据库"); + + var listDbObjColl = new List(); + + for (var i = 0; i < hatch.NumberOfLoops; i++) + { + var objColl = new DBObjectCollection(); + var loop = hatch.GetLoopAt(i); + var isCurve2d = true; + + if (loop.IsPolyline) + { + // 边界是多段线 + HatchLoopIsPolyline(loop, objColl); + isCurve2d = false; + } + else + { + // 1是不可能的,大于2的是曲线; + if (loop.Curves.Count == 2) + { + // 边界是曲线,过滤可能是圆形的情况 + var circle = TwoArcFormOneCircle(loop, objColl); + if (circle is not null) + { + objColl.Add(circle); + isCurve2d = false; + } + } + } + + // 边界是曲线 + if (isCurve2d) + HatchLoopIsCurve2d(loop, objColl); + + listDbObjColl.Add(objColl); + } + + return listDbObjColl; + } + + /// + /// 重新设置边界并计算 + /// + /// + /// 边界对象(一个边界环里所有的对象 id 组成一个 ObjectIdCollection) + ///
边界必需是封闭的环, 可以是一条线围合而成也可以是多条线首尾相连围合而成
+ ///
多个外边界的时候, 建议顺序为(外边界,外边界,外边界,普通边界....), 或(外边界, 普通边界.....外边界, 普通边界....)
+ /// + /// 关联边界(默认保持原样) + public static void ResetBoundarys(this Hatch hatch, List boundaryIds, + bool? associative = null) + { + // if (!hatch.Id.IsOk()) + // throw new ArgumentException("填充未加入或不存在于数据库"); + + boundaryIds.ForEach(ids => + { + foreach (ObjectId id in ids) + { + if (!id.IsOk()) + throw new ArgumentException("边界未加入或不存在于数据库"); + } + }); + + using (hatch.ForWrite()) + { + while (hatch.NumberOfLoops > 0) + hatch.RemoveLoopAt(0); + + if (associative != null) + hatch.Associative = associative == true; + + var isOutermost = true; + + boundaryIds.ForEach(ids => + { + try + { + // 要先添加最外面的边界 + if (isOutermost) + { + isOutermost = false; + hatch.AppendLoop(HatchLoopTypes.Outermost, ids); + } + else + { + // HatchLoopTypes.External 比 HatchLoopTypes.Default 似乎更不容易出问题 + hatch.AppendLoop(HatchLoopTypes.External, ids); + } + } + catch (Exception ex) + { + Env.Editor.WriteMessage(Environment.NewLine + "发生错误,传入的边界不符合要求,请核实传入的边界是否为封闭的"); + throw new Exception(ex.Message); + } + }); + + hatch.EvaluateHatch(true); + } + } + + #region 私有方法 + + /// + /// 处理边界多段线 + /// + /// 填充边界 + /// 收集边界图元 + private static void HatchLoopIsPolyline(HatchLoop loop, DBObjectCollection objColl) + { + // 判断为圆形: + // 上下两个圆弧,然后填充,就会生成此种填充 + // 顶点数是3,凸度是半圆,两个半圆就是一个圆形 + if (loop.Polyline.Count == 3 && loop.Polyline[0].Bulge == 1 && loop.Polyline[1].Bulge == 1 || + loop.Polyline.Count == 3 && loop.Polyline[0].Bulge == -1 && loop.Polyline[1].Bulge == -1) + { + var center = loop.Polyline[0].Vertex.GetMidPointTo(loop.Polyline[1].Vertex); + var radius = loop.Polyline[0].Vertex.GetDistanceTo(loop.Polyline[1].Vertex) * 0.5; + var circle = new Circle(center.Point3d(), Vector3d.ZAxis, radius); + objColl.Add(circle); + } + else + { + // 遍历多段线信息 + var bvc = loop.Polyline; + var pl = new Polyline(); + pl.SetDatabaseDefaults(); + for (var j = 0; j < bvc.Count; j++) + { + var bvw = new BulgeVertexWidth(bvc[j]); + pl.AddVertexAt(j, bvw.Vertex, bvw.Bulge, bvw.StartWidth, bvw.EndWidth); + } + + objColl.Add(pl); + } + } + + /// + /// 两个圆弧组成圆形 + /// + /// 填充边界 + /// 收集边界图元 + // ReSharper disable once UnusedParameter.Local + private static Circle? TwoArcFormOneCircle(HatchLoop loop, DBObjectCollection objColl) + { + if (loop.Curves.Count != 2) + { + throw new ArgumentException("边界非多段线,而且点数!=2,点数为:" + nameof(loop.Curves.Count) + + ";两个矩形交集的时候会出现此情况."); + } + + Circle? circle = null; + + // 判断为圆形: + // 用一条(不是两条)多段线画出两条圆弧为正圆,就会生成此种填充 + // 边界为曲线,数量为2,可能是两个半圆曲线,如果是,就加入圆形数据中 + + // 第一段 + var getCurves1Pts = loop.Curves[0].GetSamplePoints(3); // 曲线取样点分两份(3点) + var mid1Pt = getCurves1Pts[1]; // 腰点 + var bulge1 = loop.Curves[0].StartPoint.GetArcBulge(mid1Pt, loop.Curves[0].EndPoint); + + // 第二段 + var getCurves2Pts = loop.Curves[1].GetSamplePoints(3); + var mid2Pt = getCurves2Pts[1]; + var bulge2 = loop.Curves[1].StartPoint.GetArcBulge(mid2Pt, loop.Curves[1].EndPoint); + + // 第一段上弧&&第二段反弧 || 第一段反弧&&第二段上弧 + if (bulge1 == -1 && bulge2 == -1 || bulge1 == 1 && bulge2 == 1) + { + var center = loop.Curves[0].StartPoint.GetMidPointTo(loop.Curves[1].StartPoint); + var radius = loop.Curves[0].StartPoint.GetDistanceTo(loop.Curves[1].StartPoint) * 0.5; + circle = new Circle(center.Point3d(), Vector3d.ZAxis, radius); + } + + return circle; + } + + /// + /// 处理边界曲线 + /// + /// 填充边界 + /// 收集边界图元 + private static void HatchLoopIsCurve2d(HatchLoop loop, DBObjectCollection objColl) + { + var pLineCount = 0; //记录多段线数量 + var curveIsClosed = 0; // 取每一段曲线,曲线可能是直线来的,但是圆弧会按照顶点来分段 + var newPl = true; // 是否开始新的多段线(一个边界中可能有多条多段线) + var firstIsPl = false; //遍历边界的第一个子段为多段线(遍历时不一定从多段线的首段开始) + List? polyLineVertexes = null; + List> polyLineData = []; + + // 遍历边界的多个子段 + foreach (Curve2d curve in loop.Curves) + { + // 计数用于实现闭合 + curveIsClosed++; + + if (curve is CircularArc2d or LineSegment2d) + { + var pts = curve.GetSamplePoints(3); + var midPt = pts[1]; + + // 判断为多段线圆: + // 首尾相同,就是圆形 + if (curve.StartPoint.IsEqualTo(curve.EndPoint, new Tolerance(1e-6, 1e-6))) + { + // 获取起点,然后采样三点,中间就是对称点(直径点) + var center = curve.StartPoint.GetMidPointTo(midPt); + var radius = curve.StartPoint.GetDistanceTo(midPt) * 0.5; + var circle = new Circle(center.Point3d(), Vector3d.ZAxis, radius); + objColl.Add(circle); + // 添加在中部的多段线末尾点 + if (curveIsClosed > 1 && !newPl) + polyLineVertexes?.Add(new BulgeVertexWidth(curve.StartPoint)); + // 开始新的多段线 + newPl = true; + continue; + } + + if (curveIsClosed == 1) + firstIsPl = true; + + if (newPl) + { + polyLineVertexes = []; + polyLineData.Add(polyLineVertexes); + newPl = false; + pLineCount++; + } + + // 判断为多段线,圆弧或直线: + var bulge = curve.StartPoint.GetArcBulge(midPt, curve.EndPoint); + polyLineVertexes?.Add(new BulgeVertexWidth(curve.StartPoint, bulge)); + + // 末尾点,不闭合的情况下就要获取这个 + if (curveIsClosed == loop.Curves.Count) + { + if (firstIsPl && pLineCount > 1) + { + // 连接首尾多段线 + polyLineData[0].ForEach(bvw => polyLineData[^1].Add(bvw)); + polyLineData.RemoveAt(0); + } + else + polyLineVertexes?.Add(new BulgeVertexWidth(curve.EndPoint)); + } + + continue; + } + + // 判断为样条曲线: + if (curve is NurbCurve2d spl) + objColl.Add(spl.ToCurve()); + + // 判断为椭圆: + if (curve is EllipticalArc2d eArc2d) + { + var startParam = eArc2d.IsClockWise ? -eArc2d.EndAngle : eArc2d.StartAngle; + var endParam = eArc2d.IsClockWise ? -eArc2d.StartAngle : eArc2d.EndAngle; + var ellipse = new Ellipse(eArc2d.Center.Point3d(), Vector3d.ZAxis, + eArc2d.MajorAxis.Convert3d() * eArc2d.MajorRadius, + eArc2d.MinorRadius / eArc2d.MajorRadius, + Math.Atan2(Math.Sin(startParam) * eArc2d.MinorRadius, + Math.Cos(startParam) * eArc2d.MajorRadius), + Math.Atan2(Math.Sin(endParam) * eArc2d.MinorRadius, + Math.Cos(endParam) * eArc2d.MajorRadius)); + objColl.Add(ellipse); + } + + // 添加在中部的多段线末尾点 + if (curveIsClosed > 1 && !newPl) + polyLineVertexes?.Add(new BulgeVertexWidth(curve.StartPoint)); + // 开始新的多段线 + newPl = true; + } + + // 生成多段线 + polyLineData.ForEach(list => + { + if (list.Count == 0) return; + var pl = new Polyline(); + pl.SetDatabaseDefaults(); + for (var j = 0; j < list.Count; j++) + { + pl.AddVertexAt(j, list[j].Vertex, list[j].Bulge, list[j].StartWidth, list[j].EndWidth); + } + + objColl.Add(pl); + }); + } + + #endregion +} \ No newline at end of file diff --git "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchInfo.cs" b/src/CADShared/ExtensionMethod/Hatch/HatchInfo.cs similarity index 86% rename from "src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchInfo.cs" rename to src/CADShared/ExtensionMethod/Hatch/HatchInfo.cs index 1763aaf319f153dda11b863167e3a7ecb81b8553..14b14c8a59467adb1eb3d1af23937aab6abdca3a 100644 --- "a/src/CAD/IFox.CAD.Shared/ExtensionMethod/\346\226\260\345\273\272\345\241\253\345\205\205/HatchInfo.cs" +++ b/src/CADShared/ExtensionMethod/Hatch/HatchInfo.cs @@ -1,5 +1,9 @@  +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; /* @@ -52,7 +56,7 @@ public class HatchInfo double Angle => _hatch.PatternAngle; // 延后处理角度 - private double _angle; + private readonly double _angle; #endregion #region 构造 @@ -60,7 +64,7 @@ public class HatchInfo { _hatch = new Hatch(); _hatch.SetDatabaseDefaults(); - _boundaryIds = new(); + _boundaryIds = []; } /// @@ -159,7 +163,7 @@ public HatchInfo Mode4Gradient(GradientName name, Color colorStart, Color colorE float shadeTintValue = 0, bool gradientOneColorMode = false) { - // entget渐变的名字必然是"SOLID",但是这里作为"渐变"名,而不是"填充"名 + // entGet渐变的名字必然是"SOLID",但是这里作为"渐变"名,而不是"填充"名 _hatchName = name.ToString(); _hatch.HatchObjectType = HatchObjectType.GradientObject; // 对象类型(填充/渐变) _patternTypeGradient = GradientPatternType.PreDefinedGradient;// 模式4:渐变 @@ -168,7 +172,7 @@ public HatchInfo Mode4Gradient(GradientName name, Color colorStart, Color colorE // 设置渐变色填充的起始和结束颜色 var gColor1 = new GradientColor(colorStart, 0); var gColor2 = new GradientColor(colorEnd, 1); - _hatch.SetGradientColors(new GradientColor[] { gColor1, gColor2 }); + _hatch.SetGradientColors([gColor1, gColor2]); _hatch.GradientShift = gradientShift; // 梯度位移 _hatch.ShadeTintValue = shadeTintValue; // 阴影色值 @@ -203,7 +207,7 @@ public ObjectId Build(BlockTableRecord btrOfAddEntitySpace) // 利用 AppendLoop 重载加入,这里就不处理 if (_boundaryIds.Count > 0) - AppendLoop(_boundaryIds, HatchLoopTypes.Default); + AppendLoop(_boundaryIds); // 计算填充并显示(若边界出错,这句会异常) _hatch.EvaluateHatch(true); @@ -235,7 +239,7 @@ public HatchInfo ClearBoundary() /// public HatchInfo EraseBoundary() { - for (int i = 0; i < _boundaryIds.Count; i++) + for (var i = 0; i < _boundaryIds.Count; i++) _boundaryIds[i].Erase(); return this; } @@ -245,10 +249,10 @@ public HatchInfo EraseBoundary() ///
/// 边界id /// 加入方式 - void AppendLoop(IEnumerable boundaryIds, - HatchLoopTypes hatchLoopTypes = HatchLoopTypes.Default) + private void AppendLoop(IEnumerable boundaryIds, + HatchLoopTypes hatchLoopTypes = HatchLoopTypes.Default) { - ObjectIdCollection obIds = new(); + ObjectIdCollection obIds = []; // 边界是闭合的,而且已经加入数据库 // 填充闭合环类型.最外面 @@ -285,56 +289,26 @@ void AppendLoop(IEnumerable boundaryIds, /// 加入边界(仿高版本的填充函数) ///
/// 点集 - /// 凸度集 + /// 凸度集 /// 加入此空间 /// 加入方式 /// public HatchInfo AppendLoop(Point2dCollection pts, - DoubleCollection bluges, + DoubleCollection bulges, BlockTableRecord btrOfAddEntitySpace, HatchLoopTypes hatchLoopTypes = HatchLoopTypes.Default) { //if (pts == null) // throw new ArgumentNullException(nameof(pts)); - pts.NotNull(nameof(pts)); + ArgumentNullException.ThrowIfNull(pts); pts.End2End(); -#if NET35 - _boundaryIds.Add(CreateAddBoundary(pts, bluges, btrOfAddEntitySpace)); -#else // 2011新增API,可以不生成图元的情况下加入边界, // 通过这里进入的话,边界 _boundaryIds 是空的,那么 Build() 时候就需要过滤空的 - _hatch.AppendLoop(hatchLoopTypes, pts, bluges); -#endif + _hatch.AppendLoop(hatchLoopTypes, pts, bulges); return this; } -#if NET35 - /// - /// 通过点集和凸度生成边界的多段线 - /// - /// 点集 - /// 凸度集 - /// 加入此空间 - /// 多段线id - static ObjectId CreateAddBoundary(Point2dCollection? pts, - DoubleCollection? bluges, - BlockTableRecord btrOfAddEntitySpace) - { - if (pts is null) - throw new ArgumentException(null, nameof(pts)); - if (bluges is null) - throw new ArgumentException(null, nameof(bluges)); - - var bvws = new List(); - var itor1 = pts.GetEnumerator(); - var itor2 = bluges.GetEnumerator(); - while (itor1.MoveNext() && itor2.MoveNext()) - bvws.Add(new BulgeVertexWidth(itor1.Current, itor2.Current)); - - return btrOfAddEntitySpace.AddPline(bvws); - } -#endif #endregion #region 枚举 diff --git a/src/CADShared/ExtensionMethod/IFoxUtils.cs b/src/CADShared/ExtensionMethod/IFoxUtils.cs new file mode 100644 index 0000000000000000000000000000000000000000..583434332b2b0cc65dde44d2cdaae819d9fb35df --- /dev/null +++ b/src/CADShared/ExtensionMethod/IFoxUtils.cs @@ -0,0 +1,165 @@ +namespace IFoxCAD.Cad; + +/// +/// 工具类 +/// +// ReSharper disable once InconsistentNaming +public static class IFoxUtils +{ +#if acad + /// + /// 刷新图层状态,在修改图层的锁定或冻结状态后使用 + /// + /// 图层id集合 + public static void RegenLayers(IEnumerable layerIds) + { + var type = Acaop.Version.Major >= 21 + ? Assembly.Load("accoremgd")?.GetType("Autodesk.AutoCAD.Internal.CoreLayerUtilities") + : Assembly.Load("acmgd")?.GetType("Autodesk.AutoCAD.Internal.LayerUtilities"); + if (type == null) + return; + var mi = type.GetMethods() + .FirstOrDefault(e => + { + if (e.Name != "RegenLayers") + return false; + var parameterInfos = e.GetParameters(); + if (parameterInfos.Length != 2) + return false; + if (parameterInfos[0].ParameterType != typeof(ObjectId[])) + return false; + if (parameterInfos[1].ParameterType != typeof(int)) + return false; + return true; + }); + if (mi == null) + return; + var pi = type.GetProperties().FirstOrDefault(e => e.Name == "RegenPending"); + var regenPending = (int)(pi?.GetValue(null) ?? 0); + mi.Invoke(null, [layerIds.ToArray(), regenPending]); + } + + /// + /// 刷新图层状态,在修改图层的锁定或冻结状态后使用 + /// + /// 图层id集合 + public static void RegenLayers2(IEnumerable layerIds) + { + var isOff = false; + var layerRxc = RXObject.GetClass(typeof(LayerTableRecord)); + var entityRxc = RXObject.GetClass(typeof(Entity)); + foreach (var group in layerIds.Where(e => e.IsOk() && e.ObjectClass.IsDerivedFrom(layerRxc)) + .GroupBy(e => e.Database)) + { + var db = group.Key; + var doc = Acap.DocumentManager.GetDocument(db); + if (doc is null) + continue; // 获取不到文档说明是后台开图,后台开图就不用刷新了 + using var dl = doc.LockDocument(); + using var tr = new DBTrans(db); + var layerIdSet = group.ToHashSet(); + foreach (var ltr in layerIdSet.Select(id => tr.GetObject(id, OpenMode.ForWrite)) + .OfType()) + { + Volatile.Write(ref isOff, ltr.IsOff); + ltr.IsOff = Volatile.Read(ref isOff); + } + + for (var i = db.BlockTableId.Handle.Value; i < db.Handseed.Value; i++) + { + if (!db.TryGetObjectId(new Handle(i), out var id) || !id.IsOk() || + !id.ObjectClass.IsDerivedFrom(entityRxc)) + continue; + var ent = (Entity)tr.GetObject(id, OpenMode.ForWrite, false, true); + if (!layerIdSet.Contains(ent.LayerId)) + continue; + ent.RecordGraphicsModified(true); + try + { + ent.TransformBy(Matrix3d.Identity); + } + catch (Exception) + { + // 某些类型如blockbegin blockend等不能进行矩阵转换 + } + } + } + } + +#endif + /// + /// 发送气泡通知 + /// + /// 显示的秒数,范围1-10为相应秒数,0为常显 + /// 标题 + /// 内容1 + /// 图标样式 + /// 链接 + /// 链接地址 + /// 内容2 + public static void ShowBubbleWindow(int second, string title, string text, + IconType iconType = IconType.None, string? hyperText = null, string? hyperLink = null, + string? text2 = null) + { + TrayItem? trayItem = null; + const string name = "IFox"; + var num = Acap.StatusBar.TrayItems.Count; + for (var i = 0; i < num; i++) + { + var ti = Acap.StatusBar.TrayItems[i]; + if (ti.ToolTipText != name) + continue; + trayItem = ti; + break; + } + + if (trayItem == null) + { + trayItem = new() { ToolTipText = name, Visible = true, }; + Acap.StatusBar.TrayItems.Add(trayItem); + Acap.StatusBar.Update(); + } + + if (second <= 0) + second = 0; + else if (second % 10 == 0) + second = 10; + else + second %= 10; + Acaop.SetSystemVariable("TrayTimeOut", second); + var tibw = new TrayItemBubbleWindow + { + IconType = iconType, + Title = title, + Text = text, + HyperText = hyperText, + HyperLink = hyperLink, + Text2 = text2 + }; + Acaop.SetSystemVariable("TRAYICONS", 1); + Acaop.SetSystemVariable("TRAYNOTIFY", 1); + trayItem.Visible = true; + trayItem.ShowBubbleWindow(tibw); + } + + /// + /// 否决双击事件本身的后续操作,在双击事件中使用 + /// + public static void VetoMouseDoubleClickEvent() + { + const string key = "DBLCLKEDIT"; + var value = Acaop.GetSystemVariable(key); + Acaop.SetSystemVariable(key, 0); + IdleAction.Add(() => Acaop.SetSystemVariable(key, value)); + } + + /// + /// 获取透明度 + /// + /// cad特性栏透明度值,范围0-100 + /// cad透明度值 + public static Transparency CreateTransparency(int value) + { + return new Transparency(Convert.ToByte(Math.Floor((100 - value) * 2.55))); + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/JigEx.cs b/src/CADShared/ExtensionMethod/Jig/JigEx.cs similarity index 67% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/JigEx.cs rename to src/CADShared/ExtensionMethod/Jig/JigEx.cs index 15024ab6552f1ca810b0d2e8d219589951f890a9..eac7b62123861beea6321a79566386a58ce94afe 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/JigEx.cs +++ b/src/CADShared/ExtensionMethod/Jig/JigEx.cs @@ -1,4 +1,10 @@ - +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; + +// ReSharper disable ClassWithVirtualMembersNeverInherited.Global + +// ReSharper disable MemberCanBePrivate.Global +#endif namespace IFoxCAD.Cad; @@ -12,53 +18,57 @@ namespace IFoxCAD.Cad; * 作者: 惊惊⎛⎝◕⏝⏝◕。⎠⎞ ⎛⎝≥⏝⏝0⎠⎞ ⎛⎝⓿⏝⏝⓿。⎠⎞ ⎛⎝≥⏝⏝≤⎠⎞ * 博客: https://www.cnblogs.com/JJBox/p/15650770.html */ - +/// +/// 重绘事件 +/// +/// worldDraw public delegate void WorldDrawEvent(WorldDraw draw); + +/// +/// jig扩展类 +/// public class JigEx : DrawJig, IDisposable { #region 成员 + /// /// 事件:亮显/暗显会被刷新冲刷掉,所以这个事件用于补充非刷新的工作 /// - event WorldDrawEvent? WorldDrawEvent; + private event WorldDrawEvent? WorldDrawEvent; + /// /// 最后的鼠标点,用来确认长度 /// public Point3d MousePointWcsLast; + /// /// 最后的图元,用来生成 /// - public Entity[] Entitys => _drawEntitys.ToArray(); + public Entity[] Entities => _drawEntities.ToArray(); + /// + /// 鼠标移动时的委托 + /// + private readonly Action>? _mouseAction; - readonly Action>? _mouseAction; - readonly Tolerance _tolerance;// 容差 + private readonly Tolerance _tolerance; // 容差 - readonly Queue _drawEntitys;// 重复生成的图元,放在这里刷新 - JigPromptPointOptions? _options;// jig鼠标配置 - bool _worldDrawFlag = false; // 20220503 + private readonly Queue _drawEntities; // 委托内重复生成的图元,放在这里刷新 + private JigPromptPointOptions? _options; // jig鼠标配置 + private bool _worldDrawFlag; // 20220503 - bool _systemVariables_Orthomode = false; - bool SystemVariables_Orthomode // 正交修改还原 - { - get => _systemVariables_Orthomode; - set - { - // 1正交,0非正交 // setvar: https://www.cnblogs.com/JJBox/p/10209541.html - if (Env.OrthoMode != value) - Env.OrthoMode = _systemVariables_Orthomode = value; - } - } #endregion #region 构造 + /// /// 在界面绘制图元 /// - JigEx() + private JigEx() { - _drawEntitys = new(); - DimensionEntitys = new(); + _drawEntities = new(); + DimensionEntities = new(); + _options = JigPointOptions(); } /// @@ -76,9 +86,16 @@ public JigEx(Action>? action = null, double tolerance = 1 _mouseAction = action; _tolerance = new(tolerance, tolerance); } + #endregion + /// + /// 因为是worldDraw触发sampler不是Sample触发worldDraw,所以要记一次上次的状态 + /// + private static bool lastIsKw; + #region 重写 + /// /// 鼠标采样器 /// @@ -87,33 +104,34 @@ public JigEx(Action>? action = null, double tolerance = 1 protected override SamplerStatus Sampler(JigPrompts prompts) { if (_worldDrawFlag) - return SamplerStatus.NoChange;// OK的时候拖动鼠标与否都不出现图元 - + return SamplerStatus.NoChange; // OK的时候拖动鼠标与否都不出现图元 if (_options is null) throw new NullReferenceException(nameof(_options)); - var pro = prompts.AcquirePoint(_options); - if (pro.Status == PromptStatus.Keyword) - return SamplerStatus.OK; - else if (pro.Status != PromptStatus.OK) + if (pro.Status != PromptStatus.OK && pro.Status != PromptStatus.Keyword) return SamplerStatus.Cancel; + // 记上次的状态,因为马上要还原 + var isOk = !lastIsKw; + lastIsKw = pro.Status == PromptStatus.Keyword; // 上次鼠标点不同(一定要这句,不然图元刷新太快会看到奇怪的边线) - var mousePointWcs = pro.Value; + var mousePointWcs = lastIsKw ? MousePointWcsLast : pro.Value; // == 是比较类字段,但是最好转为哈希比较. // IsEqualTo 是方形判断(仅加法),但是cad是距离. // Distance 是圆形判断(会求平方根,使用了牛顿迭代), // 大量数据(十万以上/频繁刷新)面前会显得非常慢. - if (mousePointWcs.IsEqualTo(MousePointWcsLast, _tolerance)) + if (isOk && mousePointWcs.IsEqualTo(MousePointWcsLast, _tolerance)) + { return SamplerStatus.NoChange; + } // 上次循环的缓冲区图元清理,否则将会在vs输出遗忘 Dispose - while (_drawEntitys.Count > 0) - _drawEntitys.Dequeue().Dispose(); + while (_drawEntities.Count > 0) + _drawEntities.Dequeue().Dispose(); // 委托把容器扔出去接收新创建的图元,然后给重绘更新 - _mouseAction?.Invoke(mousePointWcs, _drawEntitys); + _mouseAction?.Invoke(mousePointWcs, _drawEntities); MousePointWcsLast = mousePointWcs; return SamplerStatus.OK; @@ -146,10 +164,10 @@ public void DatabaseEntityDraw(WorldDrawEvent action) * 四个箭头最近鼠标的亮显,其余淡显, * 在jig使用淡显ent.Unhighlight和亮显ent.Highlight() * 需要绕过重绘,否则重绘将导致图元频闪,令这两个操作失效, - * 此时需要自定义一个集合 EntityList (不使用本函数的_drawEntitys) + * 此时需要自定义一个集合 EntityList (不使用本函数的_drawEntities) * 再将 EntityList 传给 WorldDrawEvent 事件,事件内实现亮显和淡显(事件已经利用 DatabaseEntityDraw函数进行提供). * 0x03 - * draw.Geometry.Draw(_drawEntitys[i]); + * draw.Geometry.Draw(_drawEntities[i]); * 此函数有问题,acad08克隆一份数组也可以用来刷新, * 而arx上面的jig只能一次改一个,所以可以用此函数. * 起因是此函数属于异步刷新, @@ -168,34 +186,36 @@ protected override bool WorldDraw(WorldDraw draw) { _worldDrawFlag = true; WorldDrawEvent?.Invoke(draw); - _drawEntitys.ForEach(ent => { + _drawEntities.ForEach(ent => + { +#if zcad + draw.Geometry.Draw(ent); +#else draw.RawGeometry.Draw(ent); +#endif }); _worldDrawFlag = false; return true; } + #endregion #region 方法 + /// /// 鼠标配置:基点 /// /// 基点 /// 光标绑定 /// 提示信息 - /// 正交开关 public JigPromptPointOptions SetOptions(Point3d basePoint, - CursorType cursorType = CursorType.RubberBand, - string msg = "点选第二点", - bool orthomode = false) + CursorType cursorType = CursorType.RubberBand, + string msg = "\n点选第二点") { - if (orthomode) - SystemVariables_Orthomode = true; - _options = JigPointOptions(); - _options.Message = Environment.NewLine + msg; - _options.Cursor = cursorType; // 光标绑定 - _options.UseBasePoint = true; // 基点打开 + _options.Message = msg; + _options.Cursor = cursorType; // 光标绑定 + _options.UseBasePoint = true; // 基点打开 _options.BasePoint = basePoint; // 基点设定 return _options; } @@ -205,36 +225,21 @@ public JigPromptPointOptions SetOptions(Point3d basePoint, /// /// 信息 /// 关键字 - /// 正交开关 - /// + /// jig配置 public JigPromptPointOptions SetOptions(string msg, - Dictionary? keywords = null, - bool orthomode = false) + Dictionary? keywords = null) { - if (orthomode) - SystemVariables_Orthomode = true; - _options = JigPointOptions(); _options.Message = Environment.NewLine + msg; - // 加入关键字,加入时候将空格内容放到最后 - string spaceValue = string.Empty; - const string spaceKey = " "; - if (keywords != null) foreach (var item in keywords) - if (item.Key == spaceKey) - spaceValue = item.Value; - else - _options.Keywords.Add(item.Key, item.Key, item.Value); - - /// 因为默认配置函数导致此处空格触发是无效的, - /// 但是用户如果想触发,就需要在外部减去默认UserInputControls配置 - /// 要放最后,才能优先触发其他关键字 - if (spaceValue != string.Empty) - _options.Keywords.Add(spaceKey, spaceKey, spaceValue); - else - _options.Keywords.Add(spaceKey, spaceKey, "<空格退出>"); + _options.Keywords.Add(item.Key, item.Key, item.Value); + + // 因为默认配置函数导致此处空格触发是无效的, + // 但是用户如果想触发,就需要在外部减去默认UserInputControls配置 + // 要放最后,才能优先触发其他关键字 + // 外部设置减去配置 // _options.UserInputControls = @@ -247,13 +252,9 @@ public JigPromptPointOptions SetOptions(string msg, /// /// 鼠标配置:自定义 /// - /// - /// 正交开关 - public void SetOptions(Action action, bool orthomode = false) + /// 拖拽设置委托 + public void SetOptions(Action action) { - if (orthomode) - SystemVariables_Orthomode = true; - _options = new JigPromptPointOptions(); action.Invoke(_options); } @@ -261,55 +262,33 @@ public void SetOptions(Action action, bool orthomode = fa /// /// 执行 /// - /// + /// 交互结果 + [Obsolete("将在下个版本中删除,请使用Editor.Drag(JigEx)")] public PromptResult Drag() { // jig功能必然是当前前台文档,所以封装内部更好调用 - var dm = Acap.DocumentManager; + var dm = Acaop.DocumentManager; var doc = dm.MdiActiveDocument; var ed = doc.Editor; var dr = ed.Drag(this); - - if (SystemVariables_Orthomode) - SystemVariables_Orthomode = !SystemVariables_Orthomode; return dr; } - /// - /// 最后一次的图元加入数据库 - /// - /// 加入此空间 - /// 不生成的图元用于排除,例如刷新时候的提示文字 - /// 加入数据库的id集合 - public IEnumerable? AddEntityToMsPs(BlockTableRecord btrOfAddEntitySpace, - IEnumerable? removeEntity = null) - { - // 内部用 _drawEntitys 外部用 Entitys,减少一层转换 - if (_drawEntitys.Count == 0) - return null; - - IEnumerable es = _drawEntitys; - if (removeEntity != null) - es = es.Except(removeEntity);// 差集 - - return btrOfAddEntitySpace.AddEntity(es); - } - - #region 配置 + /// /// 用户输入控制默认配置 /// 令jig.Drag().Status == /// - /// - static JigPromptPointOptions JigPointOptions() + /// Jig配置 + private static JigPromptPointOptions JigPointOptions() { return new JigPromptPointOptions() { UserInputControls = - UserInputControls.GovernedByUCSDetect // 由UCS探测用 - | UserInputControls.Accept3dCoordinates // 接受三维坐标 - | UserInputControls.NullResponseAccepted // 输入了鼠标右键,结束jig + UserInputControls.GovernedByUCSDetect // 由UCS探测用 + | UserInputControls.Accept3dCoordinates // 接受三维坐标 + | UserInputControls.NullResponseAccepted // 输入了鼠标右键,结束jig | UserInputControls.AnyBlankTerminatesInput // 空格或回车,结束jig; }; } @@ -321,22 +300,22 @@ static JigPromptPointOptions JigPointOptions() public void SetSpaceIsKeyword() { var opt = _options; - //if (opt == null) - // throw new ArgumentNullException(nameof(_options)); - opt.NotNull(nameof(_options)); - + ArgumentNullException.ThrowIfNull(opt); if ((opt.UserInputControls & UserInputControls.NullResponseAccepted) == UserInputControls.NullResponseAccepted) opt.UserInputControls ^= UserInputControls.NullResponseAccepted; // 输入了鼠标右键,结束jig - if ((opt.UserInputControls & UserInputControls.AnyBlankTerminatesInput) == UserInputControls.AnyBlankTerminatesInput) + if ((opt.UserInputControls & UserInputControls.AnyBlankTerminatesInput) == + UserInputControls.AnyBlankTerminatesInput) opt.UserInputControls ^= UserInputControls.AnyBlankTerminatesInput; // 空格或回车,结束jig } + #endregion #region 注释数据 + /// /// 注释数据,可以在缩放的时候不受影响 /// - public DynamicDimensionDataCollection DimensionEntitys; + public DynamicDimensionDataCollection DimensionEntities { get; set; } /// /// 重写注释数据 @@ -346,14 +325,19 @@ public void SetSpaceIsKeyword() protected override DynamicDimensionDataCollection GetDynamicDimensionData(double dimScale) { base.GetDynamicDimensionData(dimScale); - return DimensionEntitys; + return DimensionEntities; } #endregion + #endregion #region IDisposable接口相关函数 - public bool IsDisposed { get; private set; } = false; + + /// + /// 已经销毁 + /// + public bool IsDisposed { get; private set; } /// /// 手动调用释放 @@ -372,19 +356,29 @@ public void Dispose() Dispose(false); } + /// + /// 销毁 + /// + /// 正常销毁 protected virtual void Dispose(bool disposing) { // 不重复释放,并设置已经释放 - if (IsDisposed) return; + if (IsDisposed) + return; IsDisposed = true; + if (disposing) + { + // 最后一次的图元如果没有加入数据库,就在此销毁,所以JigEx调用的时候加using + _drawEntities.ForEach(ent => + { + if (!ent.IsDisposed && ent.Database == null) + ent.Dispose(); + }); + } - // 最后一次的图元如果没有加入数据库,就在此销毁,所以JigEx调用的时候加using - _drawEntitys?.ForEach(ent => { - if (ent.Database == null && !ent.IsDisposed) - ent.Dispose(); - }); - _drawEntitys?.Clear(); + _drawEntities.Clear(); } + #endregion // 此处无测试 diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/JigExTransient.cs b/src/CADShared/ExtensionMethod/Jig/JigExTransient.cs similarity index 44% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/JigExTransient.cs rename to src/CADShared/ExtensionMethod/Jig/JigExTransient.cs index c7532b98ef14c1eecb49358b27cfbbea396f3442..e0bfeb06fcf4d6599236182dfb45720ef27621a3 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/JigExTransient.cs +++ b/src/CADShared/ExtensionMethod/Jig/JigExTransient.cs @@ -1,5 +1,4 @@ -#if acad && !ac2008 -namespace IFoxCAD.Cad; +namespace IFoxCAD.Cad; /// /// 瞬态容器 @@ -7,57 +6,71 @@ namespace IFoxCAD.Cad; public class JigExTransient : IDisposable { #region 私有字段 + // 整数集,暂时不知道有什么意义 - IntegerCollection _integerCollection; + readonly IntegerCollection _integerCollection; + // 维护集合 - HashSet _entities; + readonly HashSet _drawableSet; + readonly TransientManager _manager; + #endregion #region 公开属性 + + /// + /// 图元集合 + /// + public Entity[] Entities => _drawableSet.OfType().ToArray(); + /// /// 对象集合 /// - public Entity[] Entities => _entities.ToArray(); + public Drawable[] Drawables => _drawableSet.ToArray(); + /// /// 数量 /// - public int Count => _entities.Count; + public int Count => _drawableSet.Count; + #endregion #region 构造函数 + /// /// 瞬态容器 /// public JigExTransient() { _integerCollection = new(); - _entities = new(); + _drawableSet = []; + _manager = TransientManager.CurrentTransientManager; } + #endregion #region 方法 + /// /// 判断瞬态容器里是否含有对象 /// - /// 对象 + /// 对象 /// 含有返回true - public bool Contains(Entity ent) + public bool Contains(Drawable drawable) { - return _entities.Contains(ent); + return _drawableSet.Contains(drawable); } /// /// 向瞬态容器中添加对象 /// - /// 图元 + /// 图元 /// 绘图模式 - public void Add(Entity ent, TransientDrawingMode tdm = TransientDrawingMode.Main) + public void Add(Drawable drawable, TransientDrawingMode tdm = TransientDrawingMode.DirectShortTerm) { - if (_entities.Add(ent)) + if (_drawableSet.Add(drawable)) { - TransientManager - .CurrentTransientManager - .AddTransient(ent, tdm, 128, _integerCollection); + _manager.AddTransient(drawable, tdm, 128, _integerCollection); } } @@ -65,15 +78,13 @@ public void Add(Entity ent, TransientDrawingMode tdm = TransientDrawingMode.Main /// /// 从瞬态容器中移除图元 /// - /// 已经加入瞬态容器的图元 - public void Remove(Entity ent) + /// 已经加入瞬态容器的图元 + public void Remove(Drawable drawable) { - if (!Contains(ent)) + if (!Contains(drawable)) return; - TransientManager - .CurrentTransientManager - .EraseTransient(ent, _integerCollection); - _entities.Remove(ent); + _manager.EraseTransient(drawable, _integerCollection); + _drawableSet.Remove(drawable); } /// @@ -81,27 +92,39 @@ public void Remove(Entity ent) /// public void Clear() { - foreach (var ent in _entities) + foreach (var drawable in _drawableSet) { - TransientManager - .CurrentTransientManager - .EraseTransient(ent, _integerCollection); + _manager.EraseTransient(drawable, _integerCollection); } - _entities.Clear(); + + _drawableSet.Clear(); + } + + /// + /// 清空瞬态容器并移除图元显示 + /// + public void ClearAndDisposeDrawables() + { + foreach (var drawable in _drawableSet) + { + _manager.EraseTransient(drawable, _integerCollection); + if (!drawable.IsDisposed) + drawable.Dispose(); + } + + _drawableSet.Clear(); } /// /// 更新单个显示 /// - /// 已经加入瞬态容器的图元 - public void Update(Entity ent) + /// 已经加入瞬态容器的图元 + public void Update(Drawable drawable) { - if (!Contains(ent)) + if (!Contains(drawable)) return; - TransientManager - .CurrentTransientManager - .UpdateTransient(ent, _integerCollection); + _manager.UpdateTransient(drawable, _integerCollection); } /// @@ -109,13 +132,18 @@ public void Update(Entity ent) /// public void UpdateAll() { - foreach (var ent in _entities) - Update(ent); + foreach (var drawable in _drawableSet) + Update(drawable); } + #endregion #region IDisposable接口相关函数 - public bool IsDisposed { get; private set; } = false; + + /// + /// 是否注销 + /// + public bool IsDisposed { get; private set; } /// /// 手动释放 @@ -139,11 +167,17 @@ public void Dispose() /// protected virtual void Dispose(bool disposing) { - if (IsDisposed) return; + if (IsDisposed) + return; IsDisposed = true; - Clear();// 清空瞬态容器并移除对象在图纸上的显示 + if (disposing) + { + ClearAndDisposeDrawables(); // 清空瞬态容器并移除对象在图纸上的显示 + } + + _drawableSet.Clear(); } + #endregion -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/ObjectIdEx.cs b/src/CADShared/ExtensionMethod/ObjectIdEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..31b23e3fc05632c3178a2a1424867f9c0bd5d041 --- /dev/null +++ b/src/CADShared/ExtensionMethod/ObjectIdEx.cs @@ -0,0 +1,197 @@ +namespace IFoxCAD.Cad; + +/// +/// 对象id扩展类 +/// +public static class ObjectIdEx +{ + #region GetObject + + /// + /// 获取指定类型对象 + /// + /// 对象id + /// 打开模式 + /// 是否打开已删除对象,默认为不打开 + /// 是否打开锁定图层对象,默认为不打开 + /// 指定类型对象 + public static DBObject GetObject(this ObjectId id, OpenMode openMode = OpenMode.ForRead, + bool openErased = false, bool openLockedLayer = false) + { + var tr = DBTrans.GetTopTransaction(id.Database); + return tr.GetObject(id, openMode, openErased, openLockedLayer); + } + + /// + /// 获取指定类型对象 + /// + /// 指定的泛型 + /// 对象id + /// 打开模式 + /// 是否打开已删除对象,默认为不打开 + /// 是否打开锁定图层对象,默认为不打开 + /// 指定类型对象 + public static T? GetObject(this ObjectId id, OpenMode openMode = OpenMode.ForRead, + bool openErased = false, bool openLockedLayer = false) where T : DBObject + { + var tr = DBTrans.GetTopTransaction(id.Database); + return tr.GetObject(id, openMode, openErased, openLockedLayer) as T; + } + + /// + /// 获取指定类型对象集合 + /// + /// 指定的泛型 + /// 对象id集合 + /// 打开模式 + /// 是否打开已删除对象,默认为不打开 + /// 是否打开锁定图层对象,默认为不打开 + /// 指定类型对象集合 + [DebuggerStepThrough] + public static IEnumerable GetObject(this IEnumerable ids, + OpenMode openMode = OpenMode.ForRead, bool openErased = false, bool openLockedLayer = false) + where T : DBObject + { + var rxc = RXObject.GetClass(typeof(T)); + return ids.Where(id => id.ObjectClass.IsDerivedFrom(rxc)) + .Select(id => id.GetObject(openMode, openErased, openLockedLayer)) + .OfType(); + } + + /// + /// 获取指定类型对象集合 + /// + /// 指定的泛型 + /// 对象id集合 + /// 打开模式 + /// 是否打开已删除对象,默认为不打开 + /// 是否打开锁定图层对象,默认为不打开 + /// 指定类型对象集合 + [DebuggerStepThrough] + public static IEnumerable GetObject(this ObjectIdCollection ids, + OpenMode openMode = OpenMode.ForRead, bool openErased = false, bool openLockedLayer = false) + where T : DBObject + { + return ids.Cast().GetObject(openMode, openErased, openLockedLayer); + } + + /// + /// 返回符合类型的对象id + /// + /// 对象类型 + /// 对象id集合 + /// 精确匹配 + /// 对象id集合 + public static IEnumerable IsDerivedFrom(this IEnumerable ids, + bool exactMatch = false) where T : DBObject + { + var rxc = RXObject.GetClass(typeof(T)); + if (exactMatch) + { + var dxfName = rxc.DxfName; + return ids.Where(id => id.ObjectClass.DxfName == dxfName); + } + + return ids.Where(id => id.ObjectClass.IsDerivedFrom(rxc)); + } + + #endregion GetObject + + /// + /// 根据对象句柄字符串获取对象Id + /// + /// 数据库 + /// 句柄字符串 + /// 对象的ObjectId + public static ObjectId GetObjectId(this Database db, string handleString) + { + return db.GetObjectId(handleString.ConvertToHandle()); + } + + /// + /// 根据对象句柄获取对象ObjectId + /// + /// 数据库 + /// 句柄 + /// 对象的ObjectId + public static ObjectId GetObjectId(this Database db, Handle? handle) + { + return handle is not null && db.TryGetObjectId(handle.Value, out var id) + ? id + : ObjectId.Null; + } + + /// + /// 句柄字符串转句柄 + /// + /// 句柄字符串 + /// 句柄 + public static Handle? ConvertToHandle(this string handleString) + { + return long.TryParse(handleString, NumberStyles.HexNumber, null, out var l) + ? new Handle(l) + : null; + } + + /// + /// 获取下一个实体的id + /// + /// id + /// 跳过子对象 + /// 下一个实体的id + public static ObjectId EntNext(this ObjectId id, bool skipSub = false) + { +#if acad + return Utils.EntNext(id, skipSub); +#elif zcad + if (!id.ObjectClass.IsDerivedFrom(RXClassEx.Get())) + throw new ArgumentException("id必须是Entity类型"); + PInvokeCad.GetAdsName(out var adsName, id); + PInvokeCad.ZcdbEntNext(adsName, out var nextId); + if (skipSub && id.IsOk()) + { + var owner1 = (ObjectId)Env.EntGet(id).FirstOrDefault(e => e.TypeCode == 330).Value; + while (nextId.IsOk()) + { + var owner2 = + (ObjectId)Env.EntGet(nextId).FirstOrDefault(e => e.TypeCode == 330).Value; + if (owner1 == owner2) + break; + PInvokeCad.GetAdsName(out var nextAdsName, nextId); + PInvokeCad.ZcdbEntNext(nextAdsName, out nextId); + } + } + + return nextId; +#endif + } + + /// + /// id是否有效,未被删除 + /// + /// 对象id + /// id有效返回 ,反之返回 + public static bool IsOk(this ObjectId id) + { + return id is + { + IsNull: false, + IsValid: true, + IsErased: false, + IsEffectivelyErased: false, + IsResident: true + }; + } + + /// + /// 删除id代表的对象 + /// + /// 对象id + public static void Erase(this ObjectId id) + { + if (!id.IsOk()) + return; + var dbo = id.GetObject(OpenMode.ForWrite); + dbo.Erase(); + } +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/PaneEx.cs b/src/CADShared/ExtensionMethod/PaneEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..6295ac5ad3846287d5e770012761d7ebc70148d6 --- /dev/null +++ b/src/CADShared/ExtensionMethod/PaneEx.cs @@ -0,0 +1,175 @@ +namespace IFoxCAD.Cad; + +/// +/// 托盘类扩展 +/// +public static class PaneEx +{ + /// + /// 设置Pane的左右边距 + /// + /// Pane + /// 左边距类型 + /// 右边距类型 + public static void SetMargin(this Pane pane, PaneMarginType leftMarginType, PaneMarginType rightMarginType) + { + SetLeftMargin(pane, leftMarginType); + SetRightMargin(pane, rightMarginType); + } + + /// + /// 设置左侧的边距 + /// + /// pane + /// 边距类型 + public static void SetLeftMargin(this Pane pane, PaneMarginType marginType) + { + var hasMargin = marginType != PaneMarginType.NONE; + if (hasMargin) + { + var style = (PaneStyles)(marginType == PaneMarginType.LARGE ? 64 : 128); + while (true) + { + Acap.StatusBar.Update(); + var index = Acap.StatusBar.Panes.IndexOf(pane); + if (index == -1 || index == 0) + break; + var left1 = Acap.StatusBar.Panes[index - 1]; + var left1Style = Convert.ToInt32(left1.Style); + + if (index == 1 && (left1Style == 64 || left1Style == 128)) + { + Acap.StatusBar.Panes.Remove(left1); + continue; + } + + if (left1Style != 64 && left1Style != 128) + { + var leftAdd1 = new Pane() { ToolTipText = pane.ToolTipText, Style = style }; + Acap.StatusBar.Panes.Insert(index, leftAdd1); + continue; + } + + left1.Style = style; + if (index > 1) + { + var left2 = Acap.StatusBar.Panes[index - 2]; + var left2Style = Convert.ToInt32(left2.Style); + if (left2Style == 64 || left2Style == 128) + { + Acap.StatusBar.Panes.Remove(left2); + continue; + } + } + + break; + } + } + else + { + while (true) + { + Acap.StatusBar.Update(); + var index = Acap.StatusBar.Panes.IndexOf(pane); + if (index > 0) + { + var left1 = Acap.StatusBar.Panes[index - 1]; + var left1Style = Convert.ToInt32(left1.Style); + if (left1Style == 64 || left1Style == 128) + { + Acap.StatusBar.Panes.Remove(left1); + continue; + } + } + + break; + } + } + + Acap.StatusBar.Update(); + } + + /// + /// 设置右侧的边距 + /// + /// pane + /// 边距类型 + public static void SetRightMargin(this Pane pane, PaneMarginType marginType) + { + var hasMargin = marginType != PaneMarginType.NONE; + if (hasMargin) + { + var style = (PaneStyles)(marginType == PaneMarginType.LARGE ? 64 : 128); + while (true) + { + Acap.StatusBar.Update(); + var index = Acap.StatusBar.Panes.IndexOf(pane); + if (index == -1 || index == Acap.StatusBar.Panes.Count - 1) + break; + var right1 = Acap.StatusBar.Panes[index + 1]; + var right1Style = Convert.ToInt32(right1.Style); + if (right1Style != 64 && right1Style != 128) + { + var rightAdd1 = new Pane() { ToolTipText = pane.ToolTipText, Style = style }; + Acap.StatusBar.Panes.Insert(index + 1, rightAdd1); + continue; + } + + right1.Style = style; + if (index < Acap.StatusBar.Panes.Count - 2) + { + var right2 = Acap.StatusBar.Panes[index + 2]; + var right2Style = Convert.ToInt32(right2.Style); + if (right2Style == 64 || right2Style == 128) + { + Acap.StatusBar.Panes.Remove(right2); + continue; + } + } + + break; + } + } + else + { + while (true) + { + Acap.StatusBar.Update(); + var index = Acap.StatusBar.Panes.IndexOf(pane); + if (index < Acap.StatusBar.Panes.Count - 1) + { + var right1 = Acap.StatusBar.Panes[index + 1]; + var right1Style = Convert.ToInt32(right1.Style); + if (right1Style == 64 || right1Style == 128) + { + Acap.StatusBar.Panes.Remove(right1); + continue; + } + } + + break; + } + } + + Acap.StatusBar.Update(); + } +} + +/// +/// 托盘边距类型 +/// +public enum PaneMarginType : byte +{ + /// + /// 无 + /// + NONE, + /// + /// 小边距 + /// + SMALL, + /// + /// 大边距 + /// + LARGE +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/PromptOptionsEx.cs b/src/CADShared/ExtensionMethod/PromptOptionsEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..637cc7cbbf67a6df7a67e537d8e6feb877705d97 --- /dev/null +++ b/src/CADShared/ExtensionMethod/PromptOptionsEx.cs @@ -0,0 +1,90 @@ +// ReSharper disable UnusedAutoPropertyAccessor.Global + +namespace IFoxCAD.Cad; + +/// +/// 交互设置扩展 +/// +[SuppressMessage("ReSharper", "StringLiteralTypo")] +public static class PromptOptionsEx +{ + /// + /// 保留关键字列表 + /// + internal static readonly HashSet SsGetSaveKeywords = + [ + "WINDOW", "LAST", "CROSSWINDOW", "BOX", "ALL", "FENCE", "WPOLYGON", "CPOLYGON", "GROUP", + "ADD", "REMOVE", "MULTIPLE", "PREVIOUS", "UNDO", "AUTO", "SINGLE", "SUBOBJECT", "OBJECT" + ]; + + /// + /// 添加关键字(顺序为:关键字, 描述, 关键字, 描述)
+ /// 例如 pso.AddKeywords("SZ", "设置", "OP", "选项") + ///
+ /// 选择集选项 + /// 关键字 + public static void AddKeywords(this PromptSelectionOptions pso, params string[] keywords) + { + for (var i = 0; i < keywords.Length / 2; i++) + { + var key = keywords[i * 2].ToUpper(); + if (SsGetSaveKeywords.FirstOrDefault(e => e.StartsWith(key)) is { } saveKey) + { + throw new ArgumentException($"关键字{key}与选择集保留关键字{saveKey}冲突"); + } + + var message = keywords[i * 2 + 1]; + var end = $"({key})"; + if (!message.EndsWith(end)) + { + message += end; + } + + pso.Keywords.Add(key, key, message); + } + + var displayString = pso.Keywords.GetDisplayString(true); + pso.MessageForAdding += displayString; + pso.MessageForRemoval += displayString; + } + + /// + /// 将关键视视为错误抛出 + /// + /// 选择集选项 + public static void ThrowKeywordAsException(this PromptSelectionOptions pso) + { + pso.KeywordInput -= PsoOnKeywordInput; + pso.KeywordInput += PsoOnKeywordInput; + } + + /// + /// 选择集关键字输入时用于抛错的事件 + /// + private static void PsoOnKeywordInput(object sender, SelectionTextInputEventArgs e) + { + if (string.IsNullOrEmpty(e.Input)) + return; + throw new KeywordException(e.Input.ToUpper()); + } +} + +/// +/// 关键字错误 +/// +public class KeywordException : Exception +{ + /// + /// 关键字错误 + /// + /// 关键字 + public KeywordException(string input) + { + Input = input; + } + + /// + /// 关键字 + /// + public string Input { get; } +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/RXClassEx.cs b/src/CADShared/ExtensionMethod/RXClassEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..d077e5392fe54b1250cbd62419887628c3a77b1b --- /dev/null +++ b/src/CADShared/ExtensionMethod/RXClassEx.cs @@ -0,0 +1,28 @@ +namespace IFoxCAD.Cad; + +/// +/// RXClass扩展 +/// +public static class RXClassEx +{ + /// + /// 获取RXClass + /// + /// 类型 + /// + public static RXClass Get() where T : DBObject + { + var type = typeof(T); + if (!_dict.TryGetValue(type, out var rxClass)) + { + _dict[type] = rxClass = RXObject.GetClass(type); + } + + return rxClass; + } + + /// + /// 由于RXObject.GetClass速度极慢,采用内部字典优化速度 + /// + private static readonly Dictionary _dict = []; +} \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/General/RandomEx.cs b/src/CADShared/ExtensionMethod/RandomEx.cs similarity index 63% rename from src/Basal/IFox.Basal.Shared/General/RandomEx.cs rename to src/CADShared/ExtensionMethod/RandomEx.cs index 4d743244994bb16ba958cd52fd0f80bfb81514a6..cf245380831dbf48a0b3f3f1e1f04029ec29f243 100644 --- a/src/Basal/IFox.Basal.Shared/General/RandomEx.cs +++ b/src/CADShared/ExtensionMethod/RandomEx.cs @@ -1,13 +1,13 @@ /* -*┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━模块信息━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ -*┃ 作 者:YxrWendao -*┃ 创建时间:2022/8/30 22:49:30 -*┃ 模块描述:随机数生成器 -*┃ 使用范围:通用 -*┃ 说 明:本模块中除GetRandom与NextColor方法是IFoxCAD原有的以外,其他方法均通过网络收集整理而来。 -*┃ 代码版本:1.0 -*┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ -*/ + *┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━模块信息━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + *┃ 作 者:YxrWendao + *┃ 创建时间:2022/8/30 22:49:30 + *┃ 模块描述:随机数生成器 + *┃ 使用范围:通用 + *┃ 说 明:本模块中除GetRandom与NextColor方法是IFoxCAD原有的以外,其他方法均通过网络收集整理而来。 + *┃ 代码版本:1.0 + *┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + */ namespace IFoxCAD.Basal; @@ -28,6 +28,7 @@ public static double NextDouble(Random ran, double minValue, double maxValue) { return ran.NextDouble() * (maxValue - minValue) + minValue; } + /// /// 生成一个指定范围的浮点数值 /// @@ -38,6 +39,7 @@ public static double NextDouble(double minValue, double maxValue) { return NextDouble(GetRandom(), minValue, maxValue); } + /// /// 生成一个布尔随机数 /// @@ -46,15 +48,17 @@ public static bool NextBool() { return NextBool(GetRandom()); } + /// /// 生成一个布尔随机数
///
/// public static bool NextBool(Random ran) { - bool[] arr = { true, false }; + bool[] arr = [true, false]; return arr[ran.Next(2)]; } + /// /// 生成一个不连续或指定值的随机值 /// @@ -64,6 +68,7 @@ public static string NextString(string[] arr) { return NextString(GetRandom(), arr); } + /// /// 生成一个不连续或指定值的随机值 /// @@ -72,10 +77,10 @@ public static string NextString(string[] arr) /// public static string NextString(Random ran, string[] arr) { - ran ??= GetRandom(); - int n = ran.Next(arr.Length - 1); + var n = ran.Next(arr.Length - 1); return arr[n]; } + /// /// 生成一个不连续或指定值的随机值 /// @@ -85,6 +90,7 @@ public static double NextDouble(double[] arr) { return NextDouble(GetRandom(), arr); } + /// /// 生成不连续或指定值的随机值 /// @@ -93,10 +99,10 @@ public static double NextDouble(double[] arr) /// public static double NextDouble(Random ran, double[] arr) { - ran ??= GetRandom(); - int n = ran.Next(arr.Length - 1); + var n = ran.Next(arr.Length - 1); return arr[n]; } + /// /// 生成指定范围内的整数 /// @@ -106,6 +112,7 @@ public static int NextInt(int max) { return NextInt(GetRandom(), max); } + /// /// 生成指定范围内的整数 /// @@ -114,9 +121,9 @@ public static int NextInt(int max) /// public static int NextInt(Random ran, int max) { - ran ??= GetRandom(); return ran.Next(max); } + /// /// 生成指定范围内的整数 /// @@ -127,6 +134,7 @@ public static int NextInt(int min, int max) { return NextInt(GetRandom(), min, max); } + /// /// 生成指定范围内的整数 /// @@ -136,7 +144,6 @@ public static int NextInt(int min, int max) /// 返回一个介于之间的整数 public static int NextInt(Random ran, int min, int max) { - ran ??= GetRandom(); return ran.Next(min, max); } @@ -148,44 +155,44 @@ public static System.Drawing.Color NextColor() { return NextColor(GetRandom()); } + /// /// 生成一个随机颜色 /// /// public static System.Drawing.Color NextColor(Random ran) { - ran ??= GetRandom(); - int R = ran.Next(255); - int G = ran.Next(255); - int B = ran.Next(255); - B = (R + G > 400) ? R + G - 400 : B;// 0 : 380 - R - G; - B = (B > 255) ? 255 : B; - return System.Drawing.Color.FromArgb(R, G, B); + var r = ran.Next(255); + var g = ran.Next(255); + var b = ran.Next(255); + b = (r + g > 400) ? r + g - 400 : b; // 0 : 380 - R - G; + b = (b > 255) ? 255 : b; + return System.Drawing.Color.FromArgb(r, g, b); } /* - * 知识准备: - * | 高位64位 | 低位32位 | - * Convert.ToString(int.MaxValue, 2)输出二进制 "1111111111111111111111111111111" 31个;最高位是符号位,所以少1位 - * Convert.ToString(long.MaxValue,2)输出二进制,刚好长一倍 "11111111111111111111111111111111 1111111111111111111111111111111" 63个;最高位是符号位,所以少1位 - * Convert.ToString(0xffffffffL, 2)int.MaxValue再按位多1 "1 1111111111111111111111111111111" 32个;前面的0不会打印出来 - * - * Convert.ToString(long.MaxValue>>32, 2)相当于平移高位的到低位范围,也就是上面少打印的二进制 - * 验证右移是不是高位保留,答案是 - * var a = Convert.ToInt64("101111111111111111111111111111111111111111111111111111111111111", 2); - * Convert.ToString(a >> 32,2); - * - * 解释代码: - * 0x01: - * (int)(long.MaxValue & 0xffffffffL) | (int)(long.MaxValue >> 32); - * Convert.ToString(long.MaxValue & 0xffffffffL, 2)// 去掉高位:"11111111111111111111111111111111" 32个,再强转int - * 按位与&是保证符号位肯定是1,其他尽可能为0,高位被去掉只是MaxValue&0的原因,强转才是去掉高位..."尽可能"一词带来第一次随机性 - * 0x02: - * Convert.ToString((long.MaxValue >> 32), 2) // 去掉低位: "1111111111111111111111111111111" 31个,再强转int - * 按位或|是尽可能为1..."尽可能"一词带来第二次随机性 - * - */ + * 知识准备: + * | 高位64位 | 低位32位 | + * Convert.ToString(int.MaxValue, 2)输出二进制 "1111111111111111111111111111111" 31个;最高位是符号位,所以少1位 + * Convert.ToString(long.MaxValue,2)输出二进制,刚好长一倍 "11111111111111111111111111111111 1111111111111111111111111111111" 63个;最高位是符号位,所以少1位 + * Convert.ToString(0xffffffffL, 2)int.MaxValue再按位多1 "1 1111111111111111111111111111111" 32个;前面的0不会打印出来 + * + * Convert.ToString(long.MaxValue>>32, 2)相当于平移高位的到低位范围,也就是上面少打印的二进制 + * 验证右移是不是高位保留,答案是 + * var a = Convert.ToInt64("101111111111111111111111111111111111111111111111111111111111111", 2); + * Convert.ToString(a >> 32,2); + * + * 解释代码: + * 0x01: + * (int)(long.MaxValue & 0xffffffffL) | (int)(long.MaxValue >> 32); + * Convert.ToString(long.MaxValue & 0xffffffffL, 2)// 去掉高位:"11111111111111111111111111111111" 32个,再强转int + * 按位与&是保证符号位肯定是1,其他尽可能为0,高位被去掉只是MaxValue&0的原因,强转才是去掉高位..."尽可能"一词带来第一次随机性 + * 0x02: + * Convert.ToString((long.MaxValue >> 32), 2) // 去掉低位: "1111111111111111111111111111111" 31个,再强转int + * 按位或|是尽可能为1..."尽可能"一词带来第二次随机性 + * + */ /// /// 带有随机种子的随机数
diff --git a/src/CAD/IFox.CAD.Shared/Runtime/RedrawEx.cs b/src/CADShared/ExtensionMethod/RedrawEx.cs similarity index 78% rename from src/CAD/IFox.CAD.Shared/Runtime/RedrawEx.cs rename to src/CADShared/ExtensionMethod/RedrawEx.cs index 3799eed1ae392f7b92626ee4a03f019a9bbe00d8..d268252370807f72ff52019dc6e35c425d6136b6 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/RedrawEx.cs +++ b/src/CADShared/ExtensionMethod/RedrawEx.cs @@ -1,83 +1,106 @@ -namespace IFoxCAD.Cad; +// ReSharper disable InconsistentNaming +namespace IFoxCAD.Cad; + +/// +/// 亮显模式 +/// [Flags] -public enum BrightEntity : int +public enum BrightEntity { /// /// 块更新 /// RecordGraphicsModified = 1, + /// /// 标注更新 /// RecomputeDimensionBlock = 2, + /// /// 重画 /// Draw = 4, + /// /// 亮显 /// Highlight = 8, + /// /// 亮显取消 /// Unhighlight = 16, + /// /// 显示图元 /// VisibleTrue = 32, + /// /// 隐藏图元 /// VisibleFalse = 64, + /// /// 平移更新,可以令ctrl+z撤回时候保证刷新 /// MoveZero = 128, } +/// +/// 刷新模式 +/// [Flags] -public enum BrightEditor : int +public enum BrightEditor { /// /// 刷新屏幕,图元不生成(例如块还是旧的显示) /// UpdateScreen = 1, + /// /// 刷新全图 /// Regen = 2, + /// /// 清空选择集 /// SelectionClean = 4, + /// /// 视口外 /// ViewportsFrom = 8, + /// /// 视口内 /// ViewportsIn = 16, } +/// +/// 重绘扩展 +/// public static class RedrawEx { /// /// 刷新屏幕 /// /// 编辑器 - /// 图元,调用时候图元必须提权 + /// 图元 public static void Redraw(this Editor ed, Entity? ent = null) { - // 刷新图元 - ent?.Redraw(BrightEntity.Draw | - BrightEntity.RecordGraphicsModified | - BrightEntity.RecomputeDimensionBlock | - BrightEntity.MoveZero); - // 刷新 - ed.Redraw(BrightEditor.UpdateScreen); + using (ent?.ForWrite()) + { + // 刷新图元 + ent?.Redraw(BrightEntity.Draw | BrightEntity.RecordGraphicsModified | + BrightEntity.RecomputeDimensionBlock | BrightEntity.MoveZero); + // 刷新 + ed.Redraw(BrightEditor.UpdateScreen); + } /* * 我发现命令加 CommandFlags.Redraw 就不需要以下处理了: @@ -89,9 +112,7 @@ public static void Redraw(this Editor ed, Entity? ent = null) * tm.FlushGraphics(); // 将当前 刷新队列 的图形提交到显示器 * ed.UpdateScreen(); // 仅刷新屏幕,图元不生成(例如块还是旧的显示) */ - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var tm = doc.TransactionManager; + var tm = ed.Document.TransactionManager; tm.QueueForGraphicsFlush(); tm.FlushGraphics(); @@ -117,6 +138,7 @@ public static void Redraw(this Editor ed, BrightEditor bright) ed.Regen(); if ((bright & BrightEditor.SelectionClean) == BrightEditor.SelectionClean) + // ReSharper disable once UseCollectionExpression ed.SetImpliedSelection(new ObjectId[0]); if ((bright & BrightEditor.ViewportsFrom) == BrightEditor.ViewportsFrom) @@ -164,28 +186,4 @@ public static void Redraw(this Entity ent, BrightEntity bright) if ((bright & BrightEntity.MoveZero) == BrightEntity.MoveZero) ent.Move(Point3d.Origin, Point3d.Origin); } - - - #region 实体刷新 - /// - /// 刷新实体显示 - /// - /// 实体对象 - [Obsolete("此处已经被RedrawEx代替")] - public static void Flush(this Entity entity, DBTrans? trans = null) - { - trans ??= DBTrans.Top; - entity.RecordGraphicsModified(true); - trans.Transaction.TransactionManager.QueueForGraphicsFlush(); - trans.Document?.TransactionManager.FlushGraphics(); - } - - /// - /// 刷新实体显示 - /// - /// 实体id - [Obsolete("此处已经被RedrawEx代替")] - public static void Flush(this ObjectId id) - => Flush(DBTrans.Top.GetObject(id)!); - #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/SelectionSetEx.cs b/src/CADShared/ExtensionMethod/SelectionSetEx.cs similarity index 46% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/SelectionSetEx.cs rename to src/CADShared/ExtensionMethod/SelectionSetEx.cs index 2223554013eb6b5b60d50b90b68aa8e988f7fc27..26d39bcf8dc902d43caaabbfa60648256567e324 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/SelectionSetEx.cs +++ b/src/CADShared/ExtensionMethod/SelectionSetEx.cs @@ -1,4 +1,6 @@ - +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Cad; @@ -8,28 +10,6 @@ namespace IFoxCAD.Cad; public static class SelectionSetEx { #region 获取对象id - /// - /// 获取已选择的对象 - /// - /// 选择集 - /// 已选择的对象集合 - [System.Diagnostics.DebuggerStepThrough] - public static IEnumerable GetSelectedObjects(this SelectionSet ss) - { - return ss.Cast(); - } - - /// - /// 获取已选择的对象 - /// - /// 已选择的对象泛型 - /// 选择集 - /// 已选择的对象集合 - [System.Diagnostics.DebuggerStepThrough] - public static IEnumerable GetSelectObjects(this SelectionSet ss) where T : SelectedObject - { - return ss.Cast().OfType(); - } /// /// 从选择集中获取对象id @@ -37,14 +17,13 @@ public static IEnumerable GetSelectObjects(this SelectionSet ss) where T : /// 图元类型 /// 选择集 /// 已选择的对象id集合 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static IEnumerable GetObjectIds(this SelectionSet ss) where T : Entity { - string dxfName = RXClass.GetClass(typeof(T)).DxfName; - return - ss - .GetObjectIds() - .Where(id => id.ObjectClass().DxfName == dxfName); + var rxc = RXClassEx.Get(); + + return ss.GetObjectIds() + .Where(id => id.ObjectClass.IsDerivedFrom(rxc)); } /// @@ -52,14 +31,13 @@ public static IEnumerable GetObjectIds(this SelectionSet ss) where /// /// 选择集 /// 分组后的类型/对象id集合 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static IEnumerable> GetObjectIdGroup(this SelectionSet ss) { - return - ss - .GetObjectIds() - .GroupBy(id => id.ObjectClass().DxfName); + return ss.GetObjectIds() + .GroupBy(id => id.ObjectClass.DxfName); } + #endregion #region 获取实体对象 @@ -70,29 +48,24 @@ public static IEnumerable> GetObjectIdGroup(this Sel /// 指定类型 /// 选择集 /// 打开模式 - /// 事务 /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 /// 图元集合 - [System.Diagnostics.DebuggerStepThrough] - public static IEnumerable GetEntities(this SelectionSet ss, - OpenMode openMode = OpenMode.ForRead, - DBTrans? trans = null, - bool openErased = false, - bool openLockedLayer = false) where T : Entity + [DebuggerStepThrough] + public static IEnumerable GetEntities(this SelectionSet? ss, + OpenMode openMode = OpenMode.ForRead, + bool openErased = false, + bool openLockedLayer = false) where T : Entity { - //if (ss is null) - // throw new ArgumentNullException(nameof(ss)); - ss.NotNull(nameof(ss)); - trans ??= DBTrans.Top; - return ss.GetObjectIds() - .Select(id => trans.GetObject(id, openMode, openErased, openLockedLayer)) - .Where(ent => ent != null) - .OfType(); + return ss?.GetObjectIds() + .Select(id => id.GetObject(openMode, openErased, openLockedLayer)) + .OfType() ?? []; } + #endregion #region ForEach + /// /// 遍历选择集 /// @@ -100,20 +73,16 @@ public static IEnumerable GetEntities(this SelectionSet ss, /// 选择集 /// 处理函数;(图元) /// 打开模式 - /// 事务 /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static void ForEach(this SelectionSet ss, - Action action, - OpenMode openMode = OpenMode.ForRead, - DBTrans? tr = default, - bool openErased = false, - bool openLockedLayer = false) where T : Entity + Action action, + OpenMode openMode = OpenMode.ForRead, + bool openErased = false, + bool openLockedLayer = false) where T : Entity { - ForEach(ss, (ent, state) => { - action.Invoke(ent); - }, openMode, tr, openErased, openLockedLayer); + ForEach(ss, (ent, _) => { action.Invoke(ent); }, openMode, openErased, openLockedLayer); } /// @@ -123,23 +92,20 @@ public static void ForEach(this SelectionSet ss, /// 选择集 /// 处理函数;(图元,终止方式) /// 打开模式 - /// 事务 /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 - /// - [System.Diagnostics.DebuggerStepThrough] + /// + [DebuggerStepThrough] public static void ForEach(this SelectionSet ss, - Action action, - OpenMode openMode = OpenMode.ForRead, - DBTrans? trans = null, - bool openErased = false, - bool openLockedLayer = false) where T : Entity + Action action, + OpenMode openMode = OpenMode.ForRead, + bool openErased = false, + bool openLockedLayer = false) where T : Entity { - action.NotNull(nameof(action)); - trans ??= DBTrans.Top; + ArgumentNullException.ThrowIfNull(action); LoopState state = new(); - var ents = ss.GetEntities(openMode, trans, openErased, openLockedLayer); + var ents = ss.GetEntities(openMode, openErased, openLockedLayer); foreach (var ent in ents) { action.Invoke(ent, state); @@ -147,5 +113,6 @@ public static void ForEach(this SelectionSet ss, break; } } + #endregion } \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/SingleKeyWordHook.cs b/src/CADShared/ExtensionMethod/SingleKeyWordHook.cs new file mode 100644 index 0000000000000000000000000000000000000000..0f1f84cec713216190e24cca0c7c9371436c365b --- /dev/null +++ b/src/CADShared/ExtensionMethod/SingleKeyWordHook.cs @@ -0,0 +1,271 @@ +using Keys = System.Windows.Forms.Keys; + +namespace IFoxCAD.Cad; + +/// +/// 关键字不需要空格钩子 +/// By DYH 20230508 +/// +public sealed class SingleKeyWordHook : IDisposable +{ + #region 静态字段 + + private static readonly string _enterStr = Convert.ToChar(Keys.Enter).ToString(); + private static readonly string _backStr = Convert.ToChar(Keys.Back).ToString(); + + #endregion + + #region 私有字段 + + /// + /// 关键字合集 + /// + private readonly HashSet _keyWords; + + private bool _isResponsed; + private bool _working; + private Keys _key; + private readonly SingleKeyWordWorkType _workType; + + #endregion + + #region 公共属性 + + /// + /// 上一个触发的关键字 + /// + public Keys Key => _key; + + /// + /// 上一个触发的关键字字符串 + /// + public string StringResult => _key.ToString().ToUpper(); + + /// + /// 是否响应了 + /// + public bool IsResponsed => _isResponsed && _working; + + #endregion + + #region 构造 + + /// + /// 单字母关键字免输回车钩子 + /// + /// 使用esc(填false则使用回车) + public SingleKeyWordHook(SingleKeyWordWorkType workType = SingleKeyWordWorkType.ESCAPE) + { + IsDisposed = false; + _isResponsed = false; + _keyWords = []; + _key = Keys.None; + _working = true; + _workType = workType; + Acaop.PreTranslateMessage -= Acap_PreTranslateMessage; + Acaop.PreTranslateMessage += Acap_PreTranslateMessage; + } + + #endregion + + #region 方法 + + /// + /// 添加Keys + /// + /// Keys集合 + public void AddKeys(params Keys[] values) => values.ForEach(value => _keyWords.Add(value)); + + /// + /// 添加Keys + /// + /// 关键字集合 + public void AddKeys(KeywordCollection keywordCollection) + { + foreach (Keyword item in keywordCollection) + { + if (item.LocalName.Length != 1) continue; + var k = (Keys)item.LocalName[0]; + _keyWords.Add(k); + } + } + + /// + /// 移除Keys + /// + /// Keys集合 + public void Remove(params Keys[] values) => values.ForEach(value => _keyWords.Remove(value)); + + /// + /// 清空Keys + /// + public void Clear() => _keyWords.Clear(); + + /// + /// 复位响应状态,每个循环开始时使用 + /// + public void Reset() + { + _key = Keys.None; + _isResponsed = false; + } + + /// + /// 暂停工作 + /// + public void Pause() + { + _working = false; + } + + /// + /// 开始工作 + /// + public void Working() + { + _working = true; + } + + #endregion + + #region 事件 + + private void Acap_PreTranslateMessage(object sender, PreTranslateMessageEventArgs e) + { + if (!_working || e.Message.message != 256) return; + var tempKey = IntPtr.Size == 4 ? (Keys)e.Message.wParam.ToInt32() : (Keys)e.Message.wParam.ToInt64(); + var contains = _keyWords.Contains(tempKey); + if (!contains) return; + + // 标记为true,表示此按键已经被处理,Windows不会再进行处理 + if (_workType != SingleKeyWordWorkType.ENTER) + { + e.Handled = true; + } + + if (IsResponsed) return; //放 e.Handled 后是避免在非 ENTER 模式时长按造成动态输入框偶发性闪现关键字以至轻微卡顿问题 + + _key = tempKey; + _isResponsed = true; // 此bool是防止按键被长按时出错 + + switch (_workType) + { + case SingleKeyWordWorkType.ESCAPE: + // ESC稳妥一些,但是要判断promptResult的顺序 + KeyBoardSendKey(Keys.Escape); + break; + case SingleKeyWordWorkType.ENTER: + KeyBoardSendKey(Keys.Enter); + break; + case SingleKeyWordWorkType.WRITE_LINE: + Utils.SetFocusToDwgView(); // 恢复焦点(如果前面关键字输入错误便会将焦点移至动态输入框) + Utils.WriteToCommandLine(Convert.ToChar(_key) + _enterStr); + break; + } + } + + #endregion + + #region Dispose + + /// + /// 已经销毁 + /// + public bool IsDisposed { get; private set; } + + /// + /// 拆除事件 + /// + /// + private void Dispose(bool disposing) + { + if (IsDisposed) + return; + + Acaop.PreTranslateMessage -= Acap_PreTranslateMessage; + if (disposing) + { + _keyWords.Clear(); + } + + IsDisposed = true; + } + + /// + /// 析构里把事件拆了 + /// + ~SingleKeyWordHook() + { + Dispose(false); + } + + /// + /// 拆除事件并清空关键字 + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + + #region 静态方法 + + /// + /// 发送按键 + /// + /// + /// + /// + /// + private static void KeyBoardSendKey(Keys key, byte bScan = 0, uint dwFlags = 0, uint dwExtraInfo = 0) + { + keybd_event(key, bScan, dwFlags, dwExtraInfo); + keybd_event(key, bScan, 2, dwExtraInfo); + } + + [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)] + private static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo); + + #endregion +} +/// +/// 单文本关键字钩子扩展 +/// +public static class SingleKeywordHookEx +{ + /// + /// 钩取单文本关键字 + /// + /// 关键字集合 + /// 工作模式 + /// 单文本关键字类(需要using) + public static SingleKeyWordHook HookSingleKeyword(this KeywordCollection keywords, SingleKeyWordWorkType workType = SingleKeyWordWorkType.WRITE_LINE) + { + var singleKeyWordHook = new SingleKeyWordHook(workType); + singleKeyWordHook.AddKeys(keywords); + return singleKeyWordHook; + } +} + +/// +/// 单关键字工作模式 +/// +public enum SingleKeyWordWorkType : byte +{ + /// + /// Esc模式 + /// + ESCAPE, + + /// + /// Enter模式 + /// + ENTER, + + /// + /// Write Line 模式 + /// + WRITE_LINE, +} diff --git a/src/CADShared/ExtensionMethod/SupportPathEx.cs b/src/CADShared/ExtensionMethod/SupportPathEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..fa0803fc2f6aedd8e70af2912446c3a86f87a1e2 --- /dev/null +++ b/src/CADShared/ExtensionMethod/SupportPathEx.cs @@ -0,0 +1,75 @@ +namespace IFoxCAD.Cad; + +internal static class SupportPathEx +{ + private const string kName = "ACAD"; + + /// + /// 获取支持路径 + /// + /// 路径列表 + public static List Get() + { + var str = Env.GetEnv(kName); + var set = str.ToLower() + .Split([";"], StringSplitOptions.RemoveEmptyEntries) + .Select(s => s.TrimEnd('\\')) + .ToHashSet(); + return set.ToList(); + } + + /// + /// 添加支持路径 + /// + /// 路径列表 + public static void Add(params IEnumerable dirs) + { + var dirSet = dirs.ToLowerDirSet(); + if (dirSet.Count == 0) + return; + var supportPaths = Get(); + foreach (var dir in dirSet) + { + if (!Directory.Exists(dir)) + continue; + if (supportPaths.Contains(dir)) + continue; + supportPaths.Insert(0, dir); + } + + Set(supportPaths); + } + + /// + /// 移除支持路径 + /// + /// 路径列表 + public static void Remove(params IEnumerable dirs) + { + var dirSet = dirs.ToLowerDirSet(); + var supportPaths = Get(); + supportPaths.RemoveAll(dirSet.Contains); + Set(supportPaths); + } + + /// + /// 设置支持路径 + /// + /// 路径列表 + private static void Set(IEnumerable dirs) + { + var set = dirs.Where(Directory.Exists).ToLowerDirSet(); + var str = string.Join(";", set); + Env.SetEnv(kName, str); + } + + /// + /// 转换为小写并去除尾部反斜杠的路径集合 + /// + /// 路径列表 + /// 路径集合 + private static HashSet ToLowerDirSet(this IEnumerable dirs) + { + return dirs.Select(dir => dir.ToLower().TrimEnd('\\')).ToHashSet(); + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/SymbolTableEx.cs b/src/CADShared/ExtensionMethod/SymbolTableEx.cs similarity index 56% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/SymbolTableEx.cs rename to src/CADShared/ExtensionMethod/SymbolTableEx.cs index 4c13159977670a4c59efbf86942ca269d0148d41..f780fd663274b97e0b25bf8c6ef27b5f0be8751e 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/SymbolTableEx.cs +++ b/src/CADShared/ExtensionMethod/SymbolTableEx.cs @@ -1,4 +1,6 @@ -namespace IFoxCAD.Cad; +using ArgumentNullException = System.ArgumentNullException; + +namespace IFoxCAD.Cad; /// /// 符号表类扩展函数 @@ -6,6 +8,7 @@ public static class SymbolTableEx { #region 图层表 + /// /// 添加图层 /// @@ -17,6 +20,7 @@ public static ObjectId Add(this SymbolTable table, { return table.Add(name, lt => lt.Color = color); } + /// /// 添加图层 /// @@ -24,28 +28,30 @@ public static ObjectId Add(this SymbolTable table, /// 图层名 /// 图层颜色索引值 /// 图层id - public static ObjectId Add(this SymbolTable table, string name, int colorIndex) + public static ObjectId Add(this SymbolTable table, string name, + int colorIndex) { - colorIndex %= 257;// 防止输入的颜色超出256 - colorIndex = Math.Abs(colorIndex);// 防止负数 + colorIndex %= 257; // 防止输入的颜色超出256 + colorIndex = Math.Abs(colorIndex); // 防止负数 return table.Add(name, lt => lt.Color = Color.FromColorIndex(ColorMethod.ByColor, (short)colorIndex)); } + /// /// 更改图层名 /// /// 图层符号表 - /// 旧图层名 - /// 新图层名 - public static ObjectId Rename(this SymbolTable table, string Oldname, string NewName) + /// 旧图层名 + /// 新图层名 + public static ObjectId Rename(this SymbolTable table, string oldName, + string newName) { - if (!table.Has(Oldname)) + if (!table.Has(oldName)) return ObjectId.Null; - table.Change(Oldname, layer => { - layer.Name = NewName; - }); - return table[NewName]; + table.Change(oldName, layer => { layer.Name = newName; }); + return table[newName]; } + /// /// 删除图层 /// @@ -54,7 +60,8 @@ public static ObjectId Rename(this SymbolTable tab /// 成功返回 ,失败返回 public static bool Delete(this SymbolTable table, string name) { - if (name == "0" || name == "Defpoints" || !table.Has(name) || table[name] == DBTrans.Top.Database.Clayer) + if (SymbolUtilityServices.IsLayerZeroName(name) || SymbolUtilityServices.IsLayerDefpointsName(name) || + !table.Has(name) || table[name] == table.Database.Clayer) return false; table.CurrentSymbolTable.GenerateUsageData(); @@ -68,9 +75,11 @@ public static bool Delete(this SymbolTable table, ltr.Erase(); return true; } + #endregion #region 块表 + /// /// 添加块定义 /// @@ -78,45 +87,44 @@ public static bool Delete(this SymbolTable table, /// 块名 /// 对所添加块表的委托n /// 添加图元的委托 - /// 添加属性定义的委托 + /// 添加属性定义的委托 /// 块定义id /// TODO: 需要测试匿名块等特殊的块是否能定义 - public static ObjectId Add(this SymbolTable table, - string name, - Action? action = null, - Func>? ents = null, - Func>? attdef = null) + public static ObjectId Add(this SymbolTable table, string name, + Action? action = null, Func>? ents = null, + Func>? attDef = null) { - return table.Add(name, btr => { + return table.Add(name, btr => + { action?.Invoke(btr); - var entsres = ents?.Invoke(); - if (entsres is not null) - btr.AddEntity(entsres); + var entsRes = ents?.Invoke(); + if (entsRes is not null) + btr.AddEntity(entsRes); - var adddefres = attdef?.Invoke(); - if (adddefres is not null) - btr.AddEntity(adddefres); + var addDefRes = attDef?.Invoke(); + if (addDefRes is not null) + btr.AddEntity(addDefRes); }); } + /// /// 添加块定义 /// /// 块表 /// 块名 /// 图元 - /// 属性定义 + /// 属性定义 /// - public static ObjectId Add(this SymbolTable table, - string name, - IEnumerable? ents = null, - IEnumerable? attdef = null) + public static ObjectId Add(this SymbolTable table, string name, + IEnumerable? ents = null, IEnumerable? attDef = null) { - return table.Add(name, btr => { + return table.Add(name, btr => + { if (ents is not null) btr.AddEntity(ents); - if (attdef is not null) - btr.AddEntity(attdef); + if (attDef is not null) + btr.AddEntity(attDef); }); } @@ -127,9 +135,10 @@ public static ObjectId Add(this SymbolTable table, /// 块名 /// 图元(包括属性) /// - public static ObjectId Add(this SymbolTable table, string name, params Entity[] ents) + public static ObjectId Add(this SymbolTable table, string name, + params Entity[] ents) { - return table.Add(name, null, () => { return ents; }); + return table.Add(name, null, () => ents); } /// @@ -138,40 +147,35 @@ public static ObjectId Add(this SymbolTable table, /// 块表 /// 块定义id /// 属性列表 - public static void AddAttsToBlocks(this SymbolTable table, - ObjectId id, - List atts) + public static void AddAttsToBlocks(this SymbolTable table, ObjectId id, + List atts) { - List attTags = new(); - table.Change(id, btr => { - - btr.GetEntities() - .ForEach(def => attTags.Add(def.Tag.ToUpper())); + List attTags = []; + table.Change(id, btr => + { + btr.GetEntities().ForEach(def => attTags.Add(def.Tag.ToUpper())); - for (int i = 0; i < atts.Count; i++) - if (!attTags.Contains(atts[i].Tag.ToUpper())) - btr.AddEntity(atts[i]); + foreach (var t in atts.Where(t => !attTags.Contains(t.Tag.ToUpper()))) + btr.AddEntity(t); }); } + /// /// 添加属性到块定义 /// /// 块表 /// 块定义名字 /// 属性列表 - public static void AddAttsToBlocks(this SymbolTable table, - string name, - List atts) + public static void AddAttsToBlocks(this SymbolTable table, string name, + List atts) { - List attTags = new(); - table.Change(name, btr => { - - btr.GetEntities() - .ForEach(def => attTags.Add(def.Tag.ToUpper())); + List attTags = []; + table.Change(name, btr => + { + btr.GetEntities().ForEach(def => attTags.Add(def.Tag.ToUpper())); - for (int i = 0; i < atts.Count; i++) - if (!attTags.Contains(atts[i].Tag.ToUpper())) - btr.AddEntity(atts[i]); + foreach (var t in atts.Where(t => !attTags.Contains(t.Tag.ToUpper()))) + btr.AddEntity(t); }); } @@ -182,27 +186,43 @@ public static void AddAttsToBlocks(this SymbolTable文件名 /// 是否覆盖 /// 块定义Id - public static ObjectId GetBlockFrom(this SymbolTable table, string fileName, bool over) + public static ObjectId GetBlockFrom(this SymbolTable table, string fileName, + bool over) { - - string blkdefname = SymbolUtilityServices.RepairSymbolName( - SymbolUtilityServices.GetSymbolNameFromPathName(fileName, "dwg"), false); - - ObjectId id = table[blkdefname]; - bool has = id != ObjectId.Null; - if ((has && over) || !has) + var blkDefName = SymbolUtilityServices.GetSymbolNameFromPathName(fileName, "dwg"); +#if acad + blkDefName = SymbolUtilityServices.RepairSymbolName(blkDefName, false); +#endif + var id = table[blkDefName]; + var has = id != ObjectId.Null; + + /* 每次看这里都要反应一阵 + 如果已经有这个id,并且要覆盖,或者没有这个id就执行下面的语句,不然就直接返回id + 其实就是如果有这个id,并且不覆盖,就直接返回,其他的情况都需要重新插入 + 所以原代码可以修改 + if (has && over || !has) { - Database db = new(false, true); + using Database db = new(false, true); db.ReadDwgFile(fileName, FileShare.Read, true, null); db.CloseInput(true); - id = table.Database.Insert(BlockTableRecord.ModelSpace, blkdefname, db, false); + id = table.Database.Insert(BlockTableRecord.ModelSpace, blkDefName, db, false); + + return id; + } */ + + if (has && over is false) + { + return id; } + using Database db = new(false, true); + db.ReadDwgFile(fileName, FileShare.Read, true, null); + db.CloseInput(true); + id = table.Database.Insert(BlockTableRecord.ModelSpace, blkDefName, db, false); return id; } - /// /// 从文件中获取块定义 /// @@ -211,17 +231,17 @@ public static ObjectId GetBlockFrom(this SymbolTable块定义名 /// 是否覆盖 /// 块定义Id - public static ObjectId GetBlockFrom(this SymbolTable table, - string fileName, - string blockName, - bool over) + public static ObjectId GetBlockFrom(this SymbolTable table, string fileName, + string blockName, bool over) { return table.GetRecordFrom(t => t.BlockTable, fileName, blockName, over); } + #endregion #region 线型表 + /// /// 添加线型 /// @@ -231,64 +251,60 @@ public static ObjectId GetBlockFrom(this SymbolTable线型长度 /// 笔画长度数组 /// 线型id - public static ObjectId Add(this SymbolTable table, string name, string description, double length, double[] dash) + public static ObjectId Add(this SymbolTable table, string name, + string description, double length, double[] dash) { - return table.Add( - name, - ltt => { - ltt.AsciiDescription = description; - ltt.PatternLength = length; // 线型的总长度 - ltt.NumDashes = dash.Length; // 组成线型的笔画数目 - for (int i = 0; i < dash.Length; i++) - { - ltt.SetDashLengthAt(i, dash[i]); - } - // ltt.SetDashLengthAt(0, 0.5); // 0.5个单位的划线 - // ltt.SetDashLengthAt(1, -0.25); // 0.25个单位的空格 - // ltt.SetDashLengthAt(2, 0); // 一个点 - // ltt.SetDashLengthAt(3, -0.25); // 0.25个单位的空格 + return table.Add(name, ltt => + { + ltt.AsciiDescription = description; + ltt.PatternLength = length; // 线型的总长度 + ltt.NumDashes = dash.Length; // 组成线型的笔画数目 + for (var i = 0; i < dash.Length; i++) + { + ltt.SetDashLengthAt(i, dash[i]); } - ); + // ltt.SetDashLengthAt(0, 0.5); // 0.5个单位的划线 + // ltt.SetDashLengthAt(1, -0.25); // 0.25个单位的空格 + // ltt.SetDashLengthAt(2, 0); // 一个点 + // ltt.SetDashLengthAt(3, -0.25); // 0.25个单位的空格 + }); } + #endregion #region 文字样式表 + /// /// 添加文字样式记录 /// /// 文字样式表 /// 文字样式名 /// 字体名 - /// 宽度比例 + /// 宽度比例 /// 文字样式Id public static ObjectId Add(this SymbolTable table, - string textStyleName, - string font, - double xscale = 1.0) + string textStyleName, string font, double xScale = 1.0) { - return - table.Add( - textStyleName, - tstr => { - tstr.Name = textStyleName; - tstr.FileName = font; - tstr.XScale = xscale; - }); + return table.Add(textStyleName, tstr => + { + tstr.Name = textStyleName; + tstr.FileName = font; + tstr.XScale = xScale; + }); } + /// /// 添加文字样式记录 /// /// 文字样式表 /// 文字样式名 - /// 字体名枚举 - /// 宽度比例 + /// 字体名枚举 + /// 宽度比例 /// 文字样式Id public static ObjectId Add(this SymbolTable table, - string textStyleName, - FontTTF fontTTF, - double xscale = 1.0) + string textStyleName, FontTTF fontTtf, double xScale = 1.0) { - return table.Add(textStyleName, fontTTF.GetDesc(), xscale); + return table.Add(textStyleName, fontTtf.GetDescription(), xScale); } /// @@ -304,16 +320,13 @@ public static ObjectId Add(this SymbolTable是否强制替换 /// 文字样式Id public static ObjectId AddWithChange(this SymbolTable table, - string textStyleName, - string smallFont, - string bigFont = "", - double xScale = 1, - double height = 0, - bool forceChange = true) + string textStyleName, string smallFont, string bigFont = "", double xScale = 1, double height = 0, + bool forceChange = true) { if (forceChange && table.Has(textStyleName)) { - table.Change(textStyleName, ttr => { + table.Change(textStyleName, ttr => + { ttr.FileName = smallFont; ttr.XScale = xScale; ttr.TextSize = height; @@ -322,33 +335,14 @@ public static ObjectId AddWithChange(this SymbolTable { + + return table.Add(textStyleName, ttr => + { ttr.FileName = smallFont; ttr.XScale = xScale; ttr.TextSize = height; }); } - - #endregion - - #region 注册应用程序表 - - #endregion - - #region 标注样式表 - - #endregion - - #region 用户坐标系表 - - #endregion - - #region 视图表 - - #endregion - - #region 视口表 - #endregion -} +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/SymbolTableRecordEx.cs b/src/CADShared/ExtensionMethod/SymbolTableRecordEx.cs similarity index 33% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/SymbolTableRecordEx.cs rename to src/CADShared/ExtensionMethod/SymbolTableRecordEx.cs index 1bd99a871524aca0fd2864270ba4a7f195c9d5fc..1c2c1abc5e3000f2abbfc79c6cc440a241033547 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/SymbolTableRecordEx.cs +++ b/src/CADShared/ExtensionMethod/SymbolTableRecordEx.cs @@ -1,4 +1,9 @@ -namespace IFoxCAD.Cad; + +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; /// /// 符号表记录扩展类 @@ -8,6 +13,7 @@ public static class SymbolTableRecordEx #region 块表记录 #region 克隆实体id + /// /// 深度克隆id到块表记录 /// @@ -15,7 +21,7 @@ public static class SymbolTableRecordEx /// 0x02 若为未添加数据库图元,则利用entity.Clone();同时不需要考虑动态块属性,可以使用entity.GetTransformedCopy /// /// - /// + /// 块表记录 /// /// 克隆到当前块表记录,相当于原地克隆
/// 克隆到目标块表记录内,相当于制作新块 @@ -26,7 +32,7 @@ public static class SymbolTableRecordEx public static void DeepCloneEx(this BlockTableRecord btr, ObjectIdCollection objIds, IdMapping maoOut) { if (objIds is null || objIds.Count == 0) - throw new ArgumentNullException(nameof(objIds)); + throw new System.ArgumentNullException(nameof(objIds)); var db = objIds[0].Database; using (btr.ForWrite()) @@ -40,73 +46,84 @@ public static void DeepCloneEx(this BlockTableRecord btr, ObjectIdCollection obj // foreach (ObjectId item in blockIds) // result.Add(mapping[item].Value); } - catch (System.Exception e) + catch { - LogHelper.FlagOutVsOutput = true; - e.WriteLog("深度克隆出错了"); + // ignored } } } /// - /// 克隆图元实体(这个函数有问题,会出现偶尔成功,偶尔失败,拖动过变成匿名块) - /// 若为块则进行设置属性,因此控制动态块属性丢失; + /// 深度克隆id到块表记录 /// - /// 图元 - /// 矩阵 - // public static void EntityTransformedCopy(this Entity ent, Matrix3d matrix) - // { - // var entNew = ent.GetTransformedCopy(matrix); - // if (ent is BlockReference blockReference) - // entNew.SetPropertiesFrom(blockReference); - // } + /// 块表记录 + /// 图元id集合 + /// id词典 + public static IdMapping DeepCloneEx(this BlockTableRecord btr, ObjectIdCollection objIds) + { + if (objIds is null || objIds.Count == 0) + throw new System.ArgumentNullException(nameof(objIds)); + + var db = objIds[0].Database; + IdMapping mapOut = new(); + using (btr.ForWrite()) + { + try + { + db.DeepCloneObjects(objIds, btr.ObjectId, mapOut, false); + + // 不在此提取,为了此函数被高频调用 + // 获取克隆键值对(旧块名,新块名) + // foreach (ObjectId item in blockIds) + // result.Add(mapping[item].Value); + } + catch + { + // ignored + } + } + + return mapOut; + } #endregion #region 添加实体 + /// /// 添加实体对象 /// /// 块表记录 /// 实体 - /// 事务管理器 /// 对象 id - public static ObjectId AddEntity(this BlockTableRecord btr, Entity entity, - Transaction? trans = null) + public static ObjectId AddEntity(this BlockTableRecord btr, Entity entity) { - // if (entity is null) - // throw new ArgumentNullException(nameof(entity), "对象为 null"); - ObjectId id; - trans ??= DBTrans.Top.Transaction; + var tr = DBTrans.GetTopTransaction(btr.Database); using (btr.ForWrite()) { id = btr.AppendEntity(entity); - trans.AddNewlyCreatedDBObject(entity, true); + tr.AddNewlyCreatedDBObject(entity, true); } + return id; } /// /// 添加实体集合 /// - /// 实体类型 /// 块表记录 /// 实体集合 - /// 事务 /// 对象 id 列表 - public static IEnumerable AddEntity(this BlockTableRecord btr, IEnumerable ents, - Transaction? trans = null) where T : Entity + public static IEnumerable AddEntity(this BlockTableRecord btr, IEnumerable ents) { - // if (ents.Any(ent => ent is null)) - // throw new ArgumentNullException(nameof(ents), "实体集合内存在 null 对象"); - - trans ??= DBTrans.Top.Transaction; + var tr = DBTrans.GetTopTransaction(btr.Database); using (btr.ForWrite()) { - return ents.Select(ent => { - ObjectId id = btr.AppendEntity(ent); - trans.AddNewlyCreatedDBObject(ent, true); + return ents.Select(ent => + { + var id = btr.AppendEntity(ent); + tr.AddNewlyCreatedDBObject(ent, true); return id; }).ToList(); } @@ -120,198 +137,13 @@ public static IEnumerable AddEntity(this BlockTableRecord btr, IEnu /// 对象 id 列表 public static IEnumerable AddEntity(this BlockTableRecord btr, params Entity[] ents) { - return btr.AddEntity(ents, null); - } - #endregion - - #region 添加图元 - /// - /// 在指定绘图空间添加图元 - /// - /// 图元类型 - /// 绘图空间 - /// 图元对象 - /// 图元属性设置委托 - /// 事务管理器 - /// 图元id - private static ObjectId AddEnt(this BlockTableRecord btr, T ent, - Action? action, Transaction? trans = null) where T : Entity - { - action?.Invoke(ent); - return btr.AddEntity(ent, trans); - } - /// - /// 委托式的添加图元 - /// - /// 块表 - /// 返回图元的委托 - /// 事务 - /// 图元id,如果委托返回 null,则为 ObjectId.Null - public static ObjectId AddEnt(this BlockTableRecord btr, Func action, Transaction? trans = null) - { - var ent = action.Invoke(); - if (ent is null) - return ObjectId.Null; - - return btr.AddEntity(ent, trans); - } - - /// - /// 在指定绘图空间添加直线 - /// - /// 事务管理器 - /// 起点 - /// 终点 - /// 绘图空间 - /// 直线属性设置委托 - /// 直线的id - public static ObjectId AddLine(this BlockTableRecord btr, Point3d start, Point3d end, - Action? action = null, Transaction? trans = null) - { - var line = new Line(start, end); - return btr.AddEnt(line, action, trans); - } - /// - /// 在指定绘图空间X-Y平面添加圆 - /// - /// 绘图空间 - /// 圆心 - /// 半径 - /// 圆属性设置委托 - /// 事务管理器 - /// 圆的id - public static ObjectId AddCircle(this BlockTableRecord btr, Point3d center, double radius, - Action? action = null, Transaction? trans = null) - { - var circle = new Circle(center, Vector3d.ZAxis, radius); - return btr.AddEnt(circle, action, trans); + return btr.AddEntity(ents.ToList()); } - /// - /// 在指定绘图空间X-Y平面3点画外接圆 - /// - /// 绘图空间 - /// 第一点 - /// 第二点 - /// 第三点 - /// 圆属性设置委托 - /// 事务管理器 - /// 三点有外接圆则返回圆的id,否则返回ObjectId.Null - public static ObjectId AddCircle(this BlockTableRecord btr, Point3d p0, Point3d p1, Point3d p2, - Action? action = null, Transaction? trans = null) - { - var circle = CircleEx.CreateCircle(p0, p1, p2); - // return circle is not null ? btr.AddEnt(circle, action, trans) : throw new ArgumentNullException(nameof(circle), "对象为 null"); - //if (circle is null) - // throw new ArgumentNullException(nameof(circle), "对象为 null"); - circle.NotNull(nameof(circle)); - return btr.AddEnt(circle, action, trans); - } - /// - /// 在指定的绘图空间添加轻多段线 - /// - /// 绘图空间 - /// 多段线信息 - /// 线宽 - /// 是否闭合 - /// 轻多段线属性设置委托 - /// 事务管理器 - /// 轻多段线id - public static ObjectId AddPline(this BlockTableRecord btr, - List bvws, - double? constantWidth = null, - bool isClosed = true, - Action? action = null, Transaction? trans = null) - { - Polyline pl = new(); - pl.SetDatabaseDefaults(); - if (constantWidth is not null) - { - for (int i = 0; i < bvws.Count; i++) - pl.AddVertexAt(i, bvws[i].Vertex, bvws[i].Bulge, constantWidth.Value, constantWidth.Value); - } - else - { - for (int i = 0; i < bvws.Count; i++) - pl.AddVertexAt(i, bvws[i].Vertex, bvws[i].Bulge, bvws[i].StartWidth, bvws[i].EndWidth); - } - pl.Closed = isClosed;// 闭合 - return btr.AddEnt(pl, action, trans); - } - /// - /// 在指定的绘图空间添加轻多段线 - /// - /// 绘图空间 - /// 端点表 - /// 凸度表 - /// 端点的起始宽度 - /// 端点的终止宽度 - /// 轻多段线属性设置委托 - /// 事务管理器 - /// 轻多段线id - public static ObjectId AddPline(this BlockTableRecord btr, - List pts, - List? bulges = null, - List? startWidths = null, - List? endWidths = null, - Action? action = null, - Transaction? trans = null) - { - bulges ??= new(new double[pts.Count]); - startWidths ??= new(new double[pts.Count]); - endWidths ??= new(new double[pts.Count]); - - Polyline pl = new(); - pl.SetDatabaseDefaults(); - - for (int i = 0; i < pts.Count; i++) - pl.AddVertexAt(i, pts[i].Point2d(), bulges[i], startWidths[i], endWidths[i]); - return btr.AddEnt(pl, action, trans); - } - - /// - /// 在指定的绘图空间添加轻多段线 - /// - /// 绘图空间 - /// 端点表,利用元组(Point3d pt, double bulge, double startWidth, double endWidth) - /// 轻多段线属性设置委托 - /// 事务管理器 - /// 轻多段线id - public static ObjectId AddPline(this BlockTableRecord btr, - List<(Point3d pt, double bulge, double startWidth, double endWidth)> pts, - Action? action = null, - Transaction? trans = null) - { - Polyline pl = new(); - pl.SetDatabaseDefaults(); - - pts.ForEach((vertex, state, index) => { - pl.AddVertexAt(index, vertex.pt.Point2d(), vertex.bulge, vertex.startWidth, vertex.endWidth); - }); - - return btr.AddEnt(pl, action, trans); - } - - /// - /// 在指定绘图空间X-Y平面3点画圆弧 - /// - /// 绘图空间 - /// 圆弧起点 - /// 圆弧上的点 - /// 圆弧终点 - /// 圆弧属性设置委托 - /// 事务管理器 - /// 圆弧id - public static ObjectId AddArc(this BlockTableRecord btr, - Point3d startPoint, Point3d pointOnArc, Point3d endPoint, - Action? action = null, Transaction? trans = null) - { - var arc = ArcEx.CreateArc(startPoint, pointOnArc, endPoint); - return btr.AddEnt(arc, action, trans); - } #endregion #region 获取实体/实体id + /// /// 获取块表记录内的指定类型的实体 /// (此处不会检查id.IsOk()) @@ -319,22 +151,21 @@ public static ObjectId AddArc(this BlockTableRecord btr, /// 实体类型 /// 块表记录 /// 打开模式 - /// 事务 /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 /// 实体集合 public static IEnumerable GetEntities(this BlockTableRecord btr, - OpenMode openMode = OpenMode.ForRead, - Transaction? trans = null, - bool openErased = false, - bool openLockedLayer = false) where T : Entity + OpenMode openMode = OpenMode.ForRead, + bool openErased = false, + bool openLockedLayer = false) where T : Entity { - trans ??= DBTrans.Top.Transaction; + var rxc = RXObject.GetClass(typeof(T)); return btr - .Cast() - .Select(id => trans.GetObject(id, openMode, openErased, openLockedLayer)) - .OfType(); + .Cast() + .Where(id => id.ObjectClass.IsDerivedFrom(rxc)) + .Select(id => id.GetObject(openMode, openErased, openLockedLayer)) + .OfType(); } /// @@ -345,9 +176,9 @@ public static IEnumerable GetEntities(this BlockTableRecord btr, /// 实体Id集合 public static IEnumerable GetObjectIds(this BlockTableRecord btr) where T : Entity { - string dxfName = RXClass.GetClass(typeof(T)).DxfName; + var dxfName = RXObject.GetClass(typeof(T)).DxfName; return btr.Cast() - .Where(id => id.ObjectClass()?.DxfName == dxfName); + .Where(id => id.ObjectClass.DxfName == dxfName); } /// @@ -358,7 +189,7 @@ public static IEnumerable GetObjectIds(this BlockTableRecord btr) w public static IEnumerable> GetObjectIds(this BlockTableRecord btr) { return btr.Cast() - .GroupBy(id => id.ObjectClass().DxfName); + .GroupBy(id => id.ObjectClass.DxfName); } @@ -366,22 +197,23 @@ public static IEnumerable> GetObjectIds(this BlockTa /// 获取绘制顺序表 /// /// 块表 - /// 事务 + /// 开启方式 /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 /// 绘制顺序表 - public static DrawOrderTable? GetDrawOrderTable(this BlockTableRecord btr, - Transaction? trans = null, - bool openErased = false, - bool openLockedLayer = false) + public static DrawOrderTable GetDrawOrderTable(this BlockTableRecord btr, + OpenMode openMode = OpenMode.ForRead, + bool openErased = false, + bool openLockedLayer = false) { - trans ??= DBTrans.Top.Transaction; - return trans.GetObject(btr.DrawOrderTableId, OpenMode.ForRead, - openErased, openLockedLayer) as DrawOrderTable; + var tr = DBTrans.GetTopTransaction(btr.Database); + return (DrawOrderTable)tr.GetObject(btr.DrawOrderTableId, openMode, openErased, openLockedLayer); } + #endregion #region 插入块参照 + /// /// 插入块参照 /// @@ -391,26 +223,27 @@ public static IEnumerable> GetObjectIds(this BlockTa /// 块插入比例,默认为1 /// 块插入旋转角(弧度),默认为0 /// 属性字典{Tag,Value},默认为null - /// 事务 /// 块参照对象id public static ObjectId InsertBlock(this BlockTableRecord blockTableRecord, Point3d position, - string blockName, - Scale3d scale = default, - double rotation = default, - Dictionary? atts = null, - Transaction? trans = null) + string blockName, + Scale3d scale = default, + double rotation = default, + Dictionary? atts = null) { - trans ??= DBTrans.Top.Transaction; - if (!DBTrans.Top.BlockTable.Has(blockName)) + var tr = DBTrans.GetTop(blockTableRecord.Database); + if (!tr.BlockTable.Has(blockName)) { - DBTrans.Top.Editor?.WriteMessage($"\n不存在名字为{blockName}的块定义。"); + tr.Editor?.WriteMessage($"\n不存在名字为{blockName}的块定义。"); return ObjectId.Null; } - return blockTableRecord.InsertBlock(position, DBTrans.Top.BlockTable[blockName], scale, rotation, atts, trans); + + return blockTableRecord.InsertBlock(position, tr.BlockTable[blockName], scale, rotation, atts); } + /// /// 插入块参照 /// + /// 块表记录 /// 插入点 /// 块定义id /// 块插入比例,默认为1 @@ -418,62 +251,74 @@ public static ObjectId InsertBlock(this BlockTableRecord blockTableRecord, Point /// 属性字典{Tag,Value},默认为null /// 块参照对象id public static ObjectId InsertBlock(this BlockTableRecord blockTableRecord, - Point3d position, - ObjectId blockId, - Scale3d scale = default, - double rotation = default, - Dictionary? atts = null, - Transaction? trans = null) + Point3d position, + ObjectId blockId, + Scale3d scale = default, + double rotation = default, + Dictionary? atts = null) { - trans ??= DBTrans.Top.Transaction; - if (!DBTrans.Top.BlockTable.Has(blockId)) + //trans ??= DBTrans.Top.Transaction; + var tr = DBTrans.GetTop(blockTableRecord.Database); + + if (!tr.BlockTable.Has(blockId)) { - DBTrans.Top.Editor?.WriteMessage($"\n不存在块定义。"); + tr.Editor?.WriteMessage($"\n不存在块定义。"); return ObjectId.Null; } - using var blockref = new BlockReference(position, blockId) - { - ScaleFactors = scale, - Rotation = rotation - }; - var objid = blockTableRecord.AddEntity(blockref); - if (atts != null) + + using var blockRef = new BlockReference(position, blockId); + blockRef.ScaleFactors = scale; + blockRef.Rotation = rotation; + var objectId = blockTableRecord.AddEntity(blockRef); + // 检查块的注释性 + using var ocm = blockTableRecord.Database.ObjectContextManager; + using var occ = ocm.GetContextCollection("ACDB_ANNOTATIONSCALES"); + if (blockRef.Annotative == AnnotativeStates.True) + blockRef.AddContext(occ.CurrentContext); + + var btr = tr.GetObject(blockRef.BlockTableRecord)!; + + if (!btr.HasAttributeDefinitions) + return objectId; + + var attdefs = btr.GetEntities(); + foreach (var attdef in attdefs) { - var btr = DBTrans.Top.GetObject(blockref.BlockTableRecord)!; - if (btr.HasAttributeDefinitions) + using AttributeReference attref = new(); + attref.SetDatabaseDefaults(); + attref.SetAttributeFromBlock(attdef, blockRef.BlockTransform); + attref.Position = attdef.Position.TransformBy(blockRef.BlockTransform); + if (atts is not null && atts.TryGetValue(attdef.Tag, out var str)) { - var attdefs = btr.GetEntities(); - foreach (var attdef in attdefs) - { - using AttributeReference attref = new(); - attref.SetDatabaseDefaults(); - attref.SetAttributeFromBlock(attdef, blockref.BlockTransform); - attref.Position = attdef.Position.TransformBy(blockref.BlockTransform); - attref.AdjustAlignment(DBTrans.Top.Database); - - if (atts.ContainsKey(attdef.Tag)) - attref.TextString = atts[attdef.Tag]; - - blockref.AttributeCollection.AppendAttribute(attref); - trans.AddNewlyCreatedDBObject(attref, true); - } + attref.TextString = str; } + + if (blockRef.Annotative == AnnotativeStates.True) + attref.AddContext(occ.CurrentContext); + + blockRef.AttributeCollection.AppendAttribute(attref); + tr.Transaction.AddNewlyCreatedDBObject(attref, true); + attref.AdjustAlignment(tr.Database); } - return objid; + + return objectId; } + #endregion #endregion #region 遍历 + #line hidden // 调试的时候跳过它 /// /// 遍历符号表记录,执行委托 /// + /// 符号表记录 /// 要运行的委托 public static void ForEach(this TRecord record, Action task) - where TRecord : SymbolTableRecord, IEnumerable + where TRecord : SymbolTableRecord, IEnumerable { foreach (ObjectId id in record) task.Invoke(id); @@ -482,11 +327,12 @@ public static void ForEach(this TRecord record, Action task) /// /// 遍历符号表记录,执行委托(允许循环中断) /// + /// 符号表记录 /// 要执行的委托 public static void ForEach(this TRecord record, Action task) - where TRecord : SymbolTableRecord, IEnumerable + where TRecord : SymbolTableRecord, IEnumerable { - LoopState state = new();/*这种方式比Action改Func更友好*/ + LoopState state = new(); /*这种方式比Action改Func更友好*/ foreach (ObjectId id in record) { task.Invoke(id, state); @@ -498,16 +344,17 @@ public static void ForEach(this TRecord record, Action /// 遍历符号表记录,执行委托(允许循环中断,输出索引值) /// + /// 符号表记录 /// 要执行的委托 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public static void ForEach(this TRecord record, Action task) where TRecord : SymbolTableRecord, IEnumerable { //if (task == null) // throw new ArgumentNullException(nameof(task)); - task.NotNull(nameof(task)); - int i = 0; - LoopState state = new();/*这种方式比Action改Func更友好*/ + ArgumentNullException.ThrowIfNull(task); + var i = 0; + LoopState state = new(); /*这种方式比Action改Func更友好*/ foreach (ObjectId id in record) { task.Invoke(id, state, i); @@ -517,5 +364,6 @@ public static void ForEach(this TRecord record, Action +/// cad的事务的扩展类 +/// +public static class TransactionEx +{ + /// + /// 根据对象id获取对象 + /// + /// + /// 对象id + /// 打开模式,默认为只读 + /// 是否打开已删除对象,默认为不打开 + /// 是否打开锁定图层对象,默认为不打开 + /// 数据库DBObject对象 + public static DBObject GetObject(this Transaction tr, ObjectId id, OpenMode openMode = OpenMode.ForRead, + bool openErased = false, bool openLockedLayer = false) + { + return tr.GetObject(id, openMode, openErased, openLockedLayer); + } + + /// + /// 根据对象id获取图元对象 + /// + /// 要获取的图元对象的类型 + /// + /// 对象id + /// 打开模式,默认为只读 + /// 是否打开已删除对象,默认为不打开 + /// 是否打开锁定图层对象,默认为不打开 + /// 图元对象,类型不匹配时抛异常 + public static T? GetObject(this Transaction tr, ObjectId id, OpenMode openMode = OpenMode.ForRead, + bool openErased = false, bool openLockedLayer = false) where T : DBObject + { + return tr.GetObject(id, openMode, openErased, openLockedLayer) as T; + } +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/TrustedPathEx.cs b/src/CADShared/ExtensionMethod/TrustedPathEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..a5c37da1aa267c6802957961def57aedce49afff --- /dev/null +++ b/src/CADShared/ExtensionMethod/TrustedPathEx.cs @@ -0,0 +1,75 @@ +namespace IFoxCAD.Cad; + +internal static class TrustedPathEx +{ + private const string kName = "TRUSTEDPATHS"; + + /// + /// 获取信任路径 + /// + /// 路径列表 + public static List Get() + { + var str = Env.GetVar(kName).ToString()!; + var set = str.ToLower() + .Split([";"], StringSplitOptions.RemoveEmptyEntries) + .Select(s => s.TrimEnd('\\')) + .ToHashSet(); + return set.ToList(); + } + + /// + /// 添加信任路径 + /// + /// 路径列表 + public static void Add(params IEnumerable dirs) + { + var dirSet = dirs.ToLowerDirSet(); + if (dirSet.Count == 0) + return; + var paths = Get(); + foreach (var dir in dirSet) + { + if (!Directory.Exists(dir)) + continue; + if (paths.Contains(dir)) + continue; + paths.Insert(0, dir); + } + + Set(paths); + } + + /// + /// 移除信任路径 + /// + /// 路径列表 + public static void Remove(params IEnumerable dirs) + { + var dirSet = dirs.ToLowerDirSet(); + var paths = Get(); + paths.RemoveAll(dirSet.Contains); + Set(paths); + } + + /// + /// 设置信任路径 + /// + /// 路径列表 + private static void Set(IEnumerable dirs) + { + var set = dirs.Where(Directory.Exists).ToLowerDirSet(); + var str = string.Join(";", set); + Env.SetVar(kName, str); + } + + /// + /// 转换为小写并去除尾部反斜杠的路径集合 + /// + /// 路径列表 + /// 路径集合 + private static HashSet ToLowerDirSet(this IEnumerable dirs) + { + return dirs.Select(dir => dir.ToLower().TrimEnd('\\')).ToHashSet(); + } +} \ No newline at end of file diff --git a/src/CADShared/ExtensionMethod/WindowEx.cs b/src/CADShared/ExtensionMethod/WindowEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..bed51869d75b70d507bdcb2669dabe80963daa3c --- /dev/null +++ b/src/CADShared/ExtensionMethod/WindowEx.cs @@ -0,0 +1,101 @@ +using System.Drawing; +using System.Windows.Forms; +using Window = System.Windows.Window; + +namespace IFoxCAD.Cad; + +/// +/// 窗体扩展 +/// +public static class WindowEx +{ + /// + /// 添加Esc退出 + /// + /// wpf窗体 + public static void AddEscQuit(this Window window) + { + window.KeyDown -= Window_KeyDown_Esc; + window.KeyDown += Window_KeyDown_Esc; + window.Closed -= WindowOnClosed; + window.Closed += WindowOnClosed; + } + + /// + /// 关闭时减掉事件 + /// + private static void WindowOnClosed(object? sender, EventArgs e) + { + if (sender is not Window window) + return; + window.KeyDown -= Window_KeyDown_Esc; + window.Closed -= WindowOnClosed; + } + + private static void Window_KeyDown_Esc(object sender, System.Windows.Input.KeyEventArgs e) + { + if (e.Key != Key.Escape + || sender is not Window { IsLoaded: true, IsActive: true } window) + return; + + // 判断没有按住ctrl或shift或alt才执行 + var keys = Control.ModifierKeys; + if ((keys & Keys.Control) != 0 + || (keys & Keys.Shift) != 0 + || (keys & Keys.Alt) != 0) + return; + window.Close(); + } + + /// + /// 判断wpf是否为模态 + /// + /// 窗体 + /// 是则返回true + public static bool IsModel(this Window window) + { + return (bool)(typeof(Window) + .GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(window) ?? false); + } + + /// + /// 获取屏幕分辨率 + /// + /// 窗口句柄 + /// 屏幕尺寸 + public static Size GetScreenResolutionFromWindowHandle(IntPtr windowHandle) + { + var screen = Screen.FromHandle(windowHandle); + return new Size(screen.Bounds.Width, screen.Bounds.Height); + } + + /// + /// 通过分辨率设置面板尺寸 + /// + /// 侧栏 + /// 宽度 + /// 高度 + public static void SetSizeByScreenResolution(this PaletteSet paletteSet, int width, int height) + { + var size = GetScreenResolutionFromWindowHandle(Acaop.MainWindow.Handle); + var scale = size.Height * 1d / 1080; + var newWidth = Convert.ToInt32(width * scale); + if (newWidth > size.Width) + newWidth = size.Width; + var newHeight = Convert.ToInt32(height * scale); + if (newHeight > size.Height) + newHeight = size.Height; + // paletteSet.SetSize(new Size(newWidth, newHeight)); // 中望2025 这样调用报错找不到setsize函数 + WindowExtension.SetSize(paletteSet, new Size(newWidth, newHeight)); // 中望2025这样调用没有问题 + } + + /// + /// 获取屏幕比例 + /// + /// 比例 + public static double GetScreenScale() + { + var scale = Graphics.FromHwnd(IntPtr.Zero).DpiX / 96.0f; + return scale; + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ExtensionMethod/XrefEx.cs b/src/CADShared/ExtensionMethod/XrefEx.cs similarity index 70% rename from src/CAD/IFox.CAD.Shared/ExtensionMethod/XrefEx.cs rename to src/CADShared/ExtensionMethod/XrefEx.cs index db54edc35470d7f6570c60223f85f86df4e03e1f..5910cd3520e6a32f6e2db305114843b1750597e9 100644 --- a/src/CAD/IFox.CAD.Shared/ExtensionMethod/XrefEx.cs +++ b/src/CADShared/ExtensionMethod/XrefEx.cs @@ -1,96 +1,112 @@ -// #define error_demo - +// ReSharper disable ForCanBeConvertedToForeach +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Cad; #region 参照工厂 + +/// +/// 参照绑定模式接口 +/// public interface IXrefBindModes { /// /// 卸载 /// public void Unload(); + /// /// 重载 /// public void Reload(); + /// /// 拆离 /// public void Detach(); + /// /// 绑定 /// public void Bind(); } -public class XrefFactory : IXrefBindModes +/// +/// 参照工厂类 +/// +/// +/// 要处理的参照名称,就处理所有 +public class XrefFactory(DBTrans tr, HashSet? xrefNames = null) : IXrefBindModes { #region 私有字段 - readonly DBTrans _tr; + + private readonly DBTrans _tr = tr; + /// - /// 要处理的参照名称,就处理所有 + /// 要处理的参照名称,就处理所有 /// - readonly HashSet? _xrefNames; + private readonly HashSet? _xrefNames = xrefNames; + #endregion #region 公开字段 + /// /// 解析外部参照:线性引擎
/// 默认
/// 时会在cad命令历史打印一些AEC信息,并导致绑定慢一点...具体作用不详
///
- public bool UseThreadEngine = false; + public readonly bool UseThreadEngine = false; + /// /// 解析外部参照:仅处理 Unresolved_未融入(未解析)的参照
/// 默认 ///
- public bool DoNewOnly = true; + public readonly bool DoNewOnly = true; + /// /// 解析外部参照:包含僵尸参照 /// - public bool IncludeGhosts = true; + public readonly bool IncludeGhosts = true; /// - /// 绑定模式和双美元符号相关(与cad保持相同的默认)
+ /// 绑定模式和双美元符号相关(与cad保持相同地默认)
/// 为绑定模式,产生双美元; /// 为插入模式,块重名会以本图覆盖; ///
- public bool BindOrInsert = false; + public readonly bool BindOrInsert = false; + /// /// bind时候是否拆离参照
/// 默认:学官方的绑定后自动拆离 ///
- public bool AutoDetach = true; + public readonly bool AutoDetach = true; + /// /// bind时候是否删除被卸载的嵌套参照
/// 默认 ///
- public bool EraseNested = true; + public readonly bool EraseNested = true; + /// /// bind时候控制绑定的符号表:请保持默认
/// 目前仅推荐用于
/// 其他项有异常:
///
- public SymModes SymModesBind = SymModes.LayerTable; - #endregion + public readonly SymModes SymModesBind = SymModes.LayerTable; - #region 构造 - /// - /// 参照工厂 - /// - /// - /// 要处理的参照名称,就处理所有 - public XrefFactory(DBTrans tr, HashSet? xrefNames = null) - { - _tr = tr; - _xrefNames = xrefNames; - } #endregion + #region 重写 + + /// + /// 绑定 + /// public void Bind() { // 此功能有绑定出错的问题 @@ -101,6 +117,9 @@ public void Bind() DoubleBind(); } + /// + /// 分离 + /// public void Detach() { using ObjectIdCollection xrefIds = new(); @@ -109,6 +128,9 @@ public void Detach() _tr.Database.DetachXref(id); } + /// + /// 重载 + /// public void Reload() { using ObjectIdCollection xrefIds = new(); @@ -117,6 +139,9 @@ public void Reload() _tr.Database.ReloadXrefs(xrefIds); } + /// + /// 卸载 + /// public void Unload() { using ObjectIdCollection xrefIds = new(); @@ -124,24 +149,27 @@ public void Unload() if (xrefIds.Count > 0) _tr.Database.UnloadXrefs(xrefIds); } + #endregion #region 双重绑定 + /// /// 获取参照 /// /// 返回全部参照id - void GetAllXrefNode(ObjectIdCollection xrefIds) + private void GetAllXrefNode(ObjectIdCollection xrefIds) { // 储存要处理的参照id //var xrefIds = new ObjectIdCollection(); - XrefNodeForEach((xNodeName, xNodeId, xNodeStatus, xNodeIsNested) => { + XrefNodeForEach((xNodeName, xNodeId, _, _) => + { if (XrefNamesContains(xNodeName)) xrefIds.Add(xNodeId); }); } - bool XrefNamesContains(string xNodeName) + private bool XrefNamesContains(string xNodeName) { // 为空的时候全部加入 || 有内容时候含有目标 return _xrefNames is null || _xrefNames.Contains(xNodeName); @@ -151,47 +179,42 @@ bool XrefNamesContains(string xNodeName) /// 遍历参照 ///
/// (参照名,参照块表记录id,参照状态,是否嵌入) - void XrefNodeForEach(Action action) + private void XrefNodeForEach(Action action) { // btRec.IsFromOverlayReference 是覆盖 // btRec.GetXrefDatabase(true) 外部参照数据库 - if (action == null) - return; // 解析外部参照:此功能不能锁定文档 _tr.Database.ResolveXrefs(UseThreadEngine, DoNewOnly); var xg = _tr.Database.GetHostDwgXrefGraph(IncludeGhosts); - for (int i = 0; i < xg.NumNodes; i++) + for (var i = 0; i < xg.NumNodes; i++) { var xNode = xg.GetXrefNode(i); if (!xNode.BlockTableRecordId.IsOk()) continue; - action.Invoke(xNode.Name, - xNode.BlockTableRecordId, - xNode.XrefStatus, - xNode.IsNested); + action.Invoke(xNode.Name, xNode.BlockTableRecordId, xNode.XrefStatus, xNode.IsNested); } } /// /// 符号表记录加入容器 /// - static void AddedxbindIds(ObjectIdCollection xbindXrefsIds, - SymbolTable symbolTable) - where TTable : SymbolTable - where TRecord : SymbolTableRecord, new() + private static void AddedXBindIds(ObjectIdCollection xbindXrefsIds, + SymbolTable symbolTable) where TTable : SymbolTable + where TRecord : SymbolTableRecord, new() { - symbolTable.ForEach(tabRec => { + symbolTable.ForEach(tabRec => + { if (tabRec.IsResolved) xbindXrefsIds.Add(tabRec.ObjectId); }, checkIdOk: true); } - void GetXBindIds(ObjectIdCollection xbindIds) + private void GetXBindIds(ObjectIdCollection xbindIds) { // xbind // 0x01 它是用来绑其他符号表,绑块表会有异常 @@ -199,46 +222,52 @@ void GetXBindIds(ObjectIdCollection xbindIds) //var xbindIds = new ObjectIdCollection(); // 起初测试是将九大符号表记录均加入的,但经实测不行...(为什么?存疑) + #region Option1 + if ((SymModesBind & SymModes.LayerTable) == SymModes.LayerTable) - AddedxbindIds(xbindIds, _tr.LayerTable); + AddedXBindIds(xbindIds, _tr.LayerTable); if ((SymModesBind & SymModes.TextStyleTable) == SymModes.TextStyleTable) - AddedxbindIds(xbindIds, _tr.TextStyleTable); + AddedXBindIds(xbindIds, _tr.TextStyleTable); if ((SymModesBind & SymModes.RegAppTable) == SymModes.RegAppTable) - AddedxbindIds(xbindIds, _tr.RegAppTable); + AddedXBindIds(xbindIds, _tr.RegAppTable); if ((SymModesBind & SymModes.DimStyleTable) == SymModes.DimStyleTable) - AddedxbindIds(xbindIds, _tr.DimStyleTable); + AddedXBindIds(xbindIds, _tr.DimStyleTable); if ((SymModesBind & SymModes.LinetypeTable) == SymModes.LinetypeTable) - AddedxbindIds(xbindIds, _tr.LinetypeTable); + AddedXBindIds(xbindIds, _tr.LinetypeTable); + #endregion #region Option2 + if ((SymModesBind & SymModes.UcsTable) == SymModes.UcsTable) - AddedxbindIds(xbindIds, _tr.UcsTable); + AddedXBindIds(xbindIds, _tr.UcsTable); if ((SymModesBind & SymModes.ViewTable) == SymModes.ViewTable) - AddedxbindIds(xbindIds, _tr.ViewTable); + AddedXBindIds(xbindIds, _tr.ViewTable); if ((SymModesBind & SymModes.ViewportTable) == SymModes.ViewportTable) - AddedxbindIds(xbindIds, _tr.ViewportTable); + AddedXBindIds(xbindIds, _tr.ViewportTable); + #endregion } - void GetBindIds(ObjectIdCollection bindIds) + private void GetBindIds(ObjectIdCollection bindIds) { // bind 只绑块表 //var bindIds = new ObjectIdCollection(); - _tr.BlockTable.ForEach(btr => { + _tr.BlockTable.ForEach(btr => + { if (btr.IsLayout) return; // 外部参照 && 已融入 - if (btr.IsFromExternalReference && btr.IsResolved) + if (btr is { IsFromExternalReference: true, IsResolved: true }) bindIds.Add(btr.ObjectId); }, checkIdOk: true); } @@ -248,27 +277,28 @@ void GetBindIds(ObjectIdCollection bindIds) ///
/// 返回已卸载中含有嵌套的参照,要重载之后才能绑定 /// 返回未参照中嵌套的参照,直接拆离 - List GetDetachIds(Dictionary nested) + private List GetDetachIds(Dictionary nested) { // 直接拆离的id - List detachIds = new(); + List detachIds = []; // 收集要处理的id - XrefNodeForEach((xNodeName, xNodeId, xNodeStatus, xNodeIsNested) => { + XrefNodeForEach((xNodeName, xNodeId, xNodeStatus, xNodeIsNested) => + { switch (xNodeStatus) { - case XrefStatus.Unresolved:// 未融入_ResolveXrefs参数2 - break; - case XrefStatus.FileNotFound:// 未融入(未解析)_未找到文件 - break; - case XrefStatus.Unreferenced:// 未参照 + case XrefStatus.Unresolved: // 未融入_ResolveXrefs参数2 + break; + case XrefStatus.FileNotFound: // 未融入(未解析)_未找到文件 + break; + case XrefStatus.Unreferenced: // 未参照 { // 为空的时候全部加入 || 有内容时候含有目标 if (XrefNamesContains(xNodeName)) detachIds.Add(xNodeId); } - break; - case XrefStatus.Unloaded:// 已卸载 + break; + case XrefStatus.Unloaded: // 已卸载 { // 为空的时候全部加入 || 有内容时候含有目标 if (XrefNamesContains(xNodeName)) @@ -279,17 +309,15 @@ List GetDetachIds(Dictionary nested) if (!xNodeIsNested) detachIds.Add(xNodeId); else if (!nested.ContainsKey(xNodeId)) - nested.Add(xNodeId, xNodeName);// 嵌套参照 + nested.Add(xNodeId, xNodeName); // 嵌套参照 } } } - break; - case XrefStatus.Resolved:// 已融入_就是可以绑定的 - break; - case XrefStatus.NotAnXref:// 不是外部参照 - break; - default: - break; + break; + case XrefStatus.Resolved: // 已融入_就是可以绑定的 + break; + case XrefStatus.NotAnXref: // 不是外部参照 + break; } }); return detachIds; @@ -299,7 +327,7 @@ List GetDetachIds(Dictionary nested) /// 双重绑定参照 /// 参考链接 ///
- void DoubleBind() + private void DoubleBind() { Dictionary nested = new(); var detachIds = GetDetachIds(nested); @@ -307,9 +335,10 @@ void DoubleBind() // 拆离:未参照的文件 if (AutoDetach) { - for (int i = 0; i < detachIds.Count; i++) + for (var i = 0; i < detachIds.Count; i++) _tr.Database.DetachXref(detachIds[i]); } + // 重载:嵌套参照已卸载了,需要重载之后才能进行绑定 var keys = nested.Keys; if (keys.Count > 0) @@ -332,41 +361,21 @@ void DoubleBind() // 内部删除嵌套参照的块操作 if (EraseNested) { -#if ac2008 - // 因为Acad08索引器存在会暴露isErase的(桌子底层的原因), - // 也就是可能获取两个名称一样的,只能用遍历的方式进行 - HashSet nestedHash = new(); - foreach (var item in nested) - nestedHash.Add(item.Value); - - // 遍历全图,找到参照名称一样的删除 - _tr.BlockTable.ForEach(btr => { - if (btr.IsLayout) - return; - if (nestedHash.Contains(btr.Name)) - { - btr.UpgradeOpen(); - btr.Erase(); - btr.DowngradeOpen(); - btr.Dispose(); - } - }, checkIdOk: true); -#else foreach (var item in nested) { var name = item.Value; if (_tr.BlockTable.Has(name)) - _tr.GetObject(_tr.BlockTable[name], OpenMode.ForWrite)? - .Erase(); + _tr.GetObject(_tr.BlockTable[name], OpenMode.ForWrite)?.Erase(); } -#endif } } + #endregion } - - +/// +/// 参照扩展 +/// public static class XrefEx { /// @@ -375,28 +384,25 @@ public static class XrefEx /// /// 处理参照的枚举 /// 要处理的参照名称,就处理所有 - public static void XrefFactory(this DBTrans tr, - XrefModes xrefModes, - HashSet? xrefNames = null) + public static void XrefFactory(this DBTrans tr, XrefModes xrefModes, HashSet? xrefNames = null) { var xf = new XrefFactory(tr, xrefNames); - tr.Task(() => { + tr.Task(() => + { switch (xrefModes) { case XrefModes.Unload: - xf.Unload(); - break; + xf.Unload(); + break; case XrefModes.Reload: - xf.Reload(); - break; + xf.Reload(); + break; case XrefModes.Detach: - xf.Detach(); - break; + xf.Detach(); + break; case XrefModes.Bind: - xf.Bind(); - break; - default: - break; + xf.Bind(); + break; } }); } @@ -405,20 +411,24 @@ public static void XrefFactory(this DBTrans tr, #endregion #region 参照路径工具类 + /// /// 获取外部参照的路径 /// public class XrefPath { #region 属性 + /// /// 基础路径 /// - public string CurrentDatabasePath; + public readonly string? CurrentDatabasePath; + /// /// 是否外部参照 /// public bool IsFromExternalReference { get; private set; } + /// /// 外部参照保存的路径 /// @@ -429,28 +439,33 @@ public class XrefPath /// /// public string? PathSave { get; private set; } + /// /// 找到的路径(参照面板的名称) /// 路径不存在时,返回是外部参照dwg文件路径 /// public string? PathDescribe { get; private set; } - string? _PathComplete; + private string? _pathComplete; + /// /// 绝对路径 /// - public string? PathComplete => _PathComplete ??= - PathConverter(CurrentDatabasePath, PathDescribe, PathConverterModes.Complete); + public string? PathComplete => + _pathComplete ??= PathConverter(CurrentDatabasePath, PathDescribe, PathConverterModes.Complete); + + private string? _pathRelative; - string? _PathRelative; /// /// 相对路径 /// - public string? PathRelative => _PathRelative ??= - PathConverter(CurrentDatabasePath, PathComplete, PathConverterModes.Relative); + public string? PathRelative => + _pathRelative ??= PathConverter(CurrentDatabasePath, PathComplete, PathConverterModes.Relative); + #endregion #region 构造 + /// /// 获取外部参照的路径 /// @@ -461,10 +476,10 @@ public XrefPath(BlockReference brf, DBTrans tr) { //if (brf == null) // throw new ArgumentNullException(nameof(brf)); - brf.NotNull(nameof(brf)); + ArgumentNullException.ThrowIfNull(brf); CurrentDatabasePath = Path.GetDirectoryName(tr.Database.Filename); - var btRec = tr.GetObject(brf.BlockTableRecord);// 块表记录 + var btRec = tr.GetObject(brf.BlockTableRecord); // 块表记录 if (btRec == null) return; @@ -488,9 +503,11 @@ public XrefPath(BlockReference brf, DBTrans tr) PathDescribe = db.Filename; } } + #endregion #region 静态函数 + /// /// 获取相对路径或者绝对路径 /// 参考链接 @@ -499,28 +516,28 @@ public XrefPath(BlockReference brf, DBTrans tr) /// 相对路径或者绝对路径 /// 依照枚举返回对应的字符串 /// - public static string? PathConverter(string? directory, string? fileRelations, PathConverterModes converterModes) + public static string? PathConverter(string? directory, string? fileRelations, + PathConverterModes converterModes) { //if (directory == null) // throw new ArgumentNullException(nameof(directory)); //if (fileRelations == null) // throw new ArgumentNullException(nameof(fileRelations)); - directory.NotNull(nameof(directory)); - fileRelations.NotNull(nameof(fileRelations)); + ArgumentNullException.ThrowIfNull(directory); + ArgumentNullException.ThrowIfNull(fileRelations); string? result = null; switch (converterModes) { case PathConverterModes.Relative: - result = GetRelativePath(directory, fileRelations); - break; + result = GetRelativePath(directory, fileRelations); + break; case PathConverterModes.Complete: - result = GetCompletePath(directory, fileRelations); - break; - default: - break; + result = GetCompletePath(directory, fileRelations); + break; } + return result; } @@ -559,32 +576,33 @@ public static string GetRelativePath(string strDbPath, string strXrefPath) /// "G:\\A1.项目\\20190920金山谷黄宅\\01.饰施图\\01.辅助文件\\图框\\A3图框.dwg") /// => "..\\01.辅助文件\\图框\\A3图框.dwg" /// ]]> - static string GetRelativePath(string directory, string file) + private static string GetRelativePath(string directory, string file) { - string[] directorys = directory.Split('\\'); - string[] files = file.Split('\\'); + var directories = directory.Split('\\'); + var files = file.Split('\\'); // 获取两条路径中的最短路径 - int getMinLength = directorys.Length < files.Length ? directorys.Length : files.Length; + var getMinLength = directories.Length < files.Length ? directories.Length : files.Length; // 用于确定我们退出的循环中的位置。 - int lastCommonRoot = -1; + var lastCommonRoot = -1; int index; // 找到共根 for (index = 0; index < getMinLength; index++) { - if (directorys[index] != files[index]) + if (directories[index] != files[index]) break; lastCommonRoot = index; } + // 如果我们没有找到一个共同的前缀,那么抛出 if (lastCommonRoot == -1) throw new ArgumentException("路径没有公共相同路径部分"); // 建立相对路径 var result = new StringBuilder(); - for (index = lastCommonRoot + 1; index < directorys.Length; index++) - if (directorys[index].Length > 0) - result.Append("..\\");// 上级目录加入 + for (index = lastCommonRoot + 1; index < directories.Length; index++) + if (directories[index].Length > 0) + result.Append("..\\"); // 上级目录加入 // 添加文件夹 for (index = lastCommonRoot + 1; index < files.Length - 1; index++) @@ -594,7 +612,7 @@ static string GetRelativePath(string directory, string file) if (result.Length == 0) result.Append(".\\"); // result.Append(strXrefPaths[^1]);// 下级目录加入 - result.Append(files[files.Length - 1]);// 下级目录加入 + result.Append(files[^1]); // 下级目录加入 return result.ToString(); } #endif @@ -610,9 +628,9 @@ static string GetRelativePath(string directory, string file) /// "..\\01.辅助文件\\图框\\A3图框.dwg") /// => "G:\\A1.项目\\20190920金山谷黄宅\\01.饰施图\\01.辅助文件\\图框\\A3图框.dwg" /// ]]> - static string? GetCompletePath(string directory, string relativePath) + private static string? GetCompletePath(string directory, string relativePath) { - if (relativePath is null || relativePath.Trim() == string.Empty) + if (relativePath.Trim() == string.Empty) return null; var relativeName = Path.GetDirectoryName(relativePath); @@ -625,37 +643,42 @@ static string GetRelativePath(string directory, string file) const char slash = '\\'; // 判断向上删除几个 - var path_xiangduis = relativeName.Split(slash); - int index = 0; - for (int i = 0; i < path_xiangduis.Length; i++) + var slashes = relativeName.Split(slash); + var index = 0; + // ReSharper disable once ForCanBeConvertedToForeach + for (var i = 0; i < slashes.Length; i++) { - if (path_xiangduis[i] != "..") + if (slashes[i] != "..") break; index++; } var result = new StringBuilder(); // 前段 - var path_dwgs = directory.Split(slash); - path_dwgs = path_dwgs.Where(s => !string.IsNullOrEmpty(s)).ToArray();// 清理空数组 - for (int i = 0; i < path_dwgs.Length - index; i++) + var pathDwgs = directory.Split(slash); + pathDwgs = pathDwgs.Where(s => !string.IsNullOrEmpty(s)).ToArray(); // 清理空数组 + for (var i = 0; i < pathDwgs.Length - index; i++) { - result.Append(path_dwgs[i]); + result.Append(pathDwgs[i]); result.Append(slash); } + // 后段 - for (int i = 0; i < path_xiangduis.Length; i++) + for (var i = 0; i < slashes.Length; i++) { - var item = path_xiangduis[i]; + var item = slashes[i]; if (item != "." && item != "..") { result.Append(item); result.Append(slash); } } + result.Append(Path.GetFileName(relativePath)); return result.ToString(); } + #endregion } + #endregion \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/AcadEMR.cs b/src/CADShared/Initialize/AcadEMR.cs similarity index 57% rename from src/CAD/IFox.CAD.Shared/Runtime/AcadEMR.cs rename to src/CADShared/Initialize/AcadEMR.cs index 0d4fe6cc0beb3891aa25ccf786ebd23565669c14..3fcfc03fff2675748c74849adbb9cdf22f26b09e 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/AcadEMR.cs +++ b/src/CADShared/Initialize/AcadEMR.cs @@ -1,8 +1,7 @@ -#if true +#if true +#if acad namespace IFoxCAD.Cad; -using System.Diagnostics; - // 作者: [VB.net]福萝卜 莱昂纳多·胖子 // Email:oneeshine@163.com // QQ: 461884072 @@ -14,13 +13,13 @@ namespace IFoxCAD.Cad; /// internal class AcadEMR { - /// - /// 释放库 - /// - /// 句柄 - /// - [DllImport("kernel32.dll", CharSet = CharSet.Auto)] - static extern IntPtr FreeLibrary(IntPtr loadLibraryIntPtr); + // /// + // /// 释放库 + // /// + // /// 句柄 + // /// + // [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + // static extern IntPtr FreeLibrary(IntPtr loadLibraryIntPtr); /// /// 获取一个应用程序或dll的模块句柄,要求已经载入 @@ -48,6 +47,7 @@ internal class AcadEMR /// /// [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + // ReSharper disable once IdentifierTypo static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flNewProtect, ref uint lpflOldProtect); @@ -58,7 +58,7 @@ internal class AcadEMR public static void Remove(bool echoes = false) { var dllName = Env.GetAcapVersionDll(); - IntPtr moduleHandle = GetModuleHandle(dllName); + var moduleHandle = GetModuleHandle(dllName); if (moduleHandle == IntPtr.Zero) { if (echoes) @@ -66,43 +66,42 @@ public static void Remove(bool echoes = false) return; } - string funcname = System.Text.Encoding.Unicode.GetString(new byte[] { 63 }); + var funcName = Encoding.Unicode.GetString([63]); if (IntPtr.Size == 4) - funcname += "isEMR@AcDbDatabase@@QBE_NXZ"; + funcName += "isEMR@AcDbDatabase@@QBE_NXZ"; else - funcname += "isEMR@AcDbDatabase@@QEBA_NXZ"; + funcName += "isEMR@AcDbDatabase@@QEBA_NXZ"; - IntPtr funcAdress = GetProcAddress(moduleHandle, funcname); - if (funcAdress == IntPtr.Zero) + var funcAddress = GetProcAddress(moduleHandle, funcName); + if (funcAddress == IntPtr.Zero) { if (echoes) - Env.Printl("无法找指定函数:" + funcname); + Env.Printl("无法找指定函数:" + funcName); return; } - IntPtr ptr; - if (IntPtr.Size == 4) - ptr = new IntPtr(funcAdress.ToInt32() + 3); - else - ptr = new IntPtr(funcAdress.ToInt64() + 4); + var ptr = IntPtr.Size == 4 + ? new IntPtr(funcAddress.ToInt32() + 3) + : new IntPtr(funcAddress.ToInt64() + 4); - if (!CheckFunc(ref ptr, 51, 2))// 08 通过此处 + if (!CheckFunc(ref ptr, 51, 2)) // 08 通过此处 if (echoes) Env.Printl("无法验证函数体:0x33"); - IntPtr destPtr = ptr; + var destPtr = ptr; - if (!CheckFunc(ref ptr, 57, 6))// 08 无法通过此处,所以只是打印提示 + if (!CheckFunc(ref ptr, 57, 6)) // 08 无法通过此处,所以只是打印提示 if (echoes) Env.Printl("无法验证函数体:0x39"); - if (!CheckFunc(ref ptr, 15, 2))// 08 无法通过此处,所以只是打印提示 + if (!CheckFunc(ref ptr, 15, 2)) // 08 无法通过此处,所以只是打印提示 if (echoes) Env.Printl("无法验证函数体:0x0F"); uint flag = default; + // ReSharper disable once IdentifierTypo uint tccc = default; IntPtr ip100 = new(100); - if (!VirtualProtect(destPtr, ip100, 64, ref flag))// 修改内存权限 + if (!VirtualProtect(destPtr, ip100, 64, ref flag)) // 修改内存权限 { if (echoes) Env.Printl("内存模式修改失败!"); @@ -110,43 +109,45 @@ public static void Remove(bool echoes = false) } Marshal.WriteByte(destPtr, 137); - VirtualProtect(destPtr, ip100, flag, ref tccc);// 恢复内存权限 + VirtualProtect(destPtr, ip100, flag, ref tccc); // 恢复内存权限 } /// /// 验证函数体 /// - /// + /// /// /// /// - static bool CheckFunc(ref IntPtr adress, byte val, int len) + static bool CheckFunc(ref IntPtr address, byte val, int len) { - if (adress.ToInt64() > 0) + if (address.ToInt64() > 0) { - if (Marshal.ReadByte(adress) == 233) + if (Marshal.ReadByte(address) == 233) { if (IntPtr.Size == 4) { - var pass = Marshal.ReadInt32(new IntPtr(adress.ToInt32() + 1)); - adress = new IntPtr(adress.ToInt32() + pass + 5); + var pass = Marshal.ReadInt32(new IntPtr(address.ToInt32() + 1)); + address = new IntPtr(address.ToInt32() + pass + 5); } else { - var pass = Marshal.ReadInt64(new IntPtr(adress.ToInt64() + 1)); - adress = new IntPtr(adress.ToInt64() + pass + 5); + var pass = Marshal.ReadInt64(new IntPtr(address.ToInt64() + 1)); + address = new IntPtr(address.ToInt64() + pass + 5); } } - if (adress.ToInt64() > 0 && Marshal.ReadByte(adress) == val) + + if (address.ToInt64() > 0 && Marshal.ReadByte(address) == val) { - if (IntPtr.Size == 4) - adress = new IntPtr(adress.ToInt32() + len); - else - adress = new IntPtr(adress.ToInt64() + len); + address = IntPtr.Size == 4 + ? new IntPtr(address.ToInt32() + len) + : new IntPtr(address.ToInt64() + len); return true; - } + } } + return false; } } +#endif #endif \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/AssemInfo.cs b/src/CADShared/Initialize/AssemInfo.cs similarity index 68% rename from src/CAD/IFox.CAD.Shared/Runtime/AssemInfo.cs rename to src/CADShared/Initialize/AssemInfo.cs index 23e5c7d76d5e1fbf538122b078b38e422aa7ce24..de3f40debb2552222f27ebe1cd53b3a1bb728bb3 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/AssemInfo.cs +++ b/src/CADShared/Initialize/AssemInfo.cs @@ -6,33 +6,44 @@ [Serializable] public struct AssemInfo { + /// + /// 程序集信息 + /// + /// 程序集 + public AssemInfo(Assembly assembly) + { + Loader = assembly.Location; + Fullname = assembly.FullName!; + Name = assembly.GetName().Name!; + LoadType = AssemLoadType.Starting; + } + /// /// 注册名 /// - public string Name; + public string Name = ""; /// /// 程序集全名 /// - public string Fullname; + public string Fullname = ""; /// /// 程序集路径 /// - public string Loader; + public string Loader = ""; /// /// 加载方式 /// - public AssemLoadType LoadType; + public AssemLoadType LoadType = AssemLoadType.Starting; /// /// 程序集说明 /// - public string Description; + public string Description = ""; } - /// /// 程序集加载类型 /// @@ -41,7 +52,7 @@ public enum AssemLoadType /// /// 启动 /// - Startting = 2, + Starting = 2, /// /// 随命令 @@ -54,32 +65,39 @@ public enum AssemLoadType Disabled = 20 } - /// /// 注册中心配置信息 /// +[Flags] public enum AutoRegConfig { /// /// 不进行任何操作 /// Undefined = 0, + /// /// 注册表 /// Regedit = 1, + /// /// 反射特性 /// ReflectionAttribute = 2, + /// /// 反射接口 /// ReflectionInterface = 4, + /// /// 移除教育版 /// RemoveEMR = 8, + /// + /// 全部 + /// All = Regedit | ReflectionAttribute | ReflectionInterface | RemoveEMR, } \ No newline at end of file diff --git a/src/CADShared/Initialize/AutoReg.cs b/src/CADShared/Initialize/AutoReg.cs new file mode 100644 index 0000000000000000000000000000000000000000..b84d3f3b75fb73ff6d106a02993b2bd870aefa31 --- /dev/null +++ b/src/CADShared/Initialize/AutoReg.cs @@ -0,0 +1,88 @@ +namespace IFoxCAD.Cad; + +/// +/// 自动加载辅助类 +/// +public static class AutoReg +{ + /// + /// 获取自动加载注册表位置节点 + /// + /// 注册表节点 + public static RegistryKey? GetAcAppKey() + { + var key = HostApplicationServices.Current.UserRegistryProductRootKey; + var acKey = Registry.CurrentUser.OpenSubKey(key, true); + return acKey?.CreateSubKey("Applications"); + } + + /// + /// 是否已经自动加载 + /// + /// 程序集信息 + /// 已经设置返回true,反之返回false + public static bool SearchForReg(AssemInfo info) + { + if (GetAcAppKey() is not { } appKey || appKey.SubKeyCount == 0) + return false; + + var regApps = appKey.GetSubKeyNames(); + if (!regApps.Contains(info.Name)) + return false; + // 20220409 文件名相同,路径不同,需要判断路径 + var subKey = appKey.OpenSubKey(info.Name); + return string.Equals(subKey?.GetValue("LOADER")?.ToString(), info.Loader, StringComparison.CurrentCultureIgnoreCase); + } + + /// + /// 在注册表写入自动加载的程序集信息 + /// + /// 程序集信息 + public static void RegApp(AssemInfo info) + { + using var appKey = GetAcAppKey(); + var rk = appKey?.CreateSubKey(info.Name); + rk?.SetValue("DESCRIPTION", info.Fullname, RegistryValueKind.String); + rk?.SetValue("LOADCTRLS", info.LoadType, RegistryValueKind.DWord); + rk?.SetValue("LOADER", info.Loader, RegistryValueKind.String); + rk?.SetValue("MANAGED", 1, RegistryValueKind.DWord); + appKey?.Close(); + } + + /// + /// 在注册表写入自动加载的程序集信息 + /// + /// 程序集 + public static void RegApp(Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + var info = new AssemInfo(assembly); + RegApp(info); + } + + /// + /// 卸载注册表信息 + /// + public static bool UnRegApp(AssemInfo info) + { + using var appKey = GetAcAppKey(); + if (appKey is { SubKeyCount: 0 }) + return false; + + var regApps = appKey?.GetSubKeyNames(); + if (regApps != null && !regApps.Contains(info.Name)) return false; + appKey?.DeleteSubKey(info.Name, false); + return true; + } + + /// + /// 卸载注册表信息 + /// + /// 程序集 + public static void UnRegApp(Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + var info = new AssemInfo(assembly); + UnRegApp(info); + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/AutoRegAssem.cs b/src/CADShared/Initialize/AutoRegAssem.cs similarity index 37% rename from src/CAD/IFox.CAD.Shared/Runtime/AutoRegAssem.cs rename to src/CADShared/Initialize/AutoRegAssem.cs index e8bb7206a697783d411d77ac6ad1344fe3fa844b..8bd70dcdc5067b77663927e5303b77b5bc7ec143 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/AutoRegAssem.cs +++ b/src/CADShared/Initialize/AutoRegAssem.cs @@ -1,180 +1,115 @@ -namespace IFoxCAD.Cad; +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif +namespace IFoxCAD.Cad; /// /// 注册中心 /// -/// 初始化程序集信息写入注册表并反射特性和接口
+/// 初始化程序集信息写入注册表并反射特性和接口
/// 启动cad后的执行顺序为:
/// 1:程序集配置中心构造函数
-/// 2:特性..(多个)
+/// 2:特性..(多个)
/// 3:接口..(多个)
///
///
public abstract class AutoRegAssem : IExtensionApplication { #region 字段 - readonly AssemInfo _info; - readonly AutoReflection? _autoRef; + + private readonly AutoReflection? _autoRef; + #endregion #region 静态方法 + /// /// 程序集的路径 /// public static FileInfo Location => new(Assembly.GetCallingAssembly().Location); + /// /// 程序集的目录 /// - public static DirectoryInfo CurrDirectory => Location.Directory; + public static DirectoryInfo? CurrDirectory => Location.Directory; + /// /// 获取程序集的目录 /// /// 程序集 /// 路径对象 - public static DirectoryInfo GetDirectory(Assembly? assem) + public static DirectoryInfo? GetDirectory(Assembly? assem) { - if (assem is null) - throw new(nameof(assem)); + ArgumentNullException.ThrowIfNull(assem); return new FileInfo(assem.Location).Directory; } + #endregion #region 构造函数 + /// /// 注册中心 /// /// 配置项目 - public AutoRegAssem(AutoRegConfig autoRegConfig) + protected AutoRegAssem(AutoRegConfig autoRegConfig) { var assem = Assembly.GetCallingAssembly(); - _info = new() + var info = new AssemInfo { Loader = assem.Location, - Fullname = assem.FullName, - Name = assem.GetName().Name, - LoadType = AssemLoadType.Startting + Fullname = assem.FullName!, + Name = assem.GetName().Name!, + LoadType = AssemLoadType.Starting }; if ((autoRegConfig & AutoRegConfig.Regedit) == AutoRegConfig.Regedit) { - if (!SearchForReg()) - RegApp(); + if (!AutoReg.SearchForReg(info)) + AutoReg.RegApp(info); } +#if acad if ((autoRegConfig & AutoRegConfig.RemoveEMR) == AutoRegConfig.RemoveEMR) AcadEMR.Remove(); +#endif // 实例化了 AutoClass 之后会自动执行 IFoxAutoGo 接口下面的类, // 以及自动执行特性 [IFoxInitialize] // 类库用户不在此处进行其他代码,而是实现特性 - if ((autoRegConfig & AutoRegConfig.ReflectionInterface) == AutoRegConfig.ReflectionInterface || - (autoRegConfig & AutoRegConfig.ReflectionAttribute) == AutoRegConfig.ReflectionAttribute) - { - _autoRef = new AutoReflection(_info.Name, autoRegConfig); - _autoRef.Initialize(); - } + if ((autoRegConfig & AutoRegConfig.ReflectionInterface) != AutoRegConfig.ReflectionInterface && + (autoRegConfig & AutoRegConfig.ReflectionAttribute) != AutoRegConfig.ReflectionAttribute) return; + _autoRef = new AutoReflection(info.Name, autoRegConfig); + _autoRef.Initialize(); } + #endregion #region RegApp + // 这里的是不会自动执行的 /// - /// 获取当前cad注册表位置 - /// - /// 打开权限 - /// - public static RegistryKey GetAcAppKey(bool writable = true) - { - RegistryKey? ackey = null; - var hc = HostApplicationServices.Current; -#if acad || zcad // 中望此处缺乏测试 -#if NET35 - string key = hc.RegistryProductRootKey; -#else - string key = hc.UserRegistryProductRootKey; -#endif - ackey = Registry.CurrentUser.OpenSubKey(key, writable); -#endif - -#if gcad - // gcad 此处是否仍然有bug? 等待其他人测试反馈 - var key = hc.RegistryProductRootKey; // 浩辰2020读出来是"" - string regedit = ""; - if (Env.GetAcadVersion() == 2019) - regedit = @"Software\Gstarsoft\GstarCAD\R" + 19 + @"\zh-CN"; - if (Env.GetAcadVersion() == 2020) - regedit = @"Software\Gstarsoft\GstarCAD\B" + 20 + @"\zh-CN"; - ackey = Registry.CurrentUser.OpenSubKey(regedit, writable); -#endif - - return ackey.CreateSubKey("Applications"); - } - - /// - /// 卸载注册表信息 + /// /// - public bool UnRegApp() + public void Initialize() { - var appkey = GetAcAppKey(); - if (appkey.SubKeyCount == 0) - return false; - - var regApps = appkey.GetSubKeyNames(); - if (regApps.Contains(_info.Name)) - { - appkey.DeleteSubKey(_info.Name, false); - return true; - } - return false; } /// - /// 是否已经存在注册表 + /// /// - /// - bool SearchForReg() + public void Terminate() { - // 在使用netloadx的时候,此处注册表是失效的,具体原因要进行netloadx测试 - var appkey = GetAcAppKey(); - if (appkey.SubKeyCount == 0) - return false; - - var regApps = appkey.GetSubKeyNames(); - if (regApps.Contains(_info.Name)) - { - // 20220409 bug:文件名相同,路径不同,需要判断路径 - var info = appkey.OpenSubKey(_info.Name); - return info.GetValue("LOADER")?.ToString().ToLower() == _info.Loader.ToLower(); - } - return false; } /// - /// 在注册表写入自动加载的程序集信息 + /// /// - public void RegApp() - { - var appkey = GetAcAppKey(); - var rk = appkey.CreateSubKey(_info.Name); - rk.SetValue("DESCRIPTION", _info.Fullname, RegistryValueKind.String); - rk.SetValue("LOADCTRLS", _info.LoadType, RegistryValueKind.DWord); - rk.SetValue("LOADER", _info.Loader, RegistryValueKind.String); - rk.SetValue("MANAGED", 1, RegistryValueKind.DWord); - appkey.Close(); - } - - // 这里的是不会自动执行的 - public void Initialize() - { - } - public void Terminate() - { - } - ~AutoRegAssem() { _autoRef?.Terminate(); } + #endregion RegApp } \ No newline at end of file diff --git a/src/CADShared/Initialize/CheckFactory.cs b/src/CADShared/Initialize/CheckFactory.cs new file mode 100644 index 0000000000000000000000000000000000000000..d310854d8c6a475ec25d59270683462a1a09a767 --- /dev/null +++ b/src/CADShared/Initialize/CheckFactory.cs @@ -0,0 +1,51 @@ +namespace IFoxCAD.Cad; + +/// +/// 命令检查类 +/// +public static class CheckFactory +{ + /* + * 平时command命令的globalName如果重复,加载时会报错 + * 但是并不会告诉你是哪里错了,通常需要花大量时间来查找 + * 将此函数添加在IExtensionApplication.Initialize()函数开头 + * 虽然还会报错,但是至少能知道哪个类下哪个方法导致的报错 + * 聊胜于无吧 + * 2023-05-16 by DYH + */ + + /// + /// 检查Command命令重复 + /// + public static void CheckDuplicateCommand(Assembly? assembly = null) + { + var dic = new Dictionary>(); + assembly ??= Assembly.GetCallingAssembly(); + // 反射所有的公共类型 + var typeArray = assembly.GetExportedTypes(); + foreach (var type in typeArray) + { + if (!type.IsPublic) + continue; + foreach (var method in type.GetMethods()) + { + if (!method.IsPublic) + continue; + if (method.GetCustomAttribute() is not { } att) + continue; + if (!dic.ContainsKey(att.GlobalName)) + { + dic.Add(att.GlobalName, []); + } + + dic[att.GlobalName].Add(type.Name + "." + method.Name); + } + } + + var strings = dic.Where(o => o.Value.Count() > 1) + .Select(o => o.Key + "命令重复,在类" + string.Join("和", o.Value) + "中"); + var str = string.Join(Environment.NewLine, strings); + if (!string.IsNullOrEmpty(str)) + System.Windows.Forms.MessageBox.Show(str, @"错误:重复命令!"); + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/IAutoGo.cs b/src/CADShared/Initialize/IAutoGo.cs similarity index 65% rename from src/CAD/IFox.CAD.Shared/Runtime/IAutoGo.cs rename to src/CADShared/Initialize/IAutoGo.cs index 3b71d4cb856acc3ef17e3caf6fce7e1d5ec41ec6..cba370a3239988b5191f4c7cd4a0b30767dd057c 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/IAutoGo.cs +++ b/src/CADShared/Initialize/IAutoGo.cs @@ -1,6 +1,5 @@ namespace IFoxCAD.Cad; -using System.Collections.ObjectModel; using System.Diagnostics; /// @@ -9,8 +8,15 @@ namespace IFoxCAD.Cad; [Flags] public enum Sequence : byte { - First,// 最先 - Last, // 最后 + /// + /// 最先 + /// + First, + + /// + /// 最后 + /// + Last, } /// @@ -18,66 +24,65 @@ public enum Sequence : byte /// public interface IFoxAutoGo { - // 控制加载顺序 + /// + /// 控制加载顺序 + /// + /// Sequence SequenceId(); - // 关闭cad的时候会自动执行 + + /// + /// 关闭cad的时候会自动执行 + /// void Terminate(); - // 打开cad的时候会自动执行 + + /// + /// 打开cad的时候会自动执行 + /// void Initialize(); } /// /// 加载时自动执行特性 /// +/// +/// 用于初始化和结束回收 +/// +/// 优先级 +/// 用于初始化;用于结束回收 [AttributeUsage(AttributeTargets.Method)] -public class IFoxInitialize : Attribute +// ReSharper disable once InconsistentNaming +// ReSharper disable once ClassNeverInstantiated.Global +public class IFoxInitializeAttribute(Sequence sequence = Sequence.Last, bool isInitialize = true) : Attribute { /// /// 优先级 /// - internal Sequence SequenceId; + internal readonly Sequence SequenceId = sequence; + /// /// 用于初始化;用于结束回收 /// - internal bool IsInitialize; - /// - /// 用于初始化和结束回收 - /// - /// 优先级 - /// 用于初始化;用于结束回收 - public IFoxInitialize(Sequence sequence = Sequence.Last, bool isInitialize = true) - { - SequenceId = sequence; - IsInitialize = isInitialize; - } + internal readonly bool IsInitialize = isInitialize; } // 为了解决IExtensionApplication在一个dll内无法多次实现接口的关系 // 所以在这里反射加载所有的 IAutoGo ,以达到能分开写"启动运行"函数的目的 -class RunClass +/// +/// 执行此方法 +/// +/// +/// +/// 已经创建的对象 +internal class RunClass(MethodInfo method, Sequence sequence, object? instance = null) { - public Sequence Sequence { get; } - readonly MethodInfo _methodInfo; - object? _instance; - /// - /// 执行此方法 - /// - /// - /// - /// 已经创建的对象 - public RunClass(MethodInfo method, Sequence sequence, object? instance = null) - { - _methodInfo = method; - Sequence = sequence; - _instance = instance; - } + public Sequence Sequence { get; } = sequence; /// /// 运行方法 /// public void Run() { - _methodInfo.Invoke(ref _instance); + method.Invoke(ref instance); } } @@ -85,54 +90,49 @@ public void Run() /// 此类作为加载后cad自动运行接口的一部分,用于反射特性和接口 /// /// 启动cad后的执行顺序为:
-/// 1:特性..(多个)
+/// 1:特性..(多个)
/// 2:接口..(多个) ///
///
-public class AutoReflection +/// +/// 反射执行 +/// +/// 1.特性:
+/// 2.接口: +///
+///
+/// 约束在此dll进行加速 +/// +public class AutoReflection(string dllName, AutoRegConfig configInfo) { - static List _InitializeList = new(); // 储存方法用于初始化 - static List _TerminateList = new(); // 储存方法用于结束释放 + private static List _initializeList = []; // 储存方法用于初始化 + private static List _terminateList = []; // 储存方法用于结束释放 - readonly string _dllName; - readonly AutoRegConfig _autoRegConfig; + private readonly string _dllName = dllName; + private readonly AutoRegConfig _autoRegConfig = configInfo; /// - /// 反射执行 - /// - /// 1.特性:
- /// 2.接口: - ///
+ /// 启动cad的时候会自动执行 ///
- /// 约束在此dll进行加速 - public AutoReflection(string dllName, AutoRegConfig configInfo) - { - _dllName = dllName; - _autoRegConfig = configInfo; - } - - // 启动cad的时候会自动执行 public void Initialize() { try { // 收集特性,包括启动时和关闭时 if ((_autoRegConfig & AutoRegConfig.ReflectionAttribute) == AutoRegConfig.ReflectionAttribute) - GetAttributeFunctions(_InitializeList, _TerminateList); + GetAttributeFunctions(_initializeList, _terminateList); if ((_autoRegConfig & AutoRegConfig.ReflectionInterface) == AutoRegConfig.ReflectionInterface) { - GetInterfaceFunctions(_InitializeList, nameof(Initialize), _TerminateList, nameof(Terminate)); + GetInterfaceFunctions(_initializeList, nameof(Initialize), _terminateList, nameof(Terminate)); } - if (_InitializeList.Count > 0) - { - // 按照 SequenceId 排序_升序 - _InitializeList = _InitializeList.OrderBy(runClass => runClass.Sequence).ToList(); - RunFunctions(_InitializeList); - } + if (_initializeList.Count <= 0) return; + // 按照 SequenceId 排序_升序 + _initializeList = _initializeList.OrderBy(runClass => runClass.Sequence).ToList(); + RunFunctions(_initializeList); } - catch + catch { Debugger.Break(); } @@ -148,14 +148,12 @@ public void Terminate() //if ((_autoRegConfig & AutoRegConfig.ReflectionInterface) == AutoRegConfig.ReflectionInterface) // GetInterfaceFunctions(_TerminateList, nameof(Terminate)); - if (_TerminateList.Count > 0) - { - // 按照 SequenceId 排序_降序 - _TerminateList = _TerminateList.OrderByDescending(runClass => runClass.Sequence).ToList(); - RunFunctions(_TerminateList); - } + if (_terminateList.Count <= 0) return; + // 按照 SequenceId 排序_降序 + _terminateList = [.. _terminateList.OrderByDescending(runClass => runClass.Sequence)]; + RunFunctions(_terminateList); } - catch (System.Exception e) + catch (Exception e) { Env.Printl(e.Message); Debugger.Break(); @@ -170,43 +168,41 @@ public void Terminate() public static void AppDomainGetTypes(Action action, string? dllNameWithoutExtension = null) { #if DEBUG - int error = 0; + var error = 0; #endif try { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); -#if !NET35 + // cad2021出现如下报错 // System.NotSupportedException:动态程序集中不支持已调用的成员 // assemblies = assemblies.Where(p => !p.IsDynamic).ToArray();// 这个要容器类型转换 assemblies = Array.FindAll(assemblies, p => !p.IsDynamic); -#endif + // 主程序域 - for (int ii = 0; ii < assemblies.Length; ii++) + foreach (var assembly in assemblies) { - var assembly = assemblies[ii]; - // 获取类型集合,反射时候还依赖其他的dll就会这个错误 // 此通讯库要跳过,否则会报错. var location = Path.GetFileNameWithoutExtension(assembly.Location); if (dllNameWithoutExtension != null && location != dllNameWithoutExtension) continue; - if (location == "AcInfoCenterConn")// 通讯库 + if (location == "AcInfoCenterConn") // 通讯库 continue; - Type[]? types = null; + Type[]? types; try { types = assembly.GetTypes(); } - catch (ReflectionTypeLoadException) { continue; } - - if (types is null) + catch (ReflectionTypeLoadException) + { continue; + } - for (int jj = 0; jj < types.Length; jj++) + foreach (var type in types) { - var type = types[jj]; + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (type is not null) { #if DEBUG @@ -217,11 +213,14 @@ public static void AppDomainGetTypes(Action action, string? dllNameWithout } } } - catch (System.Exception e) - { #if DEBUG - Debugx.Printl($"出错:{nameof(AppDomainGetTypes)};计数{error};错误信息:{e.Message}"); + catch (Exception e) + { + DebugEx.Printl($"出错:{nameof(AppDomainGetTypes)};计数{error};错误信息:{e.Message}"); Debugger.Break(); +#else + catch + { #endif } } @@ -229,21 +228,23 @@ public static void AppDomainGetTypes(Action action, string? dllNameWithout /// /// 收集接口下的函数 /// - /// 储存要运行的方法 - /// 查找方法名 - /// - void GetInterfaceFunctions(List initializes, string initializeName, - List terminates, string terminateName) + /// + /// + /// + /// + private void GetInterfaceFunctions(List initializes, string initializeName, + List terminates, string terminateName) { - AppDomainGetTypes(type => { + AppDomainGetTypes(type => + { // 接口的静态类屏蔽,继承接口无法使用静态类,因此跳过 if (type.IsAbstract) return; var ints = type.GetInterfaces(); - for (int sss = 0; sss < ints.Length; sss++) + foreach (var t in ints) { - if (ints[sss].Name != nameof(IFoxAutoGo)) + if (t.Name != nameof(IFoxAutoGo)) continue; Sequence? sequence = null; @@ -251,11 +252,9 @@ void GetInterfaceFunctions(List initializes, string initializeName, MethodInfo? terminate = null; object? instance = null; - var mets = type.GetMethods(); - for (int jj = 0; jj < mets.Length; jj++) + var methods = type.GetMethods(); + foreach (var method in methods) { - var method = mets[jj]; - // 接口的静态方法屏蔽,继承的方法也不可能是静态的,因此跳过 if (method.IsAbstract) continue; @@ -268,16 +267,19 @@ void GetInterfaceFunctions(List initializes, string initializeName, sequence = (Sequence)obj; continue; } + if (method.Name == initializeName) { initialize = method; continue; } + if (method.Name == terminateName) { terminate = method; continue; } + if (sequence is not null && initialize is not null && terminate is not null) break; } @@ -286,7 +288,7 @@ void GetInterfaceFunctions(List initializes, string initializeName, // 若是释放的时候去再次构造: // 0x01 initialize构造的字段拥有的资源就处于系统释放了,这是不合理的 // 0x02 同时也发生了,为了释放而去构造这个操作 - var seq = sequence is null ? Sequence.Last : sequence.Value; + var seq = sequence ?? Sequence.Last; if (initialize is not null) initializes.Add(new(initialize, seq, instance)); if (terminate is not null) @@ -299,10 +301,11 @@ void GetInterfaceFunctions(List initializes, string initializeName, /// /// 收集特性下的函数 /// - void GetAttributeFunctions(List initializes, - List terminates) + private void GetAttributeFunctions(List initializes, + List terminates) { - AppDomainGetTypes(type => { + AppDomainGetTypes(type => + { if (!type.IsClass) return; @@ -310,25 +313,23 @@ void GetAttributeFunctions(List initializes, //if (type.IsAbstract) // return; - var mets = type.GetMethods(); - for (int ii = 0; ii < mets.Length; ii++) + var methods = type.GetMethods(); + foreach (var method in methods) { - var method = mets[ii]; - // 特性的静态方法不屏蔽 //if (method.IsAbstract) // continue; var attr = method.GetCustomAttributes(true); - for (int jj = 0; jj < attr.Length; jj++) + foreach (var t in attr) { - if (attr[jj] is IFoxInitialize jjAtt) + if (t is IFoxInitializeAttribute jjAtt) { - var runc = new RunClass(method, jjAtt.SequenceId); + var runClass = new RunClass(method, jjAtt.SequenceId); if (jjAtt.IsInitialize) - initializes.Add(runc); + initializes.Add(runClass); else - terminates.Add(runc); + terminates.Add(runClass); break; } } @@ -339,10 +340,11 @@ void GetAttributeFunctions(List initializes, /// /// 执行收集到的函数 /// - static void RunFunctions(List runClassList) + private static void RunFunctions(List runClassList) { - for (int i = 0; i < runClassList.Count; i++) - runClassList[i].Run(); + foreach (var t in runClassList) + t.Run(); + runClassList.Clear(); } diff --git a/src/CAD/IFox.CAD.Shared/Runtime/MethodInfoHelper.cs b/src/CADShared/Initialize/MethodInfoHelper.cs similarity index 69% rename from src/CAD/IFox.CAD.Shared/Runtime/MethodInfoHelper.cs rename to src/CADShared/Initialize/MethodInfoHelper.cs index 5eb5f935accaae6159eac9dfdf7877efad1ffa7a..b671885e697734f5d3251c62af81cdf51e2253a7 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/MethodInfoHelper.cs +++ b/src/CADShared/Initialize/MethodInfoHelper.cs @@ -1,4 +1,6 @@ - +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Cad; @@ -15,18 +17,18 @@ internal static class MethodInfoHelper /// 已经外部创建的对象,为空则此处创建 public static object? Invoke(this MethodInfo methodInfo, ref object? instance) { - methodInfo.NotNull(nameof(methodInfo)); + ArgumentNullException.ThrowIfNull(methodInfo); object? result = null; if (methodInfo.IsStatic) { // 新函数指针进入此处 // 参数数量一定要匹配,为null则参数个数不同导致报错, - // 参数为stirng[],则可以传入object[]代替,其他参数是否还可以实现默认构造? - var args = new List { }; + // 参数为string[],则可以传入object[]代替,其他参数是否还可以实现默认构造? + var args = new List(); var paramInfos = methodInfo.GetParameters(); - for (int i = 0; i < paramInfos.Length; i++) + for (var i = 0; i < paramInfos.Length; i++) args.Add(null!); - result = methodInfo.Invoke(null, args.ToArray());// 静态调用 + result = methodInfo.Invoke(null, args.ToArray()); // 静态调用 } else { @@ -38,27 +40,29 @@ internal static class MethodInfoHelper #endif if (instance == null) { - var reftype = methodInfo.ReflectedType; - if (reftype == null) + var refType = methodInfo.ReflectedType; + if (refType == null) return null; - var fullName = reftype.FullName; // 命名空间+类 + var fullName = refType.FullName; // 命名空间+类 if (fullName == null) return null; - var type = reftype.Assembly.GetType(fullName); + var type = refType.Assembly.GetType(fullName); if (type == null) return null; - instance = Activator.CreateInstance(type);// 构造类 + instance = Activator.CreateInstance(type); // 构造类 #if cache if (!type.IsAbstract)// 无法创建抽象类成员 methodDic.Add(methodInfo, instance); #endif } + if (instance != null) result = methodInfo.Invoke(instance, null); // 非静态,调用实例化方法 } + return result; } } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/PE/AcadPeInfo.cs b/src/CADShared/PE/AcadPeInfo.cs similarity index 84% rename from src/CAD/IFox.CAD.Shared/Runtime/PE/AcadPeInfo.cs rename to src/CADShared/PE/AcadPeInfo.cs index 3957a68420307e503b1c769fc32627e0895aa92d..fbec0a6bee1666202bda69b4d37a0cf189dc7dfa 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/PE/AcadPeInfo.cs +++ b/src/CADShared/PE/AcadPeInfo.cs @@ -2,30 +2,60 @@ namespace IFoxCAD.Cad; -// 选择模式 +/// +/// 选择模式 +/// [Flags] public enum AcadPeEnum : byte { + /// + /// AcadExe + /// AcadExe = 1, + /// + /// AccoreDll + /// AccoreDll = 2, + /// + /// Acdb + /// Acdb = 4, + /// + /// ExeAndCore + /// ExeAndCore = AcadExe | AccoreDll, } -// 这里的枚举对应 GetMethodException 错误值 +/// +/// 这里的枚举对应 GetMethodException 错误值 +/// [Flags] public enum GetMethodErrorNum : byte { + /// + /// + /// Ok = 0, + /// + /// + /// NoModule = 1, + /// + /// + /// NoFuncName = 2, } -// 自动获取本工程上面的发送命令的接口 +/// +/// 自动获取本工程上面的发送命令的接口 +/// public class AcadPeInfo { #region 静态单例获取exe/dll信息 static PeInfo? _PeForAcadExe; + /// + /// + /// public static PeInfo? PeForAcadExe { get @@ -33,7 +63,9 @@ public static PeInfo? PeForAcadExe if (_PeForAcadExe is null) { // 获取此acad.exe获取所有的函数名 - var file = Process.GetCurrentProcess().MainModule.FileName; + var processModule = Process.GetCurrentProcess().MainModule; + if (processModule == null) return _PeForAcadExe; + var file = processModule.FileName; _PeForAcadExe = new PeInfo(file); } return _PeForAcadExe; @@ -41,6 +73,9 @@ public static PeInfo? PeForAcadExe } static PeInfo? _PeForAccoreDll; + /// + /// + /// public static PeInfo? PeForAccoreDll { get @@ -48,7 +83,7 @@ public static PeInfo? PeForAccoreDll if (_PeForAccoreDll is null) { // 获取此dll所有的函数名 - var file = Process.GetCurrentProcess().MainModule.FileName; + var file = Process.GetCurrentProcess().MainModule!.FileName; var dll = Path.GetDirectoryName(file) + "\\accore.dll"; if (File.Exists(dll))// 08没有,高版本分离的 _PeForAccoreDll = new PeInfo(dll); @@ -58,6 +93,9 @@ public static PeInfo? PeForAccoreDll } static PeInfo? _PeForAcdbDll; + /// + /// + /// public static PeInfo? PeForAcdbDll { get @@ -65,8 +103,8 @@ public static PeInfo? PeForAcdbDll if (_PeForAcdbDll is null) { // 获取此dll所有的函数名 - var file = Process.GetCurrentProcess().MainModule.FileName; - var dll = Path.GetDirectoryName(file) + $"\\acdb{Acap.Version.Major}.dll"; + var file = Process.GetCurrentProcess().MainModule!.FileName; + var dll = Path.GetDirectoryName(file) + $"\\acdb{Acaop.Version.Major}.dll"; if (File.Exists(dll)) _PeForAcdbDll = new PeInfo(dll); } @@ -84,7 +122,7 @@ public List? Methods { if (_Methods is null) { - _Methods = new(); + _Methods = []; if ((_acadPeEnum & AcadPeEnum.AcadExe) == AcadPeEnum.AcadExe) GetPeMethod(PeForAcadExe); @@ -136,7 +174,7 @@ public AcadPeInfo(string methodName, AcadPeEnum acadPeEnum) #region 方法 /// - /// 储存旧值<去除修饰函数名(查找的),带修饰函数名们> + /// 储存旧值,去除修饰函数名(查找的),带修饰函数名们 /// static Dictionary> _Dict = new(); @@ -157,7 +195,7 @@ GetMethodErrorNum GetPeMethod(PeInfo? peInfo) } else { - _Methods ??= new(); + _Methods ??= []; try { PeFunction.Finds(peInfo, _findFuncName, _Methods); @@ -199,9 +237,9 @@ GetMethodErrorNum GetPeMethod(PeInfo? peInfo) // 排序,最少长度原则本身就是让完全相同字符串在最前面 // 这里替换为有序哈希,因为我总是需要不带修饰的返回函数,所以是排序长度的第一个 - _Methods = _Methods.OrderBy(str => str.CName?.Length) - .ThenBy(str => str.MethodName.Length) - .ToList(); + _Methods = _Methods?.OrderBy(str => str.CName?.Length) + .ThenBy(str => str.MethodName.Length) + .ToList(); func = Marshal.GetDelegateForFunctionPointer(Methods.First().GetProcAddress(), typeof(TDelegate)) as TDelegate; return func; @@ -226,7 +264,7 @@ public string? CName if (_CName is null && MethodName is not null) { _CName = MethodName.Replace("?", string.Empty); // 剔除cpp前缀 - int num = _CName.IndexOf("@"); + var num = _CName.IndexOf("@"); if (num > -1) _CName = _CName.Substring(0, num); // 剔除参数部分 } @@ -311,20 +349,40 @@ public static void Finds(PeInfo peInfo, /// public class GetPeMethodException : ApplicationException { + /// + /// + /// public int ErrorNum; + /// + /// + /// public string? ErrorMsg; + /// + /// + /// public Exception? InnerException1; - + /// + /// + /// + /// public GetPeMethodException(string msg) : base(msg) { ErrorMsg = msg; } - + /// + /// + /// + /// + /// public GetPeMethodException(int errorNum, string msg) : base(msg) { ErrorNum = errorNum; } - + /// + /// + /// + /// + /// public GetPeMethodException(string msg, Exception innerException) : base(msg, innerException) { InnerException1 = innerException; diff --git a/src/CAD/IFox.CAD.Shared/Runtime/PE/DBmod.cs b/src/CADShared/PE/DBmod.cs similarity index 76% rename from src/CAD/IFox.CAD.Shared/Runtime/PE/DBmod.cs rename to src/CADShared/PE/DBmod.cs index 7502e2501f40faccfd004ff16cdab4caffad0772..3886bd90f5b12ea51f7df133f07d9fb492928d4e 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/PE/DBmod.cs +++ b/src/CADShared/PE/DBmod.cs @@ -8,27 +8,55 @@ [Flags] public enum DBmod : short { - [Description("数据库冇修改")] + /// + /// 数据库未修改 + /// + [Description("数据库未修改")] DatabaseNoModifies = 0, + /// + /// 数据库有修改 + /// [Description("数据库有修改")] Database = 1, + /// + /// 变量有修改 + /// [Description("变量有修改")] Value = 4, + /// + /// 窗口有修改 + /// [Description("窗口有修改")] Window = 8, + /// + /// 视图有修改 + /// [Description("视图有修改")] View = 16, + /// + /// 字段有修改 + /// [Description("字段有修改")] Field = 32 } - +/// +/// 图形修改状态 +/// public class DBmodEx { + /// + /// 图形修改状态 + /// public static DBmod DBmod => (DBmod)Env.GetVar("dbmod"); delegate long DelegateAcdbSetDbmod(IntPtr db, DBmod newValue); static DelegateAcdbSetDbmod? acdbSetDbmod;//别改名称 - + /// + /// 设置图形修改状态 + /// + /// 数据库的指针 + /// 修改状态 + /// public static long AcdbSetDbmod(IntPtr db, DBmod newValue) { acdbSetDbmod ??= AcadPeInfo.GetDelegate( @@ -44,7 +72,7 @@ public static long AcdbSetDbmod(IntPtr db, DBmod newValue) /// public static void DBmodTask(Action action) { - var dm = Acap.DocumentManager; + var dm = Acaop.DocumentManager; if (dm.Count == 0) return; var doc = dm.MdiActiveDocument; @@ -66,7 +94,7 @@ public static void DatabaseNoModifies() { if (_flag)// 仅执行一次,在初始化时候 { - var dm = Acap.DocumentManager; + var dm = Acaop.DocumentManager; if (dm.Count == 0) return; var doc = dm.MdiActiveDocument; diff --git a/src/CAD/IFox.CAD.Shared/Runtime/PE/PostCmd.cs b/src/CADShared/PE/PostCmd.cs similarity index 81% rename from src/CAD/IFox.CAD.Shared/Runtime/PE/PostCmd.cs rename to src/CADShared/PE/PostCmd.cs index cd0b39e38ec42230c431e100d9aa3984a02a3847..3929b67c75ba8f8fb4f6c31b7618fd28ba67321c 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/PE/PostCmd.cs +++ b/src/CADShared/PE/PostCmd.cs @@ -1,5 +1,7 @@ namespace IFoxCAD.Cad; - +/// +/// 发送命令 +/// public class PostCmd { /* @@ -26,12 +28,12 @@ public class PostCmd /// static PromptStatus AcedCmd(ResultBuffer args) { - if (Acap.DocumentManager.IsApplicationContext) + if (Acaop.DocumentManager.IsApplicationContext) return 0; if (acedCmd is null) { - string str = nameof(acedCmd); - if (Acap.Version.Major >= 20)// 2015.+ + var str = nameof(acedCmd); + if (Acaop.Version.Major >= 20)// 2015.+ str += "S"; acedCmd = AcadPeInfo.GetDelegate( @@ -81,7 +83,7 @@ static PromptStatus AcedPostCommand(string args) nameof(acedPostCommand), AcadPeEnum.ExeAndCore); // 不然到CAD之后会乱码 - byte[] bytes = Encoding.Unicode.GetBytes(args); + var bytes = Encoding.Unicode.GetBytes(args); if (acedPostCommand is null) return PromptStatus.Error; return (PromptStatus)acedPostCommand.Invoke(bytes);// 调用方法 @@ -98,7 +100,7 @@ static PromptStatus AcedInvoke(string args) nameof(acedInvoke), AcadPeEnum.ExeAndCore); // 不然到CAD之后会乱码 - byte[] bytes = Encoding.Unicode.GetBytes(args); + var bytes = Encoding.Unicode.GetBytes(args); if (acedInvoke is null) return PromptStatus.Error; @@ -110,7 +112,7 @@ static PromptStatus AcedInvoke(string args) /// static void AsyncCommand(string args) { - object[] commandArray = { args + "\n" }; + object[] commandArray = [args + "\n"]; #if zcad var com = Acap.ZcadApplication; #else @@ -122,14 +124,34 @@ static void AsyncCommand(string args) doc?.GetType() .InvokeMember("SendCommand", BindingFlags.InvokeMethod, null, doc, commandArray);// 返回值是null } - + /// + /// 命令模式 + /// public enum RunCmdFlag : byte { + /// + /// 发送命令(同步)如果2015.+这里报错,那么表示vs需要提权测试 + /// AcedCmd = 1, + /// + /// 发送命令(同步) + /// AcedCommand = 2, + /// + /// 发送命令(同步),可以多线程 + /// AcedPostCommand = 4, + /// + /// 发送命令(同步) + /// AcedInvoke = 8, + /// + /// 默认的发送命令 + /// SendStringToExecute = 16, + /// + /// 异步命令 + /// AsyncCommand = 32, } @@ -137,18 +159,34 @@ public enum RunCmdFlag : byte * 发送命令会记录在命令历史 * 发送lisp的(command "xx")就不会 */ + /// + /// 发送命令 + /// + /// + /// public static PromptStatus SendCommand(ResultBuffer args) { return AcedCmd(args); } + /// + /// 发送命令 + /// + /// + /// public static PromptStatus SendCommand(IntPtr args) { return AcedCommand(args); } + /// + /// 发送命令 + /// + /// + /// + /// public static PromptStatus SendCommand(string args, RunCmdFlag flag) { - PromptStatus ret = PromptStatus.OK; - if (!Acap.DocumentManager.IsApplicationContext) + var ret = PromptStatus.OK; + if (!Acaop.DocumentManager.IsApplicationContext) { if ((flag & RunCmdFlag.AcedCmd) == RunCmdFlag.AcedCmd) { @@ -178,7 +216,7 @@ public static PromptStatus SendCommand(string args, RunCmdFlag flag) } else { - var dm = Acap.DocumentManager; + var dm = Acaop.DocumentManager; var doc = dm.MdiActiveDocument; if (doc == null) return PromptStatus.Error; diff --git a/src/CAD/IFox.CAD.Shared/Runtime/PE/ProgramPE.cs b/src/CADShared/PE/ProgramPE.cs similarity index 92% rename from src/CAD/IFox.CAD.Shared/Runtime/PE/ProgramPE.cs rename to src/CADShared/PE/ProgramPE.cs index e1f834a6cecc58f8795912d4d9499ec3723973b8..d0d61bdffb994f62880f350593c7bea283375ebb 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/PE/ProgramPE.cs +++ b/src/CADShared/PE/ProgramPE.cs @@ -1,4 +1,5 @@ -namespace IFoxCAD.Cad; +#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 +namespace IFoxCAD.Cad; using System; using System.Collections; @@ -45,7 +46,9 @@ public class PeInfo /// 获取是否正常打开文件 /// public bool OpenFile { get; private set; } = false; + public DosHeader? DosHeader { get; private set; } + public DosStub? DosStub { get; private set; } public PEHeader? PEHeader { get; private set; } public OptionalHeader? OptionalHeader { get; private set; } @@ -75,10 +78,15 @@ public class PeInfo #endregion #region 构造 + /// + /// 构造函数 + /// + /// + /// public PeInfo(string fullName) { - if (fullName is null) - throw new ArgumentException(nameof(fullName)); ; + if (string.IsNullOrWhiteSpace(fullName)) + throw new ArgumentNullException(nameof(fullName)); FullName = fullName; FileStream? file = null; @@ -86,9 +94,7 @@ public PeInfo(string fullName) try { // 文件流 - file = new FileStream(fullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);// FileShare才能进c盘 - _PEFileByte = new byte[file.Length]; - file.Read(_PEFileByte, 0, _PEFileByte.Length); + _PEFileByte = File.ReadAllBytes(fullName); LoadFile(); OpenFile = true; } @@ -157,7 +163,7 @@ private void LoadDosStub() if (DosHeader is null) return; - long Size = GetLong(DosHeader.e_PESTAR) - _PEFileIndex; // 获得SUB的大小 + var Size = GetLong(DosHeader.e_PESTAR) - _PEFileIndex; // 获得SUB的大小 DosStub = new DosStub(Size) { FileStarIndex = _PEFileIndex @@ -249,8 +255,8 @@ private void LoadOptionalDirAttrib() FileStarIndex = _PEFileIndex }; - long DirCount = GetLong(OptionalHeader.NumberOfRvaAndSizes);// 这里导致无法使用64位 - for (int i = 0; i != DirCount; i++) + var DirCount = GetLong(OptionalHeader.NumberOfRvaAndSizes);// 这里导致无法使用64位 + for (var i = 0; i != DirCount; i++) { OptionalDirAttrib.DirAttrib? directAttrib = new(); Loadbyte(ref directAttrib.DirRva); @@ -269,7 +275,7 @@ private void LoadSectionTable() return; SectionTable = new SectionTable(); - long Count = GetLong(PEHeader.NumberOfSections); + var Count = GetLong(PEHeader.NumberOfSections); SectionTable.FileStarIndex = _PEFileIndex; for (long i = 0; i != Count; i++) { @@ -304,19 +310,19 @@ private void LoadExportDirectory() GetLong(exporRVA.DirRva) == 0) return; - long exporAddress = GetLong(exporRVA.DirRva); // 获取的位置 + var exporAddress = GetLong(exporRVA.DirRva); // 获取的位置 ExportDirectory = new ExportDirectory(); if (SectionTable is null) return; - for (int i = 0; i != SectionTable.Section.Count; i++) // 循环节表 + for (var i = 0; i != SectionTable.Section.Count; i++) // 循环节表 { if (SectionTable.Section[i] is not SectionTable.SectionData sect) continue; - long starRva = GetLong(sect.SizeOfRawDataRVA); - long endRva = GetLong(sect.SizeOfRawDataSize); + var starRva = GetLong(sect.SizeOfRawDataRVA); + var endRva = GetLong(sect.SizeOfRawDataSize); if (exporAddress >= starRva && exporAddress < starRva + endRva) { @@ -338,11 +344,11 @@ private void LoadExportDirectory() Loadbyte(ref ExportDirectory.AddressOfNameOrdinals); _PEFileIndex = GetLong(ExportDirectory.AddressOfFunctions) - GetLong(sect.SizeOfRawDataRVA) + GetLong(sect.PointerToRawData); - long endIndex = GetLong(ExportDirectory.AddressOfNames) - GetLong(sect.SizeOfRawDataRVA) + GetLong(sect.PointerToRawData); - long numb = (endIndex - _PEFileIndex) / 4; + var endIndex = GetLong(ExportDirectory.AddressOfNames) - GetLong(sect.SizeOfRawDataRVA) + GetLong(sect.PointerToRawData); + var numb = (endIndex - _PEFileIndex) / 4; for (long z = 0; z != numb; z++) { - byte[] Data = new byte[4]; + var Data = new byte[4]; Loadbyte(ref Data); ExportDirectory.AddressOfFunctionsList.Add(Data); } @@ -352,7 +358,7 @@ private void LoadExportDirectory() numb = (endIndex - _PEFileIndex) / 4; for (long z = 0; z != numb; z++) { - byte[] Data = new byte[4]; + var Data = new byte[4]; Loadbyte(ref Data); ExportDirectory.AddressOfNamesList.Add(Data); } @@ -362,7 +368,7 @@ private void LoadExportDirectory() numb = (endIndex - _PEFileIndex) / 2; for (long z = 0; z != numb; z++) { - byte[] Data = new byte[2]; + var Data = new byte[2]; Loadbyte(ref Data); ExportDirectory.AddressOfNameOrdinalsList.Add(Data); } @@ -406,10 +412,10 @@ private void LoadImportDirectory() if (OptionalDirAttrib.DirByte[1] is not OptionalDirAttrib.DirAttrib ImporRVA) return; - long ImporAddress = GetLong(ImporRVA.DirRva); // 获取的位置 + var ImporAddress = GetLong(ImporRVA.DirRva); // 获取的位置 if (ImporAddress == 0) return; - long ImporSize = GetLong(ImporRVA.DirSize); // 获取大小 + var ImporSize = GetLong(ImporRVA.DirSize); // 获取大小 ImportDirectory = new ImportDirectory(); @@ -422,7 +428,7 @@ private void LoadImportDirectory() #region 获取位置 if (SectionTable is null) return; - for (int i = 0; i != SectionTable.Section.Count; i++) // 循环节表 + for (var i = 0; i != SectionTable.Section.Count; i++) // 循环节表 { if (SectionTable.Section[i] is not SectionTable.SectionData Sect) continue; @@ -464,12 +470,12 @@ private void LoadImportDirectory() #region 获取输入DLL名称 - for (int z = 0; z != ImportDirectory.ImportList.Count; z++) // 获取引入DLL名字 + for (var z = 0; z != ImportDirectory.ImportList.Count; z++) // 获取引入DLL名字 { if (ImportDirectory.ImportList[z] is not ImportDirectory.ImportDate Import) continue; - long ImportDLLName = GetLong(Import.Name) - SizeRva + PointerRva; + var ImportDLLName = GetLong(Import.Name) - SizeRva + PointerRva; _PEFileIndex = ImportDLLName; long ReadCount = 0; while (_PEFileByte is not null) // 获取引入名 @@ -486,28 +492,28 @@ private void LoadImportDirectory() #endregion #region 获取引入方法 先获取地址 然后获取名字和头 - for (int z = 0; z != ImportDirectory.ImportList.Count; z++) // 获取引入方法 + for (var z = 0; z != ImportDirectory.ImportList.Count; z++) // 获取引入方法 { if (ImportDirectory.ImportList[z] is not ImportDirectory.ImportDate import) continue; - long importDLLName = GetLong(import.OriginalFirstThunk) - SizeRva + PointerRva; + var importDLLName = GetLong(import.OriginalFirstThunk) - SizeRva + PointerRva; _PEFileIndex = importDLLName; while (true) { var function = new ImportDirectory.ImportDate.FunctionList(); Loadbyte(ref function.OriginalFirst); - long loadIndex = GetLong(function.OriginalFirst); + var loadIndex = GetLong(function.OriginalFirst); if (loadIndex == 0) break; - long oldIndex = _PEFileIndex; + var oldIndex = _PEFileIndex; _PEFileIndex = loadIndex - SizeRva + PointerRva; if (loadIndex >= StarRva && loadIndex < StarRva + EndRva) // 发现有些数字超级大 { - int ReadCount = 0; + var ReadCount = 0; while (_PEFileByte is not null) { @@ -515,7 +521,7 @@ private void LoadImportDirectory() Loadbyte(ref function.FunctionHead); if (_PEFileByte[_PEFileIndex + ReadCount] == 0) { - byte[] FunctionName = new byte[ReadCount]; + var FunctionName = new byte[ReadCount]; Loadbyte(ref FunctionName); function.FunctionName = FunctionName; @@ -547,10 +553,10 @@ private void LoadResourceDirectory() if (OptionalDirAttrib.DirByte[2] is not OptionalDirAttrib.DirAttrib ImporRVA) return; - long ImporAddress = GetLong(ImporRVA.DirRva); // 获取的位置 + var ImporAddress = GetLong(ImporRVA.DirRva); // 获取的位置 if (ImporAddress == 0) return; - long ImporSize = GetLong(ImporRVA.DirSize); // 获取大小 + var ImporSize = GetLong(ImporRVA.DirSize); // 获取大小 ResourceDirectory = new ResourceDirectory(); @@ -564,7 +570,7 @@ private void LoadResourceDirectory() if (SectionTable is null) return; - for (int i = 0; i != SectionTable.Section.Count; i++) // 循环节表 + for (var i = 0; i != SectionTable.Section.Count; i++) // 循环节表 { if (SectionTable.Section[i] is not SectionTable.SectionData sect) continue; @@ -607,34 +613,34 @@ private void AddResourceNode(ResourceDirectory node, long PEIndex, long RVA, lon Loadbyte(ref node.NumberOfNamedEntries); Loadbyte(ref node.NumberOfIdEntries); - long NameRVA = GetLong(node.NumberOfNamedEntries); - for (int i = 0; i != NameRVA; i++) + var NameRVA = GetLong(node.NumberOfNamedEntries); + for (var i = 0; i != NameRVA; i++) { var Entry = new ResourceDirectory.DirectoryEntry(); Loadbyte(ref Entry.Name); Loadbyte(ref Entry.Id); - byte[] temp = new byte[2]; + var temp = new byte[2]; temp[0] = Entry.Name[0]; temp[1] = Entry.Name[1]; if (_PEFileByte is null) return; - long NameIndex = GetLong(temp) + PEIndex; + var NameIndex = GetLong(temp) + PEIndex; temp[0] = _PEFileByte[NameIndex + 0]; temp[1] = _PEFileByte[NameIndex + 1]; - long NameCount = GetLong(temp); + var NameCount = GetLong(temp); node.Name = new byte[NameCount * 2]; - for (int z = 0; z != node.Name.Length; z++) + for (var z = 0; z != node.Name.Length; z++) node.Name[z] = _PEFileByte[NameIndex + 2 + z]; // System.Windows.Forms.MessageBox.Show(GetString(Entry.ID)); temp[0] = Entry.Id[2]; temp[1] = Entry.Id[3]; - long oldIndex = _PEFileIndex; + var oldIndex = _PEFileIndex; if (GetLong(temp) == 0) { @@ -667,19 +673,19 @@ private void AddResourceNode(ResourceDirectory node, long PEIndex, long RVA, lon node.EntryList.Add(Entry); } - long Count = GetLong(node.NumberOfIdEntries); - for (int i = 0; i != Count; i++) + var Count = GetLong(node.NumberOfIdEntries); + for (var i = 0; i != Count; i++) { var entry = new ResourceDirectory.DirectoryEntry(); Loadbyte(ref entry.Name); Loadbyte(ref entry.Id); // System.Windows.Forms.MessageBox.Show(GetString(Entry.Name)+"_"+GetString(Entry.Id)); - byte[] temp = new byte[2]; + var temp = new byte[2]; temp[0] = entry.Id[2]; temp[1] = entry.Id[3]; - long OldIndex = _PEFileIndex; + var OldIndex = _PEFileIndex; if (GetLong(temp) == 0) { @@ -694,7 +700,7 @@ private void AddResourceNode(ResourceDirectory node, long PEIndex, long RVA, lon Loadbyte(ref dataRVA.ResourTest); Loadbyte(ref dataRVA.ResourWen); - long FileRva = GetLong(dataRVA.ResourRVA) - resourSectRva + PEIndex; + var FileRva = GetLong(dataRVA.ResourRVA) - resourSectRva + PEIndex; dataRVA.FileStarIndex = FileRva; dataRVA.FileEndIndex = FileRva + GetLong(dataRVA.ResourSize); @@ -728,7 +734,7 @@ private void Loadbyte(ref byte[] data) if (_PEFileByte is null) return; - for (int i = 0; i != data.Length; i++) + for (var i = 0; i != data.Length; i++) { data[i] = _PEFileByte[_PEFileIndex]; _PEFileIndex++; @@ -741,8 +747,8 @@ private void Loadbyte(ref byte[] data) /// AA BB CC DD private string GetString(byte[] data) { - string Temp = ""; - for (int i = 0; i != data.Length - 1; i++) + var Temp = ""; + for (var i = 0; i != data.Length - 1; i++) Temp += data[i].ToString("X02") + " "; Temp += data[data.Length - 1].ToString("X02"); @@ -758,15 +764,15 @@ private string GetString(byte[] data) private string GetString(byte[] data, string type) { if (type.Trim().ToUpper() == "ASCII") - return System.Text.Encoding.ASCII.GetString(data); + return Encoding.ASCII.GetString(data); if (type.Trim().ToUpper() == "DEFAULT") - return System.Text.Encoding.Default.GetString(data); + return Encoding.Default.GetString(data); if (type.Trim().ToUpper() == "UNICODE") - return System.Text.Encoding.Unicode.GetString(data); + return Encoding.Unicode.GetString(data); if (type.Trim().ToUpper() == "BYTE") { - string Temp = ""; - for (int i = data.Length - 1; i != 0; i--) + var Temp = ""; + for (var i = data.Length - 1; i != 0; i--) Temp += data[i].ToString("X02") + " "; Temp += data[0].ToString("X02"); return Temp; @@ -780,13 +786,13 @@ private string GetString(byte[] data, string type) /// static string GetInt(byte[] data) { - string Temp = ""; - for (int i = 0; i != data.Length - 1; i++) + var Temp = ""; + for (var i = 0; i != data.Length - 1; i++) { - int ByteInt = (int)data[i]; + var ByteInt = (int)data[i]; Temp += ByteInt.ToString() + " "; } - int EndByteInt = (int)data[data.Length - 1]; + var EndByteInt = (int)data[data.Length - 1]; // int EndByteInt = (int)data[^1]; Temp += EndByteInt.ToString(); return Temp; @@ -801,9 +807,9 @@ private long GetLong(byte[] data) if (data.Length > 4) return 0; - string MC = ""; + var MC = ""; // if (data.Length <= 4) - for (int i = data.Length - 1; i != -1; i--) + for (var i = data.Length - 1; i != -1; i--) MC += data[i].ToString("X02"); return Convert.ToInt64(MC, 16); } @@ -1030,7 +1036,7 @@ private void AddTableRow(DataTable refTable, byte[]? data, string name, string d { 15, "其他表5" } }; - for (int i = 0; i != OptionalDirAttrib.DirByte.Count; i++) + for (var i = 0; i != OptionalDirAttrib.DirByte.Count; i++) { if (OptionalDirAttrib.DirByte[i] is not OptionalDirAttrib.DirAttrib MyDirByte) continue; @@ -1065,7 +1071,7 @@ private void AddTableRow(DataTable refTable, byte[]? data, string name, string d returnTable.Columns.Add("ASCII"); returnTable.Columns.Add("Describe"); - for (int i = 0; i != SectionTable.Section.Count; i++) + for (var i = 0; i != SectionTable.Section.Count; i++) { if (SectionTable.Section[i] is not SectionTable.SectionData SectionDate) continue; @@ -1129,7 +1135,7 @@ private void AddTableRow(DataTable refTable, byte[]? data, string name, string d returnTable.Columns.Add("ASCII"); returnTable.Columns.Add("Describe"); - for (int i = 0; i != ExportDirectory.FunctionNamesByte.Count; i++) + for (var i = 0; i != ExportDirectory.FunctionNamesByte.Count; i++) { AddTableRow(returnTable, ExportDirectory.FunctionNamesByte[i], @@ -1137,21 +1143,21 @@ private void AddTableRow(DataTable refTable, byte[]? data, string name, string d "_ExportDirectory.Name-Sect.SizeOfRawDataRVA+Sect.PointerToRawData"); } - for (int i = 0; i != ExportDirectory.AddressOfNamesList.Count; i++) + for (var i = 0; i != ExportDirectory.AddressOfNamesList.Count; i++) { if (ExportDirectory.AddressOfNamesList[i] is not byte[] a) continue; AddTableRow(returnTable, a, "NamesList", ""); } - for (int i = 0; i != ExportDirectory.AddressOfFunctionsList.Count; i++) + for (var i = 0; i != ExportDirectory.AddressOfFunctionsList.Count; i++) { if (ExportDirectory.AddressOfFunctionsList[i] is not byte[] a) continue; AddTableRow(returnTable, a, "Functions", ""); } - for (int i = 0; i != ExportDirectory.AddressOfNameOrdinalsList.Count; i++) + for (var i = 0; i != ExportDirectory.AddressOfNameOrdinalsList.Count; i++) { if (ExportDirectory.AddressOfNameOrdinalsList[i] is not byte[] a) continue; @@ -1172,7 +1178,7 @@ private void AddTableRow(DataTable refTable, byte[]? data, string name, string d returnTable.Columns.Add("ASCII"); returnTable.Columns.Add("Describe"); - for (int i = 0; i != ImportDirectory.ImportList.Count; i++) + for (var i = 0; i != ImportDirectory.ImportList.Count; i++) { if (ImportDirectory.ImportList[i] is not ImportDirectory.ImportDate ImportByte) continue; @@ -1200,14 +1206,14 @@ private void AddTableRow(DataTable refTable, byte[]? data, string name, string d returnTable.Columns.Add("ASCII"); returnTable.Columns.Add("Describe"); - for (int i = 0; i != ImportDirectory.ImportList.Count; i++) + for (var i = 0; i != ImportDirectory.ImportList.Count; i++) { if (ImportDirectory.ImportList[i] is not ImportDirectory.ImportDate ImportByte) continue; AddTableRow(returnTable, ImportByte.DLLName, "DLL-Name", "**********"); - for (int z = 0; z != ImportByte.DLLFunctionList.Count; z++) + for (var z = 0; z != ImportByte.DLLFunctionList.Count; z++) { if (ImportByte.DLLFunctionList[z] is not ImportDirectory.ImportDate.FunctionList Function) continue; @@ -1232,20 +1238,20 @@ private void AddTableRow(DataTable refTable, byte[]? data, string name, string d } private void AddResourceDirectoryRow(DataTable myTable, ResourceDirectory Node, string parentID) { - string Name = ""; + var Name = ""; if (Node.Name is not null) Name = GetString(Node.Name, "UNICODE"); - for (int i = 0; i != Node.EntryList.Count; i++) + for (var i = 0; i != Node.EntryList.Count; i++) { if (Node.EntryList[i] is not ResourceDirectory.DirectoryEntry Entry) continue; - long ID = GetLong(Entry.Name); + var ID = GetLong(Entry.Name); - string GUID = Guid.NewGuid().ToString(); + var GUID = Guid.NewGuid().ToString(); - string IDNAME = "ID{" + ID + "}"; + var IDNAME = "ID{" + ID + "}"; if (Name.Length != 0) IDNAME += "Name{" + Name + "}"; @@ -1275,17 +1281,17 @@ private void AddResourceDirectoryRow(DataTable myTable, ResourceDirectory Node, myTable.Rows.Add(new string[] { GUID, IDNAME, parentID }); - for (int z = 0; z != Entry.DataEntryList.Count; z++) + for (var z = 0; z != Entry.DataEntryList.Count; z++) { if (Entry.DataEntryList[z] is not ResourceDirectory.DirectoryEntry.DataEntry Data) continue; - string Text = "Address{" + GetString(Data.ResourRVA) + "} Size{" + GetString(Data.ResourSize) + "} FileBegin{" + Data.FileStarIndex.ToString() + "-" + Data.FileEndIndex.ToString() + "}"; + var Text = "Address{" + GetString(Data.ResourRVA) + "} Size{" + GetString(Data.ResourSize) + "} FileBegin{" + Data.FileStarIndex.ToString() + "-" + Data.FileEndIndex.ToString() + "}"; myTable.Rows.Add(new string[] { Guid.NewGuid().ToString(), Text, GUID }); } - for (int z = 0; z != Entry.NodeDirectoryList.Count; z++) + for (var z = 0; z != Entry.NodeDirectoryList.Count; z++) { if (Entry.NodeDirectoryList[z] is not ResourceDirectory a) continue; @@ -1409,9 +1415,9 @@ public OptionalHeader(bool is32) if (!is32) { // X64没有了,但是为了代码保留修改幅度不大,所以置0 - BaseOfData = new byte[0];// x64必须置于0 + BaseOfData = [];// x64必须置于0 // x64长度增加的 - int ulonglong = 8; + var ulonglong = 8; ImageBase = new byte[ulonglong]; // 数据基址(RVA) SizeOfStackReserve = new byte[ulonglong]; // 保留栈的大小 SizeOfStackCommit = new byte[ulonglong]; // 初始时指定栈大小 @@ -1483,7 +1489,7 @@ public class ExportDirectory /// /// 函数指针名称集合 /// - public List FunctionNamesByte = new(); + public List FunctionNamesByte = []; public long FileStarIndex = 0; public long FileEndIndex = 0; @@ -1492,8 +1498,8 @@ public class ExportDirectory /// public HashSet FunctionNames() { - HashSet names = new(); - for (int i = 0; i < FunctionNamesByte.Count; i++) + HashSet names = []; + for (var i = 0; i < FunctionNamesByte.Count; i++) names.Add(Encoding.Default.GetString(FunctionNamesByte[i])); return names; } @@ -1564,4 +1570,5 @@ public class DataEntry public long FileStarIndex = 0; public long FileEndIndex = 0; } -#endregion \ No newline at end of file +#endregion +#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释 \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ResultData/LispList.cs b/src/CADShared/ResultData/LispList.cs similarity index 96% rename from src/CAD/IFox.CAD.Shared/ResultData/LispList.cs rename to src/CADShared/ResultData/LispList.cs index c186e4399a2128a030bdab7e3bd30ba7e2aafea6..9de3669231b183ca90d97113bd0c64767e87364b 100644 --- a/src/CAD/IFox.CAD.Shared/ResultData/LispList.cs +++ b/src/CADShared/ResultData/LispList.cs @@ -22,7 +22,7 @@ public LispList(IEnumerable values) : base(values) { } /// /// lisp 列表的值 /// - public virtual List Value + protected virtual List Value { get { @@ -46,7 +46,7 @@ public virtual List Value public override void Add(int code, object? obj) { if (code < 5000) - throw new System.Exception("传入的组码值不是 lisp数据 有效范围!"); + throw new Exception("传入的组码值不是 lisp数据 有效范围!"); Add(new TypedValue(code, obj)); } @@ -164,7 +164,7 @@ public void Add(double x, double y, double z) /// lisp 列表 public void Add(LispList value) { - this.AddRange(value.Value); + AddRange(value.Value); } #endregion diff --git a/src/CAD/IFox.CAD.Shared/ResultData/TypedValueList.cs b/src/CADShared/ResultData/TypedValueList.cs similarity index 90% rename from src/CAD/IFox.CAD.Shared/ResultData/TypedValueList.cs rename to src/CADShared/ResultData/TypedValueList.cs index 16970d2b866ba2acf55c8659dcc4a95b4752aa77..51bfc5b30ff24851a34dd1cb194b508fe0886509 100644 --- a/src/CAD/IFox.CAD.Shared/ResultData/TypedValueList.cs +++ b/src/CADShared/ResultData/TypedValueList.cs @@ -1,23 +1,31 @@ namespace IFoxCAD.Cad; /// -/// 用于集中管理扩展数据/扩展字典/resultbuffer的类 +/// 用于集中管理扩展数据/扩展字典/resultBuffer的类 /// public class TypedValueList : List { #region 构造函数 + /// /// 默认无参构造函数 /// - public TypedValueList() { } + protected TypedValueList() + { + } + /// /// 采用 TypedValue 迭代器构造 TypedValueList /// /// - public TypedValueList(IEnumerable values) : base(values) { } + protected TypedValueList(IEnumerable values) : base(values) + { + } + #endregion #region 添加数据 + /// /// 添加数据 /// @@ -31,26 +39,31 @@ public virtual void Add(int code, object obj) #endregion #region 转换器 + /// /// ResultBuffer 隐式转换到 TypedValueList /// /// ResultBuffer 实例 public static implicit operator TypedValueList(ResultBuffer buffer) => new(buffer.AsArray()); + /// /// TypedValueList 隐式转换到 TypedValue 数组 /// /// TypedValueList 实例 public static implicit operator TypedValue[](TypedValueList values) => values.ToArray(); + /// /// TypedValueList 隐式转换到 ResultBuffer /// /// TypedValueList 实例 public static implicit operator ResultBuffer(TypedValueList values) => new(values); + /// /// TypedValue 数组隐式转换到 TypedValueList /// /// TypedValue 数组 public static implicit operator TypedValueList(TypedValue[] values) => new(values); + /// /// 转换为字符串 /// @@ -60,5 +73,6 @@ public override string ToString() using ResultBuffer a = new(this); return a.ToString(); } + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ResultData/XdataList.cs b/src/CADShared/ResultData/XDataList.cs similarity index 76% rename from src/CAD/IFox.CAD.Shared/ResultData/XdataList.cs rename to src/CADShared/ResultData/XDataList.cs index 94f04d7f106807ce4f3e3d69628f203dbcc57ac7..ba4758cec2d3d1839dec4473bb0447976c7aad96 100644 --- a/src/CAD/IFox.CAD.Shared/ResultData/XdataList.cs +++ b/src/CADShared/ResultData/XDataList.cs @@ -6,18 +6,25 @@ public class XDataList : TypedValueList { #region 构造函数 + /// /// 扩展数据封装类 /// - public XDataList() { } + public XDataList() + { + } /// /// 扩展数据封装类 /// - public XDataList(IEnumerable values) : base(values) { } + public XDataList(IEnumerable values) : base(values) + { + } + #endregion #region 添加数据 + /// /// 添加数据 /// @@ -25,8 +32,8 @@ public XDataList(IEnumerable values) : base(values) { } /// 组码值 public override void Add(int code, object obj) { - if (code < 1000 || code > 1071) - throw new System.Exception("传入的组码值不是 XData 有效范围!"); + if (code is < 1000 or > 1071) + throw new Exception("传入的组码值不是 XData 有效范围!"); Add(new TypedValue(code, obj)); } @@ -47,8 +54,9 @@ public void Add(DxfCode code, object obj) /// 注册名 public bool Contains(string appName) { - bool result = false; - RangeTask(appName, (tv, state, i) => { + var result = false; + RangeTask(appName, (_, state, _) => + { result = true; state.Break(); }); @@ -62,8 +70,9 @@ public bool Contains(string appName) /// 内容 public bool Contains(string appName, object value) { - bool result = false; - RangeTask(appName, (tv, state, i) => { + var result = false; + RangeTask(appName, (tv, state, _) => + { if (tv.Value.Equals(value)) { result = true; @@ -81,24 +90,26 @@ public bool Contains(string appName, object value) /// 返回任务组码的索引 public List GetXdataAppIndex(string appName, DxfCode[] dxfCodes) { - List indexs = new(); - RangeTask(appName, (tv, state, i) => { + List indexes = []; + RangeTask(appName, (tv, _, i) => + { if (dxfCodes.Contains((DxfCode)tv.TypeCode)) - indexs.Add(i); + indexes.Add(i); }); - return indexs; + return indexes; } /// /// 区间任务 /// + /// /// - void RangeTask(string appName, Action action) + private void RangeTask(string appName, Action action) { LoopState state = new(); // 在名称和名称之间找 - int appNameIndex = -1; - for (int i = 0; i < this.Count; i++) + var appNameIndex = -1; + for (var i = 0; i < Count; i++) { if (this[i].TypeCode == (short)DxfCode.ExtendedDataRegAppName) { @@ -107,40 +118,45 @@ void RangeTask(string appName, Action action) appNameIndex = i; continue; } - if (appNameIndex != -1)//找到了下一个名称 - break; - } - if (appNameIndex != -1) // 找下一个的时候,获取任务(移除)的对象 - { - action(this[i], state, i); - if (!state.IsRun) + + if (appNameIndex != -1) //找到了下一个名称 break; } + + if (appNameIndex == -1) continue; // 找下一个的时候,获取任务(移除)的对象 + action(this[i], state, i); + if (!state.IsRun) + break; } } #endregion #region 转换器 + /// /// ResultBuffer 隐式转换到 XDataList /// /// ResultBuffer 实例 - public static implicit operator XDataList(ResultBuffer buffer) => new(buffer.AsArray()); + public static implicit operator XDataList(ResultBuffer? buffer) => new(buffer?.AsArray() ?? []); + /// /// XDataList 隐式转换到 TypedValue 数组 /// /// TypedValueList 实例 public static implicit operator TypedValue[](XDataList values) => values.ToArray(); + /// /// XDataList 隐式转换到 ResultBuffer /// /// TypedValueList 实例 public static implicit operator ResultBuffer(XDataList values) => new(values); + /// /// TypedValue 数组隐式转换到 XDataList /// /// TypedValue 数组 public static implicit operator XDataList(TypedValue[] values) => new(values); + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/ResultData/XRecordDataList.cs b/src/CADShared/ResultData/XRecordDataList.cs similarity index 89% rename from src/CAD/IFox.CAD.Shared/ResultData/XRecordDataList.cs rename to src/CADShared/ResultData/XRecordDataList.cs index 708e1554f1e74a78b63aa752d3fcf8bba5a80312..10b95ba94afd9a12f74f2165aa17463d29e284ac 100644 --- a/src/CAD/IFox.CAD.Shared/ResultData/XRecordDataList.cs +++ b/src/CADShared/ResultData/XRecordDataList.cs @@ -6,18 +6,25 @@ public class XRecordDataList : TypedValueList { #region 构造函数 + /// /// 扩展字典数据封装类 /// - public XRecordDataList() { } + public XRecordDataList() + { + } /// /// 扩展字典数据封装类 /// - public XRecordDataList(IEnumerable values) : base(values) { } + public XRecordDataList(IEnumerable values) : base(values) + { + } + #endregion #region 添加数据 + /// /// 添加数据 /// @@ -26,7 +33,7 @@ public XRecordDataList(IEnumerable values) : base(values) { } public override void Add(int code, object obj) { if (code >= 1000) - throw new System.Exception("传入的组码值不是 XRecordData 有效范围!"); + throw new Exception("传入的组码值不是 XRecordData 有效范围!"); Add(new TypedValue(code, obj)); } @@ -40,28 +47,35 @@ public void Add(DxfCode code, object obj) { Add((int)code, obj); } + #endregion #region 转换器 + /// /// ResultBuffer 隐式转换到 XRecordDataList /// /// ResultBuffer 实例 - public static implicit operator XRecordDataList(ResultBuffer buffer) => new(buffer.AsArray()); + public static implicit operator XRecordDataList(ResultBuffer? buffer) => + buffer is null ? [] : new(buffer.AsArray()); + /// /// XRecordDataList 隐式转换到 TypedValue 数组 /// /// TypedValueList 实例 public static implicit operator TypedValue[](XRecordDataList values) => values.ToArray(); + /// /// XRecordDataList 隐式转换到 ResultBuffer /// /// TypedValueList 实例s public static implicit operator ResultBuffer(XRecordDataList values) => new(values); + /// /// TypedValue 数组隐式转换到 XRecordDataList /// /// TypedValue 数组 public static implicit operator XRecordDataList(TypedValue[] values) => new(values); + #endregion } \ No newline at end of file diff --git a/src/CADShared/Runtime/AcPreferences.cs b/src/CADShared/Runtime/AcPreferences.cs new file mode 100644 index 0000000000000000000000000000000000000000..53c4c9fa212c52f6d68eb54f27d692465272ebdc --- /dev/null +++ b/src/CADShared/Runtime/AcPreferences.cs @@ -0,0 +1,308 @@ +namespace IFoxCAD.Cad; + +/// +/// AcapPreference扩展 +/// +public static class AcPreferences +{ + /// + /// 显示属性 + /// + public static class Display + { + static Display() + { + dynamic preferences = Acap.Preferences; + _acadDisplay = preferences.Display; + } + + private static readonly dynamic _acadDisplay; + + /// + /// 布局显示边距 + /// + public static bool LayoutDisplayMargins + { + get => _acadDisplay.LayoutDisplayMargins; + set => _acadDisplay.LayoutDisplayMargins = value; + } + + /// + /// 布局显示纸 + /// + public static bool LayoutDisplayPaper + { + get => _acadDisplay.LayoutDisplayPaper; + set => _acadDisplay.LayoutDisplayPaper = value; + } + + /// + /// 布局显示纸张阴影 + /// + public static bool LayoutDisplayPaperShadow + { + get => _acadDisplay.LayoutDisplayPaperShadow; + set => _acadDisplay.LayoutDisplayPaperShadow = value; + } + + /// + /// 布局显示绘图设置 + /// + public static bool LayoutShowPlotSetup + { + get => _acadDisplay.LayoutShowPlotSetup; + set => _acadDisplay.LayoutShowPlotSetup = value; + } + + /// + /// 布局创建视口 + /// + public static bool LayoutCreateViewport + { + get => _acadDisplay.LayoutCreateViewport; + set => _acadDisplay.LayoutCreateViewport = value; + } + + /// + /// 显示滚动条 + /// + public static bool DisplayScrollBars + { + get => _acadDisplay.DisplayScrollBars; + set => _acadDisplay.DisplayScrollBars = value; + } + + /// + /// 显示屏幕菜单 + /// + public static bool DisplayScreenMenu + { + get => _acadDisplay.DisplayScreenMenu; + set => _acadDisplay.DisplayScreenMenu = value; + } + + /// + /// 使用光标十字的大小 + /// + public static int CursorSize + { + get => _acadDisplay.CursorSize; + set => _acadDisplay.CursorSize = value; + } + + /// + /// 停靠的可见线 + /// + public static int DockedVisibleLines + { + get => _acadDisplay.DockedVisibleLines; + set => _acadDisplay.DockedVisibleLines = value; + } + + /// + /// 显示光栅图像 + /// + public static bool ShowRasterImage + { + get => _acadDisplay.ShowRasterImage; + set => _acadDisplay.ShowRasterImage = value; + } + + /// + /// 模型空间背景颜色 + /// + public static Color GraphicsWinModelBackgrndColor + { + get + { + uint color = _acadDisplay.GraphicsWinModelBackgrndColor; + return UIntToColor(color); + } + set + { + var color = ColorToUInt(value); + _acadDisplay.GraphicsWinModelBackgrndColor = color; + } + } + + /// + /// 命令栏win文本背景颜色 + /// + public static Color TextWinBackgrndColor + { + get + { + uint color = _acadDisplay.TextWinBackgrndColor; + return UIntToColor(color); + } + set + { + var color = ColorToUInt(value); + _acadDisplay.TextWinBackgrndColor = color; + } + } + + /// + /// 命令栏win文本字体颜色 + /// + public static Color TextWinTextColor + { + get + { + uint color = _acadDisplay.TextWinTextColor; + return UIntToColor(color); + } + set + { + var color = ColorToUInt(value); + _acadDisplay.TextWinTextColor = color; + } + } + + /// + /// 模型鼠标十字颜色 + /// + public static Color ModelCrosshairColor + { + get + { + uint color = _acadDisplay.ModelCrosshairColor; + return UIntToColor(color); + } + set + { + var color = ColorToUInt(value); + _acadDisplay.ModelCrosshairColor = color; + } + } + + /// + /// 布局鼠标十字颜色 + /// + public static Color LayoutCrosshairColor + { + get + { + uint color = _acadDisplay.LayoutCrosshairColor; + return UIntToColor(color); + } + set + { + var color = ColorToUInt(value); + _acadDisplay.LayoutCrosshairColor = color; + } + } + + /// + /// 自动跟踪VEC颜色 + /// + public static Color AutoTrackingVecColor + { + get + { + uint color = _acadDisplay.AutoTrackingVecColor; + return UIntToColor(color); + } + set + { + var color = ColorToUInt(value); + _acadDisplay.AutoTrackingVecColor = color; + } + } + + /// + /// 文本字体 + /// + public static string TextFont + { + get => _acadDisplay.TextFont; + set => _acadDisplay.TextFont = value; + } + + /// + /// 文本字体样式 + /// + public static dynamic TextFontStyle + { + get => _acadDisplay.TextFontStyle; + set => _acadDisplay.TextFontStyle = value; + } + + /// + /// 文本字体大小 + /// + public static int TextFontSize + { + get => _acadDisplay.TextFontSize; + set => _acadDisplay.TextFontSize = value; + } + + /// + /// 历史文本的容量,最多2048行 + /// + public static int HistoryLines + { + get => _acadDisplay.HistoryLines; + set => _acadDisplay.HistoryLines = value; + } + + /// + /// 最大化自动设置窗体 + /// + public static bool MaxAutoCADWindow + { + get => _acadDisplay.MaxAutoCADWindow; + set => _acadDisplay.MaxAutoCADWindow = value; + } + + /// + /// 显示布局选项卡 + /// + public static bool DisplayLayoutTabs + { + get => _acadDisplay.DisplayLayoutTabs; + set => _acadDisplay.DisplayLayoutTabs = value; + } + + /// + /// 图像框架亮点 + /// + public static bool ImageFrameHighlight + { + get => _acadDisplay.ImageFrameHighlight; + set => _acadDisplay.ImageFrameHighlight = value; + } + + /// + /// 真彩色图像 + /// + public static bool TrueColorImages + { + get => _acadDisplay.TrueColorImages; + set => _acadDisplay.TrueColorImages = value; + } + + /// + /// 参照淡化 + /// + public static int XRefFadeIntensity + { + get => _acadDisplay.XRefFadeIntensity; + set => _acadDisplay.XRefFadeIntensity = value; + } + } + + private static uint ColorToUInt(Color color) + { + var c = color.ColorValue; + return (uint)(c.R | c.G << 8 | c.B << 16); + } + + private static Color UIntToColor(uint color) + { + var r = (byte)(color >> 0); + var g = (byte)(color >> 8); + var b = (byte)(color >> 16); + return Color.FromRgb(r, g, b); + } +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/DBTrans.cs b/src/CADShared/Runtime/DBTrans.cs similarity index 54% rename from src/CAD/IFox.CAD.Shared/Runtime/DBTrans.cs rename to src/CADShared/Runtime/DBTrans.cs index 1bd5c741390ad7d74215c3a4c5a82704df5fb841..dd8766bae73f4354053337d0433b2a6493f51eba 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/DBTrans.cs +++ b/src/CADShared/Runtime/DBTrans.cs @@ -1,10 +1,9 @@ namespace IFoxCAD.Cad; - - +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif using System.Diagnostics; using System.IO; -using System.Threading; -using System.Windows.Forms; /// /// 事务栈 @@ -12,35 +11,81 @@ namespace IFoxCAD.Cad; /// [DebuggerDisplay("{DebuggerDisplay,nq}")] [DebuggerTypeProxy(typeof(DBTrans))] -public class DBTrans : IDisposable +public sealed class DBTrans : IDisposable { [DebuggerBrowsable(DebuggerBrowsableState.Never)] - string DebuggerDisplay => ToString(" | "); + private string DebuggerDisplay => ToString(); + + #region 静态函数 + + /// + /// 获取顶层事务 + /// + /// 数据库 + /// 事务对象 + public static Transaction GetTopTransaction(Database database) + { + ArgumentNullException.ThrowIfNull(database); + return database.TransactionManager.TopTransaction ?? throw new Exception("没有顶层事务!"); + } + + /// + /// 获取给定数据库的顶层 DBTrans 事务 + /// + /// 数据库 + /// DBTrans 事务 + /// + public static DBTrans GetTop(Database? database = null) + { + database ??= HostApplicationServices.WorkingDatabase; + ArgumentNullException.ThrowIfNull(database); + var trans = database.TransactionManager.TopTransaction; + ArgumentNullException.ThrowIfNull(trans); + + foreach (var item in _dBTrans) + { + // 匹配事务栈内DBTrans的transaction的指针与数据库的顶层事务的指针 + if (item.Transaction.UnmanagedObject == trans.UnmanagedObject) + { + return item; + } + } + + return Top; + } + + #endregion #region 私有字段 + /// /// 事务栈 /// - static readonly Stack _dBTrans = new(); + private static readonly Stack _dBTrans = new(); + /// /// 文档锁 /// - readonly DocumentLock? _documentLock; + private readonly DocumentLock? _documentLock; + /// /// 是否提交事务 /// - bool _commit; + private bool _commit; + /// /// 文件名 /// - readonly string? _fileName; + private readonly string? _fileName; + #endregion - #region 公开属性 + #region 内部属性 + /// /// 返回当前事务 /// - public static DBTrans Top + internal static DBTrans Top { get { @@ -65,47 +110,56 @@ public static DBTrans Top // 由于大量的函数依赖本属性,强迫用户先开启事务 if (_dBTrans.Count == 0) - throw new ArgumentNullException("事务栈没有任何事务,请在调用前创建:" + nameof(DBTrans)); + throw new System.ArgumentNullException("事务栈没有任何事务,请在调用前创建:" + nameof(DBTrans)); var trans = _dBTrans.Peek(); return trans; } } + + #endregion + + #region 公开属性 + /// /// 文档 /// public Document? Document { get; private set; } + /// /// 命令行 /// public Editor? Editor { get; private set; } + /// /// 事务管理器 /// public Transaction Transaction { get; private set; } + /// /// 数据库 /// public Database Database { get; private set; } + #endregion #region 构造函数 + /// /// 事务栈 /// 默认构造函数,默认为打开当前文档,默认提交事务 /// /// 要打开的文档 /// 事务是否提交 - /// 是否锁文档 - public DBTrans(Document? doc = null, bool commit = true, bool doclock = false) + /// 是否锁文档 + public DBTrans(Document? doc = null, bool commit = true, bool docLock = false) { - Document = doc ?? Acap.DocumentManager.MdiActiveDocument; + Document = doc ?? Acaop.DocumentManager.MdiActiveDocument; Database = Document.Database; Editor = Document.Editor; + if (docLock && Document.LockMode(false) == DocumentLockMode.NotLocked) + _documentLock = Document.LockDocument(); Transaction = Database.TransactionManager.StartTransaction(); _commit = commit; - if (doclock) - _documentLock = Document.LockDocument(); - _dBTrans.Push(this); } @@ -118,6 +172,8 @@ public DBTrans(Document? doc = null, bool commit = true, bool doclock = false) public DBTrans(Database database, bool commit = true) { Database = database; + Document = Acaop.DocumentManager.GetDocument(database); + Editor = Document?.Editor; Transaction = Database.TransactionManager.StartTransaction(); _commit = commit; _dBTrans.Push(this); @@ -132,16 +188,14 @@ public DBTrans(Database database, bool commit = true) /// 开图模式 /// 密码 /// 后台打开false;前台打开true(必须设置CommandFlags.Session) - public DBTrans(string fileName, - bool commit = true, - FileOpenMode fileOpenMode = FileOpenMode.OpenForReadAndWriteNoShare, - string? password = null, - bool activeOpen = false) + public DBTrans(string fileName, bool commit = true, + FileOpenMode fileOpenMode = FileOpenMode.OpenForReadAndWriteNoShare, + string? password = null, bool activeOpen = false) { - if (fileName == null || string.IsNullOrEmpty(fileName.Trim())) - throw new ArgumentNullException(nameof(fileName)); + if (string.IsNullOrWhiteSpace(fileName)) + throw new System.ArgumentNullException(nameof(fileName)); - _fileName = fileName.Replace("/", "\\");// doc.Name总是"D:\\JX.dwg" + _fileName = fileName.Replace("/", "\\"); // doc.Name总是"D:\\JX.dwg" // 此处若为失败的文件名,那么保存的时候就会丢失名称, // 因此用 _fileName 储存 @@ -161,9 +215,8 @@ public DBTrans(string fileName, } else { - var doc = Acap.DocumentManager - .Cast() - .FirstOrDefault(doc => !doc.IsDisposed && doc.Name == _fileName); + var doc = Acaop.DocumentManager.Cast() + .FirstOrDefault(doc => !doc.IsDisposed && doc.Name == _fileName); if (activeOpen) { @@ -173,17 +226,19 @@ public DBTrans(string fileName, { // 设置命令标记: CommandFlags.Session // 若没有设置: Open()之后的会进入中断状态(不会执行,直到切换文档ctrl+tab或者关闭文档) - doc = Acap.DocumentManager.Open(fileName, fileOpenMode == FileOpenMode.OpenForReadAndReadShare, password); + doc = Acaop.DocumentManager.Open(fileName, + fileOpenMode == FileOpenMode.OpenForReadAndReadShare, password); } catch (Exception e) { throw new IOException($"错误:此文件打开错误:{fileName}\n错误信息:{e.Message}"); } } + // 设置命令标记: CommandFlags.Session // 若没有设置: doc.IsActive 会异常 if (!doc.IsActive) - Acap.DocumentManager.MdiActiveDocument = doc; + Acaop.DocumentManager.MdiActiveDocument = doc; // Open()是跨文档,所以必须要锁文档 // 否则 Editor?.Redraw() 的 tm.QueueForGraphicsFlush() 将报错提示文档锁 @@ -204,12 +259,9 @@ public DBTrans(string fileName, } else { -#if ac2008 - Database.ReadDwgFile(_fileName, FileOpenModeHelper.GetFileShare(fileOpenMode), true, password); -#else Database.ReadDwgFile(_fileName, fileOpenMode, true, password); -#endif } + Database.CloseInput(true); } else @@ -225,9 +277,11 @@ public DBTrans(string fileName, _commit = commit; _dBTrans.Push(this); } + #endregion #region 类型转换 + /// /// 隐式转换为Transaction /// @@ -237,6 +291,7 @@ public static implicit operator Transaction(DBTrans tr) { return tr.Transaction; } + #endregion #region 符号表 @@ -244,103 +299,170 @@ public static implicit operator Transaction(DBTrans tr) /// /// 块表 /// - public SymbolTable BlockTable => _BlockTable ??= new(this, Database.BlockTableId); - SymbolTable? _BlockTable; + public SymbolTable BlockTable => + _blockTable ??= new(this, Database.BlockTableId); + + private SymbolTable? _blockTable; + /// /// 当前绘图空间 /// - public BlockTableRecord CurrentSpace => BlockTable.GetRecord(Database.CurrentSpaceId)!; + public BlockTableRecord CurrentSpace + { + get + { + if (_currentSpace is null || Database.CurrentSpaceId != _lastCurrentSpaceId) + { + _lastCurrentSpaceId = Database.CurrentSpaceId; + _currentSpace = BlockTable.GetRecord(Database.CurrentSpaceId)!; + } + + return _currentSpace; + } + } + + private ObjectId _lastCurrentSpaceId = ObjectId.Null; + private BlockTableRecord? _currentSpace; + /// /// 模型空间 /// - public BlockTableRecord ModelSpace => BlockTable.GetRecord(BlockTable.CurrentSymbolTable[BlockTableRecord.ModelSpace])!; + public BlockTableRecord ModelSpace => + _modelSpace ??= + BlockTable.GetRecord(BlockTable.CurrentSymbolTable[BlockTableRecord.ModelSpace])!; + + private BlockTableRecord? _modelSpace; + /// /// 图纸空间 /// - public BlockTableRecord PaperSpace => BlockTable.GetRecord(BlockTable.CurrentSymbolTable[BlockTableRecord.PaperSpace])!; + public BlockTableRecord PaperSpace => + BlockTable.GetRecord(BlockTable.CurrentSymbolTable[BlockTableRecord.PaperSpace])!; + /// /// 层表 /// - public SymbolTable LayerTable => _LayerTable ??= new(this, Database.LayerTableId); - SymbolTable? _LayerTable; + public SymbolTable LayerTable => + _layerTable ??= new(this, Database.LayerTableId); + + private SymbolTable? _layerTable; + /// /// 文字样式表 /// - public SymbolTable TextStyleTable => _TextStyleTable ??= new(this, Database.TextStyleTableId); - SymbolTable? _TextStyleTable; + public SymbolTable TextStyleTable => + _textStyleTable ??= new(this, Database.TextStyleTableId); + + private SymbolTable? _textStyleTable; + /// /// 注册应用程序表 /// - public SymbolTable RegAppTable => _RegAppTable ??= new(this, Database.RegAppTableId); - SymbolTable? _RegAppTable; + public SymbolTable RegAppTable => + _regAppTable ??= new(this, Database.RegAppTableId); + + private SymbolTable? _regAppTable; + /// /// 标注样式表 /// - public SymbolTable DimStyleTable => _DimStyleTable ??= new(this, Database.DimStyleTableId); - SymbolTable? _DimStyleTable; + public SymbolTable DimStyleTable => + _dimStyleTable ??= new(this, Database.DimStyleTableId); + + private SymbolTable? _dimStyleTable; + /// /// 线型表 /// - public SymbolTable LinetypeTable => _LinetypeTable ??= new(this, Database.LinetypeTableId); - SymbolTable? _LinetypeTable; + public SymbolTable LinetypeTable => + _linetypeTable ??= new(this, Database.LinetypeTableId); + + private SymbolTable? _linetypeTable; + /// /// 用户坐标系表 /// - public SymbolTable UcsTable => _UcsTable ??= new(this, Database.UcsTableId); - SymbolTable? _UcsTable; + public SymbolTable UcsTable => + _ucsTable ??= new(this, Database.UcsTableId); + + private SymbolTable? _ucsTable; + /// /// 视图表 /// - public SymbolTable ViewTable => _ViewTable ??= new(this, Database.ViewTableId); - SymbolTable? _ViewTable; + public SymbolTable ViewTable => + _viewTable ??= new(this, Database.ViewTableId); + + private SymbolTable? _viewTable; + /// /// 视口表 /// - public SymbolTable ViewportTable => _ViewportTable ??= new(this, Database.ViewportTableId); - SymbolTable? _ViewportTable; + public SymbolTable ViewportTable => + _viewportTable ??= new(this, Database.ViewportTableId); + + private SymbolTable? _viewportTable; + #endregion #region 字典 + /// /// 命名对象字典 /// - public DBDictionary NamedObjectsDict => GetObject(Database.NamedObjectsDictionaryId)!; + public DBDictionary NamedObjectsDict => + GetObject(Database.NamedObjectsDictionaryId)!; + /// /// 组字典 /// public DBDictionary GroupDict => GetObject(Database.GroupDictionaryId)!; + /// /// 多重引线样式字典 /// - public DBDictionary MLeaderStyleDict => GetObject(Database.MLeaderStyleDictionaryId)!; + public DBDictionary MLeaderStyleDict => + GetObject(Database.MLeaderStyleDictionaryId)!; + /// /// 多线样式字典 /// + // ReSharper disable once InconsistentNaming public DBDictionary MLStyleDict => GetObject(Database.MLStyleDictionaryId)!; + /// /// 材质字典 /// public DBDictionary MaterialDict => GetObject(Database.MaterialDictionaryId)!; + /// /// 表格样式字典 /// public DBDictionary TableStyleDict => GetObject(Database.TableStyleDictionaryId)!; + /// /// 视觉样式字典 /// - public DBDictionary VisualStyleDict => GetObject(Database.VisualStyleDictionaryId)!; + public DBDictionary VisualStyleDict => + GetObject(Database.VisualStyleDictionaryId)!; + /// /// 颜色字典 /// public DBDictionary ColorDict => GetObject(Database.ColorDictionaryId)!; + /// /// 打印设置字典 /// - public DBDictionary PlotSettingsDict => GetObject(Database.PlotSettingsDictionaryId)!; + public DBDictionary PlotSettingsDict => + GetObject(Database.PlotSettingsDictionaryId)!; + /// /// 打印样式表名字典 /// - public DBDictionary PlotStyleNameDict => GetObject(Database.PlotStyleNameDictionaryId)!; + public DBDictionary PlotStyleNameDict => + GetObject(Database.PlotStyleNameDictionaryId)!; + /// /// 布局字典 /// @@ -352,211 +474,57 @@ public static implicit operator Transaction(DBTrans tr) /// public DBDictionary DataLinkDict => GetObject(Database.DataLinkDictionaryId)!; -#if !ac2009 /// /// 详细视图样式字典 /// - public DBDictionary DetailViewStyleDict => GetObject(Database.DetailViewStyleDictionaryId)!; + public DBDictionary DetailViewStyleDict => + GetObject(Database.DetailViewStyleDictionaryId)!; + /// /// 剖面视图样式字典 /// - public DBDictionary SectionViewStyleDict => GetObject(Database.SectionViewStyleDictionaryId)!; -#endif + public DBDictionary SectionViewStyleDict => + GetObject(Database.SectionViewStyleDictionaryId)!; + #endif + #endregion #region 获取对象 + /// - /// 根据对象id获取图元对象 + /// 根据对象id获取对象 /// - /// 要获取的图元对象的类型 /// 对象id /// 打开模式,默认为只读 /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 - /// 图元对象,类型不匹配时返回 - public T? GetObject(ObjectId id, - OpenMode openMode = OpenMode.ForRead, - bool openErased = false, - bool openLockedLayer = false) where T : DBObject + /// 数据库DBObject对象 + public DBObject GetObject(ObjectId id, OpenMode openMode = OpenMode.ForRead, + bool openErased = false, bool openLockedLayer = false) { - return Transaction.GetObject(id, openMode, openErased, openLockedLayer) as T; - } - - /// - /// 根据对象句柄字符串获取对象Id - /// - /// 句柄字符串 - /// 对象id - public ObjectId GetObjectId(string handleString) - { - var hanle = new Handle(Convert.ToInt64(handleString, 16)); - // return Database.GetObjectId(false, hanle, 0); - return DBTransHelper.TryGetObjectId(Database, hanle); - } - #endregion - - #region 保存文件 - /// - /// 保存文件 - /// - /// - public void SaveDwgFile(DwgVersion version = DwgVersion.AC1800) - { - SaveFile(version); - } - - /// - /// 保存文件
- ///
- /// 默认2004dwg;若保存dxf则需要在路径输入扩展名 - /// 为true时候无效,将变为自动识别环境变量 - /// 另存为文件,前台将调用时它将无效,将变为弹出面板 - /// 保存路径失败的提示 - public void SaveFile(DwgVersion version = DwgVersion.AC1800, - bool automatic = true, - string? saveAsFile = null, - bool echoes = true) - { - // 遍历当前所有文档,文档必然是前台的 - Document? doc = null; - foreach (Document docItem in Acap.DocumentManager) - { - if (docItem.Database.Filename == this.Database.Filename) - { - doc = docItem; - break; - } - } - // 前台开图,使用命令保存;不需要切换文档 - if (doc != null) - { - if (saveAsFile == null) - doc.SendStringToExecute("_qsave\n", false, true, true); - else - /// 无法把 给这个面板 - doc.SendStringToExecute($"_Saveas\n", false, true, true); - return; - } - - // 后台开图,用数据库保存 - string? fileMsg; - bool creatFlag = false; - saveAsFile = saveAsFile?.Trim(); - if (string.IsNullOrEmpty(saveAsFile)) - { - fileMsg = _fileName; - saveAsFile = fileMsg; - //creatFlag = true; - } - else - { - fileMsg = saveAsFile; - - // 路径失败也保存到桌面 - var path = Path.GetDirectoryName(saveAsFile); - if (string.IsNullOrEmpty(path)) - { - creatFlag = true; - } - else if (!Directory.Exists(path)) - { - try { Directory.CreateDirectory(path); } - catch { creatFlag = true; } - } - - // 文件名缺失时 - if (!creatFlag && - string.IsNullOrEmpty(Path.GetFileName(saveAsFile).Trim())) - creatFlag = true; - } - if (saveAsFile != null) - { - var fileNameWith = Path.GetFileNameWithoutExtension(saveAsFile).Trim(); - if (string.IsNullOrEmpty(fileNameWith)) - creatFlag = true; - } - else - { - creatFlag = true; - } - - if (creatFlag) - { - var (error, file) = GetOrCreateSaveAsFile(); - if (echoes && error) - MessageBox.Show($"错误参数:\n{fileMsg}\n\n它将保存:\n{file}", "错误的文件路径"); - saveAsFile = file; - } - - if (Path.GetExtension(saveAsFile).ToLower().Contains("dxf")) - { - // dxf用任何版本号都会报错 -#if acad || gcad - Database.DxfOut(saveAsFile, 7, true); -#endif - -#if zcad // 中望这里没有测试 - Database.DxfOut(saveAsFile, 7, version, true); -#endif - return; - } - - if (automatic) - version = Env.GetDefaultDwgVersion(); - - // dwg需要版本号,而dxf不用,dwg用dxf版本号会报错 - // 若扩展名和版本号冲突,按照扩展名为准 - if (version.IsDxfVersion()) - version = DwgVersion.Current; - - Database.SaveAs(saveAsFile, version); + return Transaction.GetObject(id, openMode, openErased, openLockedLayer); } - /// - /// 获取文件名,无效的话就制造 + /// 根据对象id获取图元对象 /// - /// - (bool error, string path) GetOrCreateSaveAsFile() + /// 要获取的图元对象的类型 + /// 对象id + /// 打开模式,默认为只读 + /// 是否打开已删除对象,默认为不打开 + /// 是否打开锁定图层对象,默认为不打开 + /// 图元对象 + public T? GetObject(ObjectId id, OpenMode openMode = OpenMode.ForRead, + bool openErased = false, bool openLockedLayer = false) where T : DBObject { - var file = Database.Filename; - if (!string.IsNullOrEmpty(file)) - return (false, file); - - // 为了防止用户输入了错误的路径造成无法保存, - // 所以此处将进行保存到桌面, - // 而不是弹出警告就结束 - // 防止前台关闭了所有文档导致没有Editor,所以使用 MessageBox 发送警告 - var fileName = Path.GetFileNameWithoutExtension(_fileName).Trim(); - var fileExt = Path.GetExtension(_fileName); - - if (string.IsNullOrEmpty(fileName)) - fileName = DateTime.Now.ToString("--yyMMdd--hhmmssffff"); - if (string.IsNullOrEmpty(fileExt)) - fileExt = ".dwg"; - - // 构造函数(fileName)用了不存在的路径进行后台打开,就会出现此问题 - // 测试命令 FileNotExist - var dir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) - + "\\后台保存出错的文件\\"; - - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - file = dir + fileName + fileExt; - while (File.Exists(file)) - { - var time = DateTime.Now.ToString("--yyMMdd--hhmmssffff"); - file = dir + fileName + time + fileExt; - Thread.Sleep(100); - } - return (true, file); + return Transaction.GetObject(id, openMode, openErased, openLockedLayer) as T; } #endregion #region 前台后台任务 + /// /// 前台后台任务分别处理 /// @@ -569,11 +537,10 @@ public void SaveFile(DwgVersion version = DwgVersion.AC1800, /// /// 委托 /// 开启单行文字偏移处理 + // ReSharper disable once InconsistentNaming public void Task(Action action, bool handlingDBTextDeviation = true) { - //if (action == null) - // throw new ArgumentNullException(nameof(action)); - action.NotNull(nameof(action)); + ArgumentNullException.ThrowIfNull(action); // 前台开图 || 后台直接处理 if (Document != null || !handlingDBTextDeviation) { @@ -584,13 +551,14 @@ public void Task(Action action, bool handlingDBTextDeviation = true) // 后台 // 这种情况发生在关闭了所有文档之后,进行跨进程通讯 // 此处要先获取激活的文档,不能直接获取当前数据库否则异常 - var dm = Acap.DocumentManager; + var dm = Acaop.DocumentManager; var doc = dm.MdiActiveDocument; if (doc == null) { action.Invoke(); return; } + // 处理单行文字偏移 // 前台绑定参照的时候不能用它,否则抛出异常:eWasErased // 所以本函数自动识别前后台做处理 @@ -599,9 +567,11 @@ public void Task(Action action, bool handlingDBTextDeviation = true) action.Invoke(); HostApplicationServices.WorkingDatabase = dbBak; } + #endregion #region IDisposable接口相关函数 + /// /// 取消事务 /// @@ -620,7 +590,10 @@ public void Commit() Dispose(); } - public bool IsDisposed { get; private set; } = false; + /// + /// 是否释放事务 + /// + public bool IsDisposed { get; private set; } /// /// 手动调用释放 @@ -639,74 +612,81 @@ public void Dispose() Dispose(false); } - protected virtual void Dispose(bool disposing) + /// + /// 释放函数 + /// + /// + private void Dispose(bool disposing) { /* 事务dispose流程: * 1. 根据传入的参数确定是否提交,true为提交,false为不提交 * 2. 如果锁文档就将文档锁dispose * 3. 不管是否提交,既然进入dispose,就要将事务栈的当前事务弹出 - * 注意这里的事务栈不是cad的事务管理器,而是dbtrans的事务 + * 注意这里的事务栈不是cad的事务管理器,而是DBTrans的事务 * 4. 清理非托管的字段 */ // 不重复释放,并设置已经释放 - if (IsDisposed) return; - IsDisposed = true; + if (IsDisposed) + return; - // 致命错误时候此处是空,直接跳过 - if (Transaction != null) + if (disposing) { - if (_commit) - { - // 刷新队列(后台不刷新) - Editor?.Redraw(); - // 调用cad的事务进行提交,释放托管状态(托管对象) - Transaction.Commit(); - } - else + // 致命错误时候此处是空,直接跳过 + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (Transaction != null) { - // 否则取消所有的修改 - Transaction.Abort(); + if (_commit) + { + // 调用cad的事务进行提交,释放托管状态(托管对象) + Transaction.Commit(); + } + else + { + // 防止事务回滚造成的视图回滚 + using var vtr = Editor?.GetCurrentView(); + // 否则取消所有的修改 + Transaction.Abort(); + if (Editor is not null && vtr is not null) + Editor.SetCurrentView(vtr); + } + + // 将cad事务进行销毁 + if (!Transaction.IsDisposed) + Transaction.Dispose(); } - // 将cad事务进行销毁 - if (!Transaction.IsDisposed) - Transaction.Dispose(); + // 将文档锁销毁 + _documentLock?.Dispose(); + + //直接以文件 new 事务,最好及时释放 Database + if (!string.IsNullOrWhiteSpace(_fileName)) + Database.Dispose(); } - // 将文档锁销毁 - _documentLock?.Dispose(); // 将当前事务栈弹栈 _dBTrans.Pop(); + IsDisposed = true; } + #endregion #region ToString - public override string ToString() - { - return ToString(null, null); - } - public string ToString(IFormatProvider? provider) - { - return ToString(null, provider); - } - public string ToString(string? format = null, IFormatProvider? formatProvider = null) - { - List lines = new(); - lines.Add($"StackCount = {_dBTrans.Count}"); - lines.Add($"_fileName = \"{_fileName}\""); - lines.Add($"_commit = {_commit}"); - lines.Add($"_documentLock = {_documentLock != null}"); - lines.Add($"Document = {Document != null}"); - lines.Add($"Editor = {Editor != null}"); - lines.Add($"Transaction = {Transaction != null}"); - lines.Add($"Database = {Database != null}"); + /// + public override string ToString() - if (!string.IsNullOrEmpty(format)) - return string.Join(format, lines.ToArray()); + { + List lines = + [ + $"StackCount = {_dBTrans.Count}", $"_fileName = \"{_fileName}\"", + $"_commit = {_commit}", $"_documentLock = {_documentLock != null}", + $"Document = {Document != null}", $"Editor = {Editor != null}", + $"Transaction = {Transaction.UnmanagedObject}", $"Database = {Database.Filename}" + ]; return string.Join("\n", lines.ToArray()); } + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/Env.cs b/src/CADShared/Runtime/Env.cs similarity index 57% rename from src/CAD/IFox.CAD.Shared/Runtime/Env.cs rename to src/CADShared/Runtime/Env.cs index df64594bfe7f88869f8bd27cf688cbecb143d238..fd7b3539acbad80ee637698bb1141c22b4508279 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/Env.cs +++ b/src/CADShared/Runtime/Env.cs @@ -1,13 +1,16 @@ +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif - +// ReSharper disable StringLiteralTypo namespace IFoxCAD.Cad; /// /// 系统管理类 /// -/// 封装了一些系统 osmode;cmdecho;dimblk 系统变量
-/// 封装了常用的 文档 编辑器 数据库等对象为静态变量
-/// 封装了配置页面的注册表信息获取函数 +/// 封装了一些系统 osmode;cmdecho;dimblk 系统变量
+/// 封装了常用的 文档 编辑器 数据库等对象为静态变量
+/// 封装了配置页面的注册表信息获取函数 ///
///
public static class Env @@ -22,7 +25,7 @@ public static class Env /// /// 当前文档 /// - public static Document Document => Acap.DocumentManager.MdiActiveDocument; + public static Document Document => Acaop.DocumentManager.MdiActiveDocument; /// /// 编辑器对象 @@ -47,13 +50,12 @@ public static class Env /// 对象 public static object GetCurrentProfileProperty(string subSectionName, string propertyName) { - UserConfigurationManager ucm = Acap.UserConfigurationManager; - IConfigurationSection cpf = ucm.OpenCurrentProfile(); - IConfigurationSection ss = cpf.OpenSubsection(subSectionName); + var ucm = Acaop.UserConfigurationManager; + var cpf = ucm.OpenCurrentProfile(); + var ss = cpf.OpenSubsection(subSectionName); return ss.ReadProperty(propertyName, ""); } - /// /// 获取对话框配置的数据 /// @@ -61,8 +63,8 @@ public static object GetCurrentProfileProperty(string subSectionName, string pro /// 配置项 public static IConfigurationSection GetDialogSection(object dialog) { - UserConfigurationManager ucm = Acap.UserConfigurationManager; - IConfigurationSection ds = ucm.OpenDialogSection(dialog); + var ucm = Acaop.UserConfigurationManager; + var ds = ucm.OpenDialogSection(dialog); return ds; } @@ -73,31 +75,29 @@ public static IConfigurationSection GetDialogSection(object dialog) /// 配置项 public static IConfigurationSection GetGlobalSection(string propertyName) { - UserConfigurationManager ucm = Acap.UserConfigurationManager; - IConfigurationSection gs = ucm.OpenGlobalSection(); - IConfigurationSection ss = gs.OpenSubsection(propertyName); + var ucm = Acaop.UserConfigurationManager; + var gs = ucm.OpenGlobalSection(); + var ss = gs.OpenSubsection(propertyName); return ss; } #endif + #endregion Preferences #region Enum + /// - /// 控制在AutoLISP的command函数运行时AutoCAD是否回显提示和输入, 为显示, 为不显示 + /// 获取Cad当前是否有活动命令 /// - public static bool CmdEcho - { - get => Convert.ToInt16(Acap.GetSystemVariable("cmdecho")) == 1; - set => Acap.SetSystemVariable("cmdecho", Convert.ToInt16(value)); - } + public static bool CmdActive => Convert.ToBoolean(Acaop.GetSystemVariable("CMDACTIVE")); /// - /// 控制在光标是否为正交模式, 为打开正交, 为关闭正交 + /// 控制在光标是否为正交模式, 为打开正交, 为关闭正交 /// public static bool OrthoMode { - get => Convert.ToInt16(Acap.GetSystemVariable("ORTHOMODE")) == 1; - set => Acap.SetSystemVariable("ORTHOMODE", Convert.ToInt16(value)); + get => Convert.ToInt16(Acaop.GetSystemVariable("ORTHOMODE")) == 1; + set => Acaop.SetSystemVariable("ORTHOMODE", Convert.ToInt16(value)); } #region Dimblk @@ -110,7 +110,7 @@ public enum DimblkType /// /// 实心闭合 /// - Defult, + Default, /// /// 点 @@ -208,9 +208,9 @@ public enum DimblkType ArchTick } - private static readonly Dictionary dimdescdict = new() + private static readonly Dictionary _dimDescDict = new() { - { "实心闭合", DimblkType.Defult }, + { "实心闭合", DimblkType.Default }, { "点", DimblkType.Dot }, { "小点", DimblkType.DotSmall }, { "空心点", DimblkType.DotBlank }, @@ -230,8 +230,7 @@ public enum DimblkType { "基准三角形", DimblkType.DatumBlank }, { "完整标记", DimblkType.Integral }, { "建筑标记", DimblkType.ArchTick }, - - { "", DimblkType.Defult }, + { "", DimblkType.Default }, { "_DOT", DimblkType.Dot }, { "_DOTSMALL", DimblkType.DotSmall }, { "_DOTBLANK", DimblkType.DotBlank }, @@ -250,11 +249,9 @@ public enum DimblkType { "_DATUMFILLED", DimblkType.DatumFilled }, { "_DATUMBLANK", DimblkType.DatumBlank }, { "_INTEGRAL", DimblkType.Integral }, - { "_ARCHTICK", DimblkType.ArchTick }, + { "_ARCHTICK", DimblkType.ArchTick } }; - - /// /// 标注箭头属性 /// @@ -262,26 +259,13 @@ public static DimblkType Dimblk { get { - string s = ((string)Acap.GetSystemVariable("dimblk")).ToUpper(); - // if (string.IsNullOrEmpty(s)) - // { - // return DimblkType.Defult; - // } - // else - // { - // if (dimdescdict.TryGetValue(s, out DimblkType value)) - // { - // return value; - // } - // return s.ToEnum(); - // // return s.FromDescName(); - // } - return dimdescdict[s]; + var s = ((string)Acaop.GetSystemVariable("dimblk")).ToUpper(); + return _dimDescDict[s]; } set { - string s = GetDimblkName(value); - Acap.SetSystemVariable("dimblk", s); + var s = GetDimblkName(value); + Acaop.SetSystemVariable("dimblk", s); } } @@ -292,12 +276,7 @@ public static DimblkType Dimblk /// 箭头名 public static string GetDimblkName(DimblkType dimblk) { - return - dimblk == DimblkType.Defult - ? - "." - : - "_" + dimblk.GetName(); + return dimblk == DimblkType.Default ? "." : "_" + dimblk.GetName(); } /// @@ -307,10 +286,10 @@ public static string GetDimblkName(DimblkType dimblk) /// 箭头ID public static ObjectId GetDimblkId(DimblkType dimblk) { - DimblkType oldDimblk = Dimblk; + var oldDimblk = Acaop.GetSystemVariable("dimblk"); Dimblk = dimblk; - ObjectId id = HostApplicationServices.WorkingDatabase.Dimblk; - Dimblk = oldDimblk; + var id = HostApplicationServices.WorkingDatabase.Dimblk; + Acaop.SetSystemVariable("dimblk", string.IsNullOrWhiteSpace(oldDimblk.ToString())? "." : oldDimblk); return id; } @@ -321,6 +300,7 @@ public static ObjectId GetDimblkId(DimblkType dimblk) /// /// 捕捉模式系统变量类型 /// + [Flags] public enum OSModeType { /// @@ -396,125 +376,116 @@ public enum OSModeType /// /// 平行 /// - Parallel = 8192 + Parallel = 8192, + + /// + /// 禁用 + /// + Disabled = 16384, } /// /// 捕捉模式系统变量 /// + // ReSharper disable once InconsistentNaming public static OSModeType OSMode { - get - { - return (OSModeType)Convert.ToInt16(Acap.GetSystemVariable("osmode")); - } - set - { - Acap.SetSystemVariable("osmode", (int)value); - } - } - /// - /// 捕捉模式osm1是否包含osm2 - /// - /// 原模式 - /// 要比较的模式 - /// 包含时返回 ,不包含时返回 - public static bool Include(this OSModeType osm1, OSModeType osm2) - { - return (osm1 & osm2) == osm2; + get => (OSModeType)Convert.ToInt16(Acaop.GetSystemVariable("osmode")); + set => Acaop.SetSystemVariable("osmode", (int)value); } - #endregion OsMode + #endregion OsMode - private static string GetName(this T value) + private static string? GetName(this T value) { - return Enum.GetName(typeof(T), value); + return Enum.GetName(typeof(T), value!); } #endregion Enum #region 系统变量 + /// /// 获取cad系统变量 /// /// 变量名 /// 变量值 - public static object GetVar(string? varName) + public static object GetVar(string varName) { - return Acap.GetSystemVariable(varName); + return Acaop.GetSystemVariable(varName); } + /// - /// 设置cad系统变量
- /// 0x01 建议先获取现有变量值和设置的是否相同,否则直接设置会发生异常
- /// 0x02 建议锁文档,否则 Psltscale 设置发生异常
+ /// 设置cad系统变量
+ /// 0x01 建议先获取现有变量值和设置的是否相同,否则直接设置会发生异常
+ /// 0x02 建议锁文档,否则 Psltscale 设置发生异常
/// 发生异常的时候vs输出窗口会打印一下,但是如果不介意也没啥问题 ///
/// 变量名 /// 变量值 /// 输出异常,默认true;此设置仅为打印到命令栏,无法控制vs输出 - public static void SetVar(string? varName, object? value, bool echo = true) + public static void SetVar(string varName, object value, bool echo = true) { try { - Acap.SetSystemVariable(varName, value); + Acaop.SetSystemVariable(varName, value); } - catch (System.Exception) + catch (Exception) { if (echo) - Env.Print($"{varName} 是不存在的变量!"); + Print($"{varName} 是不存在的变量!"); } } + #endregion #region 环境变量 -#if acad -#if NET35 - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedGetEnv")] - static extern int AcedGetEnv(string? envName, StringBuilder ReturnValue); - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("acad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedSetEnv")] - static extern int AcedSetEnv(string? envName, StringBuilder NewValue); -#else - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("accore.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedGetEnv")] - static extern int AcedGetEnv(string? envName, StringBuilder ReturnValue); - - [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("accore.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedSetEnv")] - static extern int AcedSetEnv(string? envName, StringBuilder NewValue); -#endif +#if acad + [SuppressUnmanagedCodeSecurity] + [DllImport("accore.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "acedGetEnv")] + private static extern int AcedGetEnv(string? envName, StringBuilder returnValue); + + [SuppressUnmanagedCodeSecurity] + [DllImport("accore.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "acedSetEnv")] + private static extern int AcedSetEnv(string? envName, StringBuilder newValue); #endif - #if gcad [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("gced.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gcedGetEnv")] + [DllImport("gced.dll", CharSet = CharSet.Auto, CallingConvention = + CallingConvention.Cdecl, EntryPoint = + "gcedGetEnv")] static extern int AcedGetEnv(string? envName, StringBuilder ReturnValue); [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("gced.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "gcedSetEnv")] + [DllImport("gced.dll", CharSet = CharSet.Auto, CallingConvention = + CallingConvention.Cdecl, EntryPoint = + "gcedSetEnv")] static extern int AcedSetEnv(string? envName, StringBuilder NewValue); #endif // TODO: 中望没有测试,此处仅为不报错;本工程所有含有"中望"均存在问题 #if zcad [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("zced.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "zcedGetEnv")] - static extern int AcedGetEnv(string? envName, StringBuilder ReturnValue); + [DllImport("zwcad.exe", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?zcedGetEnv@@YAHPEB_WPEA_W_K@Z")]//名称大小写不能换 + private static extern int AcedGetEnv(string? envName, StringBuilder returnValue); [System.Security.SuppressUnmanagedCodeSecurity] - [DllImport("zced.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, EntryPoint = "zcedSetEnv")] - static extern int AcedSetEnv(string? envName, StringBuilder NewValue); + [DllImport("zwcad.exe", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "zcedSetEnv")] + private static extern int AcedSetEnv(string? envName, StringBuilder newValue); #endif /// - /// 读取acad环境变量
+ /// 读取acad环境变量
/// 也能获取win环境变量 ///
/// 变量名 - /// 返回值从不为null,需判断 - public static string GetEnv(string? name) + /// 返回值从不为null,需判断 + public static string GetEnv(string name) { // 它将混合查询以下路径: // acad2008注册表路径: 计算机\HKEY_CURRENT_USER\SOFTWARE\Autodesk\AutoCAD\R17.1\ACAD-6001:804\FixedProfile\General @@ -524,98 +495,142 @@ public static string GetEnv(string? name) // GetEnv("Path")长度很长: // 可用内存 (最新格式) 1 MB (标准格式) // https://docs.microsoft.com/zh-cn/windows/win32/sysinfo/registry-element-size-limits - var sbRes = new StringBuilder(1 << 23); _ = AcedGetEnv(name, sbRes); return sbRes.ToString(); } /// - /// 设置acad环境变量
- /// 它是不会报错的,但是直接设置会写入注册表的,
- /// 如果是设置高低版本cad不同的变量,建议先读取判断再设置
+ /// 设置acad环境变量
+ /// 它是不会报错的,但是直接设置会写入注册表的,
+ /// 如果是设置高低版本cad不同的变量,建议先读取判断再设置
///
/// 变量名 /// 变量值 /// - public static int SetEnv(string? name, string? var) + public static int SetEnv(string name, string var) { return AcedSetEnv(name, new StringBuilder(var)); } - #endregion - #region win环境变量/由于 Aced的 能够同时获取此变量与cad内的,所以废弃 - // /// - // /// 获取系统环境变量 - // /// - // /// 变量名 - // /// 指定的环境变量的值;或者如果找不到环境变量,则返回 null - // public static string? GetEnv(string? var) - // { - // // 从当前进程或者从当前用户或本地计算机的 Windows 操作系统注册表项检索环境变量的值 - // // 用户: 计算机\HKEY_CURRENT_USER\Environment - // // 系统: 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment - // return Environment.GetEnvironmentVariable(var); - // } - // /// - // /// 设置系统环境变量 - // /// - // /// 变量名 - // /// 变量值 - // public static void SetEnv(string? var, string? value) - // { - // // 创建、修改或删除当前进程中或者为当前用户或本地计算机保留的 Windows 操作系统注册表项中存储的环境变量 - // Environment.SetEnvironmentVariable(var, value); - // } #endregion + #region 支持文件目录 + + /// + /// 添加目录至CAD支持搜索的路径 + /// + /// 目录 + public static void AppendSupportPath(params IEnumerable folders) + { + SupportPathEx.Add(folders); + } + + /// + /// 删除支持搜索文件目录 + /// + /// 目录 + public static void RemoveSupportPath(params IEnumerable folders) + { + SupportPathEx.Remove(folders); + } + + /// + /// 获取支持搜索文件目录 + /// + /// 支持搜索文件目录列表 + public static List GetSupportPath() + { + return SupportPathEx.Get(); + } + + /// + /// 添加目录至CAD受信任的位置 + /// + /// 目录 + public static void AppendTrustedPath(params string[] folders) + { + TrustedPathEx.Add(folders); + } + + /// + /// 移除信任目录 + /// + /// 目录 + public static void RemoveTrustedPath(params string[] folders) + { + TrustedPathEx.Remove(folders); + } + + /// + /// 获取受信任的位置 + /// + /// 受信任的位置列表 + public static List GetTrustedPath() + { + return TrustedPathEx.Get(); + } + + #endregion /// /// 命令行打印,会自动调用对象的toString函数 /// - /// 要打印的对象 - public static void Print(object message) => Editor.WriteMessage($"{message}\n"); + /// 要打印的对象 + public static T Print(this T obj) + { + // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract + Document?.Editor.WriteMessage(obj is null ? "null\n" : $"{obj}\n"); + return obj; + } + /// /// 命令行打印,会自动调用对象的toString函数,在打印内容前添加换行 /// /// 要打印的对象 - public static void Printl(object message) => Editor.WriteMessage($"{Environment.NewLine}{message}\n"); + public static void Printl(object message) + { + // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract + Document?.Editor.WriteMessage($"{Environment.NewLine}{message}\n"); + } /// /// 判断当前是否在UCS坐标下 /// /// Bool - public static bool IsUcs() => (short)GetVar("WORLDUCS") == 0; - + public static bool IsUcs() + { + return (short)GetVar("WORLDUCS") == 0; + } #region dwg版本号/cad版本号/年份 + /// /// 获取当前配置文件的保存版本 /// /// public static DwgVersion GetDefaultDwgVersion() { - DwgVersion version; - var ffs = Env.GetEnv("DefaultFormatForSave"); - version = ffs switch + var ffs = GetEnv("DefaultFormatForSave"); + var version = ffs switch { - "1" => DwgVersion.AC1009,// R12/LT12 dxf - "8" => DwgVersion.AC1014,// R14/LT98/LT97 dwg - "12" => DwgVersion.AC1015,// 2000 dwg - "13" => DwgVersion.AC1800a,// 2000 dxf - "24" => DwgVersion.AC1800,// 2004 dwg - "25" => (DwgVersion)26,// 2004 dxf - "36" => (DwgVersion)27,// 2007 dwg DwgVersion.AC1021 - "37" => (DwgVersion)28,// 2007 dxf + "1" => DwgVersion.AC1009, // R12/LT12 dxf + "8" => DwgVersion.AC1014, // R14/LT98/LT97 dwg + "12" => DwgVersion.AC1015, // 2000 dwg + "13" => DwgVersion.AC1800a, // 2000 dxf + "24" => DwgVersion.AC1800, // 2004 dwg + "25" => (DwgVersion)26, // 2004 dxf + "36" => (DwgVersion)27, // 2007 dwg DwgVersion.AC1021 + "37" => (DwgVersion)28, // 2007 dxf // "38" => (DwgVersion),// dwt 样板文件...啊惊没找到这个是什么 - "48" => (DwgVersion)29,// 2010 dwg DwgVersion.AC1024 - "49" => (DwgVersion)30,// 2010 dxf - "60" => (DwgVersion)31,// 2013 dwg DwgVersion.AC1027 - "61" => (DwgVersion)32,// 2013 dxf - "64" => (DwgVersion)33,// 2018 dwg DwgVersion.AC1032 - "65" => (DwgVersion)34,// 2018 dxf - _ => throw new NotImplementedException(),// 提醒维护 + "48" => (DwgVersion)29, // 2010 dwg DwgVersion.AC1024 + "49" => (DwgVersion)30, // 2010 dxf + "60" => (DwgVersion)31, // 2013 dwg DwgVersion.AC1027 + "61" => (DwgVersion)32, // 2013 dxf + "64" => (DwgVersion)33, // 2018 dwg DwgVersion.AC1032 + "65" => (DwgVersion)34, // 2018 dxf + _ => throw new NotImplementedException() // 提醒维护 }; return version; } @@ -629,14 +644,14 @@ public static bool IsDxfVersion(this DwgVersion dwgVersion) { var result = (int)dwgVersion switch { - 16 => true,// R12/LT12 dxf - 24 => true,// 2000 dxf - 26 => true,// 2004 dxf - 28 => true,// 2007 dxf - 30 => true,// 2010 dxf - 32 => true,// 2013 dxf - 34 => true,// 2018 dxf - _ => false, + 16 => true, // R12/LT12 dxf + 24 => true, // 2000 dxf + 26 => true, // 2004 dxf + 28 => true, // 2007 dxf + 30 => true, // 2010 dxf + 32 => true, // 2013 dxf + 34 => true, // 2018 dxf + _ => false }; return result; } @@ -645,10 +660,10 @@ public static bool IsDxfVersion(this DwgVersion dwgVersion) /// 获取cad年份 ///
/// 超出年份就报错 - public static int GetAcadVersion() + public static int GetAcadYear() { - var ver = Acap.Version.Major + "." + Acap.Version.Minor; - int acarVarNum = ver switch + var ver = Acaop.Version.Major + "." + Acaop.Version.Minor; + var acadVersion = ver switch { "16.2" => 2006, "17.0" => 2007, @@ -668,10 +683,13 @@ public static int GetAcadVersion() "24.0" => 2021, "24.1" => 2022, "24.2" => 2023, - _ => throw new NotImplementedException(), + "24.3" => 2024, + "25.0" => 2025, + _ => throw new NotImplementedException() }; - return acarVarNum; + return acadVersion; } + /// /// 获取带cad版本号的dll /// @@ -679,50 +697,42 @@ public static int GetAcadVersion() /// dll的前面 public static string GetAcapVersionDll(string str = "acdb") { - return str + Acap.Version.Major + ".dll"; + return str + Acaop.Version.Major + ".dll"; } - #endregion + #endregion #region cad变量功能延伸 + /// - /// 设置cad系统变量
- /// 提供一个反序列化后,无cad异常输出的功能
- /// 注意,您需要再此执行时候设置文档锁
- ///
- /// 否则也将导致修改数据库异常
+ /// 设置cad系统变量
+ /// 提供一个反序列化后,无cad异常输出的功能
+ /// 注意,您需要再此执行时候设置文档锁
+ /// 否则也将导致修改数据库异常
///
/// /// /// 成功返回当前值,失败null - /// - public static object? SetVarEx(string? key, string? value) + /// + public static object? SetVarEx(string key, string value) { - //if (key == null) - // throw new ArgumentNullException(nameof(key)); - //if (value == null) - // throw new ArgumentNullException(nameof(value)); - key.NotNull(nameof(key)); - value.NotNull(nameof(value)); - - - var currentVar = Env.GetVar(key); - if (currentVar == null) - return null; - + var currentVar = GetVar(key); object? valueType = currentVar.GetType().Name switch { "String" => value.Replace("\"", string.Empty), "Double" => double.Parse(value), "Int16" => short.Parse(value), "Int32" => int.Parse(value), - _ => throw new NotImplementedException(), + _ => null, + // _ => throw new NotImplementedException() }; + if (valueType is null) + return null; // 相同的参数进行设置会发生一次异常 - if (currentVar.ToString().ToUpper() != valueType!.ToString().ToUpper()) - Env.SetVar(key, valueType); - + if (!string.Equals(currentVar.ToString(), valueType.ToString(), + StringComparison.CurrentCultureIgnoreCase)) + SetVar(key, valueType); return currentVar; } @@ -733,29 +743,101 @@ public static string GetAcapVersionDll(string str = "acdb") /// 返回现有变量词典,然后下次就可以利用它进行设置回来了 public static Dictionary SaveCadVar(Dictionary args) { - //if (args is null) - // throw new ArgumentNullException(nameof(args)); - args.NotNull(nameof(args)); + ArgumentNullException.ThrowIfNull(args); var dict = new Dictionary(); foreach (var item in args) { // 判断是否为系统变量 var ok = SetVarEx(item.Key, item.Value); - if (ok != null) + if (ok is not null) { - dict.Add(item.Key, ok.ToString()); + dict.Add(item.Key, $"{ok}"); continue; } // 判断是否为系统变量 - var envstr = Env.GetEnv(item.Key); - if (!string.IsNullOrEmpty(envstr)) + var envStr = GetEnv(item.Key); + if (!string.IsNullOrEmpty(envStr)) { - Env.SetEnv(item.Key, item.Value); - dict.Add(item.Key, envstr); + SetEnv(item.Key, item.Value); + dict.Add(item.Key, envStr); } } + return dict; } + + #endregion + + #region EntGet功能 + + /// + /// EntGet + /// + public static TypedValue[] EntGet(ObjectId objectId) + { +#if zcad + var adsName = GetAdsName(objectId); + var intPtr = PInvokeCad.ZcdbEntGet(adsName); +#else + var adsName = GetAdsName(objectId); + var intPtr = PInvokeCad.AcdbEntGet(ref adsName); + +#endif + var typedValues = Marshaler.ResbufToTypedValues(intPtr); + return typedValues; + } + + #if acad + /// + /// EntUpd + /// + public static bool EntUpd(ObjectId objectId) + { + var adsName = GetAdsName(objectId); + var res = PInvokeCad.AcdbEntUpd(ref adsName); + return res == 5100; + } + #endif + + /// + /// EntMod + /// + public static bool EntMod(IEnumerable typedValues) + { + var tva = typedValues.ToArray(); + var intPtr = Marshaler.TypedValuesToResbuf(tva); +#if zcad + var result = PInvokeCad.ZcdbEntMod(intPtr); + #else + var result = PInvokeCad.AcdbEntMod(intPtr); +#endif + return result == 5100; + } + +#if zcad + /// + /// GetAdsName + /// + /// ObjectId + public static AdsName GetAdsName(ObjectId objectId) + { + _ = PInvokeCad.GetAdsName(out var adsName,objectId); + return adsName; + } + #else + /// + /// GetAdsName + /// + /// ObjectId + /// ads_name + public static ads_name GetAdsName(ObjectId objectId) + { + var adsName = new ads_name(); + _ = PInvokeCad.GetAdsName(ref adsName, objectId); + return adsName; + } +#endif + #endregion } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/IdleAction.cs b/src/CADShared/Runtime/IdleAction.cs similarity index 55% rename from src/CAD/IFox.CAD.Shared/Runtime/IdleAction.cs rename to src/CADShared/Runtime/IdleAction.cs index 6431391ea8bfad21ec9960389db4b1cc09054383..b3e0bd49f9aff60ce9e4ef0750a354fb1f502483 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/IdleAction.cs +++ b/src/CADShared/Runtime/IdleAction.cs @@ -1,4 +1,6 @@ -namespace IFoxCAD.Cad; +using Cursor = System.Windows.Forms.Cursor; + +namespace IFoxCAD.Cad; /// /// 空闲执行 @@ -10,49 +12,55 @@ public static class IdleAction /// /// 是否已经加载 /// - private static bool alreadyLoad = false; + private static bool alreadyLoad; + /// /// 委托列表 /// - private static readonly List actions = new(); + private static readonly Queue _actions = new(); + /// /// 未处理的委托数量 /// - public static int Count { get { return actions.Count; } } + public static int Count => _actions.Count; + /// /// 添加空闲执行委托 /// /// 委托 public static void Add(Action action) { - actions.Add(action); - if (!alreadyLoad) - { - Acap.Idle -= Acap_Idle; - Acap.Idle += Acap_Idle; - alreadyLoad = true; - } + _actions.Enqueue(action); + if (alreadyLoad) + return; + Acaop.Idle -= Acap_Idle; + Acaop.Idle += Acap_Idle; + alreadyLoad = true; } + /// /// 空闲处理事件 /// /// Acap /// 事件参数 - private static void Acap_Idle(object sender, EventArgs e) + private static void Acap_Idle(object? sender, EventArgs e) { if (Count == 0) { alreadyLoad = false; - Acap.Idle -= Acap_Idle; + Acaop.Idle -= Acap_Idle; return; } + try { - actions[0]?.Invoke(); + _actions.Dequeue()?.Invoke(); } - finally + catch { - actions.RemoveAt(0); + // ignored } + + Cursor.Position = Cursor.Position; } -} +} \ No newline at end of file diff --git a/src/CADShared/Runtime/IdleNoCommandAction.cs b/src/CADShared/Runtime/IdleNoCommandAction.cs new file mode 100644 index 0000000000000000000000000000000000000000..72a60b96c364fc1b334e0503e37534c4b5fe9248 --- /dev/null +++ b/src/CADShared/Runtime/IdleNoCommandAction.cs @@ -0,0 +1,74 @@ +namespace IFoxCAD.Cad; + +/// +/// 空闲且无命令时执行 +/// by DYH +/// 20231230 +/// +public static class IdleNoCmdAction +{ + private const string CmdActiveName = "CMDACTIVE"; + + /// + /// 是否已经加载 + /// + private static bool alreadyLoad = false; + + /// + /// 委托列表 + /// + private static readonly Queue _actions = new(); + + /// + /// 未处理的委托数量 + /// + public static int Count => _actions.Count; + + /// + /// 添加空闲执行委托 + /// + /// 委托 + public static void Add(Action action) + { + _actions.Enqueue(action); + if (!alreadyLoad) + { + Acaop.Idle -= Acap_Idle; + Acaop.Idle += Acap_Idle; + alreadyLoad = true; + } + } + + /// + /// 空闲处理事件 + /// + /// Acap + /// 事件参数 + private static void Acap_Idle(object? sender, EventArgs e) + { + if (Count == 0) + { + alreadyLoad = false; + Acaop.Idle -= Acap_Idle; + return; + } + + // 判断是否有活动的命令 + if (Convert.ToBoolean(Acaop.GetSystemVariable(CmdActiveName))) + return; +#if RELEASE + try + { +#endif + // 执行委托 + _actions.Dequeue()?.Invoke(); +#if RELEASE + } + catch + { + // 不进行操作 + } +#endif + System.Windows.Forms.Cursor.Position = System.Windows.Forms.Cursor.Position; + } +} \ No newline at end of file diff --git a/src/CADShared/Runtime/PInvokeCad.cs b/src/CADShared/Runtime/PInvokeCad.cs new file mode 100644 index 0000000000000000000000000000000000000000..f0b3af73851d345df12466685b2e73644af4168e --- /dev/null +++ b/src/CADShared/Runtime/PInvokeCad.cs @@ -0,0 +1,134 @@ +// ReSharper disable InconsistentNaming + +namespace IFoxCAD.Cad; + +/// +/// cad相关的PInvoke +/// +public static class PInvokeCad +{ +#if zcad + /// + /// EntGet + /// + [DllImport("zwcad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "zcdbEntGet")] + public static extern IntPtr ZcdbEntGet(AdsName adsName); + + /// + /// EntGet + /// + [DllImport("zwcad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "zcdbEntMod")] + public static extern int ZcdbEntMod(IntPtr intPtr); + + /// + /// GetZdsName + /// + [DllImport("ZwDatabase.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?zcdbGetZdsName@@YA?AW4ErrorStatus@Zcad@@AEAY01_JVZcDbObjectId@@@Z")] + public static extern int ZcdbGetZdsName(out AdsName adsName, ObjectId id); + + /// + /// EntNext + /// + [DllImport("zwcad.exe", EntryPoint = "zcdbEntNext", + CallingConvention = CallingConvention.Cdecl)] + public static extern int ZcdbEntNext(AdsName adsName, out ObjectId id); + + /// + /// GetAdsName + /// + public static int GetAdsName(out AdsName adsName, ObjectId id) + { + return ZcdbGetZdsName(out adsName, id); + } +#else + /// + /// Entget + /// + [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "acdbEntGet")] + public static extern IntPtr AcdbEntGet(ref ads_name adsName); + + /// + /// EntUpd + /// + [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "acdbEntUpd")] + public static extern int AcdbEntUpd(ref ads_name adsName); + + /// + /// EntMod + /// + [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "acdbEntMod")] + public static extern int AcdbEntMod(IntPtr intPtr); + + [DllImport("acdb25.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] + private static extern int AcdbGetAdsName25(ref ads_name adsName, ObjectId objectId); + + [DllImport("acdb24.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] + private static extern int AcdbGetAdsName24(ref ads_name adsName, ObjectId objectId); + + [DllImport("acdb23.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] + private static extern int AcdbGetAdsName23(ref ads_name adsName, ObjectId objectId); + + [DllImport("acdb22.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] + private static extern int AcdbGetAdsName22(ref ads_name adsName, ObjectId objectId); + + [DllImport("acdb21.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] + private static extern int AcdbGetAdsName21(ref ads_name adsName, ObjectId objectId); + + [DllImport("acdb20.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] + private static extern int AcdbGetAdsName20(ref ads_name adsName, ObjectId objectId); + + [DllImport("acdb19.dll", CallingConvention = CallingConvention.Cdecl, + EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")] + private static extern int AcdbGetAdsName19(ref ads_name adsName, ObjectId objectId); + /// + /// GetAdsName + /// + public static int GetAdsName(ref ads_name adsName, ObjectId id) + { + var major = Acaop.Version.Major; + var res = major switch + { + 25 => AcdbGetAdsName25(ref adsName, id), + 24 => AcdbGetAdsName24(ref adsName, id), + 23 => AcdbGetAdsName23(ref adsName, id), + 22 => AcdbGetAdsName22(ref adsName, id), + 21 => AcdbGetAdsName21(ref adsName, id), + 20 => AcdbGetAdsName20(ref adsName, id), + 19 => AcdbGetAdsName19(ref adsName, id), + _ => 1, + }; + return res; + } +#endif +} + +/// +/// 用于使用Entget等函数的结构体 +/// +// ReSharper disable once InconsistentNaming +public struct ads_name +{ + /// + /// 构造函数 + /// + public ads_name() + { + a = b = IntPtr.Zero; + } + + // ReSharper disable once NotAccessedField.Local + private IntPtr a; + + // ReSharper disable once NotAccessedField.Local + private IntPtr b; +} \ No newline at end of file diff --git a/src/CADShared/Runtime/ProgressMeterUtils.cs b/src/CADShared/Runtime/ProgressMeterUtils.cs new file mode 100644 index 0000000000000000000000000000000000000000..42343125216838f17d0dd3350ccbc0e5944b79b8 --- /dev/null +++ b/src/CADShared/Runtime/ProgressMeterUtils.cs @@ -0,0 +1,59 @@ +namespace IFoxCAD.Cad; + +/// +/// 进度条 +/// +public static class ProgressMeterUtils +{ + /// + /// 设置状态栏进度条 + /// + public static void SetApplicationStatusBarProgressMeter(string str, int mixPos, int maxPos) + { +#if acad + Utils.SetApplicationStatusBarProgressMeter(str, mixPos, maxPos); +#elif zcad + ZcedSetStatusBarProgressMeter(str, mixPos, maxPos); +#endif + } + + /// + /// 设置状态栏进度条 + /// + public static void SetApplicationStatusBarProgressMeter(int nPos) + { +#if acad + Utils.SetApplicationStatusBarProgressMeter(nPos); +#elif zcad + ZcedSetStatusBarProgressMeterPos(nPos); +#endif + } + + /// + /// 关闭进度条 + /// + public static void RestoreApplicationStatusBar() + { +#if acad + Utils.RestoreApplicationStatusBar(); +#elif zcad + ZcedSetStatusBarProgressMeterStop(); +#endif + } + +#if zcad + + [DllImport(DllFileNames.ZwCadExe, EntryPoint = "?zcedSetStatusBarProgressMeter@@YAHPEB_WHH@Z", + CallingConvention = CallingConvention.Cdecl)] + private static extern void ZcedSetStatusBarProgressMeter( + [MarshalAs(UnmanagedType.LPWStr)] string label, int minPos, int maxPos); + + [DllImport(DllFileNames.ZwCadExe, EntryPoint = "?zcedSetStatusBarProgressMeterPos@@YAHH@Z", + CallingConvention = CallingConvention.Cdecl)] + private static extern void ZcedSetStatusBarProgressMeterPos(int position); + + [DllImport(DllFileNames.ZwCadExe, EntryPoint = "?zcedSetStatusBarProgressMeterStop@@YAHXZ", + CallingConvention = CallingConvention.Cdecl)] + private static extern void ZcedSetStatusBarProgressMeterStop(); +#endif +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/Runtime/SymbolTable.cs b/src/CADShared/Runtime/SymbolTable.cs similarity index 74% rename from src/CAD/IFox.CAD.Shared/Runtime/SymbolTable.cs rename to src/CADShared/Runtime/SymbolTable.cs index 22fadac920464c96085f591d54335ebfcc6f70f4..c6c9422ebc5dd7275ee43a4de992704eabd39527 100644 --- a/src/CAD/IFox.CAD.Shared/Runtime/SymbolTable.cs +++ b/src/CADShared/Runtime/SymbolTable.cs @@ -1,16 +1,26 @@ -//using static System.Windows.Forms.AxHost; +// ReSharper disable RedundantNameQualifier + +#if !NET8_0_OR_GREATER +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Cad; -public class SymbolTable : IEnumerable - where TTable : SymbolTable +/// +/// 符号表管理类 +/// +/// 符号表 +/// 符号表记录 +public class SymbolTable : IEnumerable where TTable : SymbolTable where TRecord : SymbolTableRecord, new() { #region 程序集内部属性 + /// /// 事务管理器 /// - internal DBTrans DTrans { get; private set; } + private DBTrans DTrans { get; set; } + /// /// 数据库 /// @@ -19,13 +29,16 @@ public class SymbolTable : IEnumerable #endregion #region 公开属性 + /// /// 当前符号表 /// public TTable CurrentSymbolTable { get; private set; } + #endregion #region 构造函数 + /// /// 构造函数,初始化Trans和CurrentSymbolTable属性 /// @@ -53,23 +66,18 @@ internal SymbolTable(DBTrans tr, ObjectId tableId, bool defaultBehavior = true) #endregion #region 索引器 + /// /// 索引器 /// /// 对象名称 /// 对象的id - public ObjectId this[string key] - { - get - { - if (Has(key)) - return CurrentSymbolTable[key]; - return ObjectId.Null; - } - } + public ObjectId this[string key] => Has(key) ? CurrentSymbolTable[key] : ObjectId.Null; + #endregion #region Has + /// /// 判断是否存在符号表记录 /// @@ -79,6 +87,7 @@ public bool Has(string key) { return CurrentSymbolTable.Has(key); } + /// /// 判断是否存在符号表记录 /// @@ -88,15 +97,17 @@ public bool Has(ObjectId objectId) { return CurrentSymbolTable.Has(objectId); } + #endregion #region 添加符号表记录 + /// /// 添加符号表记录 /// /// 符号表记录 /// 对象id - private ObjectId Add(TRecord record) + public ObjectId Add(TRecord record) { ObjectId id; using (CurrentSymbolTable.ForWrite()) @@ -104,8 +115,10 @@ private ObjectId Add(TRecord record) id = CurrentSymbolTable.Add(record); DTrans.Transaction.AddNewlyCreatedDBObject(record, true); } + return id; } + /// /// 添加符号表记录 /// @@ -114,22 +127,40 @@ private ObjectId Add(TRecord record) /// 对象id public ObjectId Add(string name, Action? action = null) { - ObjectId id = this[name]; + var id = this[name]; + if (!id.IsNull) return id; + var record = new TRecord() { Name = name }; + id = Add(record); + using (record.ForWrite()) + action?.Invoke(record); + return id; + } + + /// + /// 有则修改无则添加符号表记录 + /// + /// 符号表记录名 + /// 符号表记录处理函数的无返回值委托 + /// 对象id + public ObjectId AddOrChange(string name, Action action) + { + var id = this[name]; if (id.IsNull) { - var record = new TRecord() - { - Name = name - }; - id = Add(record); - using (record.ForWrite()) - action?.Invoke(record); + id = Add(name, action); } + else + { + Change(name, action); + } + return id; } + #endregion #region 删除符号表记录 + /// /// 删除符号表记录 /// @@ -146,6 +177,22 @@ private static void Remove(TRecord record) /// 符号表记录名 public void Remove(string name) { + if (CurrentSymbolTable is LayerTable lt) + { + if (SymbolUtilityServices.IsLayerZeroName(name) || + SymbolUtilityServices.IsLayerDefpointsName(name)) + return; + lt.GenerateUsageData(); + if (GetRecord(name) is not LayerTableRecord { IsUsed: false } ltr) + return; + using (ltr.ForWrite()) + { + ltr.Erase(); + } + + return; + } + var record = GetRecord(name); if (record is not null) Remove(record); @@ -161,9 +208,11 @@ public void Remove(ObjectId id) if (record is not null) Remove(record); } + #endregion #region 修改符号表记录 + /// /// 修改符号表 /// @@ -173,11 +222,9 @@ public void Remove(ObjectId id) public void Change(string name, Action action) { var record = GetRecord(name); - if (record is not null) - { - using (record.ForWrite()) - action.Invoke(record); - } + if (record is null) return; + using (record.ForWrite()) + action.Invoke(record); } /// @@ -195,9 +242,11 @@ public void Change(ObjectId id, Action action) action.Invoke(record); } } + #endregion #region 获取符号表记录 + /// /// 获取符号表记录 /// @@ -207,10 +256,8 @@ public void Change(ObjectId id, Action action) /// 是否打开锁定图层对象,默认为不打开 /// 符号表记录 [System.Diagnostics.DebuggerStepThrough] - public TRecord? GetRecord(ObjectId id, - OpenMode openMode = OpenMode.ForRead, - bool openErased = false, - bool openLockedLayer = false) + public TRecord? GetRecord(ObjectId id, OpenMode openMode = OpenMode.ForRead, bool openErased = false, + bool openLockedLayer = false) { return DTrans.GetObject(id, openMode, openErased, openLockedLayer); } @@ -224,10 +271,8 @@ public void Change(ObjectId id, Action action) /// 是否打开锁定图层对象,默认为不打开 /// 符号表记录 [System.Diagnostics.DebuggerStepThrough] - public TRecord? GetRecord(string name, - OpenMode openMode = OpenMode.ForRead, - bool openErased = false, - bool openLockedLayer = false) + public TRecord? GetRecord(string name, OpenMode openMode = OpenMode.ForRead, bool openErased = false, + bool openLockedLayer = false) { return GetRecord(this[name], openMode, openErased, openLockedLayer); } @@ -274,27 +319,20 @@ public IEnumerable GetRecordNames(Func filter) /// 符号表记录名 /// 是否覆盖, 为覆盖, 为不覆盖 /// 对象id - public ObjectId GetRecordFrom(SymbolTable table, string name, bool over) + private ObjectId GetRecordFrom(SymbolTable table, string name, bool over) { - //if (table is null) - // throw new ArgumentNullException(nameof(table), "对象为null"); - table.NotNull(nameof(table)); + ArgumentNullException.ThrowIfNull(table); - ObjectId rid = this[name]; - bool has = rid != ObjectId.Null; - if ((has && over) || !has) - { - ObjectId id = table[name]; - using IdMapping map = new(); - using ObjectIdCollection ids = new() { id }; - table.Database.WblockCloneObjects( - ids, - CurrentSymbolTable.Id, - map, - DuplicateRecordCloning.Replace, - false); - rid = map[id].Value; - } + var rid = this[name]; + var has = rid != ObjectId.Null; + if ((!has || !over) && has) return rid; + var id = table[name]; + using IdMapping map = new(); + using ObjectIdCollection ids = new(); + ids.Add(id); + table.Database.WblockCloneObjects(ids, CurrentSymbolTable.Id, map, DuplicateRecordCloning.Replace, + false); + rid = map[id].Value; return rid; } @@ -307,16 +345,16 @@ public ObjectId GetRecordFrom(SymbolTable table, string name, b /// 是否覆盖, 为覆盖, 为不覆盖 /// 对象id internal ObjectId GetRecordFrom(Func> tableSelector, - string fileName, - string name, - bool over) + string fileName, string name, bool over) { using DBTrans tr = new(fileName); return GetRecordFrom(tableSelector(tr), name, over); } + #endregion #region 遍历 + #line hidden // 调试的时候跳过它 /// /// 遍历符号表,执行委托 @@ -326,14 +364,12 @@ internal ObjectId GetRecordFrom(Func> tabl /// 检查id是否删除,默认true /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 - public void ForEach(Action task, - OpenMode openMode = OpenMode.ForRead, - bool checkIdOk = true, - bool openErased = false, - bool openLockedLayer = false) + public void ForEach(Action task, OpenMode openMode = OpenMode.ForRead, bool checkIdOk = true, + bool openErased = false, bool openLockedLayer = false) { - ForEach((a, _, _) => { - task.Invoke(a);//由于此处是委托,所以 DebuggerStepThrough 特性会进入,改用预处理方式避免 + ForEach((a, _, _) => + { + task.Invoke(a); //由于此处是委托,所以 DebuggerStepThrough 特性会进入,改用预处理方式避免 }, openMode, checkIdOk, openErased, openLockedLayer); } @@ -345,15 +381,10 @@ public void ForEach(Action task, /// 检查id是否删除,默认true /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 - public void ForEach(Action task, - OpenMode openMode = OpenMode.ForRead, - bool checkIdOk = true, - bool openErased = false, - bool openLockedLayer = false) + public void ForEach(Action task, OpenMode openMode = OpenMode.ForRead, + bool checkIdOk = true, bool openErased = false, bool openLockedLayer = false) { - ForEach((a, b, _) => { - task.Invoke(a, b); - }, openMode, checkIdOk, openErased, openLockedLayer); + ForEach((a, b, _) => { task.Invoke(a, b); }, openMode, checkIdOk, openErased, openLockedLayer); } /// @@ -365,17 +396,14 @@ public void ForEach(Action task, /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 [System.Diagnostics.DebuggerStepThrough] - public void ForEach(Action task, - OpenMode openMode = OpenMode.ForRead, - bool checkIdOk = true, - bool openErased = false, - bool openLockedLayer = false) + public void ForEach(Action task, OpenMode openMode = OpenMode.ForRead, + bool checkIdOk = true, bool openErased = false, bool openLockedLayer = false) { //if (task == null) // throw new ArgumentNullException(nameof(task)); - task.NotNull(nameof(task)); - LoopState state = new();/*这种方式比Action改Func更友好*/ - int i = 0; + ArgumentNullException.ThrowIfNull(task); + LoopState state = new(); /*这种方式比Action改Func更友好*/ + var i = 0; foreach (var id in this) { if (checkIdOk && !id.IsOk()) @@ -388,11 +416,14 @@ public void ForEach(Action task, i++; } } + + /// #line default #endregion #region IEnumerable 成员 + [System.Diagnostics.DebuggerStepThrough] public IEnumerator GetEnumerator() { @@ -405,5 +436,6 @@ IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + #endregion } \ No newline at end of file diff --git a/src/CADShared/Runtime/SystemVariableManager.cs b/src/CADShared/Runtime/SystemVariableManager.cs new file mode 100644 index 0000000000000000000000000000000000000000..fd874b59b1fcd87d330d41a28e449adfd2f5bb9c --- /dev/null +++ b/src/CADShared/Runtime/SystemVariableManager.cs @@ -0,0 +1,367 @@ +// ReSharper disable InconsistentNaming + +namespace IFoxCAD.Cad; + +/// +/// 系统变量管理器 +/// +public static class SystemVariableManager +{ + #region A + + /// + /// 打开或关闭自动捕捉靶框的显示 + /// + public static bool ApBox + { + get => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(ApBox))); + set => Acaop.SetSystemVariable(nameof(ApBox), Convert.ToInt32(value)); + } + + /// + /// 对象捕捉靶框的大小,范围[1,50] + /// + public static int Aperture + { + get => Convert.ToInt32(Acaop.GetSystemVariable(nameof(Aperture))); + set => Acaop.SetSystemVariable(nameof(Aperture), value); + } + + /// + /// 图形单位-角度-类型,范围[0-十进制度数,1-度/分/秒,2-百分度,3-弧度,4-勘测单位] + /// + public static int Aunits + { + get => Convert.ToInt32(Acaop.GetSystemVariable(nameof(Aunits))); + set => Acaop.SetSystemVariable(nameof(Aunits), value); + } + + /// + /// 图形单位-角度-精度,范围[0,8] + /// + public static int Auprec + { + get => Convert.ToInt32(Acaop.GetSystemVariable(nameof(Auprec))); + set => Acaop.SetSystemVariable(nameof(Auprec), value); + } + + #endregion + + #region B + + /// + /// 是否在块编辑器中 + /// + public static bool BlockEditor => Acaop.GetSystemVariable(nameof(BlockEditor)) is 1; + + #endregion + + #region C + + /// + /// 用于设置当前空间的当前注释比例的值 + /// + public static string CanNoScale => Acaop.GetSystemVariable(nameof(CanNoScale)).ToString()!; + + /// + /// 用于显示当前的注释性比例 + /// + public static double CanNoScaleValue => + Convert.ToDouble(Acaop.GetSystemVariable(nameof(CanNoScale))); + + /// + /// 储存以公元纪年为基准的日历数据和时间 + /// + public static double CDate => Convert.ToDouble(Acaop.GetSystemVariable(nameof(CDate))); + + /// + /// 设置新对象的颜色 + /// + public static string CEColor + { + get => Acaop.GetSystemVariable(nameof(CEColor)).ToString()!; + set => Acaop.SetSystemVariable(nameof(CEColor), value); + } + + /// + /// 设置新对象的线型比例因子 + /// + public static double CELtScale + { + get => Convert.ToDouble(Acaop.GetSystemVariable(nameof(CELtScale))); + set => Acaop.SetSystemVariable(nameof(CELtScale), value); + } + + /// + /// 设置新对象的线型 + /// + public static string CELType + { + get => Acaop.GetSystemVariable(nameof(CELType)).ToString()!; + set => Acaop.SetSystemVariable(nameof(CELType), value); + } + + /// + /// 设置新对象的线宽 + /// + public static double CELWeight + { + get => Convert.ToDouble(Acaop.GetSystemVariable(nameof(CELWeight))); + set => Acaop.SetSystemVariable(nameof(CELWeight), value); + } + + /// + /// 设置圆的默认半径 + /// + public static double CircleRad + { + get => Convert.ToDouble(Acaop.GetSystemVariable(nameof(CircleRad))); + set => Acaop.SetSystemVariable(nameof(CircleRad), value); + } + + /// + /// 设置当前图层 + /// + public static string CLayer + { + get => Acaop.GetSystemVariable(nameof(CLayer)).ToString()!; + set => Acaop.SetSystemVariable(nameof(CLayer), value); + } + + /// + /// 用于确定全屏显示是打开或关闭状态 + /// + public static bool CleanScreenState => + Convert.ToBoolean(Acaop.GetSystemVariable(nameof(CleanScreenState))); + + /// + /// 指示命令窗口是隐藏还是显示状态 + /// + public static bool CliState => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(CliState))); + + /// + /// 存在活动命令 + /// + public static bool CmdActive => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(CmdActive))); + + /// + /// 控制是否要打开对话框来显示命令 + /// + public static bool CmdDia + { + get => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(CmdDia))); + set => Acaop.SetSystemVariable(nameof(CmdDia), Convert.ToInt32(value)); + } + + /// + /// 在使用 LISP 的函数时,切换回应为打开或关闭 + /// + public static bool CmdEcho + { + get => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(CmdEcho))); + set => Acaop.SetSystemVariable(nameof(CmdEcho), value ? 1 : 0); + } + + /// + /// 当前的命令 + /// + public static string CmdNames => Acaop.GetSystemVariable(nameof(CmdNames)).ToString()!; + + /// + /// 返回图形中的当前选项卡(模型或布局)的名称 + /// + public static string CTab + { + get => Acaop.GetSystemVariable(nameof(CTab)).ToString()!; + set => Acaop.SetSystemVariable(nameof(CTab), value); + } + + /// + /// 指定十字光标的显示大小。输入的数字代表十字光标相对于屏幕的比例。
+ /// 范围[1, 100] + ///
+ public static int CursorSize + { + get => Convert.ToInt32(Acaop.GetSystemVariable(nameof(CursorSize))); + set => Acaop.SetSystemVariable(nameof(CursorSize), value); + } + + /// + /// 当前viewport的编号 + /// + public static short CVPort + { + get => Convert.ToInt16(Acaop.GetSystemVariable(nameof(CVPort))); + set => Acaop.SetSystemVariable(nameof(CVPort), value); + } + + #endregion + + #region D + + /// + /// 是否开启双击 + /// + public static bool DblClkEdit + { + get => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(DblClkEdit))); + set => Acaop.SetSystemVariable(nameof(DblClkEdit), Convert.ToInt32(value)); + } + + /// + /// 指示图形的修改状态 + /// + public static DBmod DBMod => (DBmod)Acaop.GetSystemVariable(nameof(DBMod)); + + /// + /// 动态输入 + /// + public static int DynMode + { + get => Convert.ToInt32(Acaop.GetSystemVariable(nameof(DynMode))); + set => Acaop.SetSystemVariable(nameof(DynMode), value); + } + + /// + /// 动态提示 + /// + public static bool DynPrompt + { + get => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(DynPrompt))); + set => Acaop.SetSystemVariable(nameof(DynPrompt), Convert.ToInt32(value)); + } + + #endregion + + #region G + + /// + /// 显示图形栅格 + /// + public static bool GridMode + { + get => Acaop.GetSystemVariable(nameof(GridMode)) is 1; + set => Acaop.SetSystemVariable(nameof(GridMode), Convert.ToInt32(value)); + } + + #endregion + + #region H + + /// + /// 当前填充的名称 + /// + public static string HPName + { + get => Acaop.GetSystemVariable(nameof(HPName)).ToString()!; + set => Acaop.SetSystemVariable(nameof(HPName), value); + } + + /// + /// 填充比例 + /// + public static double HPScale + { + get => Convert.ToDouble(Acaop.GetSystemVariable(nameof(HPScale))); + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException(nameof(HPScale), "HPScale必须大于0"); + Acaop.SetSystemVariable(nameof(HPScale), value); + } + } + + #endregion + + #region I + + /// + /// 图形单位-插入时的缩放单位 + /// + public static UnitsValue Insunits + { + get => (UnitsValue)Acaop.GetSystemVariable(nameof(Insunits)); + set => Acaop.SetSystemVariable(nameof(Insunits), (int)value); + } + + #endregion + + #region L + + /// + /// 储存所输入相对于当前用户坐标系统(UCS)的最后点的值 + /// + public static Point3d LastPoint + { + get => (Point3d)Acaop.GetSystemVariable(nameof(LastPoint)); + set => Acaop.SetSystemVariable(nameof(LastPoint), value); + } + + /// + /// 图形单位-长度-类型,范围[1-科学,2-小数,3-工程,4-建筑,5-分数] + /// + public static int Lunits + { + get => Convert.ToInt32(Acaop.GetSystemVariable(nameof(Lunits))); + set => Acaop.SetSystemVariable(nameof(Lunits), value); + } + + /// + /// 图形单位-长度-精度,范围[0,8] + /// + public static int Luprec + { + get => Convert.ToInt32(Acaop.GetSystemVariable(nameof(Luprec))); + set => Acaop.SetSystemVariable(nameof(Luprec), value); + } + + #endregion + + #region M + + /// + /// 图形单位 + /// + public static MeasurementValue Measurement + { + get => (MeasurementValue)Acaop.GetSystemVariable(nameof(Measurement)); + set => Acaop.SetSystemVariable(nameof(Measurement), Convert.ToInt32(value)); + } + + #endregion + + #region O + + /// + /// 正交 + /// + public static bool OrthoMode + { + get => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(OrthoMode))); + set => Acaop.SetSystemVariable(nameof(OrthoMode), Convert.ToInt32(value)); + } + + #endregion + + #region P + + /// + /// 允许先选择后执行 + /// + public static bool PickFirst + { + get => Convert.ToBoolean(Acaop.GetSystemVariable(nameof(PickFirst))); + set => Acaop.SetSystemVariable(nameof(PickFirst), Convert.ToInt32(value)); + } + + #endregion + + #region T + + /// + /// 视图点 + /// + public static Point3d Target => (Point3d)Acaop.GetSystemVariable(nameof(Target)); + + #endregion +} \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpComp.cs b/src/CADShared/SelectionFilter/OpComp.cs similarity index 96% rename from src/CAD/IFox.CAD.Shared/SelectionFilter/OpComp.cs rename to src/CADShared/SelectionFilter/OpComp.cs index 040090a873c022825fe151286663f908a8627abe..050c12286544255734d7ed581bbecc36a4703395 100644 --- a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpComp.cs +++ b/src/CADShared/SelectionFilter/OpComp.cs @@ -16,10 +16,7 @@ public class OpComp : OpEqual /// /// 符号名 /// - public override string Name - { - get { return "Comp"; } - } + public override string Name => "Comp"; /// /// 比较运算符类构造函数 diff --git a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpEqual.cs b/src/CADShared/SelectionFilter/OpEqual.cs similarity index 96% rename from src/CAD/IFox.CAD.Shared/SelectionFilter/OpEqual.cs rename to src/CADShared/SelectionFilter/OpEqual.cs index 370a0c1df77d26be65336eb823bff20f15c8db18..e23e286081d4a6c61db0862975583c26d881a4a5 100644 --- a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpEqual.cs +++ b/src/CADShared/SelectionFilter/OpEqual.cs @@ -13,10 +13,7 @@ public class OpEqual : OpFilter /// /// 符号名 /// - public override string Name - { - get { return "Equal"; } - } + public override string Name => "Equal"; /// /// 相等运算符类构造函数 diff --git a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpFilter.cs b/src/CADShared/SelectionFilter/OpFilter.cs similarity index 99% rename from src/CAD/IFox.CAD.Shared/SelectionFilter/OpFilter.cs rename to src/CADShared/SelectionFilter/OpFilter.cs index 48843f4a4e81c7de11313c9a4ff49f36240585b5..7eb495db4a131fa9fd17f2e150907dee87f4752c 100644 --- a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpFilter.cs +++ b/src/CADShared/SelectionFilter/OpFilter.cs @@ -328,7 +328,7 @@ private static Op GetCompOp(string content, Op left, object right) /// /// 是否相等 /// - public override bool Equals(object obj) => base.Equals(obj); + public override bool Equals(object? obj) => base.Equals(obj); /// /// 获取HashCode diff --git a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpList.cs b/src/CADShared/SelectionFilter/OpList.cs similarity index 82% rename from src/CAD/IFox.CAD.Shared/SelectionFilter/OpList.cs rename to src/CADShared/SelectionFilter/OpList.cs index 5870be92ecccc2559d74ed49971d2628b2b23efa..d6e84d02305dbe2f0b3b92caba8143dabca98661 100644 --- a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpList.cs +++ b/src/CADShared/SelectionFilter/OpList.cs @@ -8,7 +8,7 @@ public abstract class OpList : OpLogi /// /// 过滤器列表 /// - protected List _lst = new(); + protected readonly List Lst = []; /// /// 添加过滤器条件的虚函数,子类可以重写 @@ -35,7 +35,7 @@ public abstract class OpList : OpLogi /// 过滤器对象 public virtual void Add(OpFilter value) { - _lst.Add(value); + Lst.Add(value); } /// @@ -47,7 +47,7 @@ public virtual void Add(OpFilter value) public void Add(string speccode, int code, object value) { if (speccode == "~") - _lst.Add(new OpEqual(code, value).Not); + Lst.Add(new OpEqual(code, value).Not); } /// @@ -57,7 +57,7 @@ public void Add(string speccode, int code, object value) /// 组码值 public void Add(int code, object value) { - _lst.Add(new OpEqual(code, value)); + Lst.Add(new OpEqual(code, value)); } /// @@ -67,7 +67,7 @@ public void Add(int code, object value) /// 组码值 public void Add(DxfCode code, object value) { - _lst.Add(new OpEqual(code, value)); + Lst.Add(new OpEqual(code, value)); } /// @@ -78,7 +78,7 @@ public void Add(DxfCode code, object value) /// 比较运算符 public void Add(int code, object value, string comp) { - _lst.Add(new OpComp(comp, code, value)); + Lst.Add(new OpComp(comp, code, value)); } /// @@ -89,18 +89,17 @@ public void Add(int code, object value, string comp) /// 比较运算符 public void Add(DxfCode code, object value, string comp) { - _lst.Add(new OpComp(comp, code, value)); + Lst.Add(new OpComp(comp, code, value)); } /// /// 过滤器迭代器 /// /// OpFilter迭代器 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public override IEnumerator GetEnumerator() { - foreach (var value in _lst) - yield return value; + return Lst.GetEnumerator(); } } @@ -112,10 +111,7 @@ public class OpAnd : OpList /// /// 符号名 /// - public override string Name - { - get { return "And"; } - } + public override string Name => "And"; /// /// 添加过滤条件 @@ -126,11 +122,11 @@ public override void Add(OpFilter value) if (value is OpAnd opand) { foreach (var item in opand) - _lst.Add(item); + Lst.Add(item); } else { - _lst.Add(value); + Lst.Add(value); } } } @@ -143,10 +139,7 @@ public class OpOr : OpList /// /// 符号名 /// - public override string Name - { - get { return "Or"; } - } + public override string Name => "Or"; /// /// 添加过滤条件 @@ -157,11 +150,11 @@ public override void Add(OpFilter value) if (value is OpOr opor) { foreach (var item in opor) - _lst.Add(item); + Lst.Add(item); } else { - _lst.Add(value); + Lst.Add(value); } } } \ No newline at end of file diff --git a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpLogi.cs b/src/CADShared/SelectionFilter/OpLogi.cs similarity index 82% rename from src/CAD/IFox.CAD.Shared/SelectionFilter/OpLogi.cs rename to src/CADShared/SelectionFilter/OpLogi.cs index bdacb864787797fc5fa97cc16dfac61e10fe78e8..b5570d180e8d356eecf618441064328e3e3dfb51 100644 --- a/src/CAD/IFox.CAD.Shared/SelectionFilter/OpLogi.cs +++ b/src/CADShared/SelectionFilter/OpLogi.cs @@ -8,18 +8,12 @@ public abstract class OpLogi : OpFilter, IEnumerable /// /// 返回-4组码的开始内容 /// - public TypedValue First - { - get { return new TypedValue(-4, $"<{Name}"); } - } + public TypedValue First => new(-4, $"<{Name}"); /// /// 返回-4组码的结束内容 /// - public TypedValue Last - { - get { return new TypedValue(-4, $"{Name}>"); } - } + public TypedValue Last => new(-4, $"{Name}>"); /// /// 获取过滤条件 @@ -41,10 +35,10 @@ public override IEnumerable GetValues() /// 获取迭代器 /// /// OpFilter迭代器 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public abstract IEnumerator GetEnumerator(); - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); @@ -70,16 +64,13 @@ public OpNot(OpFilter value) /// /// 符号名 /// - public override string Name - { - get { return "Not"; } - } + public override string Name => "Not"; /// /// 获取迭代器 /// /// OpFilter迭代器 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public override IEnumerator GetEnumerator() { yield return Value; @@ -115,16 +106,13 @@ public OpXor(OpFilter left, OpFilter right) /// /// 符号名 /// - public override string Name - { - get { return "Xor"; } - } + public override string Name => "Xor"; /// /// 获取迭代器 /// /// 选择集过滤器类型迭代器 - [System.Diagnostics.DebuggerStepThrough] + [DebuggerStepThrough] public override IEnumerator GetEnumerator() { yield return Left; diff --git a/src/WPF/IFox.WPF.csproj b/src/Directory.Build.props similarity index 44% rename from src/WPF/IFox.WPF.csproj rename to src/Directory.Build.props index 4f84d57b3418a4bc882050335dce137115c80b45..ecea578387dd4d2d8c628c35552bfcc1d73a0bcc 100644 --- a/src/WPF/IFox.WPF.csproj +++ b/src/Directory.Build.props @@ -1,44 +1,37 @@ - + + + + 0.9.8.1 + 支持中望cad的进度条 + - 0.4 - 开启可空类型. - - preview enable - NET45 - true - true true - ..\..\bin\$(Configuration)\ - true - xsfhlzh;vicwjb - xsfhlzh;vicwjb;liuqihong + true + true + True + True + x64 + IFoxCAD.CAD + true + true + ..\..\bin\$(Configuration)\ + + + InspireFunction - WPF的简单MVVM模式开发类库 + xsfhlzh;vicwjb;liuqihong;DYH InspireFunction - LICENSE + 基于.NET的二次开发基本类库. + true https://gitee.com/inspirefunction/ifoxcad https://gitee.com/inspirefunction/ifoxcad.git - IFoxCAD;C#;NET;WPF;MVVM git - True - - - - DEBUG;TRACE + IFox;cad;AutoCad;C#;NET;ZwCad + readme.md + LICENSE - - - - - - - True - - - - - + \ No newline at end of file diff --git a/src/CAD/IFox.CAD.ACAD/GlobalUsings.cs b/src/IFoxCAD.AutoCad/GlobalUsings.cs similarity index 44% rename from src/CAD/IFox.CAD.ACAD/GlobalUsings.cs rename to src/IFoxCAD.AutoCad/GlobalUsings.cs index dadfe53fe00dea58372bc2f77740aedf67c137a9..adf89e10316a196f8b4e189daf2deb2406ff0157 100644 --- a/src/CAD/IFox.CAD.ACAD/GlobalUsings.cs +++ b/src/IFoxCAD.AutoCad/GlobalUsings.cs @@ -1,49 +1,54 @@ -// 系统引用 +global using Autodesk.AutoCAD.ApplicationServices; +global using Autodesk.AutoCAD.DatabaseServices; +global using Autodesk.AutoCAD.EditorInput; +global using Autodesk.AutoCAD.Geometry; +global using Autodesk.AutoCAD.GraphicsInterface; +global using Autodesk.AutoCAD.Runtime; +global using Autodesk.AutoCAD.Windows; +global using Autodesk.AutoCAD.Colors; +global using Autodesk.AutoCAD.DatabaseServices.Filters; +global using Autodesk.AutoCAD.GraphicsSystem; +global using LineWeight = Autodesk.AutoCAD.DatabaseServices.LineWeight; +global using Viewport = Autodesk.AutoCAD.DatabaseServices.Viewport; +global using Color = Autodesk.AutoCAD.Colors.Color; +global using Acap = Autodesk.AutoCAD.ApplicationServices.Application; +global using Acaop = Autodesk.AutoCAD.ApplicationServices.Core.Application; +global using Polyline = Autodesk.AutoCAD.DatabaseServices.Polyline; +global using Group = Autodesk.AutoCAD.DatabaseServices.Group; +global using CursorType = Autodesk.AutoCAD.EditorInput.CursorType; +global using ColorDialog = Autodesk.AutoCAD.Windows.ColorDialog; +global using StatusBar = Autodesk.AutoCAD.Windows.StatusBar; +global using Utils = Autodesk.AutoCAD.Internal.Utils; +global using SystemVariableChangedEventArgs = Autodesk.AutoCAD.ApplicationServices.SystemVariableChangedEventArgs; +global using AcException = Autodesk.AutoCAD.Runtime.Exception; +global using Marshaler = Autodesk.AutoCAD.Runtime.Marshaler; global using System; +global using System.Reflection; global using System.Collections; global using System.Collections.Generic; global using System.IO; global using System.Linq; +global using System.Threading; global using System.Text; -global using System.Reflection; -global using System.Text.RegularExpressions; -global using Microsoft.Win32; -global using System.ComponentModel; global using System.Runtime.InteropServices; -global using System.Collections.Specialized; - +global using System.ComponentModel; +global using System.Security; global using Exception = System.Exception; - +global using DrawingColor = System.Drawing.Color; global using Registry = Microsoft.Win32.Registry; global using RegistryKey = Microsoft.Win32.RegistryKey; +global using Region = Autodesk.AutoCAD.DatabaseServices.Region; +global using Microsoft.Win32; +global using System.Linq.Expressions; +global using System.Collections.ObjectModel; +// 系统引用 +global using System.Text.RegularExpressions; +global using System.Runtime.CompilerServices; +global using System.Windows.Input; +global using System.Globalization; +global using System.Diagnostics; -// cad 引用 -global using Autodesk.AutoCAD.ApplicationServices; -global using Autodesk.AutoCAD.EditorInput; -global using Autodesk.AutoCAD.Colors; -global using Autodesk.AutoCAD.DatabaseServices; -global using Autodesk.AutoCAD.Geometry; -global using Autodesk.AutoCAD.Runtime; -global using Acap = Autodesk.AutoCAD.ApplicationServices.Application; -global using Acgi = Autodesk.AutoCAD.GraphicsInterface; - -global using Autodesk.AutoCAD.DatabaseServices.Filters; -global using Autodesk.AutoCAD; - -// jig命名空间会引起Viewport/Polyline等等重义,最好逐个引入 using Autodesk.AutoCAD.GraphicsInterface -global using Autodesk.AutoCAD.GraphicsInterface; -global using WorldDraw = Autodesk.AutoCAD.GraphicsInterface.WorldDraw; -global using Manager = Autodesk.AutoCAD.GraphicsSystem.Manager; -global using Group = Autodesk.AutoCAD.DatabaseServices.Group; -global using Viewport = Autodesk.AutoCAD.DatabaseServices.Viewport; -global using Polyline = Autodesk.AutoCAD.DatabaseServices.Polyline; -global using Cad_DwgFiler = Autodesk.AutoCAD.DatabaseServices.DwgFiler; -global using Cad_DxfFiler = Autodesk.AutoCAD.DatabaseServices.DxfFiler; -global using Cad_ErrorStatus = Autodesk.AutoCAD.Runtime.ErrorStatus; - -// ifoxcad.basal 引用 -global using IFoxCAD.Basal; - -#if !NewtonsoftJson -global using System.Web.Script.Serialization; -#endif \ No newline at end of file +// global using System.Windows.Data; +global using System.Net; +global using System.Diagnostics.CodeAnalysis; +global using IFoxCAD.Basal; \ No newline at end of file diff --git a/src/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj b/src/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj new file mode 100644 index 0000000000000000000000000000000000000000..eb42055c23f762c97898781a000bc9e54fb051ce --- /dev/null +++ b/src/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj @@ -0,0 +1,59 @@ + + + + net8.0-windows;net48 + + + + + IFox.CAD.ACAD + IFox.CAD.ACAD + IFox.CAD.ACAD + + + + none + True + + + + none + false + bin\Release\IFoxCAD.AutoCad.xml + + + + $(Configuration);acad;a2024 + + + + $(Configuration);acad;a2025 + true + + + + + True + \ + + + True + \ + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/src/IFoxCAD.ZwCad/GlobalUsings.cs b/src/IFoxCAD.ZwCad/GlobalUsings.cs new file mode 100644 index 0000000000000000000000000000000000000000..7b2f55ea664aed674b9ddb68d4961b29aad7e3ec --- /dev/null +++ b/src/IFoxCAD.ZwCad/GlobalUsings.cs @@ -0,0 +1,53 @@ +global using ZwSoft.ZwCAD.ApplicationServices; +global using ZwSoft.ZwCAD.DatabaseServices; +global using ZwSoft.ZwCAD.EditorInput; +global using ZwSoft.ZwCAD.Geometry; +global using ZwSoft.ZwCAD.GraphicsInterface; +global using ZwSoft.ZwCAD.Runtime; +global using ZwSoft.ZwCAD.Windows; +global using ZwSoft.ZwCAD.Colors; +global using ZwSoft.ZwCAD.DatabaseServices.Filters; +global using ZwSoft.ZwCAD.GraphicsSystem; +global using LineWeight = ZwSoft.ZwCAD.DatabaseServices.LineWeight; +global using Viewport = ZwSoft.ZwCAD.DatabaseServices.Viewport; +global using Color = ZwSoft.ZwCAD.Colors.Color; +global using Acap = ZwSoft.ZwCAD.ApplicationServices.Application; +global using Acaop = ZwSoft.ZwCAD.ApplicationServices.Core.Application; +global using Polyline = ZwSoft.ZwCAD.DatabaseServices.Polyline; +global using Group = ZwSoft.ZwCAD.DatabaseServices.Group; +global using CursorType = ZwSoft.ZwCAD.EditorInput.CursorType; +global using ColorDialog = ZwSoft.ZwCAD.Windows.ColorDialog; +global using StatusBar = ZwSoft.ZwCAD.Windows.StatusBar; +global using Utils = ZwSoft.ZwCAD.Internal.Utils; +global using SystemVariableChangedEventArgs = ZwSoft.ZwCAD.ApplicationServices.SystemVariableChangedEventArgs; +global using AcException = ZwSoft.ZwCAD.Runtime.Exception; +global using Marshaler = ZwSoft.ZwCAD.Runtime.Marshaler; +global using System; +global using System.Reflection; +global using System.Collections; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Threading; +global using System.Text; +global using System.Runtime.InteropServices; +global using System.ComponentModel; +global using Exception = System.Exception; +global using DrawingColor = System.Drawing.Color; +global using Registry = Microsoft.Win32.Registry; +global using RegistryKey = Microsoft.Win32.RegistryKey; +global using Region = ZwSoft.ZwCAD.DatabaseServices.Region; +global using Microsoft.Win32; +global using System.Linq.Expressions; +global using System.Collections.ObjectModel; +// 系统引用 +global using System.Text.RegularExpressions; +global using System.Runtime.CompilerServices; +global using System.Windows.Input; +global using System.Globalization; +global using System.Diagnostics; + +// global using System.Windows.Data; +global using System.Net; +global using System.Diagnostics.CodeAnalysis; +global using IFoxCAD.Basal; \ No newline at end of file diff --git a/src/IFoxCAD.ZwCad/IFoxCAD.ZwCad.csproj b/src/IFoxCAD.ZwCad/IFoxCAD.ZwCad.csproj new file mode 100644 index 0000000000000000000000000000000000000000..734e455a33f0c3486f5e0ad6086ce1e35c13752c --- /dev/null +++ b/src/IFoxCAD.ZwCad/IFoxCAD.ZwCad.csproj @@ -0,0 +1,48 @@ + + + net48;net472 + + + + IFox.CAD.ZCAD + IFox.CAD.ZCAD + IFox.CAD.ZCAD + + + + none + True + + + + none + false + bin\Release\IFoxCAD.ZwCad.xml + + + + $(Configuration);zcad;z2025 + + + + + True + \ + + + True + \ + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/src/WPF/BindingErrorTraceListener.cs b/src/WPF/BindingErrorTraceListener.cs deleted file mode 100644 index 9ba3a4b89b089ec21762575a477c06499f33ec36..0000000000000000000000000000000000000000 --- a/src/WPF/BindingErrorTraceListener.cs +++ /dev/null @@ -1,84 +0,0 @@ -namespace IFoxCAD.WPF; -using System.Text.RegularExpressions; - -/* - xaml 需要绑定失败时候报错(vs默认是不报错的): - https://cloud.tencent.com/developer/article/1342661 - 所有的绑定输出,重写方法就可以转发,构造函数上加入: - public MainWindow() - { - PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Error; - PresentationTraceSources.DataBindingSource.Listeners.Add(new BindingErrorTraceListener()); - App.Current.DispatcherUnhandledException += DispatcherUnhandledException; - // InitializeComponent(); - // DataContext = new ViewModel(); - } - private void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) - { - if (e.Exception is BindingErrorException bindingErrorException) - { - MessageBox.Show($"Binding error. {bindingErrorException.SourceObject}.{bindingErrorException.SourceProperty} {bindingErrorException.TargetElement}.{bindingErrorException.TargetProperty}"); - } - } -*/ - -/// -/// 属性绑定错误异常 -/// -public class BindingErrorException : Exception -{ - /// - /// 来源对象 - /// - public string? SourceObject { get; set; } - /// - /// 来源属性 - /// - public string? SourceProperty { get; set; } - /// - /// 目标元素 - /// - public string? TargetElement { get; set; } - /// - /// 目标属性 - /// - public string? TargetProperty { get; set; } - - public BindingErrorException() : base() - { - } - - public BindingErrorException(string message) : base(message) - { - } -} - -/// -/// 属性绑定错误侦听器 -/// -public class BindingErrorTraceListener : TraceListener -{ - const string BindingErrorPattern = - @"^BindingExpression path error(?:.+)'(.+)' property not found(?:.+)object[\s']+(.+?)'(?:.+)target element is '(.+?)'(?:.+)target property is '(.+?)'(?:.+)$"; - - public override void Write(string message) - { - Trace.WriteLine(string.Format("[Write]{0}", message)); - Debug.WriteLine(string.Format("[Write]{0}", message)); - } - - public override void WriteLine(string message) - { - var match = Regex.Match(message, BindingErrorPattern); - if (match.Success) - { - throw new BindingErrorException(message) - { - SourceObject = match.Groups[2].ToString(), - SourceProperty = match.Groups[1].ToString(), - TargetElement = match.Groups[3].ToString(), - TargetProperty = match.Groups[4].ToString() - }; - } - } -} \ No newline at end of file diff --git a/src/WPF/Converter.cs b/src/WPF/Converter.cs deleted file mode 100644 index 828ece9dbb93fb1f666b42ccad7ddbd2a6c77705..0000000000000000000000000000000000000000 --- a/src/WPF/Converter.cs +++ /dev/null @@ -1,98 +0,0 @@ -namespace IFoxCAD.WPF; - -/// -/// 字符串到整数的转换器 -/// -public class StringToIntConverter : IValueConverter -{ - /// - /// 字符串转换到整数 - /// - /// 绑定源生成的值 - /// 绑定目标属性的类型 - /// 要使用的转换器参数 - /// 要用在转换器中的区域性 - /// 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - string? a = value as string; - _ = int.TryParse(a, out int b); - return b; - } - /// - /// 整数转换到字符串 - /// - /// 绑定目标生成的值 - /// 要转换为的类型 - /// 要使用的转换器参数 - /// 要用在转换器中的区域性 - /// 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return value.ToString(); - } -} -/// -/// 字符串到实数的转换器 -/// -public class StringToDoubleConverter : IValueConverter -{ - /// - /// 字符串转换到实数 - /// - /// 绑定源生成的值 - /// 绑定目标属性的类型 - /// 要使用的转换器参数 - /// 要用在转换器中的区域性 - /// 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - string? a = value as string; - _ = double.TryParse(a, out double b); - return b; - } - /// - /// 实数转换到字符串 - /// - /// 绑定目标生成的值 - /// 要转换为的类型 - /// 要使用的转换器参数 - /// 要用在转换器中的区域性 - /// 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return value.ToString(); - } -} -/// -/// 整数到字符串的转换器 -/// -public class IntToStringConverter : IValueConverter -{ - /// - /// 整数转换到字符串 - /// - /// 绑定源生成的值 - /// 绑定目标属性的类型 - /// 要使用的转换器参数 - /// 要用在转换器中的区域性 - /// 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value.ToString(); - } - /// - /// 字符串转换到整数 - /// - /// 绑定目标生成的值 - /// 要转换为的类型 - /// 要使用的转换器参数 - /// 要用在转换器中的区域性 - /// 转换后的值。 如果该方法返回 null,则使用有效的 null 值。 - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - string? a = value as string; - _ = int.TryParse(a, out int b); - return b; - } -} diff --git a/src/WPF/DependencyObjectExtensions.cs b/src/WPF/DependencyObjectExtensions.cs deleted file mode 100644 index 085285879e5dbbf5099273f3ac88cb68a692a406..0000000000000000000000000000000000000000 --- a/src/WPF/DependencyObjectExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace IFoxCAD.WPF; - -/// -/// 依赖属性扩展类 -/// -public static class DependencyObjectExtensions -{ - /// - /// 获取父对象依赖属性 - /// - /// 子对象 - /// 依赖属性 - public static DependencyObject? GetParentObject(this DependencyObject child) - { - if (child is null) return null; - - if (child is ContentElement ce) - { - var parent = ContentOperations.GetParent(ce); - if (parent is not null) - return parent; - - var fce = ce as FrameworkContentElement; - return fce?.Parent; - } - - if (child is FrameworkElement fe) - { - var parent = fe.Parent; - if (parent is not null) - return parent; - } - - return VisualTreeHelper.GetParent(child); - } -} \ No newline at end of file diff --git a/src/WPF/EnumSelection.cs b/src/WPF/EnumSelection.cs deleted file mode 100644 index 96630e4b9fe2cb6ac62e5f849bdef5793af168e4..0000000000000000000000000000000000000000 --- a/src/WPF/EnumSelection.cs +++ /dev/null @@ -1,80 +0,0 @@ -namespace IFoxCAD.WPF; -public class EnumSelection : INotifyPropertyChanged where T : struct, IComparable, IFormattable, IConvertible -{ - private T value; // stored value of the Enum - private readonly bool isFlagged; // Enum uses flags? - private readonly bool canDeselect; // Can be deselected? (Radio buttons cannot deselect, checkboxes can) - private readonly T blankValue; // what is considered the "blank" value if it can be deselected? - - public EnumSelection(T value) : this(value, false, default) - { - } - public EnumSelection(T value, bool canDeselect) : this(value, canDeselect, default) - { - } - public EnumSelection(T value, T blankValue) : this(value, true, blankValue) - { - } - public EnumSelection(T value, bool canDeselect, T blankValue) - { - if (!typeof(T).IsEnum) - throw new ArgumentException($"{nameof(T)} must be an enum type"); // I really wish there was a way to constrain generic types to enums... - isFlagged = typeof(T).IsDefined(typeof(FlagsAttribute), false); - - this.value = value; - this.canDeselect = canDeselect; - this.blankValue = blankValue; - } - - public T Value - { - get { return value; } - set - { - if (this.value.Equals(value)) return; - this.value = value; - OnPropertyChanged(); - OnPropertyChanged("Item[]"); // Notify that the indexer property has changed - } - } - - [IndexerName("Item")] - public bool this[T key] - { - get - { - int iKey = (int)(object)key; - return isFlagged ? ((int)(object)value & iKey) == iKey : value.Equals(key); - } - set - { - if (isFlagged) - { - int iValue = (int)(object)this.value; - int iKey = (int)(object)key; - - if ((iValue & iKey) == iKey == value) - return; - - if (value) - Value = (T)(object)(iValue | iKey); - else - Value = (T)(object)(iValue & ~iKey); - } - else - { - if (this.value.Equals(key) == value) return; - if (!value && !canDeselect) return; - - Value = value ? key : blankValue; - } - } - } - - public event PropertyChangedEventHandler? PropertyChanged; - - private void OnPropertyChanged([CallerMemberName] string propertyName = "") - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } -} \ No newline at end of file diff --git a/src/WPF/EventBindingExtension.cs b/src/WPF/EventBindingExtension.cs deleted file mode 100644 index ab46a128043ee2107c4d0a1e28974f4b4583e00a..0000000000000000000000000000000000000000 --- a/src/WPF/EventBindingExtension.cs +++ /dev/null @@ -1,190 +0,0 @@ -namespace IFoxCAD.WPF; - -/// -/// 事件绑定标签类 -/// -/// -public class EventBindingExtension : MarkupExtension -{ - /// - /// 命令属性 - /// - public string? Command { get; set; } - /// - /// 命令参数属性 - /// - public string? CommandParameter { get; set; } - /// - /// 当在派生类中实现时,返回用作此标记扩展的目标属性值的对象。 - /// - /// 可为标记扩展提供服务的服务提供程序帮助程序。 - /// - /// 要在应用了扩展的属性上设置的对象值。 - /// - /// - /// - public override object? ProvideValue(IServiceProvider serviceProvider) - { - if (serviceProvider is null) - throw new ArgumentNullException(nameof(serviceProvider)); - if (serviceProvider.GetService(typeof(IProvideValueTarget)) is not IProvideValueTarget targetProvider) - throw new InvalidOperationException(message: $"{nameof(ProvideValue)}:{nameof(IProvideValueTarget)}"); - - if (targetProvider.TargetObject is not FrameworkElement targetObject) - throw new InvalidOperationException(message: $"{nameof(ProvideValue)}:{nameof(FrameworkElement)}"); - - if (targetProvider.TargetProperty is not MemberInfo memberInfo) - throw new InvalidOperationException(message: $"{nameof(ProvideValue)}:{nameof(MemberInfo)}"); - - if (string.IsNullOrWhiteSpace(Command)) - { - Command = memberInfo.Name.Replace("Add", ""); - if (Command.Contains("Handler")) - Command = Command.Replace("Handler", "Command"); - else - Command += "Command"; - } - - return CreateHandler(memberInfo, Command!, targetObject.GetType()); - } - - private Type? GetEventHandlerType(MemberInfo memberInfo) - { - Type? eventHandlerType = null; - if (memberInfo is EventInfo eventInfo) - { - // var info = memberInfo as EventInfo; - // var eventInfo = info; - eventHandlerType = eventInfo.EventHandlerType; - } - else if (memberInfo is MethodInfo methodInfo) - { - // var info = memberInfo as MethodInfo; - // var methodInfo = info; - var pars = methodInfo.GetParameters(); - eventHandlerType = pars[1].ParameterType; - } - - return eventHandlerType; - } - -#pragma warning disable IDE0060 // 删除未使用的参数 - private object? CreateHandler(MemberInfo memberInfo, string cmdName, Type targetType) -#pragma warning restore IDE0060 // 删除未使用的参数 - { - var eventHandlerType = GetEventHandlerType(memberInfo); - if (eventHandlerType is null) - return null; - - var handlerInfo = eventHandlerType.GetMethod("Invoke"); - var method = new DynamicMethod("", handlerInfo.ReturnType, - new Type[] - { - handlerInfo.GetParameters()[0].ParameterType, - handlerInfo.GetParameters()[1].ParameterType, - }); - - var gen = method.GetILGenerator(); - gen.Emit(OpCodes.Ldarg, 0); - gen.Emit(OpCodes.Ldarg, 1); - gen.Emit(OpCodes.Ldstr, cmdName); - - if (CommandParameter is null) - gen.Emit(OpCodes.Ldnull); - else - gen.Emit(OpCodes.Ldstr, CommandParameter); - - gen.Emit(OpCodes.Call, getMethod); - gen.Emit(OpCodes.Ret); - - return method.CreateDelegate(eventHandlerType); - } - - static readonly MethodInfo getMethod = typeof(EventBindingExtension) - .GetMethod("HandlerIntern", new Type[] { typeof(object), typeof(object), typeof(string), typeof(string) }); - -#pragma warning disable IDE0051 // 删除未使用的私有成员 - static void Handler(object sender, object args) -#pragma warning restore IDE0051 // 删除未使用的私有成员 - { - HandlerIntern(sender, args, "cmd", null); - } - /// - /// Handlers the intern. - /// - /// The sender. - /// The arguments. - /// Name of the command. - /// The command parameter. - public static void HandlerIntern(object sender, object args, string cmdName, string? commandParameter) - { - if (sender is FrameworkElement fe) - { - var cmd = GetCommand(fe, cmdName); - object? commandParam = null; - if (!string.IsNullOrWhiteSpace(commandParameter)) - commandParam = GetCommandParameter(fe, args, commandParameter!); - if ((cmd is not null) && cmd.CanExecute(commandParam)) - cmd.Execute(commandParam); - } - } - - internal static ICommand? GetCommand(FrameworkElement target, string cmdName) - { - var vm = FindViewModel(target); - if (vm is null) - return null; - - var vmType = vm.GetType(); - var cmdProp = vmType.GetProperty(cmdName); - if (cmdProp is not null) - return cmdProp.GetValue(vm) as ICommand; -#if DEBUG - throw new Exception("EventBinding path error: '" + cmdName + "' property not found on '" + vmType + "' 'DelegateCommand'"); -#else - return null; -#endif - } - - internal static object GetCommandParameter(FrameworkElement target, object args, string commandParameter) - { - var classify = commandParameter.Split('.'); - object ret = classify[0] switch - { - "$e" => args, - "$this" => classify.Length > 1 ? FollowPropertyPath(target, commandParameter.Replace("$this.", ""), target.GetType()) : target, - _ => commandParameter, - }; - return ret; - } - - internal static ViewModelBase? FindViewModel(FrameworkElement? target) - { - if (target is null) - return null; - if (target.DataContext is ViewModelBase vm) - return vm; - return FindViewModel(target.GetParentObject() as FrameworkElement); - } - - internal static object FollowPropertyPath(object target, string path, Type? valueType = null) - { - if (target is null) - throw new ArgumentNullException(nameof(target)); - if (path is null) - throw new ArgumentNullException(nameof(path)); - - valueType ??= target.GetType(); - var spls = path.Split('.'); - for (int i = 0; i < spls.Length; i++) - { - var property = valueType.GetProperty(spls[i]); - if (property is null) - throw new NullReferenceException("property"); - - target = property.GetValue(target); - valueType = property.PropertyType; - } - return target; - } -} \ No newline at end of file diff --git a/src/WPF/GlobalUsings.cs b/src/WPF/GlobalUsings.cs deleted file mode 100644 index 8ab21a76dba6ba34a2a08bdd6a6d0343f8572b9d..0000000000000000000000000000000000000000 --- a/src/WPF/GlobalUsings.cs +++ /dev/null @@ -1,18 +0,0 @@ -/// 系统引用 -global using System; -global using System.Collections; -global using System.Collections.Generic; -global using System.IO; -global using System.Linq; -global using System.ComponentModel; -global using System.Runtime.CompilerServices; -global using System.Diagnostics; -global using System.Windows; -global using System.Windows.Input; -global using System.Reflection.Emit; -global using System.Windows.Markup; -global using System.Reflection; -global using System.Windows.Media; -global using System.Globalization; -global using System.Windows.Data; - diff --git a/src/WPF/RelayCommand.cs b/src/WPF/RelayCommand.cs deleted file mode 100644 index 5d3577760b88c9f3dba168f4acf17883b584632f..0000000000000000000000000000000000000000 --- a/src/WPF/RelayCommand.cs +++ /dev/null @@ -1,181 +0,0 @@ -using Microsoft.Xaml.Behaviors; - -namespace IFoxCAD.WPF; - -/// -/// 命令基类 -/// -/// -public class RelayCommand : ICommand -{ - readonly Func? _canExecute; - readonly Action _execute; - /// - /// 初始化 类. - /// - /// 执行函数 - public RelayCommand(Action execute) : this(execute, null) - { - } - /// - /// 初始化 类. - /// - /// 执行函数委托 - /// 是否可执行函数委托 - /// execute - public RelayCommand(Action execute, Func? canExecute) - { - _execute = execute ?? throw new ArgumentNullException(nameof(execute)); - _canExecute = canExecute; - } - - /// - /// 当出现影响是否应执行该命令的更改时发生。 - /// - public event EventHandler CanExecuteChanged - { - add - { - if (_canExecute is not null) - CommandManager.RequerySuggested += value; - } - remove - { - if (_canExecute is not null) - CommandManager.RequerySuggested -= value; - } - } - /// - /// 定义确定此命令是否可在其当前状态下执行的方法。 - /// - /// 此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 。 - /// - /// 如果可执行此命令,则为 ;否则为 。 - /// - [DebuggerStepThrough] - public bool CanExecute(object parameter) - { - return _canExecute is null || _canExecute(parameter); - } - /// - /// 定义在调用此命令时要调用的方法。 - /// - /// 此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 。 - public void Execute(object parameter) - { - _execute(parameter); - } -} - -/// -/// 命令泛型基类 -/// -/// 事件类型 -/// -public class RelayCommand : ICommand -{ - readonly Func _canExecute; - readonly Action _execute; - /// - /// 初始化 类。 - /// - /// 执行函数 - public RelayCommand(Action execute) : this(execute, (o) => true) - { - } - - /// - /// 初始化 类。 - /// - /// 执行函数委托 - /// 是否可执行函数委托 - /// execute - public RelayCommand(Action execute, Func canExecute) - { - _execute = execute ?? throw new ArgumentNullException(nameof(execute)); - _canExecute = canExecute; - } - /// - /// 当出现影响是否应执行该命令的更改时发生。 - /// - public event EventHandler CanExecuteChanged - { - add - { - if (_canExecute is not null) - CommandManager.RequerySuggested += value; - } - remove - { - if (_canExecute is not null) - CommandManager.RequerySuggested -= value; - } - } - /// - /// 定义确定此命令是否可在其当前状态下执行的方法。 - /// - /// 此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 。 - /// - /// 如果可执行此命令,则为 ;否则为 。 - /// - public bool CanExecute(object parameter) - { - if (_canExecute is null) - return true; - return _canExecute((T)parameter); - } - /// - /// 定义在调用此命令时要调用的方法。 - /// - /// 此命令使用的数据。 如果此命令不需要传递数据,则该对象可以设置为 。 - public void Execute(object parameter) - { - if (_execute is not null && CanExecute(parameter)) - _execute((T)parameter); - } -} - -/// -/// 事件命令 -/// -public class EventCommand : TriggerAction -{ - /// - /// 执行动作 - /// - /// 要执行的动作参数, 如果动作为提供参数,就设置为null - protected override void Invoke(object parameter) - { - if (CommandParameter is not null) - parameter = CommandParameter; - if (Command is not null) - Command.Execute(parameter); - } - /// - /// 事件 - /// - public ICommand Command - { - get { return (ICommand)GetValue(CommandProperty); } - set { SetValue(CommandProperty, value); } - } - /// - /// 事件属性 - /// - public static readonly DependencyProperty CommandProperty = - DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommand), new PropertyMetadata(null)); - - /// - /// 事件参数,如果为空,将自动传入事件的真实参数 - /// - public object CommandParameter - { - get { return (object)GetValue(CommandParameterProperty); } - set { SetValue(CommandParameterProperty, value); } - } - /// - /// 事件参数属性 - /// - public static readonly DependencyProperty CommandParameterProperty = - DependencyProperty.Register("CommandParameter", typeof(object), typeof(EventCommand), new PropertyMetadata(null)); -} \ No newline at end of file diff --git a/src/WPF/ViewModelBase.cs b/src/WPF/ViewModelBase.cs deleted file mode 100644 index 6d8908a51fcac922b9edaf827362060b8170f74f..0000000000000000000000000000000000000000 --- a/src/WPF/ViewModelBase.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace IFoxCAD.WPF; - -/// -/// ViewModel基类 -/// -/// -public class ViewModelBase : INotifyPropertyChanged -{ - /// - /// 属性值更改事件。 - /// - public event PropertyChangedEventHandler? PropertyChanged; - /// - /// 属性改变时调用 - /// - /// 属性名 - public void OnPropertyChanged([CallerMemberName] string propertyName = "") - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - /// - /// 设置属性函数,自动通知属性改变事件 - /// - /// 属性类型 - /// 属性 - /// 属性值 - /// 属性名 - /// 成功返回 ,反之 - protected virtual bool Set(ref T storage, T value, [CallerMemberName] string propertyName = "") - { - if (object.Equals(storage, value)) - return false; - - storage = value; - this.OnPropertyChanged(propertyName); - - return true; - } - /// - /// 创建命令 - /// - /// 要调用的命令函数委托 - /// WPF命令 - protected RelayCommand CreateCommand(Action executeMethod) - { - return CreateCommand(executeMethod, (o) => true); - } - /// - /// 创建命令 - /// - /// 要调用的命令函数委托 - /// 命令是否可以执行的委托 - /// WPF命令 - protected RelayCommand CreateCommand(Action executeMethod, Func canExecuteMethod) - { - return new(executeMethod, canExecuteMethod); - } -} \ No newline at end of file diff --git a/tests/TestAcad09plus/Properties/Resources.Designer.cs b/tests/TestAcad09plus/Properties/Resources.Designer.cs deleted file mode 100644 index 161702059b435207c6a4ea08f19fcd8d4360891b..0000000000000000000000000000000000000000 --- a/tests/TestAcad09plus/Properties/Resources.Designer.cs +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// 此代码由工具生成。 -// 运行时版本:4.0.30319.42000 -// -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 -// -//------------------------------------------------------------------------------ - -namespace Test.Properties { - using System; - - - /// - /// 一个强类型的资源类,用于查找本地化的字符串等。 - /// - // 此类是由 StronglyTypedResourceBuilder - // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 - // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen - // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// 返回此类使用的缓存的 ResourceManager 实例。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Test.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// 重写当前线程的 CurrentUICulture 属性,对 - /// 使用此强类型资源类的所有资源查找执行重写。 - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} diff --git a/tests/TestAcad09plus/Properties/Resources.resx b/tests/TestAcad09plus/Properties/Resources.resx deleted file mode 100644 index 4fdb1b6aff69ba96d81420fab7a92b738c17f074..0000000000000000000000000000000000000000 --- a/tests/TestAcad09plus/Properties/Resources.resx +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/tests/TestAcad09plus/Properties/launchSettings.json b/tests/TestAcad09plus/Properties/launchSettings.json deleted file mode 100644 index 4b464c3296d64041c377007f682aad0199fa1e8e..0000000000000000000000000000000000000000 --- a/tests/TestAcad09plus/Properties/launchSettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "profiles": { - "Test": { - "commandName": "Executable", - "executablePath": "C:\\Program Files\\Autodesk\\AutoCAD 2021\\acad.exe", - "commandLineArgs": "/nologo", - "nativeDebugging": false - } - } -} \ No newline at end of file diff --git a/tests/TestAcad09plus/wpf/Cmd.cs b/tests/TestAcad09plus/wpf/Cmd.cs deleted file mode 100644 index 9f8140197f37f62958433ca2df2943df35c99ffd..0000000000000000000000000000000000000000 --- a/tests/TestAcad09plus/wpf/Cmd.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Test.wpf; - -public class Cmd -{ - [CommandMethod(nameof(Test_WPf))] - public void Test_WPf() - { - var test = new TestView(); - Acap.ShowModalWindow(test); - } -} \ No newline at end of file diff --git a/tests/TestAcad09plus/wpf/TestView.xaml b/tests/TestAcad09plus/wpf/TestView.xaml deleted file mode 100644 index e51e2ac54a4334535e5cd68c44e196e6b7a13905..0000000000000000000000000000000000000000 --- a/tests/TestAcad09plus/wpf/TestView.xaml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/TestAcad09plus/wpf/TestView.xaml.cs b/tests/TestAcad09plus/wpf/TestView.xaml.cs deleted file mode 100644 index 4eb001e9acea64cdee250636d9d3f9a2630dd972..0000000000000000000000000000000000000000 --- a/tests/TestAcad09plus/wpf/TestView.xaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Test.wpf; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; - - -/// -/// TestView.xaml 的交互逻辑 -/// -public partial class TestView : Window -{ - public TestView() - { - InitializeComponent(); - DataContext = new TestViewModel(); - } -} diff --git a/tests/TestAcad09plus/wpf/TestViewModel.cs b/tests/TestAcad09plus/wpf/TestViewModel.cs deleted file mode 100644 index e726029a876c62a05dfe1e8127ef3f551360bbdd..0000000000000000000000000000000000000000 --- a/tests/TestAcad09plus/wpf/TestViewModel.cs +++ /dev/null @@ -1,82 +0,0 @@ -namespace Test.wpf; - -using System.Windows; -using System.Windows.Input; - - -class TestViewModel : ViewModelBase -{ - string? name; - public string? Name - { - get { return name; } - set { Set(ref name, value); } - } - - private RelayCommand? clickCommand; - - public RelayCommand? ClickCommand - { - get - { - clickCommand ??= - new(execute => Name = "hello " + Name, - can => !string.IsNullOrEmpty(Name)); - return clickCommand; - } - } - - private bool receiveMouseMove; - public bool ReceiveMouseMove - { - get { return receiveMouseMove; } - set { Set(ref receiveMouseMove, value); } - } - - private string? tipText; - public string? TipText - { - get { return tipText; } - set { Set(ref tipText, value); } - } - - private RelayCommand? loadedCommand; - public RelayCommand? LoadCommand - { - get - { - loadedCommand ??= new(execute => MessageBox.Show("程序加载完毕")); - return loadedCommand; - } - } - - private RelayCommand? mouseMoveCommand; - public RelayCommand? MouseMoveCommand - { - get - { - mouseMoveCommand ??= new( - execute => { - var pt = execute.GetPosition(execute.Device.Target); - var left = "左键放开"; - var mid = "中键放开"; - var right = "右键放开"; - - if (execute.LeftButton == MouseButtonState.Pressed) - left = "左键放下"; - if (execute.MiddleButton == MouseButtonState.Pressed) - mid = "中键放下"; - if (execute.RightButton == MouseButtonState.Pressed) - right = "右键放下"; - TipText = $"当前鼠标位置:X={pt.X},Y={pt.Y}。当前鼠标状态:{left}、{mid}、{right}"; - }, - can => ReceiveMouseMove); - return mouseMoveCommand; - } - } - - public TestViewModel() - { - Name = "world"; - } -} diff --git "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/01.\346\213\211\344\274\270\345\241\253\345\205\205\345\217\263\351\224\256\350\217\234\345\215\225.cs" "b/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/01.\346\213\211\344\274\270\345\241\253\345\205\205\345\217\263\351\224\256\350\217\234\345\215\225.cs" deleted file mode 100644 index 6afeef78254032837e675647c965c3a5142dba8d..0000000000000000000000000000000000000000 --- "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/01.\346\213\211\344\274\270\345\241\253\345\205\205\345\217\263\351\224\256\350\217\234\345\215\225.cs" +++ /dev/null @@ -1,184 +0,0 @@ -using Autodesk.AutoCAD.Windows; -using System.Diagnostics; -using static IFoxCAD.Cad.PostCmd; -using MenuItem = Autodesk.AutoCAD.Windows.MenuItem; - -namespace JoinBoxAcad; -public class HatchPick -{ - [IFoxInitialize] - [CommandMethod(nameof(HatchPickInit))] - public void HatchPickInit() - { - Env.Printl($"※拉伸填充控制※\n{nameof(HatchPickSwitch)} - 切换开关\n"); - - if (Debugger.IsAttached) - Env.SetVar("hpscale", 22); - // 设定高版本双击填充启动修改面板 - // JoinBoxAcad.Menu.Cui.CuiInit(); - LoadHelper(true); - } - - // 只能命令卸载哦,因为关闭cad是不需要卸载的 - [CommandMethod(nameof(UnLoadHatchPick))] - public void UnLoadHatchPick() - { - LoadHelper(false); - } - - [CommandMethod(nameof(HatchPickSwitch))] - public void HatchPickSwitch() - { - if (HatchPickEvent.State.IsStop) - { - Env.Printl("已经 卸载 拉伸填充控制+ 用: " + nameof(HatchPickInit) + " 加载"); - return; - } - - if (HatchPickEvent.State.IsRun) - HatchPickEvent.State.Break(); - else - HatchPickEvent.State.Start(); - Env.Printl("已经 " + (HatchPickEvent.State.IsRun ? "开启" : "禁用") + " 拉伸填充控制+"); - } - - - internal static Dictionary MapDocHatchPickEvent = new(); - void LoadHelper(bool isLoad) - { - var dm = Acap.DocumentManager; - if (dm is null || dm.Count == 0) - return; - if (isLoad) - { - dm.DocumentCreated += Dm_DocumentCreated; - Dm_DocumentCreated(); // 自执行一次 - AddRightClickMenu(); - HatchPickEvent.AddInit(); - } - else - { - HatchPickEvent.RemoveInit(); - dm.DocumentCreated -= Dm_DocumentCreated; - UnDocumentCreated(); - HatchPick.RemoveRightClickMenu(); - } - } - - /// - /// 文档创建反应器 - /// - void Dm_DocumentCreated(object? sender = null, DocumentCollectionEventArgs? e = null) - { - var dm = Acap.DocumentManager; - if (dm is null || dm.Count == 0) - return; - var doc = dm.MdiActiveDocument; - if (doc is null) - return; - if (!MapDocHatchPickEvent.ContainsKey(doc)) - MapDocHatchPickEvent.Add(doc, new HatchPickEvent(doc)); - } - - /// - /// 卸载文档创建反应器 - /// - static void UnDocumentCreated() - { - var dm = Acap.DocumentManager; - if (dm is null || dm.Count == 0) - return; - var doc = dm.MdiActiveDocument; - if (doc is null) - return; - if (MapDocHatchPickEvent.ContainsKey(doc)) - { - MapDocHatchPickEvent[doc].Dispose(); - MapDocHatchPickEvent.Remove(doc); - } - } - - - - private const string V0 = "拉伸填充-开"; - private const string V1 = "拉伸填充-关";// (面板的独立填充必须关,否则致命错误) - private const string V2 = "独立填充";//(快捷,不需要关...目前还是会崩溃) - static readonly HashSet _menuItems = new() { V0, V1, V2 }; - static readonly ContextMenuExtension _contextMenu = new() { Title = "惊惊盒子" }; - /// - /// 添加右键菜单 - /// - void AddRightClickMenu() - { - // 右键菜单 - foreach (var item in _menuItems) - { - MenuItem mi = new(item); // 添加菜单项 - mi.Click += MenuItemClick; // 添加单击事件 - - //mi.MenuItems.Add(new MenuItem("改颜色1")); // 二级菜单 - _contextMenu.MenuItems.Add(mi); // 提交 - } - Acap.AddDefaultContextMenuExtension(_contextMenu);// 添加默认上下文菜单扩展,带标题的 - - //加入到某一种对象的右键菜单中 - //RXClass rxClass = Entity.GetClass(typeof(BlockReference)); - //Acap.AddObjectContextMenuExtension(rxClass, contextMenu); - //// 选择实体右键菜单才有用. 获得实体所属的RXClass类型 - // RXClass rx = RXObject.GetClass(typeof(Entity)); - // Acap.AddObjectContextMenuExtension(rx, contextMenu); // 这里为什么又可以不带标题 - } - - /// - /// 卸载右键菜单 - /// - static void RemoveRightClickMenu() - { - if (_contextMenu is null) - return; - Acap.RemoveDefaultContextMenuExtension(_contextMenu); - } - - /// - /// 右键点击触发 - /// - /// - /// - void MenuItemClick(object sender, EventArgs e) - { - // 获取发出命令的快捷菜单项 - if (sender is not MenuItem mi) - return; - - // 根据快捷菜单项的名字,分别调用对应的命令 - if (!_menuItems.Contains(mi.Text)) - return; - - switch (mi.Text) - { - case V0: - HatchPickEvent.State.Start(); - break; - case V1: - HatchPickEvent.State.Break(); - break; - case V2: - { - HatchPickEvent.State.Break(); - PromptSelectionOptions pso = new() - { - AllowDuplicates = true, // 不允许重复选择 - SingleOnly = true, // 隐含窗口选择(不需要空格确认) - }; - var ssPsr = Env.Editor.GetSelection(pso, HatchPickEvent.FilterForHatch); - if (ssPsr.Status != PromptStatus.OK) - return; - - Env.Editor.SetImpliedSelection(ssPsr.Value.GetObjectIds()); - SendCommand("-hatchedit H ", RunCmdFlag.AcedPostCommand); - HatchPickEvent.State.Start(); - } - break; - } - } -} \ No newline at end of file diff --git "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/02.\346\213\211\344\274\270\345\241\253\345\205\205\344\272\213\344\273\266.cs" "b/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/02.\346\213\211\344\274\270\345\241\253\345\205\205\344\272\213\344\273\266.cs" deleted file mode 100644 index f08eea85ab5352a81531811f6dbad0fc969ac15e..0000000000000000000000000000000000000000 --- "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/02.\346\213\211\344\274\270\345\241\253\345\205\205\344\272\213\344\273\266.cs" +++ /dev/null @@ -1,1029 +0,0 @@ -using System.Drawing; -using System.Runtime.CompilerServices; -using System.Windows.Forms; -using static IFoxCAD.Cad.PostCmd; - -namespace JoinBoxAcad; - -public class HatchPickEvent : IDisposable -{ - #region 静态成员 - public static ProState State = new(); - // 选择集过滤器 - public static readonly SelectionFilter FilterForHatch = new(new TypedValue[] { new TypedValue((int)DxfCode.Start, "HATCH") }); - // 临时标记(重设选择集会触发一次选择集反应器) - static bool _selectChangedStop = false; - // 临时选择集用 - static List _hatchIds = new(); - // 获取夹点在哪个图元边界上面,是为true - static bool _pickInBo = false; - static bool _vetoProperties = false; - private Tolerance _tol = new(1e-6, 1e-6); - - public static void AddInit() - { - HatchHook.SetHook(); - // 全局事件重复+=是不需要担心的 - Acap.DocumentManager.DocumentLockModeChanged += Dm_VetoCommand; - State.Start(); - } - - public static void RemoveInit() - { - State.Stop(); - Acap.DocumentManager.DocumentLockModeChanged -= Dm_VetoCommand; - HatchHook.RemoveHook(); - } - - /// - /// 反应器->命令否决触发命令前(不可锁文档) - /// - /// - /// - public static void Dm_VetoCommand(object sender, DocumentLockModeChangedEventArgs e) - { - if (!State.IsRun) - return; - if (string.IsNullOrEmpty(e.GlobalCommandName) || e.GlobalCommandName == "#") - return; - switch (e.GlobalCommandName.ToUpper()) - { - case "PROPERTIES": // 特性面板 - { - // 事件顺序问题: - // 开cad之后第一次双击必弹出特性面板 - // 所以这里直接删除填充边界 - HatchPick.MapDocHatchPickEvent[e.Document].SetPropertiesInfoTask(); - if (_vetoProperties) - { - Debugx.Printl("Dm_VetoCommand 否决了"); - e.Veto(); - _vetoProperties = false; - // 发送编辑填充命令 - SendCommand("_hatchedit ", RunCmdFlag.AcedPostCommand); - return; - } - Debugx.Printl("Dm_VetoCommand 没否决"); - } - break; - } - } - - - #endregion - - #region 动态成员 - /// - /// 在位编辑器 记录全图选择集的填充 - /// - readonly HashSet _refeditSsgeting = new(); - /// - /// 在位编辑器 获取当前选择集做差集=>内部填充 - /// - readonly HashSet _refeditSsgeted = new(); - // map<填充id,边界转换器> - readonly Dictionary _mapHatchConv = new(); - readonly Document _doc; - public HatchPickEvent(Document doc) - { - _doc = doc; - LoadHelper(true); - } - - void LoadHelper(bool isLoad) - { - if (isLoad) - { - _doc.ImpliedSelectionChanged += Md_ImpliedSelectionChanged; - _doc.CommandWillStart += Md_CommandWillStart; - _doc.LispWillStart += Md_LispWillStart; - _doc.CommandEnded += Md_CommandEnded; - _doc.Database.ObjectErased += DB_ObjectErased; - _doc.Database.ObjectModified += DB_ObjectModified; - } - else - { - _doc.ImpliedSelectionChanged -= Md_ImpliedSelectionChanged; - _doc.CommandWillStart -= Md_CommandWillStart; - _doc.LispWillStart -= Md_LispWillStart; - _doc.CommandEnded -= Md_CommandEnded; - _doc.Database.ObjectErased -= DB_ObjectErased; - _doc.Database.ObjectModified -= DB_ObjectModified; - } - } - #endregion - - #region 事件 - /// - /// 反应器->command命令完成前 - /// - /// - /// - void Md_CommandWillStart(object sender, CommandEventArgs e) - { - if (!State.IsRun) - return; - - // 此处无法使用文档锁,否则将导致文档锁无法释放,然后ctrl+z失败 - var cmdup = e.GlobalCommandName.ToUpper(); - Debugx.Printl("Md_CommandWillStart::" + cmdup); - - switch (cmdup) - { - case "REFEDIT": - { - // 在位编辑命令,执行前,获取当前空间所有填充 - var prompt = Env.Editor.SelectAll(FilterForHatch); - if (prompt.Status != PromptStatus.OK) - return; - using DBTrans tr = new(); - GetHatchIds(prompt); - if (_hatchIds.Count == 0) - return; - for (int i = 0; i < _hatchIds.Count; i++) - _refeditSsgeting.Add(_hatchIds[i]); - } - break; - } - - // 拉伸夹点命令前触发 - if (cmdup != "GRIP_STRETCH") - { - EraseAllHatchBorders(); - } - else - { - var mp = HatchHook.MouseStartPoint; - var mouseStart = Screen.ScreenToCad(mp); - Debugx.Printl("mouseStart,屏幕点::" + mp); - Debugx.Printl("mouseStart,cad点::" + mouseStart); - - // 获取当前选择的对象,然后提取所有的夹点 - var prompt = Env.Editor.SelectImplied(); - if (prompt.Status != PromptStatus.OK) - return; - using DBTrans tr = new(); - GetHatchIds(prompt); - if (_hatchIds.Count == 0) - return; - - // TODO 屏幕像素点转cad点的误差,要随着视口高度而动态计算....这里的计算可能不太正确 - var tol = (double)Env.GetVar("viewsize") / 10; - Debugx.Printl("tol::" + tol); - - // 0x01 移动了矩形填充中间的夹点,删除边界,并且重新生成填充和边界 - // 0x02 移动了填充边界上的夹点,不处理,然后它会通过关联进行自己修改 - _pickInBo = false; - for (int i = 0; i < _hatchIds.Count; i++) - { - var hatId = _hatchIds[i]; - if (!_mapHatchConv.ContainsKey(hatId)) - continue; - - _mapHatchConv[hatId].BoundaryIds.ForEach((id, idState) => { - var boEnt = tr.GetObject(id); - if (boEnt == null) - return; - - // 获取夹点在哪个图元边界上 - HashSet boPts = new(); - if (boEnt is Circle circle) - { - // 圆形的边界夹点是: 圆心+半径 - var x = circle.Center.X; - var y = circle.Center.Y; - var z = circle.Center.Z; - var r = circle.Radius; - boPts.Add(new(x + r, y, z));//上 - boPts.Add(new(x - r, y, z));//下 - boPts.Add(new(x, y - r, z));//左 - boPts.Add(new(x, y + r, z));//右 - } - else - { - // 获取所有的边点 - // 这里圆形会获取圆心,所以剔除圆形 - var tmp = GetEntityPoint3ds(boEnt); - for (int j = 0; j < tmp.Count; j++) - boPts.Add(tmp[j]); - } - - if (boEnt is Arc arc) - { - if (!arc.StartPoint.IsEqualTo(arc.EndPoint, _tol)) - { - // 圆弧的腰点 - var arc2 = arc.GetPointAtDist(arc.GetDistAtPoint(arc.EndPoint) * 0.5); - boPts.Add(arc2); - } - } - else if (boEnt is Polyline pl) - { - for (int j = 0; j < pl.NumberOfVertices; j++) - { - var bulge = pl.GetBulgeAt(j); - if (bulge == 0.0) - continue; - // 有凸度就是有每段的中点 - var pta = pl.GetPoint2dAt(j); - Point2d ptb; - if (j + 1 < pl.NumberOfVertices) - ptb = pl.GetPoint2dAt(j + 1); - else - ptb = pl.GetPoint2dAt(0); - - var p = MathHelper.GetArcMidPoint(pta, ptb, bulge); - boPts.Add(p.Point3d()); - } - } - - boPts.ForEach((pt, ptState) => { - var dist = pt.DistanceTo(mouseStart); - //Debugx.Printl("pt::" + pt + " dist::" + dist); - if (dist < tol) - { - ptState.Break(); - _pickInBo = true; - } - }); - }); - - // 点在边界上:就不处理了,它会通过cad的关联填充反应器自动修改 - if (_pickInBo) - Debugx.Printl("夹点在边界上"); - else - Debugx.Printl("夹点不在边界上"); - } - } - } - - /// - /// 图元拉伸点 - /// - /// - /// - static List GetEntityPoint3ds(Entity ent) - { - var pts3d = new Point3dCollection(); - ent.GetStretchPoints(pts3d); - return pts3d.Cast().ToList(); - } - - - - - /// - /// 反应器->command命令完成后 - /// - /// - /// - void Md_CommandEnded(object sender, CommandEventArgs e) - { - if (!State.IsRun) - return; - - var cmdup = e.GlobalCommandName.ToUpper(); - switch (cmdup) - { - case "REFEDIT": - { - Debugx.Printl("Md_CommandEnded:: REFEDIT"); - - // 在位编辑命令,执行后,获取当前空间所有填充 - var prompt = Env.Editor.SelectAll(FilterForHatch); - if (prompt.Status != PromptStatus.OK) - return; - - using DBTrans tr = new(); - GetHatchIds(prompt); - if (_hatchIds.Count == 0) - return; - - for (int i = 0; i < _hatchIds.Count; i++) - if (!_refeditSsgeting.Contains(_hatchIds[i]))//Except - _refeditSsgeted.Add(_hatchIds[i]); - - var sb = new StringBuilder(); - foreach (var id in _refeditSsgeted) - sb.AppendLine(id.ToString()); - Env.Printl("块内填充id:" + sb.ToString()); - } - break; - case "REFSET": // 加减在位编辑图元 - { - Debugx.Printl("Md_CommandEnded:: REFSET"); - - // 命令历史的最后一行是:添加/删除 - var last = Env.GetVar("lastprompt").ToString(); - if (last is null) - return; - - // 完成后必然有上次选择集 - var prompt = Env.Editor.SelectPrevious(); - if (prompt.Status != PromptStatus.OK) - return; - using DBTrans tr = new(); - GetHatchIds(prompt); - if (_hatchIds.Count == 0) - return; - - // 就是因为无法遍历到在位编辑的块内图元,只能进行布尔运算 - if (last.Contains("添加") || last.Contains("Added"))// 中英文cad - { - for (int i = 0; i < _hatchIds.Count; i++) - { - _refeditSsgeting.Remove(_hatchIds[i]); - _refeditSsgeted.Add(_hatchIds[i]); - } - return; - } - if (last.Contains("删除") || last.Contains("Removed"))// 中英文cad - { - for (int i = 0; i < _hatchIds.Count; i++) - { - _refeditSsgeted.Remove(_hatchIds[i]); - _refeditSsgeting.Add(_hatchIds[i]); - } - return; - } - } - break; - case "REFCLOSE":// 保存块,清空集合 - { - Debugx.Printl("Md_CommandEnded:: REFCLOSE"); - _refeditSsgeted.Clear(); - _refeditSsgeting.Clear(); - } - break; - case "GRIP_STRETCH":// 拉伸夹点命令后触发 - { - // 夹点在边界上,退出 - if (_pickInBo) - return; - - // 夹点不在边界上: - // cad会平移填充,在这之后,我们删除填充边界,重建填充边界 - var prompt = Env.Editor.SelectImplied(); - if (prompt.Status != PromptStatus.OK) - return; - using DBTrans tr = new(); - GetHatchIds(prompt); - if (_hatchIds.Count == 0) - return; - - // 删除指定填充的边界,并清理关联反应器 - HashSet idsOfSsget = new(); - foreach (var hatId in _hatchIds) - { - idsOfSsget.Add(hatId); - - if (!_mapHatchConv.ContainsKey(hatId)) - continue; - bool clearFlag = false; - _mapHatchConv[hatId].BoundaryIds.ForEach(boId => { - if (!boId.IsOk()) - return; - var boEnt = tr.GetObject(boId); - if (boEnt == null) - return; - if (!HatchPickEnv.IsMeCreate(boEnt)) - return; - boId.Erase(); - clearFlag = true; - }); - - if (!clearFlag) - return; - - _mapHatchConv[hatId].BoundaryIds.Clear(); - - // 清理填充反应器 - var hatch = tr.GetObject(hatId); - if (hatch == null) - return; - using (hatch.ForWrite()) - RemoveAssociative(hatch); - CreatHatchConverter(hatch, idsOfSsget); - } - SetImpliedSelection(idsOfSsget); - } - break; - } - } - - /// - /// 获取选择集上的填充,在缓存内提取 - /// - /// - /// - static void GetHatchIds(PromptSelectionResult psr, DBTrans? tr = null) - { - tr ??= DBTrans.Top; - _hatchIds.Clear(); - var ids = psr.Value.GetObjectIds(); - for (int i = 0; i < ids.Length; i++) - { - var hatch = tr.GetObject(ids[i]); - if (hatch is not null) - _hatchIds.Add(ids[i]); - } - } - - /// - /// 反应器->lisp命令 - /// - void Md_LispWillStart(object sender, LispWillStartEventArgs e) - { - if (!State.IsRun) - return; - - using DBTrans tr = new(doclock: true); - EraseAllHatchBorders(); - } - - /// - /// 反应器->选择集 - /// - /// - /// - void Md_ImpliedSelectionChanged(object sender, EventArgs e) - { - if (!State.IsRun) - return; - - // 此处必须要文档锁 - if (_selectChangedStop) - { - _selectChangedStop = false; - return; - } - Debugx.Printl("Md_ImpliedSelectionChanged"); - - using DBTrans tr = new(doclock: true); - var prompt = Env.Editor.SelectImplied(); - if (prompt.Status != PromptStatus.OK) - { - EraseAllHatchBorders(); - return; - } - - // 获取图层锁定的记录,用于跳过 - Dictionary islocks = new(); - foreach (var layerRecord in tr.LayerTable.GetRecords()) - if (!layerRecord.IsErased)// 08符号表记录保留了这个 - islocks.Add(layerRecord.Name, layerRecord.IsLocked); - - // 遍历选择,创建边界转换器 - // 重设选择集 - HashSet idsOfSsget = new(); - foreach (var entId in prompt.Value.GetObjectIds()) - { - idsOfSsget.Add(entId); - var hatch = tr.GetObject(entId, openLockedLayer: true); - if (hatch is null) - continue; - if (islocks[hatch.Layer]) - continue; - // 重复选择 || 在位编辑外 - if (_mapHatchConv.ContainsKey(entId) || _refeditSsgeting.Contains(entId)) - continue; - CreatHatchConverter(hatch, idsOfSsget); - } - SetImpliedSelection(idsOfSsget); - } - - /// - /// 创建填充和填充边界转换器 - /// - /// - /// - /// - void CreatHatchConverter(Hatch hatch, HashSet outSsgetIds, DBTrans? tr = null) - { - tr ??= DBTrans.Top; - - var hc = new HatchConverter(hatch); - ObjectId newid; - - // 如果边界在图纸上没有删除(删除就不是关联的), - // 那就不创建新的,然后选中它们 - if (hc.BoundaryIds.Count != 0) - { - Debugx.Printl("CreatHatchConverter:: 加入了现有边界到选择集"); - - // 加入选择集 - foreach (var item in hc.BoundaryIds) - outSsgetIds.Add(item); - outSsgetIds.Add(hatch.ObjectId); - newid = hatch.ObjectId; - } - else - { - Debugx.Printl("CreatHatchConverter:: 创建新填充和边界"); - - // 创建新填充和边界 - hc.GetBoundarysData(); - newid = hc.CreateBoundarysAndHatchToMsPs(tr.CurrentSpace, trans: tr); - HatchPickEnv.SetMeXData(newid, hc.BoundaryIds); - - // 清理上次,删除边界和填充 - if (_mapHatchConv.ContainsKey(hatch.ObjectId)) - { - var boIds = _mapHatchConv[hatch.ObjectId].BoundaryIds; - for (int i = 0; i < boIds.Count; i++) - boIds[i].Erase(); - _mapHatchConv.Remove(hatch.ObjectId); - } - // 删除选中的 - hatch.ObjectId.Erase(); - } - - if (!_mapHatchConv.ContainsKey(newid)) - _mapHatchConv.Add(newid, hc); - else - _mapHatchConv[newid] = hc; - - if (newid == hatch.ObjectId) - return; - - // 优先: 块内含有旧的,就加入新的 - if (_refeditSsgeted.Contains(hatch.ObjectId)) - { - _refeditSsgeted.Remove(hatch.ObjectId); - _refeditSsgeted.Add(newid); - } - else if (_refeditSsgeting.Contains(hatch.ObjectId)) - { - _refeditSsgeting.Remove(hatch.ObjectId); - _refeditSsgeting.Add(newid); - } - } - - /// - /// 重设选择集 - /// - /// 加入选择集的成员 - void SetImpliedSelection(HashSet setImpSelect) - { - // 获取填充 - foreach (var id in _mapHatchConv.Keys) - setImpSelect.Add(id); - - // 获取填充边界 - foreach (var item in _mapHatchConv.Values) - foreach (var id in item.BoundaryIds) - setImpSelect.Add(id); - - // 设置选择集,没有标记的话会死循环 - _selectChangedStop = true; - Env.Editor.SetImpliedSelection(setImpSelect.ToArray()); - } - - /// - /// 删除全部填充边界 - /// - void EraseAllHatchBorders() - { - if (_mapHatchConv.Count == 0) - return; - foreach (var dict in _mapHatchConv) - { - dict.Value.BoundaryIds.ForEach(boId => { - if (!boId.IsOk()) - return; - using DBTrans tr = new(database: boId.Database); - var boEnt = tr.GetObject(boId, OpenMode.ForWrite); - if (boEnt == null) - return; - // 删除填充边界并清理关联反应器 - if (!HatchPickEnv.IsMeCreate(boEnt)) - return; - boEnt.Erase(); - if (dict.Key.IsOk()) - { - var hatch = tr.GetObject(dict.Key, OpenMode.ForWrite); - if (hatch == null) - return; - RemoveAssociative(hatch); - } - }); - } - _mapHatchConv.Clear(); - } - - /// - /// 移除关联反应器 - /// - /// - static void RemoveAssociative(Hatch hatch) - { - // 撤回填充,没有边界就移除关联反应器 - if (!hatch.Associative) - return; - - // 填充边界反应器 - var assIds = hatch.GetAssociatedObjectIds(); - if (assIds == null) - return; - bool isok = true; - foreach (ObjectId id in assIds) - { - if (!id.IsOk()) - { - isok = false; - break; - } - } - // 这里边界id已经删除了,所以移除会导致异常 - if (isok) - hatch.RemoveAssociatedObjectIds(); - // 取消关联反应器才能生成的正确 - hatch.Associative = false; - } - - /// - /// 撤回事件(获取删除对象) - /// - /// - /// - static void DB_ObjectErased(object sender, ObjectErasedEventArgs e) - { - if (!State.IsRun) - return; - - // object erased. - if (e.Erased) - { - return; - } - - // UNDO - if (e.DBObject is Hatch hatch) - { - if (HatchPickEnv.IsMeCreate(hatch)) - RemoveAssociative(hatch); - } - else if (e.DBObject is Entity boEnt) - { - // 撤回边界 - if (HatchPickEnv.IsMeCreate(boEnt)) - { - boEnt.Erase(); - // 通过xdata回溯填充,清理关联反应器 - if (boEnt.XData != null) - { - using DBTrans tr = new(); - var hatchId = HatchPickEnv.GetXdataHatch(boEnt); - if (hatchId.IsOk()) - { - var hatchEnt = tr.GetObject(hatchId, OpenMode.ForWrite); - if (hatchEnt != null) - RemoveAssociative(hatchEnt); - } - } - } - } - } - - /// - /// 撤回事件(更改时触发) - /// 它会获取有修改步骤的图元id - /// - /// - /// - static void DB_ObjectModified(object sender, ObjectEventArgs e) - { - if (!State.IsRun) - return; - - // 然后删除我制造的拉伸填充上面的关联反应器 - if (!e.DBObject.IsUndoing) - return; - if (e.DBObject.IsErased) - return; - // 是我生成的填充才删除关联 - if (e.DBObject is Hatch hatch) - { - if (HatchPickEnv.IsMeCreate(hatch)) - RemoveAssociative(hatch); - } - } - - void SetPropertiesInfoTask() - { - // 原有选择集 - var prompt = Env.Editor.SelectImplied(); - if (prompt.Status != PromptStatus.OK) - return; - - using DBTrans tr = new(); - - // 获取记录的边界 - HashSet boAll = new(); - foreach (var hc in _mapHatchConv.Values) - foreach (var boid in hc.BoundaryIds) - boAll.Add(boid); - - // 获取选择集上面所有的填充,如果没有填充就结束(不屏蔽特性面板) - bool hasHatch = false; - HashSet idsOfSsget = new(); - foreach (var id in prompt.Value.GetObjectIds()) - { - // 含有填充 - if (_mapHatchConv.ContainsKey(id)) - hasHatch = true; - // 排除边界的加入 - if (!boAll.Contains(id)) - idsOfSsget.Add(id); - } - if (!hasHatch) - return; - - // 删除填充边界,并清理关联反应器 - EraseAllHatchBorders(); - - // 重设选择集 提供给后续命令判断 - SetImpliedSelection(idsOfSsget); - - // 如果有填充才否决 - _vetoProperties = idsOfSsget.Count != 0; - } - #endregion - - #region IDisposable接口相关函数 - public bool IsDisposed { get; private set; } = false; - - /// - /// 手动调用释放 - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// 析构函数调用释放 - /// - ~HatchPickEvent() - { - Dispose(false); - } - - protected virtual void Dispose(bool disposing) - { - // 不重复释放 - if (IsDisposed) return; - IsDisposed = true; - - if (_doc.IsDisposed) - return; - LoadHelper(false); - } - #endregion -} - -/// -/// 填充的鼠标钩子 -/// -public static class HatchHook -{ - static readonly MouseHook MouseHook; - // 夹点拉伸前的点,拉伸后利用命令后反应器去处理"GRIP_STRETCH" - static volatile int _X; - static volatile int _Y; - public static Point MouseStartPoint { get => new(_X, _Y); } - - /// - /// 鼠标双击事件 - /// - public static event EventHandler? DoubleClick; - - static HatchHook() - { - MouseHook = new(); - } - - /// - /// 查找主线程
- /// 代替
- /// 托管线程和他们不一样: - ///
- /// 主窗口 - /// 进程ID - /// 线程ID - [DllImport("user32.dll", SetLastError = true)] - static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); - - [DllImport("user32.dll")] - static extern bool IsWindowEnabled(IntPtr hWnd); - /// - /// 获取当前窗口 - /// - /// 当前窗口标识符 - [DllImport("user32.dll")] - static extern IntPtr GetForegroundWindow(); - - public static void SetHook() - { - // 如果是全局钩子会发生偶尔失效的情况,改用进程钩子反而好多了 - MouseHook.SetHook(true); - MouseHook.MouseDown += (sender, e) => { - // 此处断点时候就会使得钩子失效 - if (!IsWindowEnabled(Acap.MainWindow.Handle)) - return; - // 进程号拦截 - GetWindowThreadProcessId(GetForegroundWindow(), out uint winId); - if (MouseHook.Process.Id != winId) - return; - if (e.Button == MouseButtons.Left) - { - _X = e.X; - _Y = e.Y; - } - }; - - MouseHook.DoubleClick += (sender, e) => { - // 此处断点时候就会使得钩子失效 - if (!IsWindowEnabled(Acap.MainWindow.Handle)) - return; - // 进程号拦截 - GetWindowThreadProcessId(GetForegroundWindow(), out uint winId); - if (MouseHook.Process.Id != winId) - return; - DoubleClick?.Invoke(sender, e); - }; - } - - public static void RemoveHook() - { - MouseHook?.Dispose(); - } -} - -public static class HatchPickEnv -{ - //static readonly string _appName = nameof(JoinBox); - //static readonly string _data = nameof(CreateBoundary); - - static readonly string _appName = "JoinBox"; - static readonly string _data = "CreateBoundary"; - - /// - /// 判断图元是否由 我的转换器 创建(相对的是直接提取现有图元边界) - /// - /// 任何图元 - /// - public static bool IsMeCreate(Entity entity) - { - if (entity.XData == null) - return false; - var xl = (XDataList)entity.XData; - return xl.Contains(_appName, _data); - } - - /// - /// 我的转换器 xdata数据模板 - /// - /// - /// - /// - public static ResultBuffer GetMeBuffer(Handle hatchHandle, DBTrans? trans = null) - { - trans ??= DBTrans.Top; - trans.RegAppTable.Add(_appName); // add函数会默认的在存在这个名字的时候返回这个名字的regapp的id,不存在就新建 - ResultBuffer resBuf = new() - { - new((int)DxfCode.ExtendedDataRegAppName, _appName), - new((int)DxfCode.ExtendedDataAsciiString,_data), - new((int)DxfCode.ExtendedDataHandle, hatchHandle),//边界回溯这个填充的句柄,如果创建新填充,就需要再去改 - }; - return resBuf; - } - - /// - /// 填充和边界上面增加xdata,实现区分原生和我的数据 - /// - /// - /// - /// - public static void SetMeXData(ObjectId newHatchId, List boIds, DBTrans? trans = null) - { - trans ??= DBTrans.Top; - var hatchEnt = trans.GetObject(newHatchId); - if (hatchEnt != null) - using (hatchEnt.ForWrite()) - hatchEnt.XData = GetMeBuffer(hatchEnt.Handle, trans); // 设置xdata仅仅为debug可以通过鼠标悬停看见它数据,因此设置为自己 - - // 修改边界的xdata为新填充的 - boIds.ForEach(id => { - var boEnt = trans.GetObject(id); - if (boEnt is null) - return; - using (boEnt.ForWrite()) - { - boEnt.RemoveXData(_appName); - boEnt.XData = GetMeBuffer(newHatchId.Handle, trans); - } - }); - } - - /// - /// 通过边界ent获取填充id - /// - /// 边界图元 - /// - /// - public static ObjectId GetXdataHatch(Entity boEntity, DBTrans? trans = null) - { - if (boEntity.XData == null) - return ObjectId.Null; - XDataList data = boEntity.XData; - - if (!data.Contains(_appName, _data)) - return ObjectId.Null; - - var indexs = data.GetXdataAppIndex(_appName, new DxfCode[] { DxfCode.ExtendedDataHandle }); - if (indexs.Count == 0) - return ObjectId.Null; - - trans ??= DBTrans.Top; - return trans.GetObjectId(data[indexs[0]].Value.ToString()); - } -} - -public static class MathHelper -{ - /// - /// 圆弧的腰点 - /// - /// 圆弧点1 - /// 圆弧点3 - /// 凸度 - /// 返回腰点 - /// - [MethodImpl] - public static Point2d GetArcMidPoint(Point2d arc1, Point2d arc3, double bulge) - { - if (bulge == 0) - throw new ArgumentException("凸度为0,此线是平的"); - - var center = GetArcBulgeCenter(arc1, arc3, bulge); - var angle1 = center.GetVectorTo(arc1).GetAngle2XAxis(); - var angle3 = center.GetVectorTo(arc3).GetAngle2XAxis(); - // 利用边点进行旋转,就得到腰点,旋转角/2 - // 需要注意镜像的多段线 - double angle = angle3 - angle1; - if (bulge > 0) - { - if (angle < 0) - angle += Math.PI * 2; - } - else - { - if (angle > 0) - angle += Math.PI * 2; - } - return arc1.RotateBy(angle / 2, center); - } - /// http://bbs.xdcad.net/thread-722387-1-1.html - /// https://blog.csdn.net/jiangyb999/article/details/89366912 - /// - /// 凸度求圆心 - /// - /// 圆弧头点 - /// 圆弧尾点 - /// 凸度 - /// 圆心 - [MethodImpl] - public static Point2d GetArcBulgeCenter(Point2d arc1, Point2d arc3, double bulge) - { - if (bulge == 0) - throw new ArgumentException("凸度为0,此线是平的"); - - var x1 = arc1.X; - var y1 = arc1.Y; - var x2 = arc3.X; - var y2 = arc3.Y; - - var b = (1 / bulge - bulge) / 2; - var x = (x1 + x2 - b * (y2 - y1)) / 2; - var y = (y1 + y2 + b * (x2 - x1)) / 2; - return new Point2d(x, y); - } - - /// - /// X轴到向量的弧度,cad的获取的弧度是1PI,所以转换为2PI(上小,下大) - /// - /// 向量 - /// X轴到向量的弧度 - public static double GetAngle2XAxis(this Vector2d ve, double tolerance = 1e-6) - { - const double Tau = Math.PI + Math.PI; - // 世界重合到用户 Vector3d.XAxis->两点向量 - double al = Vector2d.XAxis.GetAngleTo(ve); - al = ve.Y > 0 ? al : Tau - al; // 逆时针为正,大于0是上半圆,小于则是下半圆,如果-负值控制正反 - al = Math.Abs(Tau - al) <= tolerance ? 0 : al; - return al; - } -} \ No newline at end of file diff --git "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/HatchHelper.cs" "b/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/HatchHelper.cs" deleted file mode 100644 index 6d6c24312b06942b062ecdb8bb4c732a4f2d4275..0000000000000000000000000000000000000000 --- "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/HatchHelper.cs" +++ /dev/null @@ -1,124 +0,0 @@ -namespace JoinBoxAcad; - -public static class HatchHelper -{ - /// - /// 遍历填充每条边 - /// - /// - /// - public static void ForEach(this Hatch hatch, Action action) - { - for (int i = 0; i < hatch.NumberOfLoops; i++) - action.Invoke(hatch.GetLoopAt(i)); - } - - -#if false - /// - /// 分离填充边界 - /// 将外边界和包含的边界成为一个集 - /// - /// 填充的边界(只有多段线和圆) - /// 多个id集,id中第一个是外边界 - public static IEnumerable[] SeparationBorder(this IEnumerable bianjie) - { - IEnumerable[] objectIds = null; - if (bianjie.Length < 1) return null; - - Database db = bianjie[0].Database; - - // 首先获取一个图元,这个图元默认成边界,看它是否包含第二个,如果是,加入a集 - // 如果不是,它是否把自己包含了, - // 如果是,把它加入a集,并下次使用它来成为外边界 - // 如果不是,则为新边界,把它加入b集 - List alist = new List(); // 边界包含 - List blist = new List(); // 有另外的边界 - List> clist = new List>();// 边界集 - - using (Transaction tr = db.TransactionManager.StartTransaction()) - { - while (true) - { - for (int i = 0; i < bianjie.Length; i++) - { - Entity ent = bianjie[i].ObjectIdToEntity(false); - ent.UpgradeOpen(); - for (int j = i + 1; j < bianjie.Length; j++) - { - if (ent is Polyline polyline)// 多段线 - { - } - else if (ent is Circle circle) // 圆 - { - } - } - ent.DowngradeOpen(); - } - - if (blist.Count == 0)// 没有其他边界就结束循环 - { - break; - } - // 把blist的第一个用来作为新的外边界 - } - } - return objectIds; - } - - /// - /// 判断边界是否包含图元 布尔算法... - /// - /// 边界 - /// 包含的图元 - /// 是true,否false - public static bool BorderIntoCollect(this ObjectId border, ObjectId include) - { - bool flag = false; - Database db = border.Database; - using (Transaction tr = db.TransactionManager.StartTransaction()) - { - Entity ent = border.ObjectIdToEntity(false); - Entity ent2 = include.ObjectIdToEntity(false); - - if (ent is Polyline polyline)// 多段线边界 - { - if (ent2 is Polyline polyline2)// 多段线 - { - } - else if (ent2 is Circle circle2) // 圆 - { - // 判断圆心在多段线内 - if (circle2.Center.RayCasting(polyline.GetPolylinePoints()) != 3) - { - if (true)// 半径若大于多段线最长那段,表示包含不到,是圆包含了多段线(含有弧度就错了) - { - flag = true; - } - } - else // 圆心不在边界内,判断边界是否有交点 - { - } - } - } - else if (ent is Circle circle) // 圆边界 - { - if (ent2 is Polyline polyline2)// 多段线 - { - } - else if (ent2 is Circle circle2) // 圆 - { - // 填充边界不存在交集 - // 两个圆心的距离>两个圆的半径和=两圆分离 - double length = circle.Center.GetDistanceBetweenTwoPoint(circle2.Center); - if (length < circle.Radius + circle2.Radius) - { - flag = true; - } - } - } - return flag; - } - } -#endif -} \ No newline at end of file diff --git "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\345\261\217\345\271\225\345\235\220\346\240\207\350\275\254cad\345\235\220\346\240\207.cs" "b/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\345\261\217\345\271\225\345\235\220\346\240\207\350\275\254cad\345\235\220\346\240\207.cs" deleted file mode 100644 index 1856a61a7f4fe036cabfdd69c3fe7d2695b6cee3..0000000000000000000000000000000000000000 --- "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\345\261\217\345\271\225\345\235\220\346\240\207\350\275\254cad\345\235\220\346\240\207.cs" +++ /dev/null @@ -1,133 +0,0 @@ -//#define cpp -namespace JoinBoxAcad; - -using System.Drawing; -using static IFoxCAD.Basal.WindowsAPI; - -public partial class Screen -{ - [CommandMethod(nameof(GetScreenToCadxx))] - public static void GetScreenToCadxx() - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var ed = doc.Editor; - var ucsPoint = GetScreenToCad(); - ed.WriteMessage(ucsPoint.ToString() + "\n"); - } - - /// - /// 屏幕坐标转cad坐标 - /// - public static Point3d GetScreenToCad() - { - // 两种获取方式都可以 - var cursorPos = System.Windows.Forms.Control.MousePosition; - // GetCursorPos(out Point cursorPos); - return ScreenToCad(cursorPos); - } - - /// - /// 屏幕像素点转cad图纸坐标点 - /// - /// 屏幕像素点 - /// 返回ucs的点 - public static Point3d ScreenToCad(Point cursorPos) - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var ed = doc.Editor; - var mid = WindowsAPI.GetParent(doc.Window.Handle); - - ScreenToClient(mid, ref cursorPos); - var vn = ed.GetViewportNumber(cursorPos);// System.Windows.Forms.Control.MousePosition - var wcsPoint = ed.PointToWorld(cursorPos, vn); - var ucsPoint = wcsPoint.TransformBy(doc.Editor.CurrentUserCoordinateSystem.Inverse()); - return ucsPoint; - } - - /// - /// 屏幕坐标到客户区坐标转换 - /// - /// 窗口句柄 - /// 点结构,返回屏幕坐标 - /// - [DllImport("user32.dll")] - public static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint); - [DllImport("user32.dll")] - static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint); - - public static Point CadToScreen(Point3d pt3d, Point mousePosition) - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var ed = doc.Editor; - var mid = WindowsAPI.GetParent(doc.Window.Handle); - - var vn = ed.GetViewportNumber(mousePosition);//System.Windows.Forms.Control.MousePosition - var ptScr = Env.Editor.PointToScreen(pt3d, vn);// 高版本这个不一样,转为客户区 - var ptScrWin = new Point((int)ptScr.X, (int)ptScr.Y); - ClientToScreen(mid, ref ptScrWin); - return ptScrWin; - } - - //#if NET35 - // [DllImport("acad.exe", EntryPoint = "?acedGetAcadDwgView@@YAPAVCView@@XZ")] //acad08 - //#else - // [DllImport("acad.exe", EntryPoint = "?acedGetAcadDwgView@@YAPEAVCView@@XZ")]//acad21 - //#endif - // static extern IntPtr AcedGetAcadDwgview(); - - delegate IntPtr DelegateAcedGetAcadDwgview(); - static DelegateAcedGetAcadDwgview? acedGetAcadDwgView; - /// - /// 获取视口指针 - /// - public static IntPtr AcedGetAcadDwgview() - { - if (acedGetAcadDwgView is null) - { - acedGetAcadDwgView = AcadPeInfo - .GetDelegate( - nameof(acedGetAcadDwgView), AcadPeEnum.AcadExe); - } - if (acedGetAcadDwgView is not null) - return acedGetAcadDwgView.Invoke();// 调用方法 - return IntPtr.Zero; - } - - delegate int DelegateAcedGetWinNum(int x, int y); - static DelegateAcedGetWinNum? acedGetWinNum; - /// - /// 获取窗口数字 - /// - public static int AcedGetWinNum(int x, int y) - { - if (acedGetWinNum is null) - acedGetWinNum = AcadPeInfo - .GetDelegate( - nameof(acedGetWinNum), AcadPeEnum.ExeAndCore); - if (acedGetWinNum is not null) - return acedGetWinNum.Invoke(x, y);// 调用方法 - return 0; - } - - /// - /// 将坐标从绘图窗口转换为活动视口坐标系 - /// - /// - /// - /// - /// -#if NET35 - // 此处都是acad08这个有重载,不知道PeInfo能不能正常运行 - [DllImport("acad.exe", EntryPoint = "?acedCoordFromPixelToWorld@@YAHHVCPoint@@QAN@Z")] - static extern int AcedCoordFromPixelToWorld(int windnum, Point pt, out Point3D ptOut); - - [DllImport("acad.exe", EntryPoint = "?acedCoordFromPixelToWorld@@YAXABVCPoint@@QAN@Z")]//这个重载参数不知道 - static extern int AcedCoordFromPixelToWorld(Point pt, out Point3D ptOut); -#else - [DllImport("accore.dll", EntryPoint = "?acedCoordFromPixelToWorld@@YAHHVCPoint@@QEAN@Z")] - static extern int AcedCoordFromPixelToWorld(int windnum, Point pt, out Point3D ptOut); -#endif -} \ No newline at end of file diff --git "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\344\270\200\344\270\252\346\227\240\346\263\225\347\247\273\345\212\250\347\272\242\350\211\262\345\234\206\347\232\204\344\276\213\345\255\220.cs" "b/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\344\270\200\344\270\252\346\227\240\346\263\225\347\247\273\345\212\250\347\272\242\350\211\262\345\234\206\347\232\204\344\276\213\345\255\220.cs" deleted file mode 100644 index 4e45d212f21d85d6b68830a38f677a676d012d04..0000000000000000000000000000000000000000 --- "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\344\270\200\344\270\252\346\227\240\346\263\225\347\247\273\345\212\250\347\272\242\350\211\262\345\234\206\347\232\204\344\276\213\345\255\220.cs" +++ /dev/null @@ -1,94 +0,0 @@ -// 一个无法移动红色圆的例子 https://www.keanw.com/2008/08/rolling-back-th.html -#if true2 -namespace JoinBoxAcad; - -public class CmdReactor -{ - Document? _doc; - ObjectIdCollection _ids = new(); - Point3dCollection _pts = new(); - - [CommandMethod(nameof(Test_REACTOR))] - public void Test_REACTOR() - { - _doc = Acap.DocumentManager.MdiActiveDocument; - _doc.CommandWillStart += Doc_CommandWillStart; - } - - /// - /// 挂载一个命令反应器,如果出现了move就挂载一个 - /// - /// - /// - void Doc_CommandWillStart(object sender, CommandEventArgs e) - { - if (e.GlobalCommandName == "MOVE") - { - _ids.Clear(); - _pts.Clear(); - - if (_doc is null) - return; - _doc.Database.ObjectOpenedForModify += Db_ObjectOpenedForModify; - _doc.CommandCancelled += Doc_CommandEnded; - _doc.CommandEnded += Doc_CommandEnded; - _doc.CommandFailed += Doc_CommandEnded; - } - } - - /// - /// 卸载一堆反应器 - /// - void RemoveEventHandlers() - { - if (_doc is null) - return; - _doc.CommandCancelled -= Doc_CommandEnded; - _doc.CommandEnded -= Doc_CommandEnded; - _doc.CommandFailed -= Doc_CommandEnded; - _doc.Database.ObjectOpenedForModify -= Db_ObjectOpenedForModify; - } - - void Doc_CommandEnded(object sender, CommandEventArgs e) - { - // 在恢复位置之前删除数据库reactor - RemoveEventHandlers(); - RollbackLocations(); - } - - /// - /// 颜色是1的圆加入集合 - /// - /// - /// - void Db_ObjectOpenedForModify(object sender, ObjectEventArgs e) - { - if (e.DBObject is Circle circle && circle.ColorIndex == 1)// 如果颜色是1 - { - // 不含有就加入集合 - if (!_ids.Collection.Contains(circle.ObjectId)) - { - _ids.Add(circle.ObjectId); - _pts.Add(circle.Center); - } - } - } - - /// - /// 修改圆心 - /// - void RollbackLocations() - { - Debug.Assert(_ids.Count == _pts.Count, "预计相同数量的ID和位置"); - _doc?.Database.Action(tr => { - int i = 0; - foreach (ObjectId id in _ids.Collection) - { - var circle = tr.GetObject(id, OpenMode.ForWrite) as Circle; - if (circle is not null) - circle.Center = _pts[i++]; - } - }); - } -} -#endif \ No newline at end of file diff --git "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\350\207\252\345\256\232\344\271\211\345\233\276\345\205\203\345\241\253\345\205\205\350\276\271\347\225\214.txt" "b/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\350\207\252\345\256\232\344\271\211\345\233\276\345\205\203\345\241\253\345\205\205\350\276\271\347\225\214.txt" deleted file mode 100644 index 50ccab0d7cc1a64306f9d6064b7b0ad89ac0131d..0000000000000000000000000000000000000000 --- "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\350\207\252\345\256\232\344\271\211\345\233\276\345\205\203\345\241\253\345\205\205\350\276\271\347\225\214.txt" +++ /dev/null @@ -1,104 +0,0 @@ -拉伸填充bug: -1号: 不闭合的多段线,新建边界会丢失一个不和头点重叠的倒数第二个点. -与头点重叠是ok的 -闭合是ok的 -解决:因为倒数第二个点要从 curve.EndPoint 获取. - -2号: -如果画了一个矩形,然后填充,再删除边界,再点选填充,那么通过生成出来关联标注, -移动第一个点的时候,是没有响应的,移动第二次的时候才会响应. - -两种想法解决这个问题, -a:生成之后,用移动矩阵影响一下关联反应器. - 答:不会触发的,即使我分成两个事务分别提交. -b:先克隆一个填充,再创建关联边界. - 答:可行的,但是会导致3号问题的发生. - -3号: -由于我是生成填充的,所以在在位编辑的时候会在长事务内部: - -【贵妃】惊惊 2019/7/13 17:52:02 -我遇到了一个问题,如果是在位编辑的时候,当前空间是模型空间,那么我用函数克隆一个块外的东西到模型空间,实际上会克隆到在位编辑的内部... -我都不知道怎么处理这个情况了..莫非要关闭用户的在位编辑状态么.. - -【才人】edata 2019/7/13 17:57:15 -在位编辑是这样的. - -【贵妃】惊惊 2019/7/13 17:58:08 -那桌子是怎么控制在位编辑-减出去块外的? - -【才人】edata 2019/7/13 17:58:20 -在位编辑实际上是对当前空间的修改,然后移动回块定义.. - -【才人】edata 2019/7/13 17:58:44 -这个就不是很清楚了... - -【贵妃】惊惊 2019/7/13 17:58:47 -也就是长事务上面记录了要移动回去的id? -如果减选了就是剔除了id? - -【才人】edata 2019/7/13 17:59:27 -你能卡到这个长事务吗? - -【贵妃】惊惊 2019/7/13 17:59:39 -net貌似无法控制长事务呀 -应该桌子有考虑到的,只是我还没有挖出来具体怎么处理的.. - -【才人】edata 2019/7/13 18:08:59 -用命令去移除当前在位编辑. - -我用了命令去移除块外的填充和边界,这样操作是可行的, -然后又产生了一个问题,如果是块内的填充,我并不想减去. -想法: 用命令反应器在在位编辑前获取当前空间所有的图元,然后在位编辑时候就知道两个集合的交叉部分了 -答:证明是可以分类出来的,但是会引起一个问题,在位编辑复制的填充id不在任何一个表上. - -判断执行的时候不是选择前的填充均执行产生边界(这样就不用复制反应器了 -再检测命令 _refset 加减三个集合的填充 -但是命令反应器无法检测二级命令,只能通过 lastprompt 获取最后一行命令,判断添加或者删除 - -命令完成后,执行选择上次选择,便是_refset命令的选择 -然后把id改成加减到判断的两个集合中 - - - - - -U 大写命令,用户回滚的时会导致集合信息不符: -之前koz找到的方法,先选择在位编辑命令触发时的所有图元,再选择触发后的所有图元,分别建立两个集合储存,然后进行差集运算, -得出那些是块内图元,这个方法是可行的,然后我发现在使用+加入块内和-减出块内这也都可以判断, -问题就是....如果是使用了U回滚,那么我将不知道如何修改这两个集合.... - -检测在位编辑命令启动之后,而无结束命令的时候, -期间如果用户使用了u就提示用户是否禁止拉伸填充. - -挂载一个图元的反应器,如果使用了命令U,那么判断填充是否被更改了-> ObjectOpenedForModify 反应器 -如果更改了,更改方式无法知道?? 可能是改颜色,也可能是会在块内外加减操作更改. -无解决方案! - - - -拉伸非圆的时候,如果中心移动,那么边界不会跟随 -发生了拉伸命令的时候, -答: 选择的对象有填充,就克隆填充,并且删除原有的边界,及填充 - - - - -频闪控制 -grips=0 - - - - -编辑填充 -样条曲线边界生成 - -在cad2008设计一条填充边界 -填充边界的自定义图元名称叫做: HatchBoundary -设定HatchBoundary变量,0为使用,1为不使用边界 -想法破产:不会自定义图元. - - - -在位编辑的锁定图元的方法,该不是一个隐藏图层导致的吧. -不是,但是在位编辑的时候出现了一个图层 0-RefEdit0 \ No newline at end of file diff --git "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\350\216\267\345\217\226\345\244\271\347\202\271\344\276\213\345\255\220.cs" "b/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\350\216\267\345\217\226\345\244\271\347\202\271\344\276\213\345\255\220.cs" deleted file mode 100644 index a2d7a98ae0e355589fbbbdb634ca5be75cd5e3e6..0000000000000000000000000000000000000000 --- "a/tests/TestAcad09plus/\346\213\211\344\274\270\345\241\253\345\205\205/\350\277\207\347\250\213\346\226\207\344\273\266/\350\216\267\345\217\226\345\244\271\347\202\271\344\276\213\345\255\220.cs" +++ /dev/null @@ -1,100 +0,0 @@ -#if !ac2008 -namespace GripOverruleTest; - -// https://through-the-interface.typepad.com/through_the_interface/2009/08/knowing-when-an-autocad-object-is-grip-edited-using-overrules-in-net.html -public class GripVectorOverrule : GripOverrule -{ - // A static pointer to our overrule instance - static public GripVectorOverrule theOverrule = new(); - // A flag to indicate whether we're overruling - static bool overruling = false; - // A single set of grips would not have worked in - // the case where multiple objects were selected. - static Dictionary _gripDict = new(); - - private string GetKey(Entity e) - { - // Generate a key based on the name of the object's type - // and its geometric extents - // (We cannot use the ObjectId, as this is null during - // grip-stretch operations.) - return e.GetType().Name + ":" + e.GeometricExtents.ToString(); - } - // Save the locations of the grips for a particular entity - private void StoreGripInfo(Entity e, Point3dCollection grips) - { - string key = GetKey(e); - if (_gripDict.ContainsKey(key)) - { - // Clear the grips if any already associated - Point3dCollection grps = _gripDict[key]; - using (grps) - grps.Clear(); - _gripDict.Remove(key); - } - // Now we add our grips - Point3d[] pts = new Point3d[grips.Count]; - grips.CopyTo(pts, 0); - Point3dCollection gps = new(pts); - _gripDict.Add(key, gps); - } - // Get the locations of the grips for an entity - private Point3dCollection? RetrieveGripInfo(Entity e) - { - Point3dCollection? grips = null; - string key = GetKey(e); - if (_gripDict.ContainsKey(key)) - grips = _gripDict[key]; - return grips; - } - public override void GetGripPoints(Entity e, Point3dCollection grips, IntegerCollection snaps, IntegerCollection geomIds) - { - base.GetGripPoints(e, grips, snaps, geomIds); - StoreGripInfo(e, grips); - } - public override void MoveGripPointsAt(Entity e, IntegerCollection indices, Vector3d offset) - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var ed = doc.Editor; - - var grips = RetrieveGripInfo(e); - if (grips != null) - { - // Could get multiple points moved at once, - // hence the integer collection - foreach (int i in indices) - { - // Get the grip point from our internal state - Point3d pt = grips[i]; - // Draw a vector from the grip point to the newly - // offset location, using the index into the - // grip array as the color (excluding colours 0 and 7). - // These vectors don't getting cleared, which makes - // for a fun effect. - ed.DrawVector( - pt, - pt + offset, - (i >= 6 ? i + 2 : i + 1), // exclude colours 0 and 7 - false - ); - } - } - base.MoveGripPointsAt(e, indices, offset); - } - [CommandMethod(nameof(GripOverruleOnOff))] - public static void GripOverruleOnOff() - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var ed = doc.Editor; - if (overruling) - RemoveOverrule(GetClass(typeof(Entity)), theOverrule); - else - AddOverrule(GetClass(typeof(Entity)), theOverrule, true); - overruling = !overruling; - Overruling = overruling; - ed.WriteMessage("\nGrip overruling turned {0}.", overruling ? "on" : "off"); - } -} -#endif \ No newline at end of file diff --git a/tests/TestAcad09plus/GlobalUsings.cs b/tests/TestAcad2025/GlobalUsings.cs similarity index 93% rename from tests/TestAcad09plus/GlobalUsings.cs rename to tests/TestAcad2025/GlobalUsings.cs index 82e3ea728deb8741d28701daa3b5eff8e481fae1..045196f703ea51e14af47638509ed97287167b95 100644 --- a/tests/TestAcad09plus/GlobalUsings.cs +++ b/tests/TestAcad2025/GlobalUsings.cs @@ -11,7 +11,7 @@ global using System.ComponentModel; global using System.Runtime.InteropServices; global using System.Collections.Specialized; - +global using System.Threading; global using Exception = System.Exception; global using Registry = Microsoft.Win32.Registry; @@ -25,6 +25,7 @@ global using Autodesk.AutoCAD.Geometry; global using Autodesk.AutoCAD.Runtime; global using Acap = Autodesk.AutoCAD.ApplicationServices.Application; +global using Acaop = Autodesk.AutoCAD.ApplicationServices.Core.Application; global using Acgi = Autodesk.AutoCAD.GraphicsInterface; global using Autodesk.AutoCAD.DatabaseServices.Filters; @@ -45,10 +46,5 @@ /// ifoxcad global using IFoxCAD.Cad; global using IFoxCAD.Basal; -#if !ac2008 -global using IFoxCAD.WPF; -#endif -#if !NewtonsoftJson -global using System.Web.Script.Serialization; -#endif \ No newline at end of file +global using Test; diff --git a/tests/TestAcad2025/TestAcad2025.csproj b/tests/TestAcad2025/TestAcad2025.csproj new file mode 100644 index 0000000000000000000000000000000000000000..8ff61fe8fae33f65b30dada82c6141adaaeec507 --- /dev/null +++ b/tests/TestAcad2025/TestAcad2025.csproj @@ -0,0 +1,51 @@ + + + preview + enable + net48;net8.0-windows + true + true + x64 + True + 1.0.0.* + 1.0.0.0 + false + + + + full + false + + + + none + true + + + + $(Configuration);acad;a2024 + + + + $(Configuration);acad;a2025 + true + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/TestConsole/GlobalUsings.cs b/tests/TestConsole/GlobalUsings.cs deleted file mode 100644 index 6328a6745828c422b1cd7873beb6a2c9206e73bd..0000000000000000000000000000000000000000 --- a/tests/TestConsole/GlobalUsings.cs +++ /dev/null @@ -1,14 +0,0 @@ -/// 系统引用 -global using System; -global using System.Collections; -global using System.Collections.Generic; -global using System.IO; -global using System.Linq; -global using System.Text; -global using System.Reflection; -global using System.Text.RegularExpressions; -global using Microsoft.Win32; -global using System.ComponentModel; -global using System.Runtime.CompilerServices; - -global using IFoxCAD.Basal; \ No newline at end of file diff --git a/tests/TestConsole/Helper.cs b/tests/TestConsole/Helper.cs deleted file mode 100644 index 6fba76627d029ef735d722370f22e42fd05a86be..0000000000000000000000000000000000000000 --- a/tests/TestConsole/Helper.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace TestConsole; - -public static class Helper -{ - public static void ForEach(this IEnumerable ints, Action action) - { - LoopState state = new(); - foreach (var item in ints) - { - action(item, state); - if (!state.IsRun) - break; - } - - // int forNum = 5; - // var result = Parallel.For(0, forNum, (int i, ParallelLoopState pls) => { - // if (i > 2) - // pls.Break(); - // Task.Delay(10).Wait(); - // }); - } -} \ No newline at end of file diff --git a/tests/TestConsole/Info.cs b/tests/TestConsole/Info.cs deleted file mode 100644 index 7c41b7159846f14a1bc063d8ed0ade64a03c398d..0000000000000000000000000000000000000000 --- a/tests/TestConsole/Info.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Runtime.InteropServices; - -namespace TestConsole; - -[Flags] -public enum PlugIn -{ - [Description("惊惊")] - JoinBox = 1, - [Description("源泉")] - YuanQuan = 2, - [Description("迷你")] - IMinCad = 4, - - Lisp = JoinBox | YuanQuan | IMinCad, - - DOCBAR = 8, - DUOTAB = 16, - - All = Lisp | DOCBAR | DUOTAB -} - - -[Flags] -public enum PlugIn2 -{ - [Description("惊惊")] - JoinBox = 1, - [Description("源泉")] - YuanQuan = 2, - [Description("迷你")] - IMinCad = 4, - - [Description("*Lisp*")] - Lisp = JoinBox | YuanQuan | IMinCad, - - DOCBAR = 8, - DUOTAB = 16, - - // all == *Lisp*|DOCBAR|DUOTAB - // 采取的行为是:注释的行为是特殊的,就按照注释的,否则,遍历子元素提取注释 - All = Lisp | DOCBAR | DUOTAB -} \ No newline at end of file diff --git a/tests/TestConsole/Program.cs b/tests/TestConsole/Program.cs deleted file mode 100644 index 514c252e7de44180183b1049a1f3e379bbf0a114..0000000000000000000000000000000000000000 --- a/tests/TestConsole/Program.cs +++ /dev/null @@ -1,176 +0,0 @@ -// See https://aka.ms/new-console-template for more information -using System; -using System.Runtime.InteropServices; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; -using TestConsole; -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -#if true -namespace CalculatorDemo -{ - class Program - { - static void Main(string[] args) - { -#if false - int nResult = AddTwoNumbers(10, 20); - Console.WriteLine(nResult); - - AddTwoNumbers22((a, b) => { - Console.WriteLine(a + b); - }); - - var a = new int[] { 1, 2, 3, 4, 5, 6, 78, 9, 92, }; - a.ForEach(a => { - Console.WriteLine(a); - }); -#endif - - var aa = new int[] { 1, 2, 3, 4, 5, 6, 78, 9, 92, }; - Console.WriteLine(aa[1..^2]); - - - var time = Timer.RunTime(() => { - for (int i = 0; i < 10000000; i++) - i++; - }, Timer.TimeEnum.Second); - Console.WriteLine($"代码执行的时间:{time}"); - } - - private static int addtuple((int ,int ) b) - { - return b.Item1 + b.Item2; - } - - - [DebuggerHidden] - private static int AddTwoNumbers(int nNum1, int nNum2) - { - return Add(nNum1, nNum2); - } - private static int Add(int op1, int op2) - { - return op1 + op2; - } - - [DebuggerHidden] - private static void AddTwoNumbers22(Action action) - { - action(10, 20); - } - } - - public static class Fors - { - /// - /// 遍历集合,执行委托 - /// - /// 集合值的类型 - /// 集合 - /// 委托 - [DebuggerHidden] - public static void ForEach(this IEnumerable source, Action action) - { - foreach (var element in source) - { - action.Invoke(element); - } - } - } -} -#endif - -#if true2 - -Console.WriteLine("***************************************************"); - - -List list = new List(); -list.Add(1); -list.Add(2); -list.Add(3); -list.Add(4); -list.Add(5); -list.ForEach((x, loop) => { - if (x == 3) - loop.Break(); - Console.WriteLine(x); -}); - - - -// 乱序 -Console.WriteLine(PlugIn.JoinBox.PrintNote()); -Console.WriteLine(PlugIn.Lisp.PrintNote());// 这里先交换顺序来试试能不能成功 -Console.WriteLine(PlugIn.IMinCad.PrintNote()); -Console.WriteLine(PlugIn.YuanQuan.PrintNote()); -Console.WriteLine(PlugIn.All.PrintNote()); -Console.WriteLine(PlugIn.DOCBAR.PrintNote()); -Console.WriteLine(PlugIn.DUOTAB.PrintNote()); -Console.WriteLine("***************************************************"); -// 乱序2 -Console.WriteLine(PlugIn2.JoinBox.PrintNote()); -Console.WriteLine(PlugIn2.Lisp.PrintNote());// 这里先交换顺序来试试能不能成功 -Console.WriteLine(PlugIn2.IMinCad.PrintNote()); -Console.WriteLine(PlugIn2.YuanQuan.PrintNote()); -Console.WriteLine(PlugIn2.All.PrintNote()); -Console.WriteLine(PlugIn2.DOCBAR.PrintNote()); -Console.WriteLine(PlugIn2.DUOTAB.PrintNote()); - -EnumEx.CleanCache(); - -// 表达式树例子 -TestConsole.Test_Expression.Demo3(); -// TestConsole.Test_Expression.Demo1(); - -#region 元组测试 -var valuetuple = (1, 2); - -Console.WriteLine(valuetuple.ToString()); - -int[] someArray = new int[5] { 1, 2, 3, 4, 5 }; -int lastElement = someArray[^1]; // lastElement = 5 -Console.WriteLine(lastElement); -int midElement = someArray[^3]; -Console.WriteLine(midElement); -var range = someArray[1..3]; -foreach (var item in range) - Console.WriteLine(item); -#endregion - -Console.ReadLine(); - - -#region 测试遍历枚举 -// Season a = Season.Autumn; -// Console.WriteLine($"Integral value of {a} is {(int)a}"); // output: Integral value of Autumn is 2 -// foreach (var enumItem in Enum.GetValues(typeof(Season))) -// Console.WriteLine((byte)enumItem); - -var sb = new StringBuilder(); -/*因为 net framework 没写好的原因,导致直接使用迭代器反而更慢,到了NET60就迭代器比foreach更快*/ -var enums = Enum.GetValues(typeof(Season)).GetEnumerator(); -while (enums.MoveNext()) -{ - sb.Append(((byte)enums.Current).ToString()); - sb.Append(","); -} -Console.WriteLine(sb); - -sb.Remove(sb.Length - 1, 1);// 剔除末尾, -// 因为有返回值所以容易理解成 sb = sb.Remove(sb.Length - 1, 1); -Console.WriteLine(sb); - -public enum Season : byte -{ - Spring, - Summer, - Autumn, - Winter -} -#endregion -#endif \ No newline at end of file diff --git a/tests/TestConsole/RuntimeHelpers.cs b/tests/TestConsole/RuntimeHelpers.cs deleted file mode 100644 index fb91a153f3911d3b0694bb0cc694ddc94d6e6778..0000000000000000000000000000000000000000 --- a/tests/TestConsole/RuntimeHelpers.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -// 如果要用range的语法比如 a[1..3],那么需要将本文件复制到你的项目里 -#if true -namespace System.Runtime.CompilerServices -{ - internal static class RuntimeHelpers - { - /// - /// Slices the specified array using the specified range. - /// - public static T[] GetSubArray(T[] array, Range range) - { - if (array == null) - { - throw new ArgumentNullException(); - } - - (int offset, int length) = range.GetOffsetAndLength(array.Length); - - if (default(T)! != null || typeof(T[]) == array.GetType()) // NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757) - { - // We know the type of the array to be exactly T[]. - - if (length == 0) - { - // return Array.Empty(); - return new T[0]; - } - - var dest = new T[length]; - Array.Copy(array, offset, dest, 0, length); - return dest; - } - else - { - // The array is actually a U[] where U:T. - T[] dest = (T[])Array.CreateInstance(array.GetType().GetElementType()!, length); - Array.Copy(array, offset, dest, 0, length); - return dest; - } - } - } -} -#endif \ No newline at end of file diff --git a/tests/TestConsole/TestConsole.csproj b/tests/TestConsole/TestConsole.csproj deleted file mode 100644 index 673e547532c24179549526d919d56d9cd550aab2..0000000000000000000000000000000000000000 --- a/tests/TestConsole/TestConsole.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - preview - enable - - Exe - NET45 - enable - preview - - - - - - - NET40 - enable - preview - NOINDEX;NORANGE;NOVALUETUPLE - - - - - - - - - - - diff --git a/tests/TestConsole/TestSerialize.cs b/tests/TestConsole/TestSerialize.cs deleted file mode 100644 index 413764d8766b0927c7af76a9e2c65ab506d56fd0..0000000000000000000000000000000000000000 --- a/tests/TestConsole/TestSerialize.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Runtime.Serialization; - -namespace TestConsole; - -[Serializable] -public struct StructDemo -{ - public char[] Chars1; - public char[] Chars2; -} - -[Serializable] -public struct StructDemo2 : ISerializable -{ - public char[] Chars1; - public char[] Chars2; - - public void GetObjectData(SerializationInfo info, StreamingContext context) - { - info.AddValue("i", Chars1); - info.AddValue("j", Chars2); - } -} - -// 二进制序列化,存在元数据 -//{ -// StructDemo structDemo = new(); -// structDemo.Chars1 = "aaa".ToCharArray(); -// structDemo.Chars2 = "bbb".ToCharArray(); - -// using MemoryStream stream = new(); -// BinaryFormatter formatter = new(); -// formatter.Serialize(stream, structDemo); -// var str = Encoding.ASCII.GetString(stream.ToArray()); -// Console.WriteLine(str); -//} - -//{ -// StructDemo2 structDemo = new(); -// structDemo.Chars1 = "aaa".ToCharArray(); -// structDemo.Chars2 = "bbb".ToCharArray(); - -// using MemoryStream stream = new(); -// BinaryFormatter formatter = new(); -// formatter.Serialize(stream, structDemo); -// var str = Encoding.ASCII.GetString(stream.ToArray()); -// Console.WriteLine(str); -//} \ No newline at end of file diff --git "a/tests/TestConsole/\350\241\250\350\276\276\345\274\217\346\240\221.cs" "b/tests/TestConsole/\350\241\250\350\276\276\345\274\217\346\240\221.cs" deleted file mode 100644 index 4c706ddf96ee66567ba18edfdf4e06ce887ebb34..0000000000000000000000000000000000000000 --- "a/tests/TestConsole/\350\241\250\350\276\276\345\274\217\346\240\221.cs" +++ /dev/null @@ -1,142 +0,0 @@ -namespace TestConsole; - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; - -/// -/// 表达式树 -/// MSDN链接 -/// -public class Test_Expression -{ - public static void Demo1() - { - // 官方例子:表达式体内只有一个式子 - // 创建表达式树 - Expression> exprTree = num => num < 5; - - // 分解表达式树 - ParameterExpression param = exprTree.Parameters[0];// num - BinaryExpression operation = (BinaryExpression)exprTree.Body;// 函数体 {(num < 5)} - ParameterExpression left = (ParameterExpression)operation.Left;// 左节点 num - ConstantExpression right = (ConstantExpression)operation.Right;// 右表达式 5 - - Console.WriteLine("表达式树例子: {0} => {1} {2} {3}", - param.Name, left.Name, operation.NodeType, right.Value); - Console.Read(); - } - - - public static void Demo2() - { - // 这里是会报错的!! 原因就是体内有多个例子需要分解!! - // Expression> exprTree = x => x > 5 && x < 50; - // - // // 分解表达式树 - // ParameterExpression param = exprTree.Parameters[0];// x - // BinaryExpression operation = (BinaryExpression)exprTree.Body;// 函数体 {((x > 5) AndAlso (x < 50))} - // - // ParameterExpression left = (ParameterExpression)operation.Left;// 左节点.......这里报错 - // ConstantExpression right = (ConstantExpression)operation.Right;// 右表达式.....这里报错 - // - // Console.WriteLine("表达式树例子: {0} => {1} {2} {3}", - // param.Name, left.Name, operation.NodeType, right.Value); - } - - - // 博客园例子,表达式体内有多个式子 - public static void Demo3() - { - List names = new() { "Cai", "Edward", "Beauty" }; - - Console.WriteLine("******************一个表达式"); - Expression> lambda2 = name => name.Length > 2 && name.Length < 4; - var method2 = ReBuildExpression(lambda2); - var query2 = names.Where(method2); - foreach (string n in query2) - Console.WriteLine(n); - - Console.WriteLine("******************二个表达式"); - Expression> lambda0 = item => item.Length > 2; - Expression> lambda1 = item => item.Length < 4; - var method = ReBuildExpression(lambda0, lambda1); - var query = names.Where(method); - foreach (string n in query) - Console.WriteLine(n); - Console.WriteLine("******************表达式结束"); - Console.Read(); - } - - - static Func ReBuildExpression(Expression> lambda) - { - MyExpressionVisitor my = new() - { - Parameter = Expression.Parameter(typeof(string), "name") - }; - - Expression left = my.Modify(lambda.Body); - // 构造一个新的表达式 - var newLambda = Expression.Lambda>(left, my.Parameter); - return newLambda.Compile(); - } - - - - /// - /// 重构表达式_合并 - /// - /// 匿名函数表达式1 - /// 匿名函数表达式2 - /// - static Func ReBuildExpression(Expression> lambda0, - Expression> lambda1) - { - MyExpressionVisitor my = new() - { - Parameter = Expression.Parameter(typeof(string), "name") - }; - - Expression left = my.Modify(lambda0.Body); - Expression right = my.Modify(lambda1.Body); - var expression = Expression.AndAlso(left, right);// 就是 && 合并两个匿名函数 - - // 构造一个新的表达式 - var newLambda = Expression.Lambda>(expression, my.Parameter); - return newLambda.Compile(); - } -} - - -/// -/// 表达式参数分解 -/// 博客园链接 -/// -public class MyExpressionVisitor : ExpressionVisitor -{ - /// - /// 公共参数 - /// - public ParameterExpression? Parameter; - /// - /// 返回替换后的参数表达式 - /// - /// - /// - public Expression Modify(Expression exp) - { - return Visit(exp); - } - /// - /// 重写参数 - /// - /// - /// - protected override Expression? VisitParameter(ParameterExpression p) - { - return Parameter; - } -} diff --git a/tests/TestShared/CmdINI.cs b/tests/TestShared/CmdINI.cs index 0eeff285c443700900062d4ad821ecee303928da..e4deab7421abeb2990a02f75dbac0bbf64dc6f90 100644 --- a/tests/TestShared/CmdINI.cs +++ b/tests/TestShared/CmdINI.cs @@ -167,22 +167,27 @@ public void Terminate() } } #endif + + + #endif -public class Init : AutoLoad +public class Init { - public override void Initialize() + [CommandMethod(nameof(Initialize))] + public void Initialize() { - Env.Print("loading..."); - // 将程序的目录加入信任路径 - AppendSupportPath(CurrentDirectory.FullName); + // var assembly= Assembly.GetExecutingAssembly(); + // Env.Printl(assembly.GetName().Name); + // var info = new AssemInfo(assembly); + // Env.Printl(info.ToString()); + // AutoReg.RegApp(info); + AutoReg.RegApp(); } - public override void Terminate() + public void Terminate() { - // 这里不能调用输出函数,因为这个函数执行的时候,已经没有editor对象了。 - // 所以如果不是想要在cad关闭的时候清理某些东西,这里不用写任何的代码。 - + } } \ No newline at end of file diff --git a/tests/TestShared/Copyclip.cs b/tests/TestShared/Copyclip.cs index cc4558c58a8e472009135d06f83299e7e0960cd2..370936c4a4158fbc94fca8b843d321bfefa97382 100644 --- a/tests/TestShared/Copyclip.cs +++ b/tests/TestShared/Copyclip.cs @@ -1,9 +1,8 @@ #define test #define COPYCLIP #define PASTECLIP - +#if false namespace Test; -using Autodesk.AutoCAD.DatabaseServices; using System; using System.Diagnostics; using System.Drawing.Imaging; @@ -185,7 +184,7 @@ public void Terminate() /// 其他线程写入需要等待本次写入结束之后才能继续写入 /// 参考链接 /// - static ReaderWriterLockSlim _rwLock = new(); + static readonly ReaderWriterLockSlim _rwLock = new(); /// /// 储存准备删除的文件 @@ -288,11 +287,14 @@ void Copy(bool getPoint, bool isEraseSsget = false) if (ent == null) continue; var info = ent.GetBoundingBoxEx(); - if (ent is BlockReference brf) - info.Move(brf.Position, Point3d.Origin); - minx = minx > info.MinX ? info.MinX : minx; - miny = miny > info.MinY ? info.MinY : miny; - minz = minz > info.MinZ ? info.MinZ : minz; + if (info != null) + { + if (ent is BlockReference brf) + info.Value.Move(brf.Position, Point3d.Origin); + minx = minx > info.Value.MinX ? info.Value.MinX : minx; + miny = miny > info.Value.MinY ? info.Value.MinY : miny; + minz = minz > info.Value.MinZ ? info.Value.MinZ : minz; + } } pt = new(minx, miny, minz); } @@ -316,7 +318,7 @@ void Copy(bool getPoint, bool isEraseSsget = false) // 大于dwg07格式的,保存为07,以实现高低版本通用剪贴板 // 小于dwg07格式的,本工程没有支持cad06dll if ((int)DwgVersion.Current >= 27) - fileTr.SaveFile((DwgVersion)27, false); + fileTr.Database.SaveFile((DwgVersion)27, false); else throw new ArgumentException($"版本过低,无法保存,版本号:{DwgVersion.Current}"); } @@ -404,7 +406,7 @@ void Paste(bool isBlock) } // 获取临时文件的图元id - var fileEntityIds = new List(); + List fileEntityIds = []; using (DBTrans fileTr = new(cadClipType.File, commit: false, fileOpenMode: FileOpenMode.OpenForReadAndAllShare)) { @@ -590,13 +592,13 @@ void Paste(bool isBlock) catch (Exception e) { Debugger.Break(); - Debugx.Printl(e); + DebugEx.Printl(e); } } catch (Exception e)//{"剪贴板上的数据无效 (异常来自 HRESULT:0x800401D3 (CLIPBRD_E_BAD_DATA))"} { Debugger.Break(); - Debugx.Printl(e); + DebugEx.Printl(e); } finally { @@ -688,7 +690,7 @@ static string CreateTempFileName(string format = "X") } } -#if !ac2008 + public class TestImageFormat { public ImageFormat GetFormat(string filename) @@ -738,7 +740,7 @@ public void CreatePreviewImage() }); } } -#endif + public class OleTestClass { @@ -874,4 +876,6 @@ public void GetOleForOffice() } } #endif -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/tests/TestShared/TestAOP.cs b/tests/TestShared/TestAOP.cs deleted file mode 100644 index 872bf35646c1cc67b634688bf5624a324c2c32cd..0000000000000000000000000000000000000000 --- a/tests/TestShared/TestAOP.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Test; - -// 被注入的函数将不能使用断点, -// 因此用户要充分了解才能使用 -#if false -/* - * 类库用户想侵入的命名空间是用户的, - * 所以需要用户手动进行AOP.Run(), - * 默认情况不侵入用户的命令,必须用户手动启用此功能; - * 启动执行策略之后,侵入命名空间下的命令, - * 此时有拒绝特性的策略保证豁免,因为用户肯定是想少写一个事务注入的特性; - */ -public class AutoAOP -{ - [IFoxInitialize] - public void Initialize() - { - AOP.Run(nameof(Test_)); - } -} - -namespace Test -{ - /* - * 天秀的事务注入,让你告别事务处理 - * https://www.cnblogs.com/JJBox/p/16157578.html - */ - public class AopTestClass - { - // 类不拒绝,这里拒绝 - [IFoxRefuseInjectionTransaction] - [CommandMethod(nameof(IFoxRefuseInjectionTransaction))] - public void IFoxRefuseInjectionTransaction() - { - } - - // 不拒绝 - [CommandMethod(nameof(InjectionTransaction))] - public void InjectionTransaction() - { - // 怎么用事务呢? - // 直接用 DBTrans.Top - var dBTrans = new DBTrans(); - dBTrans.Commit(); - } - } - - // 拒绝注入事务,写类上,则方法全都拒绝 - [IFoxRefuseInjectionTransaction] - public class AopTestClassRefuseInjection - { - // 此时这个也是拒绝的..这里加特性只是无所谓 - [IFoxRefuseInjectionTransaction] - [CommandMethod(nameof(IFoxRefuseInjectionTransaction2))] - public void IFoxRefuseInjectionTransaction2() - { - // 拒绝注入就要自己开事务,通常用在循环提交事务上面. - // 另见 报错0x02 https://www.cnblogs.com/JJBox/p/10798940.html - using DBTrans tr = new(); - } - - [CommandMethod(nameof(InjectionTransaction2))] - public void InjectionTransaction2() - { - } - } -} -#endif \ No newline at end of file diff --git a/tests/TestShared/TestAddEntity.cs b/tests/TestShared/TestAddEntity.cs index 9b1dcd8e7319518567445ad7b6000cccb42fd30f..123ba77b7c46ef0d7960697ec7a8d38925a32628 100644 --- a/tests/TestShared/TestAddEntity.cs +++ b/tests/TestShared/TestAddEntity.cs @@ -1,322 +1,17 @@ -using System.Diagnostics; -using System.Web.UI.WebControls; - -namespace Test; +namespace Test; public partial class Test { - [CommandMethod(nameof(Test_DBTrans))] - public void Test_DBTrans() - { - using DBTrans tr = new(); - if (tr.Editor is null) - return; - tr.Editor.WriteMessage("\n测试 Editor 属性是否工作!"); - tr.Editor.WriteMessage("\n----------开始测试--------------"); - tr.Editor.WriteMessage("\n测试document属性是否工作"); - if (tr.Document == Getdoc()) - { - tr.Editor.WriteMessage("\ndocument 正常"); - } - tr.Editor.WriteMessage("\n测试database属性是否工作"); - if (tr.Database == Getdb()) - { - tr.Editor.WriteMessage("\ndatabase 正常"); - } - - Line line = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - Circle circle = new(new Point3d(0, 0, 0), Vector3d.ZAxis, 2); - // var lienid = tr.AddEntity(line); - // var cirid = tr.AddEntity(circle); - // var linent = tr.GetObject(lienid); - // var lineent = tr.GetObject(cirid); - // var linee = tr.GetObject(cirid); // 经测试,类型不匹配,返回null - // var dd = tr.GetObject(lienid); - // List ds = new() { linee, dd }; - // tr.CurrentSpace.AddEntity(line,tr); - } - - // add entity test - [CommandMethod(nameof(Test_Addent))] - public void Test_Addent() - { - using DBTrans tr = new(); - Line line = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - tr.CurrentSpace.AddEntity(line); - Line line1 = new(new Point3d(10, 10, 0), new Point3d(41, 1, 0)); - tr.ModelSpace.AddEntity(line1); - Line line2 = new(new Point3d(-10, 10, 0), new Point3d(41, 1, 0)); - tr.PaperSpace.AddEntity(line2); - } - - [CommandMethod(nameof(Test_Drawarc))] - public void Test_Drawarc() - { - using DBTrans tr = new(); - Arc arc1 = ArcEx.CreateArcSCE(new Point3d(2, 0, 0), new Point3d(0, 0, 0), new Point3d(0, 2, 0));// 起点,圆心,终点 - Arc arc2 = ArcEx.CreateArc(new Point3d(4, 0, 0), new Point3d(0, 0, 0), Math.PI / 2); // 起点,圆心,弧度 - Arc arc3 = ArcEx.CreateArc(new Point3d(1, 0, 0), new Point3d(0, 0, 0), new Point3d(0, 1, 0)); // 起点,圆上一点,终点 - tr.CurrentSpace.AddEntity(arc1, arc2, arc3); - tr.CurrentSpace.AddArc(new Point3d(0, 0, 0), new Point3d(1, 1, 0), new Point3d(2, 0, 0));// 起点,圆上一点,终点 - } - - [CommandMethod(nameof(Test_DrawCircle))] - public void Test_DrawCircle() - { - using DBTrans tr = new(); - var circle1 = CircleEx.CreateCircle(new Point3d(0, 0, 0), new Point3d(1, 0, 0)); // 起点,终点 - var circle2 = CircleEx.CreateCircle(new Point3d(-2, 0, 0), new Point3d(2, 0, 0), new Point3d(0, 2, 0));// 三点画圆,成功 - var circle3 = CircleEx.CreateCircle(new Point3d(-2, 0, 0), new Point3d(0, 0, 0), new Point3d(2, 0, 0));// 起点,圆心,终点,失败 - tr.CurrentSpace.AddEntity(circle1, circle2!); - if (circle3 is not null) - tr.CurrentSpace.AddEntity(circle3); - else - tr.Editor?.WriteMessage("三点画圆失败"); - tr.CurrentSpace.AddEntity(circle3!); - tr.CurrentSpace.AddCircle(new Point3d(0, 0, 0), new Point3d(1, 1, 0), new Point3d(2, 0, 0));// 三点画圆,成功 - tr.CurrentSpace.AddCircle(new Point3d(0, 0, 0), new Point3d(1, 1, 0), new Point3d(2, 2, 0));// 起点,圆上一点,终点(共线) - } - - [CommandMethod(nameof(Test_LayerAdd0))] - public void Test_LayerAdd0() - { - using DBTrans tr = new(); - tr.LayerTable.Add("1"); - tr.LayerTable.Add("2", lt => { - lt.Color = Color.FromColorIndex(ColorMethod.ByColor, 1); - lt.LineWeight = LineWeight.LineWeight030; - }); - tr.LayerTable.Remove("3"); - tr.LayerTable.Delete("0"); - tr.LayerTable.Change("4", lt => { - lt.Color = Color.FromColorIndex(ColorMethod.ByColor, 2); - }); - } - - - // 添加图层 - [CommandMethod(nameof(Test_LayerAdd1))] - public void Test_LayerAdd1() - { - using DBTrans tr = new(); - tr.LayerTable.Add("test1", Color.FromColorIndex(ColorMethod.ByColor, 1)); - } - - // 添加图层 - [CommandMethod(nameof(Test_LayerAdd2))] - public void Test_LayerAdd2() - { - using DBTrans tr = new(); - tr.LayerTable.Add("test2", 2); - // tr.LayerTable["3"] = new LayerTableRecord(); - } - // 删除图层 - [CommandMethod(nameof(Test_LayerDel))] - public void Test_LayerDel() - { - using DBTrans tr = new(); - Env.Editor.WriteMessage(tr.LayerTable.Delete("0").ToString()); // 删除图层 0 - Env.Editor.WriteMessage(tr.LayerTable.Delete("Defpoints").ToString());// 删除图层 Defpoints - Env.Editor.WriteMessage(tr.LayerTable.Delete("1").ToString()); // 删除不存在的图层 1 - Env.Editor.WriteMessage(tr.LayerTable.Delete("2").ToString()); // 删除有图元的图层 2 - Env.Editor.WriteMessage(tr.LayerTable.Delete("3").ToString()); // 删除图层 3 - - tr.LayerTable.Remove("2"); // 测试是否能强制删除 - } - - // 添加直线 - [CommandMethod(nameof(Test_AddLine1))] - public void Test_AddLine1() - { - using DBTrans tr = new(); - // tr.ModelSpace.AddEnt(line); - // tr.ModelSpace.AddEnts(line,circle); - - // tr.PaperSpace.AddEnt(line); - // tr.PaperSpace.AddEnts(line,circle); - - // tr.addent(btr,line); - // tr.addents(btr,line,circle); - - - // tr.BlockTable.Add(new BlockTableRecord(), line => - // { - // line. - // }); - Line line1 = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - Line line2 = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - Line line3 = new(new Point3d(1, 1, 0), new Point3d(3, 3, 0)); - Circle circle = new(new Point3d(0, 0, 0), Vector3d.ZAxis, 10); - tr.CurrentSpace.AddEntity(line1); - tr.CurrentSpace.AddEntity(line2, line3, circle); - } - - // 增加多段线1 - [CommandMethod(nameof(Test_AddPolyline1))] - public void Test_AddPolyline1() - { - using DBTrans tr = new(); - Polyline pl = new(); - pl.SetDatabaseDefaults(); - pl.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0); - pl.AddVertexAt(1, new Point2d(10, 10), 0, 0, 0); - pl.AddVertexAt(2, new Point2d(20, 20), 0, 0, 0); - pl.AddVertexAt(3, new Point2d(30, 30), 0, 0, 0); - pl.AddVertexAt(4, new Point2d(40, 40), 0, 0, 0); - pl.Closed = true; - pl.Color = Color.FromColorIndex(ColorMethod.ByColor, 6); - tr.CurrentSpace.AddEntity(pl); - } - - // 增加多段线2 - [CommandMethod(nameof(Test_AddPolyline2))] - public void Test_AddPolyline2() - { - var pts = new List<(Point3d, double, double, double)> - { - (new Point3d(0,0,0),0,0,0), - (new Point3d(10,0,0),0,0,0), - (new Point3d(10,10,0),0,0,0), - (new Point3d(0,10,0),0,0,0), - (new Point3d(5,5,0),0,0,0) - }; - using DBTrans tr = new(); - tr.CurrentSpace.AddPline(pts); - } - - - - - // 测试扩展数据 - static readonly string _appname = "myapp2"; - // 增 - [CommandMethod(nameof(Test_AddXdata))] - public void Test_AddXdata() - { - using DBTrans tr = new(); - var appname = "myapp2"; - - tr.RegAppTable.Add("myapp1"); - tr.RegAppTable.Add(appname); // add函数会默认的在存在这个名字的时候返回这个名字的regapp的id,不存在就新建 - tr.RegAppTable.Add("myapp3"); - tr.RegAppTable.Add("myapp4"); - - var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)) - { - XData = new XDataList() - { - { DxfCode.ExtendedDataRegAppName, "myapp1" }, // 可以用dxfcode和int表示组码 - { DxfCode.ExtendedDataAsciiString, "xxxxxxx" }, - {1070, 12 }, - { DxfCode.ExtendedDataRegAppName, appname }, // 可以用dxfcode和int表示组码,移除中间的测试 - { DxfCode.ExtendedDataAsciiString, "要移除的我" }, - {1070, 12 }, - { DxfCode.ExtendedDataRegAppName, "myapp3" }, // 可以用dxfcode和int表示组码 - { DxfCode.ExtendedDataAsciiString, "aaaaaaaaa" }, - {1070, 12 }, - { DxfCode.ExtendedDataRegAppName, "myapp4" }, // 可以用dxfcode和int表示组码 - { DxfCode.ExtendedDataAsciiString, "bbbbbbbbb" }, - {1070, 12 } - } - }; - - tr.CurrentSpace.AddEntity(line); - } - // 删 - [CommandMethod(nameof(Test_RemoveXdata))] - public void Test_RemoveXdata() - { - var res = Env.Editor.GetEntity("\n select the entity:"); - if (res.Status == PromptStatus.OK) - { - using DBTrans tr = new(); - var ent = tr.GetObject(res.ObjectId); - if (ent == null || ent.XData == null) - return; - - Env.Printl("\n移除前:" + ent.XData.ToString()); - - ent.RemoveXData(_appname, DxfCode.ExtendedDataAsciiString); - Env.Printl("\n移除成员后:" + ent.XData.ToString()); - - ent.RemoveXData(_appname); - Env.Printl("\n移除appName后:" + ent.XData.ToString()); - } - } - // 查 - [CommandMethod(nameof(Test_GetXdata))] - public void Test_GetXdata() - { - using DBTrans tr = new(); - tr.RegAppTable.ForEach(id => - id.GetObject()?.Name.Print()); - tr.RegAppTable.GetRecords().ForEach(rec => rec.Name.Print()); - tr.RegAppTable.GetRecordNames().ForEach(name => name.Print()); - tr.RegAppTable.ForEach(reg => reg.Name.Print(), checkIdOk: false); - - // var res = ed.GetEntity("\n select the entity:"); - // if (res.Status == PromptStatus.OK) - // { - // using DBTrans tr = new(); - // tr.RegAppTable.ForEach(id => id.GetObject().Print()); - // var data = tr.GetObject(res.ObjectId).XData; - // ed.WriteMessage(data.ToString()); - // } - - // 查询appName里面是否含有某个 - - var res = Env.Editor.GetEntity("\n select the entity:"); - if (res.Status == PromptStatus.OK) - { - var ent = tr.GetObject(res.ObjectId); - if (ent == null || ent.XData == null) - return; - XDataList data = ent.XData; - if (data.Contains(_appname)) - Env.Printl("含有appName:" + _appname); - else - Env.Printl("不含有appName:" + _appname); - var str = "要移除的我"; - if (data.Contains(_appname, str)) - Env.Printl("含有内容:" + str); - else - Env.Printl("不含有内容:" + str); - } - } - // 改 - [CommandMethod(nameof(Test_ChangeXdata))] - public void Test_ChangeXdata() - { - var res = Env.Editor.GetEntity("\n select the entity:"); - if (res.Status != PromptStatus.OK) - return; - using DBTrans tr = new(); - var data = tr.GetObject(res.ObjectId)!; - data.ChangeXData(_appname, DxfCode.ExtendedDataAsciiString, "change"); - if (data.XData == null) - return; - Env.Printl(data.XData.ToString()); - } + + + - [CommandMethod(nameof(Test_PrintLayerName))] - public void Test_PrintLayerName() - { - using DBTrans tr = new(); - foreach (var layerRecord in tr.LayerTable.GetRecords()) - { - tr.Editor?.WriteMessage(layerRecord.Name); - } - foreach (var layerRecord in tr.LayerTable.GetRecords()) - { - tr.Editor?.WriteMessage(layerRecord.Name); - break; - } - } + [CommandMethod(nameof(Test_Rec))] @@ -348,34 +43,20 @@ public void Test_Rec() #pragma warning disable CS0219 // 变量已被赋值,但从未使用过它的值 Tools.TestTimes(1000000, "三次点乘", () => { - var result = false; - if (Math.Abs(p12.DotProduct(p23)) < 1e8 && - Math.Abs(p23.DotProduct(p34)) < 1e8 && - Math.Abs(p34.DotProduct(p41)) < 1e8) - result = true; + bool result = Math.Abs(p12.DotProduct(p23)) < 1e8 && + Math.Abs(p23.DotProduct(p34)) < 1e8 && + Math.Abs(p34.DotProduct(p41)) < 1e8; }); Tools.TestTimes(1000000, "三次垂直", () => { - var result = false; - if (p12.IsParallelTo(p23) && - p23.IsParallelTo(p34) && - p34.IsParallelTo(p41)) - result = true; + bool result = p12.IsParallelTo(p23) && + p23.IsParallelTo(p34) && + p34.IsParallelTo(p41); }); #pragma warning restore CS0219 // 变量已被赋值,但从未使用过它的值 } - public Database Getdb() - { - var db = Acap.DocumentManager.MdiActiveDocument.Database; - return db; - } - - public Document Getdoc() - { - var doc = Acap.DocumentManager.MdiActiveDocument; - return doc; - } + [CommandMethod(nameof(Test_EntRoration))] @@ -407,4 +88,22 @@ public void Test_TypeSpeed() var tt = line1.GetRXClass().DxfName == nameof(Line); }); } + + [CommandMethod(nameof(Test_sleeptrans))] + public static void Test_sleeptrans() + { + using var tr = new DBTrans(); + for (int i = 0; i < 100; i++) + { + var cir = CircleEx.CreateCircle(new Point3d(i, i, 0), 0.5); + if (cir is null) + { + return; + } + cir.ColorIndex = i; + tr.CurrentSpace.AddEntity(cir); + tr.Editor?.Redraw(cir); + System.Threading.Thread.Sleep(10); + } + } } \ No newline at end of file diff --git a/tests/TestShared/TestBlkVisibility.cs b/tests/TestShared/TestBlkVisibility.cs new file mode 100644 index 0000000000000000000000000000000000000000..8417fa3328e2571b3119cf84e8216af1896a4893 --- /dev/null +++ b/tests/TestShared/TestBlkVisibility.cs @@ -0,0 +1,20 @@ +using System.Windows; + +namespace TestAcad2025; + +public static class TestBlkVisibility +{ + [CommandMethod(nameof(TestBlkVisibility))] + public static void Main() + { + var r1 = Env.Editor.GetEntity("\n选择块参照"); + if (r1.Status != PromptStatus.OK) + return; + using var tr = new DBTrans(); + if (tr.GetObject(r1.ObjectId) is not BlockReference { IsDynamicBlock: true } brf) + return; + var info = brf.GetVisibilityInfo(); + MessageBox.Show( + $"块{brf.Name}的可见性名字:{info.PropertyName},参数:{string.Join(", ", info.AllowedValues)}。是否可见?{info.Has}"); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestBlock.cs b/tests/TestShared/TestBlock.cs index 75403c346d899dcff30fde2f4ee8352b62437286..918dca2d7ae0c19fc18c9111adc921e13aec0b2f 100644 --- a/tests/TestShared/TestBlock.cs +++ b/tests/TestShared/TestBlock.cs @@ -1,4 +1,5 @@ -namespace Test; + +namespace Test; public class TestBlock { @@ -27,15 +28,15 @@ public void Test_Refedit() public void Test_GetBoundingBoxEx() { using DBTrans tr = new(); - var ents = Env.Editor.SSGet()?.Value?.GetEntities(); + var ents = Env.Editor.SSGet().Value?.GetEntities(); if (ents == null) return; foreach (var item in ents) { - if (item is null) - continue; - var box = item.GetBoundingBoxEx(); - Env.Print("min:" + box.Min + ";max" + box.Max); + var box = item?.GetBoundingBoxEx(); + Env.Print("min:" + box?.BottomLeft + ";max" + box?.TopRight); + if (box != null) + tr.CurrentSpace.AddEntity(new Line(box.Value.BottomLeft, box.Value.TopRight)); } } @@ -46,13 +47,12 @@ public void Test_BlockDef() using DBTrans tr = new(); // var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); tr.BlockTable.Add("test", - btr => { + btr => + { btr.Origin = new Point3d(0, 0, 0); }, () => // 图元 - { - return new List { new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)) }; - }, + new List { new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)) }, () => // 属性定义 { var id1 = new AttributeDefinition() { Position = new Point3d(0, 0, 0), Tag = "start", Height = 0.2 }; @@ -63,14 +63,14 @@ public void Test_BlockDef() // ObjectId objectId = tr.BlockTable.Add("a");// 新建块 // objectId.GetObject().AddEntity();// 测试添加空实体 tr.BlockTable.Add("test1", - btr => { + btr => + { btr.Origin = new Point3d(0, 0, 0); }, - () => { + () => + { var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - var acText = new TextInfo("123", Point3d.Origin, AttachmentPoint.BaseLeft) - .AddDBTextToEntity(); - + var acText = DBTextEx.CreateDBText(Point3d.Origin, "123", 2.5); return new List { line, acText }; }); } @@ -82,7 +82,8 @@ public void Test_BlockDefbehind() using DBTrans tr = new(@"C:\Users\vic\Desktop\test.dwg"); // var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); tr.BlockTable.Add("test", - btr => { + btr => + { btr.Origin = new Point3d(0, 0, 0); }, () => // 图元 @@ -99,17 +100,18 @@ public void Test_BlockDefbehind() // ObjectId objectId = tr.BlockTable.Add("a");// 新建块 // objectId.GetObject().AddEntity();// 测试添加空实体 tr.BlockTable.Add("test1", - btr => { + btr => + { btr.Origin = new Point3d(0, 0, 0); }, - () => { + () => + { var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); - var acText = new TextInfo("12345", Point3d.Origin, AttachmentPoint.BaseLeft) - .AddDBTextToEntity(); - + var acText = DBTextEx.CreateDBText(Point3d.Origin, "12345", 2.5); + return new List { line, acText }; }); - tr.SaveDwgFile(); + tr.Database.SaveDwgFile(); } @@ -131,19 +133,23 @@ public void Test_BlockDefChange() // }); - tr.BlockTable.Change("test", btr => { + tr.BlockTable.Change("test", btr => + { foreach (var id in btr) { var ent = tr.GetObject(id); using (ent!.ForWrite()) { - if (ent is Dimension dBText) + switch (ent) { - dBText.DimensionText = "234"; - dBText.RecomputeDimensionBlock(true); + case Dimension dBText: + dBText.DimensionText = "234"; + dBText.RecomputeDimensionBlock(true); + break; + case Hatch hatch: + hatch.ColorIndex = 0; + break; } - if (ent is Hatch hatch) - hatch.ColorIndex = 0; } } }); @@ -161,7 +167,7 @@ public void Test_InsertBlockDef() tr.BlockTable.Add("test1", line1, line2, att1, att2); - var ents = new List(); + List ents = []; var line5 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); var line6 = new Line(new Point3d(0, 0, 0), new Point3d(-1, 1, 0)); ents.Add(line5); @@ -192,9 +198,35 @@ public void Test_InsertBlockDef() { "tagTest4", "" } }; tr.CurrentSpace.InsertBlock(new Point3d(10, 10, 0), "test2", atts: def2); + tr.CurrentSpace.InsertBlock(new Point3d(20, 20, 0), "test2"); tr.CurrentSpace.InsertBlock(new Point3d(-10, 0, 0), "test44"); } + [CommandMethod(nameof(Test_InsertBlockWithDoubleDatabase))] + public void Test_InsertBlockWithDoubleDatabase() + { + using var tr = new DBTrans(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.dwg")); + using var trans = new DBTrans(); + + tr.BlockTable.Add("test456", + btr => + { + btr.Origin = new(0, 0, 0); + }, + () => + { + var line = new Line(new(0, 0, 0), new(1, 1, 0)); + var actext = DBTextEx.CreateDBText(Point3d.Origin, "123", 2.5, database: tr.Database); + + return new List { line, actext }; + + }); + tr.CurrentSpace.InsertBlock(Point3d.Origin, "test456"); + tr.Database.SaveDwgFile(); + } + + + [CommandMethod(nameof(Test_AddAttsDef))] public void Test_AddAttsDef() { @@ -213,7 +245,7 @@ public void Test_BlockNullBug() { using DBTrans tr = new(); - var ents = new List(); + List ents = []; var line5 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); var line6 = new Line(new Point3d(0, 0, 0), new Point3d(-1, 1, 0)); ents.Add(line5); @@ -230,12 +262,76 @@ public void Test_BlockFile() tr.CurrentSpace.InsertBlock(Point3d.Origin, id); } + [CommandMethod(nameof(Test_BlockFiledxf))] + public void Test_BlockFiledxf() + { + string [] files; + var folder= new System.Windows.Forms.FolderBrowserDialog(); + if (folder.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + files = Directory.GetFiles(folder.SelectedPath,"*.dxf",SearchOption.AllDirectories); + using DBTrans tr = new(); + foreach (var item in files) + { + var id = tr.BlockTable.GetBlockFrom(item, false); + var pt = Env.Editor.GetPoint("pick pt"); + if (pt.Status == PromptStatus.OK) + { + tr.CurrentSpace.InsertBlock(pt.Value, id); + Env.Editor.Redraw(); + } + + } + + } + + + } + + [CommandMethod("Test_CreateMTextAttributeBlock")] + public void Test_CreateMTextAttributeBlock() + { + + using var tr = new DBTrans(); + + tr.BlockTable.Add("MTextAttributeBlock",btr => + { + btr.Origin = Point3d.Origin; + // 创建一个多行文字作为块的一部分 + var mtext = new MText(); + mtext.Contents = "默认多行文字内容\n第二行内容\n第三行内容"; + mtext.Location = new Point3d(0, 0, 0); + mtext.Width = 200; // 多行文字宽度 + mtext.Height = 2.5; // 文字高度 + btr.AddEntity(mtext); + + + // 创建属性定义 + var attrDef = new AttributeDefinition(); + attrDef.Position = new Point3d(0, -50, 0); // 位置在多行文字下方 + attrDef.Prompt = "请输入属性值"; + attrDef.Tag = "ATTR_TAG"; + attrDef.TextString = "默认属性值"; + attrDef.Height = 2.5; + attrDef.Justify = AttachmentPoint.MiddleCenter; // 居中对齐 + + // 设置为多行属性 + attrDef.SetMTextAttribute(att => att.Width = 100); + btr.AddEntity(attrDef); + }); + + tr.CurrentSpace.InsertBlock(Point3d.Origin, "MTextAttributeBlock"); + + + } + [CommandMethod(nameof(Test_ClipBlock))] public void Test_ClipBlock() { using DBTrans tr = new(); - tr.BlockTable.Add("test1", btr => { + tr.BlockTable.Add("test1", btr => + { btr.Origin = new Point3d(0, 0, 0); btr.AddEntity(new Line(new Point3d(0, 0, 0), new Point3d(10, 10, 0)), new Line(new Point3d(10, 10, 0), new Point3d(10, 0, 0))); @@ -244,13 +340,29 @@ public void Test_ClipBlock() var id = tr.CurrentSpace.InsertBlock(new Point3d(0, 0, 0), "test1"); var brf1 = tr.GetObject(id)!; var pts = new List { new Point3d(3, 3, 0), new Point3d(7, 3, 0), new Point3d(7, 7, 0), new Point3d(3, 7, 0) }; - brf1.ClipBlockRef(pts); + brf1.XClip(pts); var id1 = tr.CurrentSpace.InsertBlock(new Point3d(20, 20, 0), "test1"); var brf2 = tr.GetObject(id); - brf2?.ClipBlockRef(new Point3d(13, 13, 0), new Point3d(17, 17, 0)); + brf2?.XClip(new Point3d(13, 13, 0), new Point3d(17, 17, 0)); + } + + + [CommandMethod(nameof(Test_ClipBlock1))] + public void Test_ClipBlock1() + { + using DBTrans tr = new(); + var ent = Env.Editor.GetEntity("pick block"); + if (ent.Status != PromptStatus.OK) return; + + var brf1 = tr.GetObject(ent.ObjectId)!; + var pts = new List { new Point3d(3, 3, 0), new Point3d(7, 3, 0), new Point3d(7, 7, 0), new Point3d(3, 7, 0) }; + brf1.XClip(pts); + } + + // 给用户的测试程序,不知道对错 [CommandMethod(nameof(Test_Block_ej))] public void Test_Block_ej() @@ -275,7 +387,8 @@ public void Test_Block_ej() var blockdef = tr.BlockTable.GetBlockFrom(fullFileName, false); tr.Database.Clayer = tr.LayerTable["0"];// 当前图层切换为0图层 - tr.LayerTable.Change(tr.Database.Clayer, ltr => { + tr.LayerTable.Change(tr.Database.Clayer, ltr => + { ltr.Color = Color.FromColorIndex(ColorMethod.ByAci, 2); // ColorMethod.ByAci可以让我们使用AutoCAD ACI颜色索引……这里为2(表示黄色) }); @@ -300,7 +413,8 @@ public void Test_Block_ej() var btr = tr2.BlockTable[brf2.Name]; - tr2.BlockTable.Change(btr, ltr => { + tr2.BlockTable.Change(btr, ltr => + { foreach (ObjectId oid in ltr) { var ent = tr2.GetObject(oid); @@ -310,12 +424,12 @@ public void Test_Block_ej() switch (mText.Text) { case "$$A": - mText.Contents = "hahaha"; - break; + mText.Contents = "hahaha"; + break; case "$$B": - break; + break; default: - break; + break; } } else if (ent is DBText dBText) @@ -329,11 +443,11 @@ public void Test_Block_ej() switch (dimension.DimensionText) { case "$$pipeLen": - dimension.DimensionText = "350"; - dimension.RecomputeDimensionBlock(true); - break; + dimension.DimensionText = "350"; + dimension.RecomputeDimensionBlock(true); + break; default: - break; + break; } } } @@ -358,7 +472,7 @@ public void Test_QuickBlockDef2() { // SelectionSet ss = rss.Value; // ObjectId[] ids = ss.GetObjectIds(); - // var ents = new List>(); + // List> ents = []; // var extents = new Extents3d(); // foreach (var id in ids) // { @@ -386,7 +500,7 @@ public void Test_QuickBlockDef2() var extents = ents!.GetExtents(); Point3d pt = extents.MinPoint; Matrix3d matrix = Matrix3d.Displacement(Point3d.Origin - pt); - // var newEnts = new List(); + // List newEnts = []; // foreach (var ent in ents) // { // var newEnt = ent.Key; @@ -492,8 +606,8 @@ void Wblock() var db = curdb.Wblock(ids, Point3d.Origin); db.SaveAs(@"c:\test.dwg", DwgVersion.Current); } - - void ChangeDynameicBlock() + [CommandMethod(nameof(ChangeDynameicBlock))] + public void ChangeDynameicBlock() { var pro = new Dictionary { @@ -505,6 +619,19 @@ void ChangeDynameicBlock() brf.ChangeBlockProperty(pro); // 这是第一个函数的用法 } + [CommandMethod(nameof(ChangeBlockProperty))] + public void ChangeBlockProperty() + { + Dictionary? pro = new() + { + { "haha", "1" } + }; + var blockid = Env.Editor.GetEntity("选择个块").ObjectId; + using DBTrans tr = new(); + var brf = tr.GetObject(blockid)!; + brf.ChangeBlockProperty(pro); + // 这是第一个函数的用法 + } [CommandMethod(nameof(Test_Back))] public void Test_Back() @@ -518,18 +645,144 @@ public void Test_Back() } using DBTrans tr = new(dwg); - tr.ModelSpace.GetEntities().ForEach(ent => { + tr.ModelSpace.GetEntities().ForEach(ent => + { ent.ForWrite(e => e.ColorIndex = 3); }); tr.Database.SaveAs(dwg, DwgVersion.Current); - tr.ModelSpace.GetEntities().ForEach(ent => { + tr.ModelSpace.GetEntities().ForEach(ent => + { ent.ForWrite(e => e.ColorIndex = 4); }); tr.Database.SaveAs(dwg, DwgVersion.Current); } + + [CommandMethod(nameof(Test_ExplodeBlock))] + public void Test_ExplodeBlock() + { + var r1 = Env.Editor.GetEntity("pick block"); + if (r1.Status != PromptStatus.OK) + return; + using var tr = new DBTrans(); + if (tr.GetObject(r1.ObjectId, OpenMode.ForWrite) is not BlockReference brf) + return; + var dboc = new DBObjectCollection(); + // brf.Explode(dboc); + brf.ExplodeToOwnerSpace(); + // foreach (Entity item in dboc) + // { + // tr.CurrentSpace.AddEntity(item); + // } + using (brf.ForWrite()) + { + brf.Erase(); + } + } } + + +public static class Blocks +{ + + [CommandMethod("TestExplodeToOwnerSpace3")] + public static void TestExplodeToOwnerSpace3_Method() + { + Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; + try + { + PromptEntityOptions prEntOpt = new PromptEntityOptions("\nSelect an INSERT:"); + prEntOpt.SetRejectMessage("\nIt is not an INSERT!"); + prEntOpt.AddAllowedClass(typeof(BlockReference), true); + PromptEntityResult selRes = ed.GetEntity(prEntOpt); + if (selRes.Status == PromptStatus.OK) + { + ObjectIdCollection ids = ExplodeToOwnerSpace3(selRes.ObjectId); + ed.WriteMessage("{0} entities were added into database.", ids.Count); + } + else + { + ed.WriteMessage("\nEntity Selection failed!"); + } + } + catch (System.Exception ex) + { + ed.WriteMessage(ex.Message); + } + } + + public static void ExplodeToOwnerSpace2(ObjectId id, bool erase = true) + { + ExplodeToOwnerSpace3(id, erase); + } + + public static void ExplodeToOwnerSpace2(this BlockReference br) + { + ExplodeToOwnerSpace3(br); + } + + public static ObjectIdCollection ExplodeToOwnerSpace3(ObjectId id, bool erase = true) + { + ObjectIdCollection ids; + + using (Transaction tr = id.Database.TransactionManager.StartTransaction()) + { + BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); + ids = br.ExplodeToOwnerSpace3(); + + if (erase) + { + br.UpgradeOpen(); + br.Erase(); + } + + tr.Commit(); + } + + return ids; + } + + private static ObjectIdCollection idsAdded = []; + public static ObjectIdCollection ExplodeToOwnerSpace3(this BlockReference br) + { + idsAdded = new ObjectIdCollection(); + + Transaction tr = br.Database.TransactionManager.TopTransaction; + BlockTableRecord spaceBtr = (BlockTableRecord)tr.GetObject(br.BlockId, OpenMode.ForWrite); + LoopThroughInsertAndAddEntity2n3(br.BlockTransform, br, spaceBtr); + + return idsAdded; + } + // 不能用于非等比 + public static void LoopThroughInsertAndAddEntity2n3(Matrix3d mat, BlockReference br, BlockTableRecord space) + { + Transaction tr = space.Database.TransactionManager.TopTransaction; + BlockTableRecord btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead); + + foreach (ObjectId id in btr) + { + DBObject obj = tr.GetObject(id, OpenMode.ForRead); + Entity? ent = obj.Clone() as Entity; + if (ent is BlockReference) + { + BlockReference br1 = (BlockReference)ent; + LoopThroughInsertAndAddEntity2n3(br1.BlockTransform.PreMultiplyBy(mat), br1, space); + } + else + { + ent?.TransformBy(mat); + space.AppendEntity(ent); + tr.AddNewlyCreatedDBObject(ent, true); + + idsAdded.Add(ent!.ObjectId); + } + } + } + +} + + public class BlockImportClass { [CommandMethod(nameof(Test_Cbll))] @@ -543,7 +796,7 @@ public void Test_Cbll() tr.Database.Insert(blkdefname, tr1.Database, false); // 插入了块定义,未插入块参照 } -#if !NET35 + [CommandMethod(nameof(Test_CombineBlocksIntoLibrary))] public void Test_CombineBlocksIntoLibrary() { @@ -645,5 +898,5 @@ public void Test_CombineBlocksIntoLibrary() pathName ); } -#endif + } \ No newline at end of file diff --git a/tests/TestShared/TestBubbleWindow.cs b/tests/TestShared/TestBubbleWindow.cs new file mode 100644 index 0000000000000000000000000000000000000000..2edae8cb3483bfccb820dadd29dc12ecbd1ef2cd --- /dev/null +++ b/tests/TestShared/TestBubbleWindow.cs @@ -0,0 +1,10 @@ +namespace TestAcad2025; + +public static class TestBubbleWindow +{ + [CommandMethod(nameof(TestBubbleWindow))] + public static void Run() + { + IFoxUtils.ShowBubbleWindow(5, "测试", "测试"); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestCadFilePath.cs b/tests/TestShared/TestCadFilePath.cs index 4a32dd520a763fd659e283429ffd4d8deb82697c..c0354d53598e2c502242888a31cdf9c84e6c5075 100644 --- a/tests/TestShared/TestCadFilePath.cs +++ b/tests/TestShared/TestCadFilePath.cs @@ -6,25 +6,22 @@ public class TestCadFilePath [CommandMethod("TestCadFilePath")] public void TestCadFilePathfun() { - string key = HostApplicationServices.Current.UserRegistryProductRootKey; + var key = HostApplicationServices.Current.UserRegistryProductRootKey; // 计算机\HKEY_CURRENT_USER\SOFTWARE\Autodesk\AutoCAD\R24.0\ACAD-4101:804 - RegistryKey ackey = Registry.CurrentUser.OpenSubKey(key); - var profileskey = ackey.OpenSubKey("Profiles"); + var ackey = Registry.CurrentUser.OpenSubKey(key); + var profileskey = ackey?.OpenSubKey("Profiles"); - var listkey = profileskey.GetSubKeyNames(); + var listkey = profileskey?.GetSubKeyNames(); + if (listkey == null) return; foreach (var item in listkey) { - var acadkey = profileskey.OpenSubKey($@"{item}\General",true); - var name = "ACAD"; - var str = acadkey.GetValue(name)?.ToString(); - if (str is not null && !str.Contains("nihao")) - { - Env.Print(str); - acadkey.SetValue(name, $@"{str}\nihao;", RegistryValueKind.String); - } - - + if (profileskey == null) continue; + var acadkey = profileskey.OpenSubKey($@"{item}\General", true); + const string name = "ACAD"; + var str = acadkey?.GetValue(name)?.ToString(); + if (str == null || str.Contains("nihao")) continue; + Env.Print(str); + acadkey?.SetValue(name, $@"{str}\nihao;", RegistryValueKind.String); } - } } diff --git a/tests/TestShared/TestConvexHull.cs b/tests/TestShared/TestConvexHull.cs index 380bc4453f65b6bda27c8a79e6f4bbf703cd72c8..03692ae5ffc3cceec783cd35c053079e7374ba03 100644 --- a/tests/TestShared/TestConvexHull.cs +++ b/tests/TestShared/TestConvexHull.cs @@ -7,7 +7,7 @@ public class TestConvexHull public void Test_ConvexHull() { // using DBTrans tr = new(); - // var pts = new List(); + // List pts = []; // var flag = true; // while (flag) // { diff --git a/tests/TestShared/TestCurve.cs b/tests/TestShared/TestCurve.cs index 803d7603d764eceb30fc3e6faa7b8f2c162a6caa..fd75698f2af5472409a2139940e55ee400d0e113 100644 --- a/tests/TestShared/TestCurve.cs +++ b/tests/TestShared/TestCurve.cs @@ -21,6 +21,7 @@ public void Test_PointInDict() Env.Print(dict[pt1]); } +#if false [CommandMethod(nameof(Test_Graph1))] public void Test_Graph1() { @@ -37,6 +38,7 @@ public void Test_Graph1() }); } + [CommandMethod(nameof(Test_Graphspeed))] public void Test_Graphspeed() { @@ -48,11 +50,7 @@ public void Test_Graphspeed() var graph = new IFoxCAD.Cad.Graph(); // 为了调试先把图的访问改为internal foreach (var curve in ents) { -#if NET35 - graph.AddEdge(curve!.ToCurve3d()!); -#else graph.AddEdge(curve!.GetGeCurve()); -#endif } // 新建 dfs @@ -80,12 +78,188 @@ public void Test_Graphspeed() // tr.CurrentSpace.AddEntity(res); } +#endif } +public partial class TestCurve +{ + [CommandMethod(nameof(Test_CurveExtend))] + public void Test_CurveExtend() + { + using var tr = new DBTrans(); + var ent = Env.Editor.GetEntity("pick curve").ObjectId.GetObject(); + if (ent is Curve curve) + curve.ForWrite(e => e.Extend(e.EndParam + 1)); + + } + + + private Arc ToArc1(CircularArc2d a2d) + { + double startangle, endangle; + double refangle = a2d.ReferenceVector.Angle; + + if (a2d.IsClockWise) + { + startangle = -a2d.EndAngle + refangle; + endangle = -a2d.StartAngle + refangle; + } + else + { + startangle = a2d.StartAngle + refangle; + endangle = a2d.EndAngle + refangle; + } + + return + new Arc( + new Point3d(new Plane(), a2d.Center), + Vector3d.ZAxis, + a2d.Radius, + startangle, + endangle); + } + + +#if false + [CommandMethod(nameof(Test_Curve_ToArc))] + public void Test_Curve_ToArc() + { + using var tr = new DBTrans(); + var gearc = new CircularArc2d(new Point2d(0,0),new Point2d(0.5,0.5),new Point2d(1,0)); + var dbarc = gearc.ToArc(); + var dbarc1 = ToArc1(gearc); + dbarc.ColorIndex = 1; + tr.CurrentSpace.AddEntity(dbarc); + dbarc1.ColorIndex = 2; + tr.CurrentSpace.AddEntity(dbarc1); + + var gearc3 = new CircularArc3d(new(0,0,0),new(0.5,0.5,0),new Point3d(1,0,0)); + var dbarc3 = (Arc)Curve.CreateFromGeCurve(gearc3); + dbarc3.ColorIndex = 3; + tr.CurrentSpace.AddEntity(dbarc3); + + + + Polyline pl0 = new();//创建有圆弧的多段线 + + pl0.AddVertexAt(0, new(-520, 200), -0.74, 0, 0); + pl0.AddVertexAt(1, new(-100, 140), 0.52, 0, 0); + pl0.AddVertexAt(2, new(16, -120), -0.27, 0, 0); + pl0.AddVertexAt(3, new(400, -130), 0.75, 0, 0); + pl0.AddVertexAt(4, new(450, 200), -0.69, 0, 0); + tr.CurrentSpace.AddEntity(pl0); + + + for (int FFF = 0; FFF < pl0.NumberOfVertices; FFF++) + { + if (pl0.GetSegmentType(FFF) == SegmentType.Arc) + { + var bulge = pl0.GetBulgeAt(FFF); + + //将 CircularArc2d 转为Arc 颜色为红 + CircularArc2d arc2d = pl0.GetArcSegment2dAt(FFF); + + Arc arc = arc2d.ToArc(); + if (bulge < 0) arc.ReverseCurve(); + arc.ColorIndex = 1; + tr.CurrentSpace.AddEntity(arc); + Env.Printl($"arc的ge:ReferenceVector:{MathEx.ConvertRadToDeg(arc2d.ReferenceVector.Angle)}"); + Env.Printl($"arc的ge:顺时针:{arc2d.IsClockWise}"); + Env.Printl($"arc的ge:起点角度:{MathEx.ConvertRadToDeg(arc2d.StartAngle)},终点角度:{MathEx.ConvertRadToDeg(arc2d.EndAngle)}"); + Env.Printl($"arc的db:起点角度:{MathEx.ConvertRadToDeg(arc.StartAngle)},终点角度:{MathEx.ConvertRadToDeg(arc.EndAngle)}"); + + //将 CircularArc2d 转为Arc 颜色为黄 + CircularArc2d arc2d1 = pl0.GetArcSegment2dAt(FFF); + Arc arc1 = ToArc1(arc2d1); + if (bulge < 0) arc1.ReverseCurve(); + arc1.ColorIndex = 2; + tr.CurrentSpace.AddEntity(arc1); + Env.Printl($"arc1的ge:ReferenceVector:{MathEx.ConvertRadToDeg(arc2d1.ReferenceVector.Angle)}"); + Env.Printl($"arc的ge:顺时针:{arc2d1.IsClockWise}"); + Env.Printl($"arc1的ge:起点角度:{MathEx.ConvertRadToDeg(arc2d1.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc2d1.EndAngle)}"); + Env.Printl($"arc1的db:起点角度:{MathEx.ConvertRadToDeg(arc1.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc1.EndAngle)}"); + + //将 CircularArc3d 转为Arc 颜色为黄色 + CircularArc3d arc3d = pl0.GetArcSegmentAt(FFF); + Arc arc2 = arc3d.ToArc(); + + arc2.ColorIndex = 3; + tr.CurrentSpace.AddEntity(arc2); + Env.Printl($"arc2的ge:ReferenceVector:{MathEx.ConvertRadToDeg(arc3d.ReferenceVector.AngleOnPlane(new Plane()))}"); + Env.Printl($"arc2的ge:起点角度:{MathEx.ConvertRadToDeg(arc3d.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc3d.EndAngle)}"); + Env.Printl($"arc2的db:起点角度:{MathEx.ConvertRadToDeg(arc2.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc2.EndAngle)}"); + +/* + + +arc的ge: ReferenceVector:154.872779886857 +arc的ge: 顺时针:True +arc的ge:起点角度:0,终点角度:146.005764482025 +arc的db: 起点角度:334.872779886857,终点角度:120.878544368882 +arc1的ge: ReferenceVector:154.872779886857 +arc的ge: 顺时针:True +arc1的ge:起点角度:0 ,终点角度: 146.005764482025 +arc1的db: 起点角度:334.872779886857 ,终点角度: 120.878544368882 +arc2的ge: ReferenceVector:154.872779886857 +arc2的ge: 起点角度:0 ,终点角度: 146.005764482025 +arc2的db: 起点角度:25.1272201131434 ,终点角度: 171.132984595169 + + +arc的ge: ReferenceVector:149.095360016814 +arc的ge: 顺时针:False +arc的ge:起点角度:0,终点角度:109.897726505109 +arc的db: 起点角度:149.095360016814,终点角度:258.993086521922 +arc1的ge: ReferenceVector:149.095360016814 +arc的ge: 顺时针:False +arc1的ge:起点角度:0 ,终点角度: 109.897726505109 +arc1的db: 起点角度:149.095360016814 ,终点角度: 258.993086521922 +arc2的ge: ReferenceVector:149.095360016814 +arc2的ge: 起点角度:0 ,终点角度: 109.897726505109 +arc2的db: 起点角度:149.095360016814 ,终点角度: 258.993086521922 + + +arc的ge: ReferenceVector:118.727409809308 +arc的ge: 顺时针:True +arc的ge:起点角度:0,终点角度:60.4383004893619 +arc的db: 起点角度:298.727409809308,终点角度:359.16571029867 +arc1的ge: ReferenceVector:118.727409809308 +arc的ge: 顺时针:True +arc1的ge:起点角度:0 ,终点角度: 60.4383004893619 +arc1的db: 起点角度:298.727409809308 ,终点角度: 359.16571029867 +arc2的ge: ReferenceVector:118.727409809308 +arc2的ge: 起点角度:0 ,终点角度: 60.4383004893619 +arc2的db: 起点角度:61.2725901906918 ,终点角度: 121.710890680054 + + +arc的ge: ReferenceVector:277.644556524148 +arc的ge: 顺时针:False +arc的ge:起点角度:0,终点角度:147.479590583376 +arc的db: 起点角度:277.644556524148,终点角度:65.124147107524 +arc1的ge: ReferenceVector:277.644556524148 +arc的ge: 顺时针:False +arc1的ge:起点角度:0 ,终点角度: 147.479590583376 +arc1的db: 起点角度:277.644556524148 ,终点角度: 65.124147107524 +arc2的ge: ReferenceVector:277.644556524148 +arc2的ge: 起点角度:0 ,终点角度: 147.479590583376 +arc2的db: 起点角度:277.644556524148 ,终点角度: 65.124147107524 + + + + + + +*/ + } + } + + } +#endif +} + -public class TestCurve +public partial class TestCurve { [CommandMethod(nameof(Test_BreakCurve))] public void Test_BreakCurve() @@ -104,8 +278,8 @@ public void Test_CurveCurveIntersector3d() { using DBTrans tr = new(); var ents = Env.Editor.SSGet()? - .Value.GetEntities() - .Select(e => e?.ToCompositeCurve3d()).ToList(); + .Value.GetEntities() + .Select(e => e?.ToCompositeCurve3d()).ToList(); if (ents == null) return; diff --git a/tests/TestShared/TestDBTrans.cs b/tests/TestShared/TestDBTrans.cs index 0dc60500b8abcff9d9ca5164c86a5a5c451388c4..41eb67d81a467ecaa1183c6e1868921d79890b9a 100644 --- a/tests/TestShared/TestDBTrans.cs +++ b/tests/TestShared/TestDBTrans.cs @@ -2,6 +2,41 @@ public class TestTrans { + [CommandMethod(nameof(Test_DBTrans))] + public void Test_DBTrans() + { + using DBTrans tr = new(); + if (tr.Editor is null) + return; + tr.Editor.WriteMessage("\n测试 Editor 属性是否工作!"); + tr.Editor.WriteMessage("\n----------开始测试--------------"); + tr.Editor.WriteMessage("\n测试document属性是否工作"); + if (tr.Document == Getdoc()) + { + tr.Editor.WriteMessage("\ndocument 正常"); + } + tr.Editor.WriteMessage("\n测试database属性是否工作"); + if (tr.Database == Getdb()) + { + tr.Editor.WriteMessage("\ndatabase 正常"); + } + } + + private static Database Getdb() + { + var db = Acaop.DocumentManager.MdiActiveDocument.Database; + return db; + } + + private static Document Getdoc() + { + var doc = Acaop.DocumentManager.MdiActiveDocument; + return doc; + } + + + + [CommandMethod(nameof(CmdTest_DBTransActiveOpenDwg), CommandFlags.Session)] public static void CmdTest_DBTransActiveOpenDwg() { @@ -26,7 +61,7 @@ public static void CmdTest_ForEachDemo() // id.Print(); //} - tr.BlockTable.ForEach(action: (id, state) => { + tr.BlockTable.ForEach(action: (id) => { id.Print(); }); tr.BlockTable.ForEach(action: (id, state, index) => { @@ -66,7 +101,7 @@ public static void CmdTest_ForEachDemo() public void FileNotExist() { using DBTrans tr = new("test.dwg"); - tr.SaveFile((DwgVersion)24, false); + tr.Database.SaveFile((DwgVersion)24, false); } // 前台:由于是弹出面板,此时路径不会起任何作用 @@ -74,7 +109,7 @@ public void FileNotExist() public void FileNotExist2() { using DBTrans tr = new(); - tr.SaveFile(saveAsFile: "D:\\"); + tr.Database.SaveFile(saveAsFile: "D:\\"); } // 后台:只有路径,没有文件名 @@ -82,10 +117,10 @@ public void FileNotExist2() public void FileNotExist3() { using DBTrans tr = new("D:\\"); - tr.SaveDwgFile(); + tr.Database.SaveDwgFile(); using DBTrans tr2 = new("D:\\"); - tr2.SaveFile(saveAsFile: "D:\\"); + tr2.Database.SaveFile(saveAsFile: "D:\\"); } @@ -94,15 +129,17 @@ public void Test_SaveDwgFile() { string filename = @"C:\Users\vic\Desktop\test.dwg"; using DBTrans tr = new(filename); - tr.ModelSpace.AddCircle(new Point3d(10, 10, 0), 20); + var circle = CircleEx.CreateCircle(new Point3d(10, 10, 0), 20)!; + tr.ModelSpace.AddEntity(circle); // tr.Database.SaveAs(filename,DwgVersion.Current); - tr.SaveDwgFile(); + tr.Database.SaveDwgFile(); } [CommandMethod(nameof(Test_DBTransAbort))] public void Test_DBTransAbort() { using DBTrans tr = new(); - tr.ModelSpace.AddCircle(new Point3d(0, 0, 0), 20); + var circle = CircleEx.CreateCircle(new Point3d(10, 10, 0), 20)!; + tr.ModelSpace.AddEntity(circle); tr.Abort(); // tr.Commit(); } @@ -138,23 +175,29 @@ public void Test_TopTransaction() var tr1 = HostApplicationServices.WorkingDatabase.TransactionManager.TopTransaction; using DBTrans tr2 = new(); var tr3 = HostApplicationServices.WorkingDatabase.TransactionManager.TopTransaction; - var tr6 = Acap.DocumentManager.MdiActiveDocument.TransactionManager.TopTransaction; + var tr6 = Acaop.DocumentManager.MdiActiveDocument.TransactionManager.TopTransaction; Env.Print(tr2.Transaction == tr3); Env.Print(tr3 == tr6); using DBTrans tr4 = new(); var tr5 = HostApplicationServices.WorkingDatabase.TransactionManager.TopTransaction; - var tr7 = Acap.DocumentManager.MdiActiveDocument.TransactionManager.TopTransaction; + var tr7 = Acaop.DocumentManager.MdiActiveDocument.TransactionManager.TopTransaction; Env.Print(tr4.Transaction == tr5); Env.Print(tr5 == tr7); var trm = HostApplicationServices.WorkingDatabase.TransactionManager; - // var ptt = tr.GetObject(pl).GetClosestPointTo(pt,false); - // var pt1 = new Point3d(0, 0.00000000000001, 0); - // var pt2 = new Point3d(0, 0.00001, 0); - // Env.Print(Tolerance.Global.EqualPoint); - // Env.Print(pt1.IsEqualTo(pt2).ToString()); - // Env.Print(pt1.IsEqualTo(pt2,new Tolerance(0.0,1e-6)).ToString()); - // Env.Print((pt1 == pt2).ToString()); - // Env.Print((pt1 != pt2).ToString()); } + + [CommandMethod(nameof(Test_DBTrans_BlockCount))] + public void Test_DBTrans_BlockCount() + { + using var tr = new DBTrans(); + var i = tr.CurrentSpace + .GetEntities() + .Where(ent => ent.GetBlockName() == "自定义块"); + + var block = i.ToList()[0]; + Env.Print(i.Count()); + } + + } \ No newline at end of file diff --git a/tests/TestShared/TestDBobject.cs b/tests/TestShared/TestDBobject.cs new file mode 100644 index 0000000000000000000000000000000000000000..f0cb142afe65c59161842eedc5ccfd0415047840 --- /dev/null +++ b/tests/TestShared/TestDBobject.cs @@ -0,0 +1,27 @@ + + +namespace TestShared +{ + public static class TestDBobject + { + [CommandMethod(nameof(TestForWrite))] + public static void TestForWrite() + { + using var tr = new DBTrans(); + var ent = Env.Editor.GetEntity("\npick entity"); + if (ent.Status is not PromptStatus.OK) return; + var entid = ent.ObjectId.GetObject()!; + Tools.TestTimes3(100000, "using:", i => { + using (entid.ForWrite()) + { + entid.ColorIndex = i % 7; + } + }); + Tools.TestTimes3(100000, "action:", i => { + entid.ForWrite(e => { + e.ColorIndex = i % 7; + }); + }); + } + } +} diff --git a/tests/TestShared/TestDwgFilerEx.cs b/tests/TestShared/TestDwgFilerEx.cs index d2267af46b95cdba1d5cc7cdeeda3d75940a5958..32a5f78a16bb4f32b3ca077c9995737cda62f62b 100644 --- a/tests/TestShared/TestDwgFilerEx.cs +++ b/tests/TestShared/TestDwgFilerEx.cs @@ -1,158 +1,150 @@ -namespace Test; - -using DxfFiler = IFoxCAD.Cad.DxfFiler; +#if acad +namespace Test; public class CmdTestDwgFilerEx { - [CommandMethod(nameof(CmdTest_DwgFilerEx))] + [CommandMethod(nameof(CmdTest_DwgFilerEx), CommandFlags.UsePickSet)] public static void CmdTest_DwgFilerEx() { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var db = doc.Database; - var ed = doc.Editor; - ed.WriteMessage("\n****测试,序列化图元"); - - var ssPsr = ed.SelectImplied();// 预选 - if (ssPsr.Status != PromptStatus.OK) - { - ssPsr = ed.GetSelection();// 手选 这里输入al会变成all,无法删除ssget的all关键字 - if (ssPsr.Status != PromptStatus.OK) - return; - } - - using DBTrans tr = new(); - var ids = ssPsr.Value.GetObjectIds(); - foreach (var id in ids) - { - if (!id.IsOk()) - continue; - var ent = tr.GetObject(id, OpenMode.ForRead); - if (ent is null) - continue; - var dwgFilerEx = new DwgFilerEx(ent); - ed.WriteMessage(Environment.NewLine + dwgFilerEx.ToString()); - } - } - - [CommandMethod(nameof(CmdTest_EntDxfout))] - public static void CmdTest_EntDxfout() - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var db = doc.Database; - var ed = doc.Editor; - - // 定义选择集选项 - var pso = new PromptSelectionOptions - { - RejectObjectsOnLockedLayers = true, // 不选择锁定图层对象 - AllowDuplicates = true, // 不允许重复选择 - }; - var ssPsr = ed.GetSelection(pso);// 手选 这里输入al会变成all,无法删除ssget的all关键字 - if (ssPsr.Status != PromptStatus.OK) + var ed = Env.Editor; + var r1 = ed.GetSelection(); + if (r1.Status != PromptStatus.OK) return; - using DBTrans tr = new(); - var ids = ssPsr.Value.GetObjectIds(); - foreach (var id in ids) + using var tr = new DBTrans(); + var ents = r1.Value.GetEntities(); + foreach (var ent in ents) { - if (!id.IsOk()) - continue; - var ent = tr.GetObject(id, OpenMode.ForRead); - if (ent is null) - continue; - // ResultBuffer rbDxf = new(); - var filer = new DxfFiler(ent.UnmanagedObject, true);/// 这里有问题 - ent.DxfOut(filer); + var dwgFiler = new IFoxDwgFiler(); + ent.DwgOut(dwgFiler); + foreach (var objectId in dwgFiler.SoftPointerIdList) + { + objectId.ObjectClass.DxfName.Print(); + } + + // ed.WriteMessage(Environment.NewLine + dwgFiler.ToString()); } } + // [CommandMethod(nameof(CmdTest_EntDxfout))] + // public static void CmdTest_EntDxfout() + // { + // var dm = Acap.DocumentManager; + // var doc = dm.MdiActiveDocument; + // var db = doc.Database; + // var ed = doc.Editor; + // + // // 定义选择集选项 + // var pso = new PromptSelectionOptions + // { + // RejectObjectsOnLockedLayers = true, // 不选择锁定图层对象 + // AllowDuplicates = true, // 不允许重复选择 + // }; + // var ssPsr = ed.GetSelection(pso);// 手选 这里输入al会变成all,无法删除ssget的all关键字 + // if (ssPsr.Status != PromptStatus.OK) + // return; + // + // using DBTrans tr = new(); + // var ids = ssPsr.Value.GetObjectIds(); + // foreach (var id in ids) + // { + // if (!id.IsOk()) + // continue; + // var ent = tr.GetObject(id, OpenMode.ForRead); + // if (ent is null) + // continue; + // // ResultBuffer rbDxf = new(); + // var filer = new DxfFiler(ent.UnmanagedObject, true);/// 这里有问题 + // ent.DxfOut(filer); + // } + // } - [CommandMethod(nameof(CmdTest_TextOut))] - public static void CmdTest_TextOut() - { - var dm = Acap.DocumentManager; - var doc = dm.MdiActiveDocument; - var db = doc.Database; - var ed = doc.Editor; - -#if true - var peo1 = new PromptEntityOptions(Environment.NewLine + "点选源TCH_WIREDIM2:") - { - AllowObjectOnLockedLayer = false, - AllowNone = false - }; - var gt1 = ed.GetEntity(peo1); - if (gt1.Status != PromptStatus.OK) - return; -#else - var peo2 = new PromptEntityOptions(Environment.NewLine + "点选目标TCH_WIREDIM2:") - { - AllowObjectOnLockedLayer = false, - AllowNone = false - }; - var gt2 = ed.GetEntity(peo2); - if (gt2.Status != PromptStatus.OK) - return; -#endif - - using DBTrans tr = new(); - var dwgFilerEx = new DwgFilerEx(); - var bText = tr.GetObject(gt1.ObjectId, OpenMode.ForRead); - if (bText is null) - return; - - // DwgFilerEx.StringList[0] = "1@2@3@4@5@6@7@"; - // 复制 TCH_WIREDIM2 不行,TEXT 也不行,直接崩溃。line等线就没事 - bText.DwgOut(dwgFilerEx.DwgFiler); - - int testNum = 1 | 2 | 4 | 8; - - if ((testNum & 1) == 1) - { - // 错误,原地克隆也是不行的,它会生成在了模型中. - var sIds = new List - { - bText.ObjectId - }; - // 克隆到目标块表内 - using ObjectIdCollection bindIds = new(sIds.ToArray()); - using IdMapping map = new(); +// [CommandMethod(nameof(CmdTest_TextOut))] +// public static void CmdTest_TextOut() +// { +// var dm = Acap.DocumentManager; +// var doc = dm.MdiActiveDocument; +// var db = doc.Database; +// var ed = doc.Editor; +// +// #if true +// var peo1 = new PromptEntityOptions(Environment.NewLine + "点选源TCH_WIREDIM2:") +// { +// AllowObjectOnLockedLayer = false, +// AllowNone = false +// }; +// var gt1 = ed.GetEntity(peo1); +// if (gt1.Status != PromptStatus.OK) +// return; +// #else +// var peo2 = new PromptEntityOptions(Environment.NewLine + "点选目标TCH_WIREDIM2:") +// { +// AllowObjectOnLockedLayer = false, +// AllowNone = false +// }; +// var gt2 = ed.GetEntity(peo2); +// if (gt2.Status != PromptStatus.OK) +// return; +// #endif +// +// using DBTrans tr = new(); +// var dwgFilerEx = new DwgFilerEx(); +// var bText = tr.GetObject(gt1.ObjectId, OpenMode.ForRead); +// if (bText is null) +// return; +// +// // DwgFilerEx.StringList[0] = "1@2@3@4@5@6@7@"; +// // 复制 TCH_WIREDIM2 不行,TEXT 也不行,直接崩溃。line等线就没事 +// bText.DwgOut(dwgFilerEx.DwgFiler); +// +// int testNum = 1 | 2 | 4 | 8; +// +// if ((testNum & 1) == 1) +// { +// // 错误,原地克隆也是不行的,它会生成在了模型中. +// var sIds = new List +// { +// bText.ObjectId +// }; +// // 克隆到目标块表内 +// using ObjectIdCollection bindIds = new(sIds.ToArray()); +// using IdMapping map = new(); +// +// tr.CurrentSpace.DeepCloneEx(bindIds, map); +// var newTexts = map.GetValues().GetObject(); +// newTexts.ForEach(nText => { +// if (nText == null) +// return; +// // 通过上面的克隆就已经在块表上面了.所以下面的设置也跟设置到已有图元上一样报错. +// nText.UpgradeOpen(); +// nText.DwgIn(dwgFilerEx); +// tr.CurrentSpace.AddEntity(nText); +// nText.DowngradeOpen(); +// }); +// } +// if ((testNum & 2) == 2) +// { +// // 出错 +// // 直接设置 +// bText.DwgIn(dwgFilerEx); +// } +// if ((testNum & 4) == 4) +// { +// // 出错 +// // 此时是内存中对象.... +// var nText = (DBText)bText.Clone(); +// nText.DwgIn(dwgFilerEx); +// tr.CurrentSpace.AddEntity(nText); +// } +// if ((testNum & 8) == 8) +// { +// // 新对象相当于克隆,是ok的 +// DBText nText = new(); +// nText.SetDatabaseDefaults(); +// nText.DwgIn(dwgFilerEx); +// tr.CurrentSpace.AddEntity(nText); +// } +// } +} - tr.CurrentSpace.DeepCloneEx(bindIds, map); - var newTexts = map.GetValues().GetObject(); - newTexts.ForEach(nText => { - if (nText == null) - return; - // 通过上面的克隆就已经在块表上面了.所以下面的设置也跟设置到已有图元上一样报错. - nText.UpgradeOpen(); - nText.DwgIn(dwgFilerEx); - tr.CurrentSpace.AddEntity(nText); - nText.DowngradeOpen(); - }); - } - if ((testNum & 2) == 2) - { - // 出错 - // 直接设置 - bText.DwgIn(dwgFilerEx); - } - if ((testNum & 4) == 4) - { - // 出错 - // 此时是内存中对象.... - var nText = (DBText)bText.Clone(); - nText.DwgIn(dwgFilerEx); - tr.CurrentSpace.AddEntity(nText); - } - if ((testNum & 8) == 8) - { - // 新对象相当于克隆,是ok的 - DBText nText = new(); - nText.SetDatabaseDefaults(); - nText.DwgIn(dwgFilerEx); - tr.CurrentSpace.AddEntity(nText); - } - } -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/tests/TestShared/TestDwgMark.cs b/tests/TestShared/TestDwgMark.cs new file mode 100644 index 0000000000000000000000000000000000000000..cf0d712a10b0a146bf02f9985329a7b2ad7eb4b4 --- /dev/null +++ b/tests/TestShared/TestDwgMark.cs @@ -0,0 +1,11 @@ +namespace Test; +using IFoxCAD.Cad; +public class TestDwgMark { + [CommandMethod(nameof(DwgMarktest))] + public void DwgMarktest() { + FileInfo file = new FileInfo(@"D:\TEST\1.dwg"); + DwgMark.AddMark(file, 0x4D); + DwgMark.RemoveMark(file); + int A = DwgMark.GetMark(file); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestEditor.cs b/tests/TestShared/TestEditor.cs index 656ddaa8ceadb82a34cc341f8146c86dd2753d1c..5f83345d9fa456752e52a55b975c6177a1c37b6a 100644 --- a/tests/TestShared/TestEditor.cs +++ b/tests/TestShared/TestEditor.cs @@ -44,19 +44,28 @@ public void Test_ZoomExtents() Env.Editor.ZoomExtents(); } + [CommandMethod(nameof(Test_Zoom_1))] + public void Test_Zoom_1() + { + Env.Editor.Zoom(new(0, 0, 0),200,200); + } + [CommandMethod(nameof(Test_Zoom_2))] + public void Test_Zoom_2() + { + Env.Editor.ZoomWindow(new Point3d(-100,-100,0),new(100,100,0)); + } + [CommandMethod(nameof(Test_Ssget))] public void Test_Ssget() { - var action_a = () => { Env.Print("this is a"); }; - var action_b = () => { Env.Print("this is b"); }; - var keyword = new Dictionary + var keyword = new Dictionary { - { "A", action_a }, - { "B", action_b } + { "D", ("你好", () => { Env.Print("this is c"); }) }, + { "B", ("hello", () => { Env.Print("this is b"); }) } }; - var ss = Env.Editor.SSGet(":S", messages: new string[2] { "get", "del" }, + var ss = Env.Editor.SSGet(/*":S", */ messages: ("get", "del" ), keywords: keyword); Env.Print(ss!); } @@ -73,6 +82,6 @@ public void Test_ExportWMF() var ids = psr.Value.GetObjectIds(); // acad21(acad08没有)先选择再执行..会让你再选择一次 // 而且只发生在启动cad之后第一次执行. - Env.Editor.ComExportWMF("D:\\桌面\\aaa.dwg", ids); + Env.Editor.ComExportWMF(@"C:\Users\vic\Desktop\aaa.dwg", ids); } } \ No newline at end of file diff --git a/tests/TestShared/TestEntity/TestAddEntity.cs b/tests/TestShared/TestEntity/TestAddEntity.cs new file mode 100644 index 0000000000000000000000000000000000000000..920e6e03772c73b068e522d4d2a27374ad5c76f6 --- /dev/null +++ b/tests/TestShared/TestEntity/TestAddEntity.cs @@ -0,0 +1,157 @@ +namespace Test; + +public class TestAddEntity +{ +#region 直线 + [CommandMethod(nameof(Test_AddLinetoCurrentSpace))] + public void Test_AddLinetoCurrentSpace() + { + using DBTrans tr = new(); // 开启事务 + + Line line = new(new(0, 0, 0), new(1, 1, 0)); // 定义一个直线 + tr.CurrentSpace.AddEntity(line); // 将直线添加到当前空间 + } + + [CommandMethod(nameof(Test_AddLinetoModelSpace))] + public void Test_AddLinetoModelSpace() + { + using DBTrans tr = new(); // 开启事务 + + Line line = new(new(0, 0, 0), new(1, 1, 0)); // 定义一个直线 + tr.ModelSpace.AddEntity(line); // 将直线添加到模型空间 + } + + [CommandMethod(nameof(Test_AddLinetoPaperSpace))] + public void Test_AddLinetoPaperSpace() + { + using DBTrans tr = new(); // 开启事务 + + Line line = new(new(0, 0, 0), new(1, 1, 0)); // 定义一个直线 + tr.PaperSpace.AddEntity(line); // 将直线添加到图纸空间 + } + + [CommandMethod(nameof(Test_AddEntities))] + public void Test_AddEntities() + { + // 开启事务 + using DBTrans tr = new(); + // 定义三条直线 + Line line1 = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + Line line2 = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + Line line3 = new(new Point3d(1, 1, 0), new Point3d(3, 3, 0)); + Circle circle = new(); + // 一次性添加到当前空间 + tr.CurrentSpace.AddEntity(line2, line2, line3, circle); + // 或者可以传入个列表 + List lines = [line1, line2, line3]; + tr.CurrentSpace.AddEntity(lines); + // 或者可以传入个数组 + Line[] lines1 = [line1, line2, line3]; + tr.CurrentSpace.AddEntity(lines1); + // 图元数组 + Entity[] lines2 = [line1, line2, line3, circle]; + tr.CurrentSpace.AddEntity(lines2); + // c#12 新语法,集合表达式 + tr.CurrentSpace.AddEntity([line1, line2, circle]); + } +#endregion + +#region 圆 + [CommandMethod(nameof(Test_AddCircle))] + public void Test_AddCircle() + { + var cir = CircleEx.CreateCircle(Point3d.Origin, new(1,0,0)); // 两点创建圆 + var cir1 = CircleEx.CreateCircle(Point3d.Origin, new(1,1,0), new(2,0,0)); //三点创建圆 + var cir2 = CircleEx.CreateCircle(Point3d.Origin, 5); // 圆心半径创建圆 + + using DBTrans tr = new(); + tr.CurrentSpace.AddEntity(cir, cir2); + + // 由于三点不一定能成功创建一个圆,因此返回值是可空的,需要判空 + if (cir1 is not null) + { + tr.CurrentSpace.AddEntity(cir1); + } + } +#endregion + +#region 圆弧 + [CommandMethod(nameof(Test_AddArc))] + public void Test_AddArc() + { + using DBTrans tr = new(); + Arc arc1 = ArcEx.CreateArcSCE(new Point3d(2, 0, 0), new Point3d(0, 0, 0), new Point3d(0, 2, 0));// 起点,圆心,终点 + Arc arc2 = ArcEx.CreateArc(new Point3d(4, 0, 0), new Point3d(0, 0, 0), Math.PI / 2); // 起点,圆心,弧度 + Arc arc3 = ArcEx.CreateArc(new Point3d(1, 0, 0), new Point3d(0, 0, 0), new Point3d(0, 1, 0)); // 起点,圆上一点,终点 + tr.CurrentSpace.AddEntity(arc1, arc2, arc3); + } + +#endregion + + + + + +#region 多段线 + [CommandMethod(nameof(Test_AddPolyline1))] + public void Test_AddPolyline1() + { + using DBTrans tr = new(); + Polyline pl = new(); + pl.SetDatabaseDefaults(); + pl.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0); + pl.AddVertexAt(1, new Point2d(10, 10), 0, 0, 0); + pl.AddVertexAt(2, new Point2d(20, 20), 0, 0, 0); + pl.AddVertexAt(3, new Point2d(30, 30), 0, 0, 0); + pl.AddVertexAt(4, new Point2d(40, 40), 0, 0, 0); + pl.Closed = true; + pl.Color = Color.FromColorIndex(ColorMethod.ByColor, 6); + tr.CurrentSpace.AddEntity(pl); + } + + [CommandMethod(nameof(Test_AddPolyline2))] + public void Test_AddPolyline2() + { + // 集合表达式 + List<(Point3d, double, double, double)> pts = + [ + (new Point3d(0,0,0),0,0,0), + (new Point3d(10,0,0),0,0,0), + (new Point3d(10,10,0),0,0,0), + (new Point3d(0,10,0),0,0,0), + (new Point3d(5,5,0),0,0,0) + ]; + + using DBTrans tr = new(); + var pl = pts.CreatePolyline(); + tr.CurrentSpace.AddEntity(pl); + } + + [CommandMethod(nameof(Test_AddPolyline3))] + public void Test_AddPolyline3() + { + using var tr = new DBTrans(); + + List pts = + [ + new(0, 0, 0), + new(0, 1, 0), + new(1, 1, 0), + new(1, 0, 0) + ]; + var pline = pts.CreatePolyline(); + tr.CurrentSpace.AddEntity(pline); + + // 可以通过委托,一次性的创建多段线并设置属性 + var pline1 = pts.CreatePolyline(p => + { + p.Closed = true; + p.ConstantWidth = 0.2; + p.ColorIndex = 1; + }); + tr.CurrentSpace.AddEntity(pline1); + } + +#endregion + +} diff --git a/tests/TestShared/TestEnv.cs b/tests/TestShared/TestEnv.cs index 8b9d2f2056313474b8429929fb82820ae6474355..b785dedf715e891ec7c7955d3ba8162c9619322c 100644 --- a/tests/TestShared/TestEnv.cs +++ b/tests/TestShared/TestEnv.cs @@ -5,12 +5,12 @@ public class Testenv [CommandMethod(nameof(Test_Enum))] public void Test_Enum() { - Env.CmdEcho = true; + SystemVariableManager.CmdEcho = true; } [CommandMethod(nameof(Test_Enum1))] public void Test_Enum1() { - Env.CmdEcho = false; + SystemVariableManager.CmdEcho = false; } [CommandMethod(nameof(Test_Dimblk))] @@ -19,9 +19,9 @@ public void Test_Dimblk() Env.Dimblk = Env.DimblkType.Dot; Env.Print(Env.Dimblk); Env.Print(Env.GetDimblkId(Env.DimblkType.Dot)); - Env.Dimblk = Env.DimblkType.Defult; + Env.Dimblk = Env.DimblkType.Default; Env.Print(Env.Dimblk); - Env.Print(Env.GetDimblkId(Env.DimblkType.Defult)); + Env.Print(Env.GetDimblkId(Env.DimblkType.Default)); Env.Dimblk = Env.DimblkType.Oblique; Env.Print(Env.Dimblk); Env.Print(Env.GetDimblkId(Env.DimblkType.Oblique)); @@ -46,7 +46,7 @@ public void Test_Osmode() // 追加模式 Env.OSMode |= Env.OSModeType.Center; // 检查是否有某个模式 - var os = Env.OSMode.Include(Env.OSModeType.Center); + var os = Env.OSMode.HasFlag(Env.OSModeType.Center); // 取消某个模式 Env.OSMode ^= Env.OSModeType.Center; Env.Editor.WriteMessage(Env.OSMode.ToString()); @@ -57,7 +57,7 @@ public void Test_Osmode1() var dim = Env.OSMode; Env.Editor.WriteMessage(dim.ToString()); } - +#if false [CommandMethod(nameof(Test_Cadver))] public void Test_Cadver() { @@ -67,7 +67,7 @@ public void Test_Cadver() 1.Print(); "1".Print(); } - +#endif [CommandMethod(nameof(Test_GetVar))] public void Test_GetVar() { @@ -89,7 +89,7 @@ public void Test_GetVar() //} -#if !NET35 && !NET40 +#if !zcad // 通过此功能获取全部变量,尚不清楚此处如何设置,没有通过测试 [CommandMethod(nameof(Test_GetvarAll))] public static void Test_GetvarAll() @@ -123,5 +123,62 @@ public static void Test_GetEnv() Env.Printl("GetEnv:" + Env.GetEnv("abc")); Env.Printl("GetEnv PATH:" + Env.GetEnv("PATH")); + + Env.Printl($"getenv-acad: {Env.GetEnv("ACAD")}"); + Env.Printl($"getvar-acad: {Env.GetVar("TRUSTEDPATHS")}"); + Env.Printl($"getenv-TRUSTEDPATHS: {Env.GetEnv("TRUSTEDPATHS")}"); + Env.Printl($"getenv-osmode: {Env.GetEnv("osmode")}"); + Env.Printl($"getvar-osmode: {Env.GetVar("osmode")}"); + } + [CommandMethod(nameof(Test_AppendPath))] + public static void Test_AppendPath() + { + Directory.Exists(@"C:\Folder4").Print(); + Env.AppendSupportPath(@"C:\Folder4", @"C:\Folder5", @"C:\Folder6"); + // Env.AppendTrustedPath(@"c:\a\x",@"c:\a\c"); + // AppendSupportPath(@"c:\a\c"); + Env.GetEnv("ACAD").Print(); + // Env.SetEnv("ACAD", @"C:\Folder1;"+Env.GetEnv("ACAD")); + Env.GetEnv("ACAD").Contains(@"C:\Folder1").Print(); + + } + + [CommandMethod(nameof(Test_RemovePath))] + public static void Test_RemovePath() + { + // var acad = Acaop.TryGetSystemVariable("ACAD").ToString(); + // acad.Print(); + // Acaop.SetSystemVariable("ACAD", acad + @";c:\a\x"); + Env.GetEnv("ACAD").Print(); + Env.RemoveSupportPath(); + // Env.RemoveTrustedPath(@"c:\a\x"); + Env.GetEnv("ACAD").Print(); } + + public static void AppendSupportPath(string path) + { + + string key = HostApplicationServices.Current.UserRegistryProductRootKey; + // 计算机\HKEY_CURRENT_USER\SOFTWARE\Autodesk\AutoCAD\R24.0\ACAD-4101:804 + var ackey = Registry.CurrentUser.OpenSubKey($@"{key}\Profiles") ?? null; + + if (ackey != null) + { + var listkey = ackey.GetSubKeyNames(); + foreach (var item in listkey) + { + var acadkey = ackey.OpenSubKey($@"{item}\General", true); + const string name = "ACAD"; + var str = acadkey?.GetValue(name)?.ToString(); + if (str != null && !str.ToLower().Contains(path.ToLower())) + { + acadkey?.SetValue(name, $@"{str}{path};"); + } + } + } + + ackey?.Close(); + } + + } \ No newline at end of file diff --git a/tests/TestShared/TestExtents.cs b/tests/TestShared/TestExtents.cs new file mode 100644 index 0000000000000000000000000000000000000000..96c04db04ec8d7e080b1edf6ccd797b69afcc61e --- /dev/null +++ b/tests/TestShared/TestExtents.cs @@ -0,0 +1,108 @@ +namespace TestShared; + +public class TestExtents +{ + [CommandMethod(nameof(Test_BlockExtents))] + public void Test_BlockExtents() + { + using var tr = new DBTrans(); + var ent = Env.Editor.GetEntity("pick the entity"); + if (ent.Status != PromptStatus.OK ) + { + return; + } + + var block = ent.ObjectId.GetObject(); + if (block != null && block.Bounds.HasValue) + { + var extent = block.GeometricExtents; + List pts = [ + extent.MinPoint, + new Point3d(extent.MinPoint.X,extent.MaxPoint.Y,0), + extent.MaxPoint, + new Point3d(extent.MaxPoint.X,extent.MinPoint.Y,0), + + ]; + + tr.CurrentSpace.AddEntity(pts.CreatePolyline(action: e => e.ColorIndex = 1)); + + if (block is BlockReference block1) + { + var extents = block1.GeometryExtentsBestFit(); + List pts1 = + [ + extents.MinPoint, + new Point3d(extents.MinPoint.X, extents.MaxPoint.Y, 0), + extents.MaxPoint, + new Point3d(extents.MaxPoint.X, extents.MinPoint.Y, 0), + ]; + tr.CurrentSpace.AddEntity(pts.CreatePolyline(action: e => e.ColorIndex = 2)); + + var extents2 = block1.GetBoundingBoxEx(); + tr.CurrentSpace.AddEntity(pts.CreatePolyline(action: e => e.ColorIndex = 3)); + + // 此处是计算块定义的包围盒,不是块参照的,所以一般情况下不需要使用。 + var ext = new Extents3d(); + ext.AddBlockExtents(block1.BlockTableRecord.GetObject()); + tr.CurrentSpace.AddEntity(ext.CreatePolyline(action: e => e.ColorIndex = 4)); + } + + + } + } + + [CommandMethod(nameof(Test_entextents))] + public void Test_entextents() + { + using var tr = new DBTrans(); + var a = Env.Editor.GetSelection().Value. + GetEntities(OpenMode.ForWrite); + foreach (var e in a) + { + var b = e.Bounds.HasValue; //获取是否有包围盒 + var name = e.ObjectId.ObjectClass.DxfName; + Env.Print($"{name}是否有包围盒-" + b); + if (b) + { + tr.CurrentSpace.AddEntity(e.Bounds!.Value.CreatePolyline(action: e => + { + e.ColorIndex = 4; + e.Closed = true; + })); + var ext = e.GetBoundingBoxEx(); + if (ext.HasValue) + { + tr.CurrentSpace.AddEntity( + ext.Value.Extents3d.CreatePolyline(action: e => + { + e.ColorIndex = 5; + e.Closed = true; + })); + } + + if (e is Curve spline) + { + var ge = spline.GetGeCurve(); + var box = ge.BoundBlock; + List lst = + [ + box.BasePoint, + box.BasePoint + box.Direction1, + box.BasePoint + box.Direction2, + box.BasePoint + box.Direction3, + ]; + tr.CurrentSpace.AddEntity(lst.CreatePolyline(action: e => + { + e.ColorIndex = 6; + e.Closed = true; + })); + } + + } + + + + + } + } +} \ No newline at end of file diff --git a/tests/TestShared/TestHatchinfo.cs b/tests/TestShared/TestHatchinfo.cs index 52dbfaf9bc282807a79faf5b9de60852152f26cd..e241dfba01184c80bb1a7470f8e9048f39c92296 100644 --- a/tests/TestShared/TestHatchinfo.cs +++ b/tests/TestShared/TestHatchinfo.cs @@ -8,11 +8,9 @@ public void TestHatchInfo() using var tr = new DBTrans(); var sf = new SelectionFilter(new TypedValue[] { new TypedValue(0, "*line,circle,arc") }); var ids = Env.Editor.SSGet(null, sf).Value?.GetObjectIds(); - if (ids.Count() > 0) - { - HatchInfo hf = new HatchInfo(ids, false, null, 1, 0).Mode2UserDefined(); - hf.Build(tr.CurrentSpace); - } + if (ids == null || ids.Count() <= 0) return; + var hf = new HatchInfo(ids!, false, null, 1, 0).Mode2UserDefined(); + hf.Build(tr.CurrentSpace); } } diff --git a/tests/TestShared/TestJig.cs b/tests/TestShared/TestJig.cs index 6db1f386f18a6ab5ec537e0328ccf947a3ad5f03..d0076f4fde2dd02dcf19b666e8a7bb79ba8c58b3 100644 --- a/tests/TestShared/TestJig.cs +++ b/tests/TestShared/TestJig.cs @@ -1,4 +1,4 @@ -namespace Test; +namespace Test; using System.Windows.Forms; @@ -27,7 +27,7 @@ public static void Test_Jig33() // 所以此处不加入已经在数据库的图元,而是加入new Entity的. // drawEntitys.Enqueue(cir); }); - moveJig.SetOptions(cir.GeometricExtents.MinPoint, orthomode: true); + moveJig.SetOptions(cir.GeometricExtents.MinPoint); // 此处详见方法注释 moveJig.DatabaseEntityDraw(draw => { @@ -36,7 +36,7 @@ public static void Test_Jig33() while (true) { - var prDrag = moveJig.Drag(); + var prDrag = Env.Editor.Drag(moveJig); if (prDrag.Status == PromptStatus.OK) break; } @@ -69,29 +69,31 @@ public void Test_Jig44() // 不要这样做: jig.SetOptions(closestPt) 而是使用底层暴露 options!.BasePoint = closestPt; - // 需要避免重复加入同一个关键字 + // 允许在循环中替换关键字,需要避免重复加入同一个关键字 if (!options.Keywords.Contains("A")) options.Keywords.Add("A"); // 生成文字 var dictString = (pl.GetDistAtPoint(closestPt) * 0.001).ToString("0.00"); - var acText = new TextInfo(dictString, closestPt, AttachmentPoint.BaseLeft, textHeight: 200) - .AddDBTextToEntity(); + var acText = DBTextEx.CreateDBText(closestPt, dictString, 200); // 加入刷新队列 drawEntitys.Enqueue(acText); }); options = jig.SetOptions(per.PickedPoint); - + + // 在这里加入关键字 // 如果没有这个,那么空格只会是 PromptStatus.None 而不是 PromptStatus.Keyword // options.Keywords.Add(" ", " ", "空格结束啊"); // jig.SetSpaceIsKeyword(); + options.Keywords.Add("A","A","A"); + bool flag = true; while (flag) { - var pr = jig.Drag(); + var pr = Env.Editor.Drag(jig); if (pr.Status == PromptStatus.Keyword) { switch (pr.StringResult) @@ -114,7 +116,7 @@ public void Test_Jig44() else flag = false; } - tr.CurrentSpace.AddEntity(jig.Entitys); + tr.CurrentSpace.AddEntity(jig.Entities); } [CommandMethod(nameof(Test_MessageFilter))] @@ -186,10 +188,7 @@ static public void Test_QuickText() var btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); // Create the text object, set its normal and contents - var acText = new TextInfo(pr.StringResult, - Point3d.Origin, - AttachmentPoint.BaseLeft, textHeight: 200) - .AddDBTextToEntity(); + var acText = DBTextEx.CreateDBText(Point3d.Origin, pr.StringResult, 200); acText.Normal = ed.CurrentUserCoordinateSystem.CoordinateSystem3d.Zaxis; btr.AppendEntity(acText); diff --git a/tests/TestShared/TestJigExTransient.cs b/tests/TestShared/TestJigExTransient.cs index 37611712007e06d7044392c180d5af52be54bcc8..52eb3f4be1f074790dfdaf2fea4e84c8a5c3dfb7 100644 --- a/tests/TestShared/TestJigExTransient.cs +++ b/tests/TestShared/TestJigExTransient.cs @@ -1,4 +1,4 @@ -#if !ac2008 + namespace Test; public partial class Test @@ -86,4 +86,3 @@ public static void Test_JigExTransentDim() tr.CurrentSpace.AddEntity(dimension); } } -#endif \ No newline at end of file diff --git a/tests/TestShared/TestJson.cs b/tests/TestShared/TestJson.cs index 9205679c53a0bc6a302eefd3076e92d455f8fef0..281e1b1bce4ee8e0a21e9aa11696d9f83b7ae2fd 100644 --- a/tests/TestShared/TestJson.cs +++ b/tests/TestShared/TestJson.cs @@ -12,14 +12,16 @@ public class TestJson [CommandMethod(nameof(JavaScriptSerializer))] public void JavaScriptSerializer() { - var RegisteredUsers = new List(); + List RegisteredUsers = []; RegisteredUsers.Add(0); RegisteredUsers.Add(1); RegisteredUsers.Add(2); RegisteredUsers.Add(3); + + var serializedResult = System.Text.Json.JsonSerializer.Serialize(RegisteredUsers); + var deserializedResult = System.Text.Json.JsonSerializer.Deserialize>(serializedResult); - var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); - var serializedResult = serializer.Serialize(RegisteredUsers); - var deserializedResult = serializer.Deserialize>(serializedResult); + + } } \ No newline at end of file diff --git a/tests/TestShared/TestLayer.cs b/tests/TestShared/TestLayer.cs new file mode 100644 index 0000000000000000000000000000000000000000..62df5e1bf2723132947d5374c1f7b6d20389fbce --- /dev/null +++ b/tests/TestShared/TestLayer.cs @@ -0,0 +1,66 @@ +namespace Test; + +public class TestLayer +{ + [CommandMethod(nameof(Test_LayerAdd0))] + public void Test_LayerAdd0() + { + using DBTrans tr = new(); + tr.LayerTable.Add("1"); + tr.LayerTable.Add("2", lt => { + lt.Color = Color.FromColorIndex(ColorMethod.ByColor, 1); + lt.LineWeight = LineWeight.LineWeight030; + }); + tr.LayerTable.Remove("3"); + tr.LayerTable.Delete("0"); + tr.LayerTable.Change("4", lt => { + lt.Color = Color.FromColorIndex(ColorMethod.ByColor, 2); + }); + } + + + // 添加图层 + [CommandMethod(nameof(Test_LayerAdd1))] + public void Test_LayerAdd1() + { + using DBTrans tr = new(); + tr.LayerTable.Add("test1", Color.FromColorIndex(ColorMethod.ByColor, 1)); + } + + // 添加图层 + [CommandMethod(nameof(Test_LayerAdd2))] + public void Test_LayerAdd2() + { + using DBTrans tr = new(); + tr.LayerTable.Add("test2", 2); + // tr.LayerTable["3"] = new LayerTableRecord(); + } + // 删除图层 + [CommandMethod(nameof(Test_LayerDel))] + public void Test_LayerDel() + { + using DBTrans tr = new(); + tr.LayerTable.Remove("0"); // 删除图层 0 + tr.LayerTable.Remove("Defpoints");// 删除图层 Defpoints + tr.LayerTable.Remove("1"); // 删除不存在的图层 1 + tr.LayerTable.Remove("2"); // 删除有图元的图层 2 + tr.LayerTable.Remove("3"); // 删除图层 3 // 删除图层 3 + + tr.LayerTable.Remove("2"); // 测试是否能强制删除 + } + + [CommandMethod(nameof(Test_PrintLayerName))] + public void Test_PrintLayerName() + { + using DBTrans tr = new(); + foreach (var layerRecord in tr.LayerTable.GetRecords()) + { + Env.Printl(layerRecord.Name); + } + foreach (var layerRecord in tr.LayerTable.GetRecords()) + { + Env.Printl(layerRecord.Name); + break; + } + } +} \ No newline at end of file diff --git a/tests/TestShared/TestLisp.cs b/tests/TestShared/TestLisp.cs index 8f79a39e91f1a2c737415d2fc4363244656c0a48..4bd7b193b39beb6d5b61f31a5d4b7945ee7551f6 100644 --- a/tests/TestShared/TestLisp.cs +++ b/tests/TestShared/TestLisp.cs @@ -46,17 +46,18 @@ public static object LispTest_RunLisp(ResultBuffer rb) [CommandMethod("CmdTest_RunLisp17", CommandFlags.Interruptible)] // 命令不会被记录在命令历史记录 [CommandMethod("CmdTest_RunLisp18", CommandFlags.NoHistory)] +#if (!zcad) // 命令不会被 UNDO取消 [CommandMethod("CmdTest_RunLisp19", CommandFlags.NoUndoMarker)] // 不能在参照块中使用命令 [CommandMethod("CmdTest_RunLisp20", CommandFlags.NoBlockEditor)] -#if !ac2008 + // acad09增,不会被动作录制器 捕捉到 [CommandMethod("CmdTest_RunLisp21", CommandFlags.NoActionRecording)] // acad09增,会被动作录制器捕捉 [CommandMethod("CmdTest_RunLisp22", CommandFlags.ActionMacro)] -#endif -#if !NET35 + + // 推断约束时不能使用命令 [CommandMethod("CmdTest_RunLisp23", CommandFlags.NoInferConstraint)] // 命令允许在选择图元时临时显示动态尺寸 diff --git a/tests/TestShared/TestMarshal.cs b/tests/TestShared/TestMarshal.cs index 834fe12349a21bdd8bc0e126dff683674e08e231..80398e2910a1312defdfbd13c97c6b5cf2c834b1 100644 --- a/tests/TestShared/TestMarshal.cs +++ b/tests/TestShared/TestMarshal.cs @@ -58,11 +58,11 @@ public void Test_ImplicitPoint3D() { Point3d pt1 = new(1, 56, 89); var a1 = (Point3D*)&pt1; - Debugx.Printl("指针类型转换,获取x::" + a1->X); + DebugEx.Printl("指针类型转换,获取x::" + a1->X); var pt2 = Point3D.Create(new IntPtr(&pt1)); - Debugx.Printl("pt1地址::" + (int)&pt1); - Debugx.Printl("pt2地址::" + (int)&pt2); + DebugEx.Printl("pt1地址::" + (int)&pt1); + DebugEx.Printl("pt2地址::" + (int)&pt2); Debug.Assert(&pt1 == &pt2);//不相等,是申请了新内存 } } @@ -104,7 +104,7 @@ public void Test_Marshal() IntPtr structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pt)); Marshal.StructureToPtr(pt, structPtr, true); Marshal.Copy(structPtr, bytes, 0, typeSize); - var result = (Point3d)Marshal.PtrToStructure(structPtr, typeof(Point3d)); + var result = (Point3d)(Marshal.PtrToStructure(structPtr, typeof(Point3d)) ?? throw new InvalidOperationException()); "内存拷贝:".Print(); result.Print(); diff --git a/tests/TestShared/TestMirrorFile.cs b/tests/TestShared/TestMirrorFile.cs index 20503f7427cb80e79047273586111f070ba86f71..76ac0337f5b8d657fbe37014ed74e07d24699c46 100644 --- a/tests/TestShared/TestMirrorFile.cs +++ b/tests/TestShared/TestMirrorFile.cs @@ -1,6 +1,4 @@ -using Autodesk.AutoCAD.DatabaseServices; - -namespace Test; +namespace Test; public class MirrorFile { diff --git a/tests/TestShared/TestPoint.cs b/tests/TestShared/TestPoint.cs index f3ba101225a06a3293c5fe92374bb85a01f047c0..b69afeaec8a2e1a781ed669b371fee360d94c7e9 100644 --- a/tests/TestShared/TestPoint.cs +++ b/tests/TestShared/TestPoint.cs @@ -1,11 +1,66 @@ namespace Test; - - -using System.Diagnostics; - - public class TestPoint { +#if false + [CommandMethod(nameof(Test_GetAngle))] + public void Test_GetAngle() + { + var pt1 = new Point2d(0, 0); + var pt2 = new Point2d(1, 1); + var angle_pt1_pt2 = pt1.GetAngle(pt2); + var angle_pt2_pt1 = pt2.GetAngle(pt1); + Env.Printl($"pt1-pt2 angle is : {angle_pt1_pt2}, 角度是: {MathEx.ConvertRadToDeg(angle_pt1_pt2)}"); + Env.Printl($"pt2-pt1 angle is : {angle_pt2_pt1}, 角度是: {MathEx.ConvertRadToDeg(angle_pt2_pt1)}"); + + var polar = pt1.Polar(Math.PI / 2, 10); + Env.Printl($"pt1 90° 距离10的点是: {polar}"); + + } +#endif + [CommandMethod(nameof(Test_Endtoend))] + public void Test_Endtoend() + { + var pts = new Point2dCollection + { + new(0, 0), + new(0, 1), + new(1, 1), + new(1, 0) + }; + + + foreach (Point2d pt in pts) + { + Env.Printl($"X={pt.X},Y={pt.Y}"); + } + pts.End2End(); + Env.Printl("-------"); + foreach (Point2d pt in pts) + { + Env.Printl($"X={pt.X},Y={pt.Y}"); + } + Env.Printl("--------"); + var ptss = new Point3dCollection + { + new(0, 0,0), + new(0, 1,0), + new(1, 1,0), + new(1, 0,0) + }; + + foreach (Point3d pt in ptss) + { + Env.Printl($"X={pt.X},Y={pt.Y},Z={pt.Z}"); + } + ptss.End2End(); + Env.Printl("-------"); + foreach (Point3d pt in ptss) + { + Env.Printl($"X={pt.X},Y={pt.Y},Z={pt.Z}"); + } + + } + /// /// 红黑树排序点集 /// @@ -29,7 +84,7 @@ public void Test_PtSortedSet() foreach (var item in ss1) { if (item.X > 3 && item.X < 7) - Debugx.Printl(item); + DebugEx.Printl(item); else if (item.X >= 7) break; } @@ -98,9 +153,9 @@ public void Test_ListEqualspeed() { var lst1 = new List { 1, 2, 3, 4 }; var lst2 = new List { 1, 2, 3, 4 }; - lst1.EqualsAll(null!); + lst1.SequenceEqual(null!); Tools.TestTimes2(1000000, "eqaulspeed:", () => { - lst1.EqualsAll(lst2); + lst1.SequenceEqual(lst2); }); } diff --git a/tests/TestShared/TestPointEx.cs b/tests/TestShared/TestPointEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..39ec186514fdec152ece92e8a84e23f52067743d --- /dev/null +++ b/tests/TestShared/TestPointEx.cs @@ -0,0 +1,6 @@ +namespace Test; + +public class TestPointEx +{ + +} \ No newline at end of file diff --git a/tests/TestShared/TestPointOnRegion.cs b/tests/TestShared/TestPointOnRegion.cs new file mode 100644 index 0000000000000000000000000000000000000000..62996a70d0b3672950126ea3be1c8e5371df844d --- /dev/null +++ b/tests/TestShared/TestPointOnRegion.cs @@ -0,0 +1,24 @@ +namespace TestAcad2025; + +public static class TestPointOnRegion +{ + [CommandMethod(nameof(TestPointOnRegionCommand))] + public static void TestPointOnRegionCommand() + { + var r1 = Env.Editor.GetEntity("\n选择多段线"); + if (r1.Status != PromptStatus.OK) + return; + using var tr = new DBTrans(); + if (tr.GetObject(r1.ObjectId) is not Polyline pl || pl.HasBulges) + return; + var stretchPoints = pl.GetStretchPoints(); + while (true) + { + var r2 = Env.Editor.GetPoint("\n选择点"); + if (r2.Status != PromptStatus.OK) + return; + var pt = r2.Value.Ucs2Wcs(); + stretchPoints.PointOnRegion(pt).Print(); + } + } +} \ No newline at end of file diff --git a/tests/TestShared/TestQuadTree.cs b/tests/TestShared/TestQuadTree.cs index 74cd52dc3a5137dcaf38f2e30c888d0b9b62296c..1c2e2a880eac3880a65558d5475e90cb187fae59 100644 --- a/tests/TestShared/TestQuadTree.cs +++ b/tests/TestShared/TestQuadTree.cs @@ -1,6 +1,5 @@ namespace Test; -#pragma warning disable CS8632 // 只能在 "#nullable" 注释上下文内的代码中使用可为 null 的引用类型的注释。 /* * 这里属于用户调用例子, * 调用时候必须要继承它,再提供给四叉树 @@ -28,7 +27,6 @@ public override int GetHashCode() return (base.GetHashCode(), ObjectId.GetHashCode()).GetHashCode(); } } -#pragma warning restore CS8632 // 只能在 "#nullable" 注释上下文内的代码中使用可为 null 的引用类型的注释。 @@ -79,7 +77,7 @@ public void Test_QuadTree() (new Point3d(pl[2].X,pl[2].Y,0),0,0,0), (new Point3d(pl[3].X,pl[3].Y,0),0,0,0), }; - tr.CurrentSpace.AddPline(databaseBoundary); + tr.CurrentSpace.AddEntity(databaseBoundary.CreatePolyline(action: e => e.Closed = true)); // 生成多少个图元,导致cad会令undo出错(八叉树深度过大 treemax) // int maximumItems = 30_0000; @@ -173,7 +171,7 @@ public void CmdTest_QuadTree20() var ed = doc.Editor; ed.WriteMessage("\n自动加入全图到四叉树"); - var ss = new List(); + List ss = []; int entnum = 0; var time1 = Timer.RunTime(() => { db.Action(tr => { @@ -302,12 +300,12 @@ public void CmdTest_CreateNodesRect() // 需要把事务放在循环体内部 // 报错: 0x6B00500A (msvcr80.dll)处(位于 acad.exe 中)引发的异常: 0xC0000005: 写入位置 0xFFE00000 时发生访问冲突。 // 画出所有的四叉树节点边界,因为事务放在外面引起 - var nodeRects = new List(); + List nodeRects = []; _quadTreeRoot.ForEach(node => { nodeRects.Add(node); return false; }); - var rectIds = new List(); + List rectIds = []; foreach (var item in nodeRects)// Count = 97341 当数量接近这个量级 { db.Action(tr => { diff --git a/tests/TestShared/TestSelectfilter.cs b/tests/TestShared/TestSelectfilter.cs index ff47d0001f03802e3388f0b8266d99c0062587e7..cab6c92c10c3b97915bf39ac743edb9e938e1031 100644 --- a/tests/TestShared/TestSelectfilter.cs +++ b/tests/TestShared/TestSelectfilter.cs @@ -29,4 +29,30 @@ public void Test_Selectanpoint() var sel2 = Env.Editor.SelectAtPoint(new Point3d(0, 0, 0)); Env.Editor.WriteMessage(""); } +} + +public class TestSelectObjectType +{ + [CommandMethod(nameof(Test_Select_type))] + public void Test_Select_type() + { + var sel = Env.Editor.SSGet(); + if (sel.Status != PromptStatus.OK) return; + var ids = sel.Value.GetObjectIds(); + foreach (var item in ids) + { + item.Print(); + } + + var dxfName = RXObject.GetClass(typeof(Dimension)).DxfName; + dxfName.Print(); + var idss = sel.Value.GetObjectIds(); + foreach (var item in idss) + { + item.Print(); + item.ObjectClass.DxfName.Print(); + } + + } + } \ No newline at end of file diff --git a/tests/TestShared/TestShared.projitems b/tests/TestShared/TestShared.projitems index bd01c5c24e4e74d281e2e9d34ffe54f2312751ee..ec7e67ee37c8cd8a4bbaaccb2a0a787e6b6641d2 100644 --- a/tests/TestShared/TestShared.projitems +++ b/tests/TestShared/TestShared.projitems @@ -12,29 +12,44 @@ - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/TestShared/TestSingleKeyWordHook.cs b/tests/TestShared/TestSingleKeyWordHook.cs new file mode 100644 index 0000000000000000000000000000000000000000..73fe216cf7e19ba408589117d8f99a58290527bb --- /dev/null +++ b/tests/TestShared/TestSingleKeyWordHook.cs @@ -0,0 +1,48 @@ +namespace TestShared; +public static class TestSingleKeyWordHook +{ + [CommandMethod(nameof(TestSingleKeyWordHookDemo))] + public static void TestSingleKeyWordHookDemo() + { + var line1 = new Line(Point3d.Origin, new Point3d(100, 100, 0)); + line1.SetDatabaseDefaults(); + using var j1 = new JigEx((mpw, _) => { + line1.Move(line1.StartPoint, mpw); + }); + j1.DatabaseEntityDraw(wd => wd.Geometry.Draw(line1)); + var jppo = j1.SetOptions("\n选择位置或"); + jppo.Keywords.Add("A", "A", "旋转90°(A)"); + jppo.Keywords.Add("D", "D", "旋转45°(D)"); + // 创建关键字钩子 + using var skwh = new SingleKeyWordHook(); + // 添加关键字 + skwh.AddKeys(jppo.Keywords); + while (true) + { + // 循环开始时复位 + skwh.Reset(); + var r1 = Env.Editor.Drag(j1); + if (skwh.IsResponsed || r1.Status == PromptStatus.Keyword) + { + // 此钩子完整保留了原关键字的鼠标点击功能,所以要同时支持两种情况,也方便在已经写好的关键字功能上扩展 + // 如果响应了关键字 + switch (skwh.IsResponsed ? skwh.StringResult : r1.StringResult.ToUpper()) + { + case "A": + line1.Rotation(line1.StartPoint, Math.PI * 0.5, Vector3d.ZAxis); + break; + case "D": + line1.Rotation(line1.StartPoint, Math.PI * 0.25, Vector3d.ZAxis); + break; + } + continue; + } + if (r1.Status == PromptStatus.OK) + { + using var tr = new DBTrans(); + tr.CurrentSpace.AddEntity(line1); + } + return; + } + } +} diff --git a/tests/TestShared/TestText.cs b/tests/TestShared/TestText.cs new file mode 100644 index 0000000000000000000000000000000000000000..b25dab69dab226d5dbcbc7708afb9c7bb8240209 --- /dev/null +++ b/tests/TestShared/TestText.cs @@ -0,0 +1,49 @@ + +namespace TestShared; + +public class TestText +{ + + [CommandMethod(nameof(TestDBText))] + public void TestDBText() + { + using var tr = new DBTrans(); + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action:t=> t.ColorIndex = 1)); + + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action: t => { + t.Justify = AttachmentPoint.BaseCenter; + t.AlignmentPoint = new(1, 1, 0); + t.ColorIndex = 2; + })); + } + + [CommandMethod(nameof(TestBackDBText))] + public void TestBackDBText() + { + using var tr = new DBTrans(@"C:\Users\vic\Desktop\test.dwg"); + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action: t => t.ColorIndex = 1)); + + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action: t => + { + t.Justify = AttachmentPoint.BaseCenter; + t.AlignmentPoint = new(1, 1, 0); + t.ColorIndex = 2; + })); + tr.Database.SaveDwgFile(); + } + + + + [CommandMethod(nameof(TestMText))] + public void TestMText() + { + using var tr = new DBTrans(); + tr.CurrentSpace.AddEntity(MTextEx.CreateMText(new(5, 5, 0), "123", 2.5, action: t => t.ColorIndex = 1)); + + tr.CurrentSpace.AddEntity(MTextEx.CreateMText(new(5, 5, 0), "123", 2.5, action: t => { + t.Attachment = AttachmentPoint.TopCenter; + t.ColorIndex = 2; + })); + } + +} diff --git a/tests/TestShared/TestXRecord.cs b/tests/TestShared/TestXRecord.cs index 313bf8c5aecb2ba000399429afd421661bb512d9..1fcb85c819ed51ebc0a1629dddd4447f88ed5b5a 100644 --- a/tests/TestShared/TestXRecord.cs +++ b/tests/TestShared/TestXRecord.cs @@ -192,36 +192,7 @@ static void BytesTask(byte[] buffer, int max, Action action) } #endregion -#if NET35 - /// - /// 设置描述(容量无限) - /// - /// - /// - /// - public static void SetSummaryInfoAtt(this Database db, string key, string value) - { - var info = new DatabaseSummaryInfoBuilder(db.SummaryInfo); - if (!info.CustomProperties.ContainsKey(key)) - info.CustomProperties.Add(key, value); - else - info.CustomProperties[key] = value; - db.SummaryInfo = info.ToDatabaseSummaryInfo(); - } - /// - /// 获取描述 - /// - /// - /// - /// - public static object? GetSummaryInfoAtt(this Database db, string key) - { - var info = new DatabaseSummaryInfoBuilder(db.SummaryInfo); - if (info.CustomProperties.ContainsKey(key)) - return info.CustomProperties[key]; - return null; - } -#else + /// /// 设置描述(容量无限) /// @@ -250,7 +221,7 @@ public static void SetSummaryInfoAtt(this Database db, string key, object value) return info.CustomPropertyTable[key]; return null; } -#endif + } public class TestABCList : List diff --git a/tests/TestShared/TestXdata.cs b/tests/TestShared/TestXdata.cs new file mode 100644 index 0000000000000000000000000000000000000000..a0c10afdeafa950b4893b6ef0445bfb9baa7fb32 --- /dev/null +++ b/tests/TestShared/TestXdata.cs @@ -0,0 +1,132 @@ +namespace Test; + +public class TestXdata +{ + // 测试扩展数据 + private const string Appname = "myapp2"; + + // 增 + [CommandMethod(nameof(Test_AddXdata))] + public void Test_AddXdata() + { + using DBTrans tr = new(); + + tr.RegAppTable.Add("myapp1"); + tr.RegAppTable.Add(Appname); // add函数会默认的在存在这个名字的时候返回这个名字的regapp的id,不存在就新建 + tr.RegAppTable.Add("myapp3"); + tr.RegAppTable.Add("myapp4"); + + var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)) + { + XData = new XDataList() + { + { DxfCode.ExtendedDataRegAppName, "myapp1" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "xxxxxxx" }, + {1070, 12 }, + { DxfCode.ExtendedDataRegAppName, Appname }, // 可以用dxfcode和int表示组码,移除中间的测试 + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + {1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp3" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "aaaaaaaaa" }, + {1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp4" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "bbbbbbbbb" }, + {1070, 12 } + } + }; + + var line1 = new Line(new(0, 0, 0), new(2, 0, 0)); + line1.XData = new XDataList() + { + { DxfCode.ExtendedDataRegAppName, "myapp1" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "xxxxxxx" }, + { 1070, 12 }, + { DxfCode.ExtendedDataRegAppName, Appname }, // 可以用dxfcode和int表示组码,移除中间的测试 + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { 1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp3" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "aaaaaaaaa" }, + { DxfCode.ExtendedDataAsciiString, "ccccccccc" }, + { 1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp4" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "bbbbbbbbb" }, + { 1070, 12 } + }; + + tr.CurrentSpace.AddEntity(line,line1); + } + // 删 + [CommandMethod(nameof(Test_RemoveXdata))] + public void Test_RemoveXdata() + { + var res = Env.Editor.GetEntity("\n select the entity:"); + if (res.Status != PromptStatus.OK) return; + + using DBTrans tr = new(); + var ent = tr.GetObject(res.ObjectId); + if (ent == null || ent.XData == null) + return; + + Env.Printl("\n移除前:" + ent.XData); + + ent.RemoveXData(Appname, DxfCode.ExtendedDataAsciiString); + Env.Printl("\n移除成员后:" + ent.XData); + + ent.RemoveXData(Appname); + Env.Printl("\n移除appName后:" + ent.XData); + } + // 查 + [CommandMethod(nameof(Test_GetXdata))] + public void Test_GetXdata() + { + using DBTrans tr = new(); + tr.RegAppTable.ForEach(id => + id.GetObject()?.Name.Print()); + tr.RegAppTable.GetRecords().ForEach(rec => rec.Name.Print()); + tr.RegAppTable.GetRecordNames().ForEach(name => name.Print()); + tr.RegAppTable.ForEach(reg => reg.Name.Print(), checkIdOk: false); + + // 查询appName里面是否含有某个 + + var res = Env.Editor.GetEntity("\n select the entity:"); + if (res.Status != PromptStatus.OK) return; + + var ent = tr.GetObject(res.ObjectId); + if (ent == null || ent.XData == null) + return; + + XDataList data = ent.XData; + if (data.Contains(Appname)) + Env.Printl("含有appName:" + Appname); + else + Env.Printl("不含有appName:" + Appname); + + const string str = "要移除的我"; + if (data.Contains(Appname, str)) + Env.Printl("含有内容:" + str); + else + Env.Printl("不含有内容:" + str); + } + // 改 + [CommandMethod(nameof(Test_ChangeXdata))] + public void Test_ChangeXdata() + { + var res = Env.Editor.GetEntity("\n select the entity:"); + if (res.Status != PromptStatus.OK) return; + + using DBTrans tr = new(); + var data = tr.GetObject(res.ObjectId)!; + data.ChangeXData(Appname, DxfCode.ExtendedDataAsciiString, "change"); + + if (data.XData == null) + return; + Env.Printl(data.XData.ToString()); + } + +} \ No newline at end of file diff --git a/tests/TestShared/TestXrefEx.cs b/tests/TestShared/TestXrefEx.cs index 81422006a11439cf8c03803e2f43027051ef8ad5..7fa7f3e8b7ae0542f611061f082e48ac44c44130 100644 --- a/tests/TestShared/TestXrefEx.cs +++ b/tests/TestShared/TestXrefEx.cs @@ -10,7 +10,7 @@ public static void Test_Bind1() using var tr = new DBTrans(fileName, fileOpenMode: FileOpenMode.OpenForReadAndAllShare/*后台绑定特别注意*/); tr.XrefFactory(XrefModes.Bind); - tr.SaveDwgFile(); + tr.Database.SaveDwgFile(); } //前台绑定 @@ -19,6 +19,6 @@ public static void Test_Bind2() { using var tr = new DBTrans(); tr.XrefFactory(XrefModes.Bind); - tr.SaveDwgFile(); + tr.Database.SaveDwgFile(); } } \ No newline at end of file diff --git a/src/Basal/IFox.Basal.Shared/General/Timer.cs b/tests/TestShared/Timer.cs similarity index 75% rename from src/Basal/IFox.Basal.Shared/General/Timer.cs rename to tests/TestShared/Timer.cs index d489cb547aadf5323bdd7e29ddbeb07ee0042088..6bd03f1efb38e28c6da60571626f24edcdbafb56 100644 --- a/src/Basal/IFox.Basal.Shared/General/Timer.cs +++ b/tests/TestShared/Timer.cs @@ -1,4 +1,6 @@ -namespace IFoxCAD.Basal; + + +namespace Test; /* // 测试例子,同时验证两个计时器 @@ -20,7 +22,6 @@ public class Timer /// /// 时间单位枚举 /// - [Flags] public enum TimeEnum { /// @@ -42,7 +43,7 @@ public enum TimeEnum } [DllImport("Kernel32.dll")] - static extern bool QueryPerformanceCounter(out long lpPerformanceCount); + private static extern bool QueryPerformanceCounter(out long lpPerformanceCount); /// /// 这个函数会检索性能计数器的频率. @@ -53,10 +54,10 @@ public enum TimeEnum /// /// [DllImport("Kernel32.dll")] - static extern bool QueryPerformanceFrequency(out long lpFrequency); + private static extern bool QueryPerformanceFrequency(out long lpFrequency); - long _startTime, _stopTime; - readonly long _freq; + private long _startTime, _stopTime; + private readonly long _freq; /// /// 构造函数 /// @@ -75,7 +76,7 @@ public Timer() /// public void Start() { - System.Threading.Thread.Sleep(0); + Thread.Sleep(0); QueryPerformanceCounter(out _startTime); } @@ -85,27 +86,27 @@ public void Start() public void Stop() { QueryPerformanceCounter(out _stopTime); - _Second = (double)(_stopTime - _startTime) / _freq; + Second = (double)(_stopTime - _startTime) / _freq; } - double _Second = 0; // 返回计时器经过时间 /// /// 秒 /// - public double Second => _Second; + public double Second { get; private set; } + /// /// 毫秒 /// - public double Millisecond => _Second * 1000.0; + public double Millisecond => Second * 1000.0; /// /// 微秒 /// - public double Microsecond => _Second * 1000000.0; + public double Microsecond => Second * 1000000.0; /// /// 纳秒 /// - public double Nanosecond => _Second * 1000000000.0; + public double Nanosecond => Second * 1000000000.0; /// /// 计算执行委托的时间 /// @@ -120,22 +121,14 @@ public static double RunTime(Action action, action(); nanoSecond.Stop(); - var time = 0.0; - switch (timeEnum) + var time = timeEnum switch { - case TimeEnum.Second: - time = nanoSecond.Second; - break; - case TimeEnum.Millisecond: - time = nanoSecond.Millisecond; - break; - case TimeEnum.Microsecond: - time = nanoSecond.Microsecond; - break; - case TimeEnum.Nanosecond: - time = nanoSecond.Nanosecond; - break; - } + TimeEnum.Second => nanoSecond.Second, + TimeEnum.Millisecond => nanoSecond.Millisecond, + TimeEnum.Microsecond => nanoSecond.Microsecond, + TimeEnum.Nanosecond => nanoSecond.Nanosecond, + _ => 0.0 + }; //string timeNameZn = ""; //switch (timeEnum) //{ diff --git a/tests/TestShared/Tools.cs b/tests/TestShared/Tools.cs new file mode 100644 index 0000000000000000000000000000000000000000..4a9eefa144f623f27836936913f7ae06894632bd --- /dev/null +++ b/tests/TestShared/Tools.cs @@ -0,0 +1,75 @@ +namespace Test; + +public static class Tools +{ + /// + /// 计时器 + /// + [System.Diagnostics.DebuggerStepThrough] + public static void TestTimes2(int count, string message, Action action) + { + System.Diagnostics.Stopwatch watch = new(); + watch.Start(); // 开始监视代码运行时间 + for (var i = 0; i < count; i++) + action.Invoke(); // 需要测试的代码 + watch.Stop(); // 停止监视 + var timespan = watch.Elapsed; // 获取当前实例测量得出的总时间 + var time = timespan.TotalMilliseconds; + var name = "毫秒"; + if (timespan.TotalMilliseconds > 1000) + { + time = timespan.TotalSeconds; + name = "秒"; + } + + $"{message} 代码执行 {count} 次的时间:{time} ({name})".Print(); // 总毫秒数 + } + + /// + /// 计时器 + /// + [System.Diagnostics.DebuggerStepThrough] + public static void TestTimes3(int count, string message, Action action) + { + System.Diagnostics.Stopwatch watch = new(); + watch.Start(); // 开始监视代码运行时间 + for (var i = 0; i < count; i++) + action.Invoke(i); // 需要测试的代码 + watch.Stop(); // 停止监视 + var timespan = watch.Elapsed; // 获取当前实例测量得出的总时间 + var time = timespan.TotalMilliseconds; + var name = "毫秒"; + if (timespan.TotalMilliseconds > 1000) + { + time = timespan.TotalSeconds; + name = "秒"; + } + + $"{message} 代码执行 {count} 次的时间:{time} ({name})".Print(); // 总毫秒数 + } + + + /// + /// 纳秒计时器 + /// + [System.Diagnostics.DebuggerStepThrough] + public static void TestTimes(int count, string message, Action action, + Timer.TimeEnum timeEnum = Timer.TimeEnum.Millisecond) + { + var time = Timer.RunTime(() => + { + for (var i = 0; i < count; i++) + action.Invoke(); + }, timeEnum); + + var timeNameZn = timeEnum switch + { + Timer.TimeEnum.Millisecond => " 毫秒", + Timer.TimeEnum.Microsecond => " 微秒", + Timer.TimeEnum.Nanosecond => " 纳秒", + _ => " 秒" + }; + + $"{message} 代码执行 {count} 次的时间:{time} ({timeNameZn})".Print(); + } +} \ No newline at end of file diff --git a/tests/TestShared/readme.md b/tests/TestShared/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..81b106fd2b210f7fc23c9a0297d73b54fc171b46 --- /dev/null +++ b/tests/TestShared/readme.md @@ -0,0 +1,20 @@ +# 测试项目文件结构 +- 图元类 - TestEntity + + TestAddEntity.cs + + TestRemoveEntity.cs + + .... +- 事务类 - TestDBtrans +- 符号表类 - TestSymTable + + TestLayer.cs + + TestTextStyle.cs + + ... +- 选择集类 +- 扩展数据类 +- editor类 +- 数据库对象类 +- env类 +- jig类 +- 数据交互类 +- lisp类 +- 算法类 +- \ No newline at end of file diff --git a/src/CAD/IFox.CAD.ZCAD/GlobalUsings.cs b/tests/TestZcad2025/GlobalUsings.cs similarity index 81% rename from src/CAD/IFox.CAD.ZCAD/GlobalUsings.cs rename to tests/TestZcad2025/GlobalUsings.cs index add17740c5107dfc01d97ff5c9e08dfbabf7c28c..2c24797f6c0cde2a403ff8c6672248a0cb46058e 100644 --- a/src/CAD/IFox.CAD.ZCAD/GlobalUsings.cs +++ b/tests/TestZcad2025/GlobalUsings.cs @@ -11,13 +11,14 @@ global using System.ComponentModel; global using System.Runtime.InteropServices; global using System.Collections.Specialized; - +global using System.Threading; +global using System.Diagnostics; global using Exception = System.Exception; - +global using System.Runtime.CompilerServices; global using Registry = Microsoft.Win32.Registry; global using RegistryKey = Microsoft.Win32.RegistryKey; -/// cad 引用 +// cad 引用 global using ZwSoft.ZwCAD.ApplicationServices; global using ZwSoft.ZwCAD.EditorInput; global using ZwSoft.ZwCAD.Colors; @@ -25,10 +26,10 @@ global using ZwSoft.ZwCAD.Geometry; global using ZwSoft.ZwCAD.Runtime; global using Acap = ZwSoft.ZwCAD.ApplicationServices.Application; - +global using Acaop = ZwSoft.ZwCAD.ApplicationServices.Application; +global using AcException = ZwSoft.ZwCAD.Runtime.Exception; global using ZwSoft.ZwCAD.DatabaseServices.Filters; -global using ZwSoft.ZwCAD; - +global using Acgi = ZwSoft.ZwCAD.GraphicsInterface; // jig命名空间会引起Viewport/Polyline等等重义,最好逐个引入 using ZwSoft.ZwCAD.GraphicsInterface global using ZwSoft.ZwCAD.GraphicsInterface; global using WorldDraw = ZwSoft.ZwCAD.GraphicsInterface.WorldDraw; @@ -40,9 +41,9 @@ global using Cad_DxfFiler = ZwSoft.ZwCAD.DatabaseServices.DxfFiler; global using Cad_ErrorStatus = ZwSoft.ZwCAD.Runtime.ErrorStatus; -/// ifoxcad.basal 引用 + +/// ifoxcad +global using IFoxCAD.Cad; global using IFoxCAD.Basal; -#if !NewtonsoftJson -global using System.Web.Script.Serialization; -#endif \ No newline at end of file +global using Test; \ No newline at end of file diff --git a/tests/TestAcad09plus/TestAcad09plus.csproj b/tests/TestZcad2025/TestZcad2025.csproj similarity index 36% rename from tests/TestAcad09plus/TestAcad09plus.csproj rename to tests/TestZcad2025/TestZcad2025.csproj index 35a06362e9f6b69a70612160528172e0afc6c56e..a0587c508aa02dd771f394daed8966b7d3c697f3 100644 --- a/tests/TestAcad09plus/TestAcad09plus.csproj +++ b/tests/TestZcad2025/TestZcad2025.csproj @@ -1,40 +1,25 @@ - + preview enable - - NET45 + NET48 true true x64 True - - $(Configuration);acad;ac2015 + + $(Configuration);zcad - - - - - - + - - TestView.xaml - + + - + - - Designer - + - - - - - - - \ No newline at end of file +