├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .vscode
├── launch.json
└── tasks.json
├── Directory.Build.props
├── Directory.Build.targets
├── IxMilia.Step.sln
├── LICENSE.txt
├── README.md
├── build-and-test.cmd
├── build-and-test.sh
├── global.json
├── src
├── IxMilia.Step.Test
│ ├── IxMilia.Step.Test.csproj
│ ├── StepFileTests.cs
│ ├── StepHeaderTests.cs
│ ├── StepItemTests.cs
│ ├── StepTestBase.cs
│ └── StepTokenTests.cs
├── IxMilia.Step
│ ├── Items
│ │ ├── StepAdvancedFace.cs
│ │ ├── StepAxis2Placement.cs
│ │ ├── StepAxis2Placement2D.cs
│ │ ├── StepAxis2Placement3D.cs
│ │ ├── StepBSplineCurve.cs
│ │ ├── StepBSplineCurveWithKnots.cs
│ │ ├── StepBoundedCurve.cs
│ │ ├── StepCartesianPoint.cs
│ │ ├── StepCircle.cs
│ │ ├── StepConic.cs
│ │ ├── StepCurve.cs
│ │ ├── StepCylindricalSurface.cs
│ │ ├── StepDirection.cs
│ │ ├── StepEdge.cs
│ │ ├── StepEdgeCurve.cs
│ │ ├── StepEdgeLoop.cs
│ │ ├── StepElementarySurface.cs
│ │ ├── StepEllipse.cs
│ │ ├── StepFace.cs
│ │ ├── StepFaceBound.cs
│ │ ├── StepFaceOuterBound.cs
│ │ ├── StepFaceSurface.cs
│ │ ├── StepGeometricRepresentationItem.cs
│ │ ├── StepItemType.cs
│ │ ├── StepLine.cs
│ │ ├── StepLoop.cs
│ │ ├── StepOrientedEdge.cs
│ │ ├── StepPlacement.cs
│ │ ├── StepPlane.cs
│ │ ├── StepPoint.cs
│ │ ├── StepRepresentationItem.cs
│ │ ├── StepRepresentationItem_FromTypedParameter.cs
│ │ ├── StepSurface.cs
│ │ ├── StepTopologicalRepresentationItem.cs
│ │ ├── StepTriple.cs
│ │ ├── StepVector.cs
│ │ ├── StepVertex.cs
│ │ └── StepVertexPoint.cs
│ ├── IxMilia.Step.csproj
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── StepBinder.cs
│ ├── StepBoundItem.cs
│ ├── StepFile.cs
│ ├── StepLexer.cs
│ ├── StepReadException.cs
│ ├── StepReader.cs
│ ├── StepSchemaTypes.cs
│ ├── StepTokenizer.cs
│ ├── StepWriter.cs
│ ├── Syntax
│ │ ├── StepAutoSyntax.cs
│ │ ├── StepComplexItemSyntax.cs
│ │ ├── StepDataSectionSyntax.cs
│ │ ├── StepEntityInstanceReferenceSyntax.cs
│ │ ├── StepEntityInstanceSyntax.cs
│ │ ├── StepEnumerationValueSyntax.cs
│ │ ├── StepFileSyntax.cs
│ │ ├── StepHeaderMacroSyntax.cs
│ │ ├── StepHeaderSectionSyntax.cs
│ │ ├── StepIntegerSyntax.cs
│ │ ├── StepItemSyntax.cs
│ │ ├── StepOmittedSyntax.cs
│ │ ├── StepRealSyntax.cs
│ │ ├── StepSimpleItemSyntax.cs
│ │ ├── StepStringSyntax.cs
│ │ ├── StepSyntax.cs
│ │ ├── StepSyntaxExtensions.cs
│ │ ├── StepSyntaxList.cs
│ │ └── StepSyntaxType.cs
│ └── Tokens
│ │ ├── StepAsteriskToken.cs
│ │ ├── StepCommaToken.cs
│ │ ├── StepConstantInstanceToken.cs
│ │ ├── StepConstantValueToken.cs
│ │ ├── StepEntityInstanceToken.cs
│ │ ├── StepEnumerationToken.cs
│ │ ├── StepEqualsToken.cs
│ │ ├── StepInstanceValueToken.cs
│ │ ├── StepIntegerToken.cs
│ │ ├── StepKeywordToken.cs
│ │ ├── StepLeftParenToken.cs
│ │ ├── StepOmittedToken.cs
│ │ ├── StepRealToken.cs
│ │ ├── StepRightParenToken.cs
│ │ ├── StepSemiColonToken.cs
│ │ ├── StepStringToken.cs
│ │ ├── StepToken.cs
│ │ └── StepTokenKind.cs
├── create-package.cmd
└── create-package.sh
└── version.txt
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 |
7 | build:
8 | runs-on: ${{ matrix.os }}
9 | strategy:
10 | matrix:
11 | os: [ubuntu-latest, windows-latest]
12 | configuration: [Debug, Release]
13 | steps:
14 | - uses: actions/checkout@v4
15 | - uses: actions/setup-dotnet@v4
16 | - name: Build and test
17 | shell: pwsh
18 | run: |
19 | $shellExt = if ($IsWindows) { "cmd" } else { "sh" }
20 | & ./build-and-test.$shellExt --configuration ${{ matrix.configuration }}
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore VS files
2 | *.suo
3 | *.user
4 | .vs/
5 |
6 | # ignore artifacts
7 | artifacts/
8 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to find out which attributes exist for C# debugging
3 | // Use hover for the description of the existing attributes
4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": ".NET Core Launch (console)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | // If you have changed target frameworks, make sure to update the program path.
13 | "program": "${workspaceRoot}/src/IxMilia.Step.Test/bin/Debug/netcoreapp1.0/IxMilia.Step.Test.dll",
14 | "args": [],
15 | "cwd": "${workspaceRoot}/src/IxMilia.Step.Test",
16 | // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
17 | "console": "internalConsole",
18 | "stopAtEntry": false,
19 | "internalConsoleOptions": "openOnSessionStart"
20 | },
21 | {
22 | "name": ".NET Core Attach",
23 | "type": "coreclr",
24 | "request": "attach",
25 | "processId": "${command:pickProcess}"
26 | }
27 | ]
28 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "command": "dotnet",
4 | "args": [],
5 | "tasks": [
6 | {
7 | "label": "build",
8 | "type": "shell",
9 | "command": "dotnet",
10 | "args": [
11 | "build",
12 | "${workspaceRoot}/src/IxMilia.Step.Test/IxMilia.Step.Test.csproj"
13 | ],
14 | "problemMatcher": "$msCompile",
15 | "group": {
16 | "_id": "build",
17 | "isDefault": false
18 | }
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)version.txt').Trim())
5 | $(MSBuildThisFileDirectory)artifacts
6 | $(ArtifactsDir)\packages
7 | $(ArtifactsDir)\bin\$(MSBuildProjectName)
8 | $(ArtifactsDir)\obj\$(MSBuildProjectName)
9 | $(ArtifactsPackagesDir)\$(Configuration)
10 | embedded
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(Version)
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/IxMilia.Step.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IxMilia.Step", "src\IxMilia.Step\IxMilia.Step.csproj", "{7BEB4FB6-8A3E-4690-B06C-357130AB4226}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IxMilia.Step.Test", "src\IxMilia.Step.Test\IxMilia.Step.Test.csproj", "{078EDA8D-F0BB-4D60-A7BD-1782A9CF713C}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {7BEB4FB6-8A3E-4690-B06C-357130AB4226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {7BEB4FB6-8A3E-4690-B06C-357130AB4226}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {7BEB4FB6-8A3E-4690-B06C-357130AB4226}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {7BEB4FB6-8A3E-4690-B06C-357130AB4226}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {078EDA8D-F0BB-4D60-A7BD-1782A9CF713C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {078EDA8D-F0BB-4D60-A7BD-1782A9CF713C}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {078EDA8D-F0BB-4D60-A7BD-1782A9CF713C}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {078EDA8D-F0BB-4D60-A7BD-1782A9CF713C}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) IxMilia.
4 | All rights reserved.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | IxMilia.Step
2 | ============
3 |
4 | A portable .NET library for reading and writing STEP CAD files.
5 |
6 | ## Usage
7 |
8 | Open a STEP file:
9 |
10 | ``` C#
11 | using System.IO;
12 | using IxMilia.Step;
13 | using IxMilia.Step.Items;
14 | // ...
15 |
16 | //------------------------------------------------------------ read from a file
17 | StepFile stepFile;
18 | using (FileStream fs = new FileStream(@"C:\Path\To\File.stp", FileMode.Open))
19 | {
20 | stepFile = StepFile.Load(fs);
21 | }
22 |
23 | // if on >= NETStandard1.3 you can use:
24 | // StepFile stepFile = StepFile.Load(@"C:\Path\To\File.stp");
25 |
26 | //---------------------------------------------- or read directly from a string
27 | StepFile stepFile = StepFile.Parse(@"ISO-10303-21;
28 | HEADER;
29 | ...
30 | END-ISO-103030-21;");
31 | //-----------------------------------------------------------------------------
32 |
33 | foreach (StepRepresentationItem item in stepFile.Items)
34 | {
35 | switch (item.ItemType)
36 | {
37 | case StepItemType.Line:
38 | StepLine line = (StepLine)item;
39 | // ...
40 | break;
41 | // ...
42 | }
43 | }
44 | ```
45 |
46 | Save a STEP file:
47 |
48 | ``` C#
49 | using System.IO;
50 | using IxMilia.Step;
51 | using IxMilia.Step.Items;
52 | // ...
53 |
54 | StepFile stepFile = new StepFile();
55 | stepFile.Items.Add(new StepDirection("direction-label", 1.0, 0.0, 0.0));
56 | // ...
57 |
58 | //------------------------------------------------------------- write to a file
59 | using (FileStream fs = new FileStream(@"C:\Path\To\File.stp", FileMode.Create))
60 | {
61 | stepFile.Save(fs);
62 | }
63 |
64 | // if on >= NETStandard1.3 you can use
65 | // stepFile.Save(@"C:\Path\To\File.stp");
66 |
67 | //------------------------------------------------------- or output as a string
68 | string contents = stepFile.GetContentsAsString();
69 | ```
70 |
71 | ## Building locally
72 |
73 | To build locally, install the [latest .NET Core 3.0 SDK](https://dotnet.microsoft.com/download).
74 |
75 | ## Specification
76 |
77 | Using spec from steptools.com [here](http://www.steptools.com/library/standard/IS_final_p21e3.html).
78 |
79 | STEP Application Protocols [here](http://www.steptools.com/support/stdev_docs/express/).
80 |
--------------------------------------------------------------------------------
/build-and-test.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | setlocal
3 |
4 | set thisdir=%~dp0
5 | set configuration=Debug
6 | set runtests=true
7 |
8 | :parseargs
9 | if "%1" == "" goto argsdone
10 | if /i "%1" == "-c" goto set_configuration
11 | if /i "%1" == "--configuration" goto set_configuration
12 | if /i "%1" == "-notest" goto set_notest
13 | if /i "%1" == "--notest" goto set_notest
14 |
15 | echo Unsupported argument: %1
16 | goto error
17 |
18 | :set_configuration
19 | set configuration=%2
20 | shift
21 | shift
22 | goto parseargs
23 |
24 | :set_notest
25 | set runtests=false
26 | shift
27 | goto parseargs
28 |
29 | :argsdone
30 |
31 | :: build
32 | dotnet restore
33 | if errorlevel 1 exit /b 1
34 | dotnet build -c %configuration%
35 | if errorlevel 1 exit /b 1
36 |
37 | :: test
38 | if /i "%runtests%" == "true" (
39 | dotnet test -c %configuration% --no-restore --no-build
40 | if errorlevel 1 goto error
41 | )
42 |
--------------------------------------------------------------------------------
/build-and-test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | _SCRIPT_DIR="$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )"
4 |
5 | CONFIGURATION=Debug
6 | RUNTESTS=true
7 |
8 | while [ $# -gt 0 ]; do
9 | case "$1" in
10 | --configuration|-c)
11 | CONFIGURATION=$2
12 | shift
13 | ;;
14 | --notest)
15 | RUNTESTS=false
16 | ;;
17 | *)
18 | echo "Invalid argument: $1"
19 | exit 1
20 | ;;
21 | esac
22 | shift
23 | done
24 |
25 | # build
26 | dotnet restore
27 | dotnet build -c $CONFIGURATION
28 |
29 | # test
30 | if [ "$RUNTESTS" = "true" ]; then
31 | dotnet test -c $CONFIGURATION --no-restore --no-build
32 | fi
33 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "8.0.300",
4 | "rollForward": "latestMinor"
5 | }
6 | }
--------------------------------------------------------------------------------
/src/IxMilia.Step.Test/IxMilia.Step.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/IxMilia.Step.Test/StepFileTests.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Linq;
3 | using IxMilia.Step.Items;
4 | using Xunit;
5 |
6 | namespace IxMilia.Step.Test
7 | {
8 | public class StepFileTests : StepTestBase
9 | {
10 | [Fact]
11 | public void FileSystemAPITest()
12 | {
13 | var filePath = Path.GetTempFileName();
14 | var stepFile = new StepFile();
15 | var point = new StepCartesianPoint("some-label", 1.0, 2.0, 3.0);
16 | stepFile.Items.Add(point);
17 |
18 | // round trip
19 | stepFile.Save(filePath);
20 | var stepFile2 = StepFile.Load(filePath);
21 |
22 | var point2 = (StepCartesianPoint)stepFile2.Items.Single();
23 | Assert.Equal(point.Name, point2.Name);
24 | Assert.Equal(point.X, point2.X);
25 | Assert.Equal(point.Y, point2.Y);
26 | Assert.Equal(point.Z, point2.Z);
27 |
28 | try
29 | {
30 | File.Delete(filePath);
31 | }
32 | catch
33 | {
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/IxMilia.Step.Test/StepHeaderTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Xunit;
4 |
5 | namespace IxMilia.Step.Test
6 | {
7 | public class StepHeaderTests : StepTestBase
8 | {
9 | private StepFile ReadFileFromHeader(string header)
10 | {
11 | var file = $@"
12 | {StepFile.MagicHeader};
13 | {StepFile.HeaderText};
14 | {header.Trim()}
15 | {StepFile.EndSectionText};
16 | {StepFile.DataText};
17 | {StepFile.EndSectionText};
18 | {StepFile.MagicFooter};
19 | ";
20 | return StepFile.Parse(file.Trim());
21 | }
22 |
23 | [Fact]
24 | public void FileDescriptionTest()
25 | {
26 | var file = ReadFileFromHeader("FILE_DESCRIPTION(('some description'), '2;1');");
27 | Assert.Equal("some description", file.Description);
28 | Assert.Equal("2;1", file.ImplementationLevel);
29 | }
30 |
31 | [Fact]
32 | public void FileDescriptionWithMultiplePartsTest()
33 | {
34 | var file = ReadFileFromHeader("FILE_DESCRIPTION(('some description', ', ', 'more description'), '2;1');");
35 | Assert.Equal("some description, more description", file.Description);
36 | Assert.Equal("2;1", file.ImplementationLevel);
37 | }
38 |
39 | [Fact]
40 | public void FullHeaderTest()
41 | {
42 | var file = ReadFileFromHeader(@"
43 | FILE_DESCRIPTION(('description'), '2;1');
44 | FILE_NAME('file-name', '2010-01-01T', ('author'), ('organization'), 'preprocessor', 'originator', 'authorization');
45 | FILE_SCHEMA(('EXPLICIT_DRAUGHTING'));
46 | ");
47 | Assert.Equal("description", file.Description);
48 | Assert.Equal("2;1", file.ImplementationLevel);
49 | Assert.Equal("file-name", file.Name);
50 | Assert.Equal(new DateTime(2010, 1, 1), file.Timestamp);
51 | Assert.Equal("author", file.Author);
52 | Assert.Equal("organization", file.Organization);
53 | Assert.Equal("preprocessor", file.PreprocessorVersion);
54 | Assert.Equal("originator", file.OriginatingSystem);
55 | Assert.Equal("authorization", file.Authorization);
56 | Assert.Equal(StepSchemaTypes.ExplicitDraughting, file.Schemas.Single());
57 | }
58 |
59 | [Fact]
60 | public void ReadDifferentTimeStampsTest()
61 | {
62 | var file = ReadFileFromHeader(@"FILE_NAME('', '2016-06-26T13:59:52+02:00', (), (), '', '', '');");
63 | Assert.Equal(2016, file.Timestamp.Year);
64 | Assert.Equal(6, file.Timestamp.Month);
65 | }
66 |
67 | [Fact]
68 | public void ReadTimeStampMonthWithoutLeadingZerosTest()
69 | {
70 | var file = ReadFileFromHeader(@"FILE_NAME('', '2004-3-17T2:58:55 PM+8:00', (), (), '', '', '');");
71 | Assert.Equal(2004, file.Timestamp.Year);
72 | Assert.Equal(3, file.Timestamp.Month);
73 | }
74 |
75 | [Fact]
76 | public void WriteHeaderTest()
77 | {
78 | var file = new StepFile();
79 | file.Description = "some description";
80 | file.ImplementationLevel = "2;1";
81 | file.Name = "file-name";
82 | file.Timestamp = new DateTime(2010, 1, 1);
83 | file.Author = "author";
84 | file.Organization = "organization";
85 | file.PreprocessorVersion = "preprocessor";
86 | file.OriginatingSystem = "originator";
87 | file.Authorization = "authorization";
88 | file.Schemas.Add(StepSchemaTypes.ExplicitDraughting);
89 | AssertFileIs(file, @"
90 | ISO-10303-21;
91 | HEADER;
92 | FILE_DESCRIPTION(('some description'),'2;1');
93 | FILE_NAME('file-name','2010-01-01T00:00:00.0000000',('author'),('organization'),'preprocessor','originator','authorization');
94 | FILE_SCHEMA(('EXPLICIT_DRAUGHTING'));
95 | ENDSEC;
96 | DATA;
97 | ENDSEC;
98 | END-ISO-10303-21;
99 | ".TrimStart());
100 | }
101 |
102 | [Fact]
103 | public void WriteHeaderWithLongDescriptionTest()
104 | {
105 | var file = new StepFile();
106 | file.Description = new string('a', 257);
107 | file.Timestamp = new DateTime(2010, 1, 1);
108 | file.Schemas.Add(StepSchemaTypes.ExplicitDraughting);
109 | AssertFileIs(file, $@"
110 | ISO-10303-21;
111 | HEADER;
112 | FILE_DESCRIPTION(('{new string('a', 256)}','a'),'');
113 | FILE_NAME('','2010-01-01T00:00:00.0000000',(''),(''),'','','');
114 | FILE_SCHEMA(('EXPLICIT_DRAUGHTING'));
115 | ENDSEC;
116 | DATA;
117 | ENDSEC;
118 | END-ISO-10303-21;
119 | ".TrimStart());
120 | }
121 |
122 | [Fact]
123 | public void ReadHeaderWithUnsupportedSchemaTest()
124 | {
125 | var file = ReadFileFromHeader(@"FILE_SCHEMA(('EXPLICIT_DRAUGHTING','UNSUPPORTED_SCHEMA'));");
126 | Assert.Single(file.Schemas);
127 | Assert.Single(file.UnsupportedSchemas);
128 | }
129 |
130 | [Fact]
131 | public void WriteHeaderWithUnsupportedSchemaTest()
132 | {
133 | var file = new StepFile();
134 | file.UnsupportedSchemas.Add("UNSUPPORTED_SCHEMA");
135 | AssertFileContains(file, "FILE_SCHEMA(('UNSUPPORTED_SCHEMA'));");
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/IxMilia.Step.Test/StepItemTests.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using IxMilia.Step.Items;
3 | using Xunit;
4 |
5 | namespace IxMilia.Step.Test
6 | {
7 | public class StepItemTests : StepTestBase
8 | {
9 | private StepFile ReadFile(string data)
10 | {
11 | var text = $@"
12 | ISO-10303-21;
13 | HEADER;
14 | ENDSEC;
15 | DATA;
16 | {data.Trim()}
17 | ENDSEC;
18 | END-ISO-10303-21;
19 | ";
20 | var file = StepFile.Parse(text.Trim());
21 | return file;
22 | }
23 |
24 | private StepRepresentationItem ReadTopLevelItem(string data)
25 | {
26 | var file = ReadFile(data);
27 | return file.GetTopLevelItems().Single();
28 | }
29 |
30 | private void AssertFileContains(StepRepresentationItem item, string expected)
31 | {
32 | var file = new StepFile();
33 | file.Items.Add(item);
34 | AssertFileContains(file, expected);
35 | }
36 |
37 | [Fact]
38 | public void ReadCartesianPointTest1()
39 | {
40 | var point = (StepCartesianPoint)ReadTopLevelItem("#1=CARTESIAN_POINT('name',(1.0,2.0,3.0));");
41 | Assert.Equal("name", point.Name);
42 | Assert.Equal(1.0, point.X);
43 | Assert.Equal(2.0, point.Y);
44 | Assert.Equal(3.0, point.Z);
45 | }
46 |
47 | [Fact]
48 | public void ReadCartesianPointTest2()
49 | {
50 | var point = (StepCartesianPoint)ReadTopLevelItem("#1=CARTESIAN_POINT('name',(1.0));");
51 | Assert.Equal("name", point.Name);
52 | Assert.Equal(1.0, point.X);
53 | Assert.Equal(0.0, point.Y);
54 | Assert.Equal(0.0, point.Z);
55 | }
56 |
57 | [Fact]
58 | public void ReadCartesianPointWithOmittedNameTest()
59 | {
60 | var point = (StepCartesianPoint)ReadTopLevelItem("#1=CARTESIAN_POINT($,(0.0,0.0,0.0));");
61 | Assert.Equal(string.Empty, point.Name);
62 | }
63 |
64 | [Fact]
65 | public void ReadDirectionTest()
66 | {
67 | var direction = (StepDirection)ReadTopLevelItem("#1=DIRECTION('name',(1.0,2.0,3.0));");
68 | Assert.Equal("name", direction.Name);
69 | Assert.Equal(1.0, direction.X);
70 | Assert.Equal(2.0, direction.Y);
71 | Assert.Equal(3.0, direction.Z);
72 | }
73 |
74 | [Fact]
75 | public void ReadSubReferencedItemTest()
76 | {
77 | var vector = (StepVector)ReadTopLevelItem("#1=VECTOR('name',DIRECTION('',(0.0,0.0,1.0)),15.0);");
78 | Assert.Equal(new StepDirection("", 0.0, 0.0, 1.0), vector.Direction);
79 | Assert.Equal(15.0, vector.Length);
80 | }
81 |
82 | [Fact]
83 | public void ReadPreviouslyReferencedItemsTest()
84 | {
85 | var vector = (StepVector)ReadTopLevelItem(@"
86 | #1=DIRECTION('',(0.0,0.0,1.0));
87 | #2=VECTOR('',#1,15.0);
88 | ");
89 | Assert.Equal(new StepDirection("", 0.0, 0.0, 1.0), vector.Direction);
90 | Assert.Equal(15.0, vector.Length);
91 | }
92 |
93 | [Fact]
94 | public void ReadPostReferencedItemTest()
95 | {
96 | var vector = (StepVector)ReadTopLevelItem(@"
97 | #1=VECTOR('',#2,15.0);
98 | #2=DIRECTION('',(0.0,0.0,1.0));
99 | ");
100 | Assert.Equal(new StepDirection("", 0.0, 0.0, 1.0), vector.Direction);
101 | Assert.Equal(15.0, vector.Length);
102 | }
103 |
104 | [Fact]
105 | public void ReadLineTest()
106 | {
107 | var line = (StepLine)ReadTopLevelItem(@"
108 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
109 | #2=DIRECTION('',(0.0,0.0,1.0));
110 | #3=VECTOR('',#2,15.0);
111 | #4=LINE('',#1,#3);
112 | ");
113 | Assert.Equal(new StepCartesianPoint("", 1.0, 2.0, 3.0), line.Point);
114 | Assert.Equal(15.0, line.Vector.Length);
115 | Assert.Equal(new StepDirection("", 0.0, 0.0, 1.0), line.Vector.Direction);
116 | }
117 |
118 | [Fact]
119 | public void WriteLineTest()
120 | {
121 | var file = new StepFile();
122 | file.Items.Add(new StepLine("", new StepCartesianPoint("", 1.0, 2.0, 3.0), new StepVector("", new StepDirection("", 1.0, 0.0, 0.0), 4.0)));
123 | AssertFileContains(file, @"
124 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
125 | #2=DIRECTION('',(1.0,0.0,0.0));
126 | #3=VECTOR('',#2,4.0);
127 | #4=LINE('',#1,#3);
128 | ");
129 | }
130 |
131 | [Fact]
132 | public void WriteLineWithInlineReferencesTest()
133 | {
134 | var file = new StepFile();
135 | file.Items.Add(new StepLine("", new StepCartesianPoint("", 1.0, 2.0, 3.0), new StepVector("", new StepDirection("", 1.0, 0.0, 0.0), 4.0)));
136 | AssertFileContains(file, @"
137 | #1=LINE('',CARTESIAN_POINT('',(1.0,2.0,3.0)),VECTOR('',DIRECTION('',(1.0,0.0,0.0
138 | )),4.0));
139 | ", inlineReferences: true);
140 | }
141 |
142 | [Fact]
143 | public void ReadCircleTest()
144 | {
145 | var circle = (StepCircle)ReadTopLevelItem(@"
146 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
147 | #2=DIRECTION('',(0.0,0.0,1.0));
148 | #3=AXIS2_PLACEMENT_2D('',#1,#2);
149 | #4=CIRCLE('',#3,5.0);
150 | ");
151 | Assert.Equal(new StepCartesianPoint("", 1.0, 2.0, 3.0), ((StepAxis2Placement2D)circle.Position).Location);
152 | Assert.Equal(new StepDirection("", 0.0, 0.0, 1.0), ((StepAxis2Placement2D)circle.Position).RefDirection);
153 | Assert.Equal(5.0, circle.Radius);
154 | }
155 |
156 | [Fact]
157 | public void WriteCircleTest()
158 | {
159 | var circle = new StepCircle("", new StepAxis2Placement2D("", new StepCartesianPoint("", 1.0, 2.0, 3.0), new StepDirection("", 0.0, 0.0, 1.0)), 5.0);
160 | AssertFileContains(circle, @"
161 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
162 | #2=DIRECTION('',(0.0,0.0,1.0));
163 | #3=AXIS2_PLACEMENT_2D('',#1,#2);
164 | #4=CIRCLE('',#3,5.0);
165 | ");
166 | }
167 |
168 | [Fact]
169 | public void ReadEllipseTest()
170 | {
171 | var ellipse = (StepEllipse)ReadTopLevelItem(@"
172 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
173 | #2=DIRECTION('',(0.0,0.0,1.0));
174 | #3=AXIS2_PLACEMENT_2D('',#1,#2);
175 | #4=ELLIPSE('',#3,3.0,4.0);
176 | ");
177 | Assert.Equal(new StepCartesianPoint("", 1.0, 2.0, 3.0), ellipse.Position.Location);
178 | Assert.Equal(new StepDirection("", 0.0, 0.0, 1.0), ellipse.Position.RefDirection);
179 | Assert.Equal(3.0, ellipse.SemiAxis1);
180 | Assert.Equal(4.0, ellipse.SemiAxis2);
181 | }
182 |
183 | [Fact]
184 | public void ReadTopLevelReferencedItemsTest()
185 | {
186 | var file = ReadFile(@"
187 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
188 | #2=DIRECTION('',(0.0,0.0,1.0));
189 | #3=AXIS2_PLACEMENT_2D('',#1,#2);
190 | #4=ELLIPSE('',#3,3.0,4.0);
191 | ");
192 |
193 | Assert.Equal(4, file.Items.Count);
194 |
195 | // only ELLIPSE() isn't referenced by another item
196 | var ellipse = (StepEllipse)file.GetTopLevelItems().Single();
197 | }
198 |
199 | [Fact]
200 | public void ReadTopLevelInlinedItemsTest()
201 | {
202 | var file = ReadFile("#1=ELLIPSE('',AXIS2_PLACEMENT_2D('',CARTESIAN_POINT('',(1.0,2.0,3.0)),DIRECTION('',(0.0,0.0,1.0))),3.0,4.0);");
203 |
204 | Assert.Single(file.Items);
205 |
206 | // only ELLIPSE() isn't referenced by another item
207 | var ellipse = (StepEllipse)file.GetTopLevelItems().Single();
208 | }
209 |
210 | [Fact]
211 | public void ReadBSplineWithKnotsItemsTest()
212 | {
213 | var spline = (StepBSplineCurveWithKnots)ReadTopLevelItem(@"
214 | #1=CARTESIAN_POINT('Ctrl Pts',(-2.09228759117738,32.4775276519752,7.66388871568773));
215 | #2=CARTESIAN_POINT('Ctrl Pts',(-2.09228759389655,30.5382976972817,7.66388872564781));
216 | #3=CARTESIAN_POINT('Ctrl Pts',(-2.09228913953809,28.5997370344523,7.66389438721404));
217 | #4=CARTESIAN_POINT('Ctrl Pts',(-2.09228986816456,26.5173645163537,7.66389705611683));
218 | #5=CARTESIAN_POINT('Ctrl Pts',(-2.09228981902238,26.4462306775892,7.6638968761128));
219 | #6=CARTESIAN_POINT('Ctrl Pts',(-2.0922902432834,25.9015378442672,7.66389843014835));
220 | #7=CARTESIAN_POINT('Ctrl Pts',(-2.11494520023805,24.945781133428,7.74688179710576));
221 | #8=CARTESIAN_POINT('Ctrl Pts',(-2.21905874762543,23.5389919187115,8.1282417231202));
222 | #9=CARTESIAN_POINT('Ctrl Pts',(-2.39215391928761,22.2144888644552,8.76227603964325));
223 | #10=CARTESIAN_POINT('Ctrl Pts',(-2.62666223390231,21.041382550633,9.62126198100665));
224 | #11=CARTESIAN_POINT('Ctrl Pts',(-2.81820100260438,20.3836711077483,10.3228537766386));
225 | #12=CARTESIAN_POINT('Ctrl Pts',(-2.91923318155533,20.0960030522361,10.6929268867829));
226 | #13=B_SPLINE_CURVE_WITH_KNOTS('',3,(#1,#2,#3,#4,#5,#6,#7,#8,#9,#10,#11,#12)
227 | ,.UNSPECIFIED.,.F.,.F.,(4,2,2,1,1,1,1,4),(0.00162506910839039,0.4223270995939,
228 | 0.437186866643407,0.53596295034332,0.634739034043234,0.733515117743147,
229 | 0.832291201443061,0.927367642384199),.UNSPECIFIED.);
230 | ");
231 | Assert.Equal(12, spline.ControlPointsList.Count);
232 | Assert.Equal(8, spline.Knots.Count);
233 | Assert.Equal(8, spline.KnotMultiplicities.Count);
234 | Assert.Equal(3, spline.Degree);
235 | }
236 |
237 | [Fact]
238 | public void WriteEllipseTest()
239 | {
240 | var ellipse = new StepEllipse("", new StepAxis2Placement2D("", new StepCartesianPoint("", 1.0, 2.0, 3.0), new StepDirection("", 0.0, 0.0, 1.0)), 3.0, 4.0);
241 | AssertFileContains(ellipse, @"
242 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
243 | #2=DIRECTION('',(0.0,0.0,1.0));
244 | #3=AXIS2_PLACEMENT_2D('',#1,#2);
245 | #4=ELLIPSE('',#3,3.0,4.0);
246 | ");
247 | }
248 |
249 | [Fact]
250 | public void ReadEdgeCurveTest()
251 | {
252 | var edgeCurve = (StepEdgeCurve)ReadTopLevelItem(@"
253 | #1=CIRCLE('',AXIS2_PLACEMENT_2D('',CARTESIAN_POINT('',(0.0,0.0,0.0)),DIRECTION('',(0.0,0.0,1.0))),5.0);
254 | #2=EDGE_CURVE('',VERTEX_POINT('',CARTESIAN_POINT('',(1.0,2.0,3.0))),VERTEX_POINT('',CARTESIAN_POINT('',(4.0,5.0,6.0))),#1,.T.);
255 | ");
256 | Assert.IsType(edgeCurve.EdgeGeometry);
257 | Assert.True(edgeCurve.IsSameSense);
258 | }
259 |
260 | [Fact]
261 | public void WriteEdgeCurveTest()
262 | {
263 | var edgeCurve = new StepEdgeCurve(
264 | "",
265 | new StepVertexPoint("", new StepCartesianPoint("", 1.0, 2.0, 3.0)),
266 | new StepVertexPoint("", new StepCartesianPoint("", 4.0, 5.0, 6.0)),
267 | new StepCircle("",
268 | new StepAxis2Placement2D("", new StepCartesianPoint("", 7.0, 8.0, 9.0), new StepDirection("", 0.0, 0.0, 1.0)),
269 | 5.0),
270 | true);
271 | AssertFileContains(edgeCurve, @"
272 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
273 | #2=VERTEX_POINT('',#1);
274 | #3=CARTESIAN_POINT('',(4.0,5.0,6.0));
275 | #4=VERTEX_POINT('',#3);
276 | #5=CARTESIAN_POINT('',(7.0,8.0,9.0));
277 | #6=DIRECTION('',(0.0,0.0,1.0));
278 | #7=AXIS2_PLACEMENT_2D('',#5,#6);
279 | #8=CIRCLE('',#7,5.0);
280 | #9=EDGE_CURVE('',#2,#4,#8,.T.);
281 | ");
282 | }
283 |
284 | [Fact]
285 | public void ReadPlaneTest()
286 | {
287 | var plane = (StepPlane)ReadTopLevelItem(@"
288 | #1=CARTESIAN_POINT('',(0.0,0.0,0.0));
289 | #2=DIRECTION('',(0.0,0.0,1.0));
290 | #3=DIRECTION('',(1.0,0.0,0.0));
291 | #4=AXIS2_PLACEMENT_3D('',#1,#2,#3);
292 | #5=PLANE('',#4);
293 | ");
294 | }
295 |
296 | [Fact]
297 | public void WritePlaneTest()
298 | {
299 | var plane = new StepPlane(
300 | "",
301 | new StepAxis2Placement3D("", new StepCartesianPoint("", 1.0, 2.0, 3.0), new StepDirection("", 0.0, 0.0, 1.0), new StepDirection("", 1.0, 0.0, 0.0)));
302 | AssertFileContains(plane, @"
303 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
304 | #2=DIRECTION('',(0.0,0.0,1.0));
305 | #3=DIRECTION('',(1.0,0.0,0.0));
306 | #4=AXIS2_PLACEMENT_3D('',#1,#2,#3);
307 | #5=PLANE('',#4);
308 | ");
309 | }
310 |
311 | [Fact]
312 | public void ReadOrientedEdgeTest()
313 | {
314 | var orientedEdge = (StepOrientedEdge)ReadTopLevelItem(@"
315 | #1=CIRCLE('',AXIS2_PLACEMENT_2D('',CARTESIAN_POINT('',(0.0,0.0,0.0)),DIRECTION('',(0.0,0.0,1.0))),5.0);
316 | #2=EDGE_CURVE('',VERTEX_POINT('',CARTESIAN_POINT('',(1.0,2.0,3.0))),VERTEX_POINT('',CARTESIAN_POINT('',(4.0,5.0,6.0))),#1,.T.);
317 | #3=ORIENTED_EDGE('',*,*,#2,.T.);
318 | ");
319 | Assert.True(orientedEdge.Orientation);
320 | }
321 |
322 | [Fact]
323 | public void WriteOrientedEdgeTest()
324 | {
325 | var orientedEdge = new StepOrientedEdge(
326 | "",
327 | null,
328 | null,
329 | new StepEdgeCurve(
330 | "",
331 | new StepVertexPoint("", new StepCartesianPoint("", 1.0, 2.0, 3.0)),
332 | new StepVertexPoint("", new StepCartesianPoint("", 4.0, 5.0, 6.0)),
333 | new StepCircle("",
334 | new StepAxis2Placement2D("", new StepCartesianPoint("", 7.0, 8.0, 9.0), new StepDirection("", 0.0, 0.0, 1.0)),
335 | 5.0),
336 | true),
337 | true);
338 | AssertFileContains(orientedEdge, @"
339 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
340 | #2=VERTEX_POINT('',#1);
341 | #3=CARTESIAN_POINT('',(4.0,5.0,6.0));
342 | #4=VERTEX_POINT('',#3);
343 | #5=CARTESIAN_POINT('',(7.0,8.0,9.0));
344 | #6=DIRECTION('',(0.0,0.0,1.0));
345 | #7=AXIS2_PLACEMENT_2D('',#5,#6);
346 | #8=CIRCLE('',#7,5.0);
347 | #9=EDGE_CURVE('',#2,#4,#8,.T.);
348 | #10=ORIENTED_EDGE('',*,*,#9,.T.);
349 | ");
350 | }
351 |
352 | [Fact]
353 | public void ReadEdgeLoopTest()
354 | {
355 | var edgeLoop = (StepEdgeLoop)ReadTopLevelItem(@"
356 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
357 | #2=DIRECTION('',(0.58,0.58,0.58));
358 | #3=VECTOR('',#2,5.2);
359 | #4=LINE('',#1,#3);
360 | #5=EDGE_CURVE('',*,*,#4,.T.);
361 | #6=ORIENTED_EDGE('',*,*,#5,.T.);
362 | #7=CARTESIAN_POINT('',(7.0,8.0,9.0));
363 | #8=VECTOR('',#2,5.2);
364 | #9=LINE('',#7,#8);
365 | #10=EDGE_CURVE('',*,*,#9,.F.);
366 | #11=EDGE_LOOP('',(#6,#12));
367 | /* ensure that forward references are resolved when binding */
368 | #12=ORIENTED_EDGE('',*,*,#10,.F.);
369 | ");
370 | Assert.Equal(2, edgeLoop.EdgeList.Count);
371 | Assert.NotNull(edgeLoop.EdgeList[0]);
372 | Assert.NotNull(edgeLoop.EdgeList[1]);
373 | }
374 |
375 | [Fact]
376 | public void ReadAdvancedFaceTest()
377 | {
378 | var file = ReadFile(@"
379 | #1=FACE_OUTER_BOUND('',#2,.T.);
380 | #2=EDGE_LOOP('',(#12,#13,#14,#15));
381 | #3=LINE('',#31,#4);
382 | #4=VECTOR('',#24,2.5);
383 | #5=CIRCLE('',#18,2.5);
384 | #6=CIRCLE('',#19,2.5);
385 | #7=VERTEX_POINT('',#28);
386 | #8=VERTEX_POINT('',#30);
387 | #9=EDGE_CURVE('',#7,#7,#5,.T.);
388 | #10=EDGE_CURVE('',#7,#8,#3,.T.);
389 | #11=EDGE_CURVE('',#8,#8,#6,.T.);
390 | #12=ORIENTED_EDGE('',*,*,#9,.F.);
391 | #13=ORIENTED_EDGE('',*,*,#10,.T.);
392 | #14=ORIENTED_EDGE('',*,*,#11,.F.);
393 | #15=ORIENTED_EDGE('',*,*,#10,.F.);
394 | #16=CYLINDRICAL_SURFACE('',#17,2.5);
395 | #17=AXIS2_PLACEMENT_3D('',#27,#20,#21);
396 | #18=AXIS2_PLACEMENT_3D('',#29,#22,#23);
397 | #19=AXIS2_PLACEMENT_3D('',#32,#25,#26);
398 | #20=DIRECTION('center_axis',(0.,0.,-1.));
399 | #21=DIRECTION('ref_axis',(-1.,0.,0.));
400 | #22=DIRECTION('center_axis',(0.,0.,-1.));
401 | #23=DIRECTION('ref_axis',(-1.,0.,0.));
402 | #24=DIRECTION('',(0.,0.,-1.));
403 | #25=DIRECTION('center_axis',(0.,0.,1.));
404 | #26=DIRECTION('ref_axis',(-1.,0.,0.));
405 | #27=CARTESIAN_POINT('Origin',(0.,0.,5.));
406 | #28=CARTESIAN_POINT('',(2.5,3.06161699786838E-16,5.));
407 | #29=CARTESIAN_POINT('Origin',(0.,0.,5.));
408 | #30=CARTESIAN_POINT('',(2.5,3.06161699786838E-16,0.));
409 | #31=CARTESIAN_POINT('',(2.5,-3.06161699786838E-16,5.));
410 | #32=CARTESIAN_POINT('Origin',(0.,0.,0.));
411 | #33=ADVANCED_FACE('',(#1),#16,.F.);
412 | ");
413 | var face = file.GetTopLevelItems().OfType().FirstOrDefault();
414 | Assert.NotNull(face);
415 | Assert.NotNull(face.FaceGeometry);
416 | Assert.Single(face.Bounds);
417 | }
418 |
419 | [Fact]
420 | public void WriteEdgeLoopTest()
421 | {
422 | var edgeLoop = new StepEdgeLoop(
423 | "",
424 | new StepOrientedEdge("", null, null, new StepEdgeCurve("", null, null, StepLine.FromPoints(1.0, 2.0, 3.0, 4.0, 5.0, 6.0), true), true),
425 | new StepOrientedEdge("", null, null, new StepEdgeCurve("", null, null, StepLine.FromPoints(7.0, 8.0, 9.0, 10.0, 11.0, 12.0), false), false));
426 | AssertFileContains(edgeLoop, @"
427 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
428 | #2=DIRECTION('',(0.58,0.58,0.58));
429 | #3=VECTOR('',#2,5.2);
430 | #4=LINE('',#1,#3);
431 | #5=EDGE_CURVE('',*,*,#4,.T.);
432 | #6=ORIENTED_EDGE('',*,*,#5,.T.);
433 | #7=CARTESIAN_POINT('',(7.0,8.0,9.0));
434 | #8=VECTOR('',#2,5.2);
435 | #9=LINE('',#7,#8);
436 | #10=EDGE_CURVE('',*,*,#9,.F.);
437 | #11=ORIENTED_EDGE('',*,*,#10,.F.);
438 | #12=EDGE_LOOP('',(#6,#11));
439 | ");
440 | }
441 |
442 | [Fact]
443 | public void ReadFaceBoundTest()
444 | {
445 | var faceBound = (StepFaceBound)ReadTopLevelItem(@"
446 | #1=CARTESIAN_POINT('',(0.0,0.0,0.0));
447 | #2=DIRECTION('',(1.0,0.0,0.0));
448 | #3=VECTOR('',#2,1.0);
449 | #4=LINE('',#1,#3);
450 | #5=EDGE_CURVE('',*,*,#4,.T.);
451 | #6=ORIENTED_EDGE('',*,*,#5,.T.);
452 | #7=EDGE_LOOP('',(#6));
453 | #8=FACE_BOUND('',#7,.T.);
454 | ");
455 | Assert.True(faceBound.Orientation);
456 | }
457 |
458 | [Fact]
459 | public void WriteFaceBoundTest()
460 | {
461 | var faceBound = new StepFaceBound(
462 | "",
463 | new StepEdgeLoop(
464 | "",
465 | new StepOrientedEdge(
466 | "",
467 | null,
468 | null,
469 | new StepEdgeCurve(
470 | "",
471 | null,
472 | null,
473 | StepLine.FromPoints(0.0, 0.0, 0.0, 1.0, 0.0, 0.0),
474 | true),
475 | true)),
476 | true);
477 | AssertFileContains(faceBound, @"
478 | #1=CARTESIAN_POINT('',(0.0,0.0,0.0));
479 | #2=DIRECTION('',(1.0,0.0,0.0));
480 | #3=VECTOR('',#2,1.0);
481 | #4=LINE('',#1,#3);
482 | #5=EDGE_CURVE('',*,*,#4,.T.);
483 | #6=ORIENTED_EDGE('',*,*,#5,.T.);
484 | #7=EDGE_LOOP('',(#6));
485 | #8=FACE_BOUND('',#7,.T.);
486 | ");
487 | }
488 |
489 | [Fact]
490 | public void ReadFaceOuterBoundTest()
491 | {
492 | var faceOuterBound = (StepFaceOuterBound)ReadTopLevelItem(@"
493 | #1=CARTESIAN_POINT('',(0.0,0.0,0.0));
494 | #2=DIRECTION('',(1.0,0.0,0.0));
495 | #3=VECTOR('',#2,1.0);
496 | #4=LINE('',#1,#3);
497 | #5=EDGE_CURVE('',*,*,#4,.T.);
498 | #6=ORIENTED_EDGE('',*,*,#5,.T.);
499 | #7=EDGE_LOOP('',(#6));
500 | #8=FACE_OUTER_BOUND('',#7,.T.);
501 | ");
502 | Assert.True(faceOuterBound.Orientation);
503 | }
504 |
505 | [Fact]
506 | public void WriteFaceOuterBoundTest()
507 | {
508 | var faceOuterBound = new StepFaceOuterBound(
509 | "",
510 | new StepEdgeLoop(
511 | "",
512 | new StepOrientedEdge(
513 | "",
514 | null,
515 | null,
516 | new StepEdgeCurve(
517 | "",
518 | null,
519 | null,
520 | StepLine.FromPoints(0.0, 0.0, 0.0, 1.0, 0.0, 0.0),
521 | true),
522 | true)),
523 | true);
524 | AssertFileContains(faceOuterBound, @"
525 | #1=CARTESIAN_POINT('',(0.0,0.0,0.0));
526 | #2=DIRECTION('',(1.0,0.0,0.0));
527 | #3=VECTOR('',#2,1.0);
528 | #4=LINE('',#1,#3);
529 | #5=EDGE_CURVE('',*,*,#4,.T.);
530 | #6=ORIENTED_EDGE('',*,*,#5,.T.);
531 | #7=EDGE_LOOP('',(#6));
532 | #8=FACE_OUTER_BOUND('',#7,.T.);
533 | ");
534 | }
535 |
536 | [Fact]
537 | public void ReadCylindricalSurfaceTest()
538 | {
539 | var surface = (StepCylindricalSurface)ReadTopLevelItem(@"
540 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
541 | #2=DIRECTION('',(0.0,0.0,1.0));
542 | #3=DIRECTION('',(1.0,0.0,0.0));
543 | #4=AXIS2_PLACEMENT_3D('',#1,#2,#3);
544 | #5=CYLINDRICAL_SURFACE('',#4,12.0);
545 | ");
546 | Assert.Equal(12.0, surface.Radius);
547 | }
548 |
549 | [Fact]
550 | public void WriteCylindricalSurfaceTest()
551 | {
552 | var surface = new StepCylindricalSurface(
553 | "",
554 | new StepAxis2Placement3D(
555 | "",
556 | new StepCartesianPoint("", 1.0, 2.0, 3.0),
557 | new StepDirection("", 0.0, 0.0, 1.0),
558 | new StepDirection("", 1.0, 0.0, 0.0)),
559 | 12.0);
560 | AssertFileContains(surface, @"
561 | #1=CARTESIAN_POINT('',(1.0,2.0,3.0));
562 | #2=DIRECTION('',(0.0,0.0,1.0));
563 | #3=DIRECTION('',(1.0,0.0,0.0));
564 | #4=AXIS2_PLACEMENT_3D('',#1,#2,#3);
565 | #5=CYLINDRICAL_SURFACE('',#4,12.0);
566 | ");
567 | }
568 |
569 | [Fact]
570 | public void WriteBSplineWithKnotsTest()
571 | {
572 | var spline = new StepBSplineCurveWithKnots(
573 | "",
574 | new StepCartesianPoint("", 0.0, 0.0, 0.0),
575 | new StepCartesianPoint("", 1.0, 0.0, 0.0),
576 | new StepCartesianPoint("", 1.0, 2.0, 0.0));
577 | spline.KnotMultiplicities.Add(1);
578 | spline.Knots.Add(2.0);
579 |
580 | AssertFileContains(spline, @"
581 | #1=CARTESIAN_POINT('',(0.0,0.0,0.0));
582 | #2=CARTESIAN_POINT('',(1.0,0.0,0.0));
583 | #3=CARTESIAN_POINT('',(1.0,2.0,0.0));
584 | #4=B_SPLINE_CURVE_WITH_KNOTS('',0,(#1,#2,#3),.UNSPECIFIED.,.F.,.F.,(1),(2.0),
585 | .UNSPECIFIED.);
586 | ");
587 | }
588 | }
589 | }
590 |
--------------------------------------------------------------------------------
/src/IxMilia.Step.Test/StepTestBase.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Xunit;
3 |
4 | namespace IxMilia.Step.Test
5 | {
6 | public abstract class StepTestBase
7 | {
8 | protected static string NormalizeLineEndings(string str)
9 | {
10 | var lines = str.Split('\n').Select(l => l.TrimEnd('\r'));
11 | return string.Join("\r\n", lines);
12 | }
13 |
14 | protected void AssertFileIs(StepFile file, string expected, bool inlineReferences = false)
15 | {
16 | var actual = file.GetContentsAsString(inlineReferences);
17 | var expectedNormalizedLines = NormalizeLineEndings(expected);
18 | Assert.Equal(expectedNormalizedLines, actual);
19 | }
20 |
21 | protected void AssertFileContains(StepFile file, string expected, bool inlineReferences = false)
22 | {
23 | var actual = file.GetContentsAsString(inlineReferences);
24 | var expectedNormalizedLines = NormalizeLineEndings(expected);
25 | Assert.Contains(expectedNormalizedLines, actual);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/IxMilia.Step.Test/StepTokenTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using IxMilia.Step.Tokens;
8 | using Xunit;
9 |
10 | namespace IxMilia.Step.Test
11 | {
12 | public class StepTokenTests : StepTestBase
13 | {
14 | private StepToken[] GetTokens(string text)
15 | {
16 | using (var stream = new MemoryStream())
17 | using (var writer = new StreamWriter(stream))
18 | {
19 | writer.Write(text);
20 | writer.Flush();
21 | stream.Seek(0, SeekOrigin.Begin);
22 | var tokenizer = new StepTokenizer(stream);
23 | return tokenizer.GetTokens().ToArray();
24 | }
25 | }
26 |
27 | delegate bool TokenVerifier(StepToken token);
28 |
29 | private TokenVerifier WithKind(StepTokenKind kind)
30 | {
31 | return token => token.Kind == kind;
32 | }
33 |
34 | private TokenVerifier Semicolon()
35 | {
36 | return WithKind(StepTokenKind.Semicolon);
37 | }
38 |
39 | private TokenVerifier Keyword(string keyword)
40 | {
41 | return token => WithKind(StepTokenKind.Keyword)(token) && ((StepKeywordToken)token).Value == keyword;
42 | }
43 |
44 | private TokenVerifier Enumeration(string enumName)
45 | {
46 | return token => WithKind(StepTokenKind.Enumeration)(token) && ((StepEnumerationToken)token).Value == enumName;
47 | }
48 |
49 | private TokenVerifier Real(double value)
50 | {
51 | return token => WithKind(StepTokenKind.Real)(token) && ((StepRealToken)token).Value == value;
52 | }
53 |
54 | private TokenVerifier Integer(int value)
55 | {
56 | return token => WithKind(StepTokenKind.Integer)(token) && ((StepIntegerToken)token).Value == value;
57 | }
58 |
59 | private void VerifyTokens(string text, params TokenVerifier[] expected)
60 | {
61 | var actual = GetTokens(text);
62 | var upper = Math.Min(actual.Length, expected.Length);
63 | for (int i = 0; i < upper; i++)
64 | {
65 | Assert.True(expected[i](actual[i]));
66 | }
67 | }
68 |
69 | [Fact]
70 | public void SpecialTokenTest()
71 | {
72 | VerifyTokens("ISO-10303-21;",
73 | Keyword("ISO-10303-21"), Semicolon());
74 | }
75 |
76 | [Fact]
77 | public void EmptyFileTest()
78 | {
79 | VerifyTokens(@"
80 | ISO-10303-21;
81 | HEADER;
82 | ENDSEC;
83 | DATA;
84 | ENDSEC;
85 | END-ISO-10303-21;",
86 | Keyword("ISO-10303-21"), Semicolon(),
87 | Keyword("HEADER"), Semicolon(),
88 | Keyword("ENDSEC"), Semicolon(),
89 | Keyword("DATA"), Semicolon(),
90 | Keyword("ENDSEC"), Semicolon(),
91 | Keyword("END-ISO-10303-21"), Semicolon());
92 | }
93 |
94 | [Fact]
95 | public void TokensWithCommentsTest1()
96 | {
97 | VerifyTokens(@"
98 | HEADER;
99 | /* comment DATA; (comment's end is on the same line) */
100 | ENDSEC;",
101 | Keyword("HEADER"), Semicolon(),
102 | Keyword("ENDSEC"), Semicolon());
103 | }
104 |
105 | [Fact]
106 | public void TokensWithCommentsTest2()
107 | {
108 | VerifyTokens(@"
109 | HEADER;
110 | /* comment (comment's end is on another line)
111 | DATA; */
112 | ENDSEC;",
113 | Keyword("HEADER"), Semicolon(),
114 | Keyword("ENDSEC"), Semicolon());
115 | }
116 |
117 | [Fact]
118 | public void TokensWithCommentsTest3()
119 | {
120 | VerifyTokens(@"
121 | HEADER;
122 | /* comment
123 | (comment's end is on another line and farther back)
124 | DATA; */
125 | ENDSEC;",
126 | Keyword("HEADER"), Semicolon(),
127 | Keyword("ENDSEC"), Semicolon());
128 | }
129 |
130 | [Fact]
131 | public void TokensWithEmptylines()
132 | {
133 | VerifyTokens(@"
134 |
135 | HEADER;
136 |
137 | ENDSEC;
138 |
139 | ",
140 | Keyword("HEADER"), Semicolon(),
141 | Keyword("ENDSEC"), Semicolon());
142 | }
143 |
144 | [Fact]
145 | public void ParseEnumTokensTest()
146 | {
147 | VerifyTokens(".SOME_ENUM_VALUE.", Enumeration("SOME_ENUM_VALUE"));
148 | }
149 |
150 | [Fact]
151 | public void ParseInvarianCultureTest()
152 | {
153 | var existingCulture = CultureInfo.CurrentCulture;
154 | try
155 | {
156 | CultureInfo.CurrentCulture = new CultureInfo("de-DE");
157 | VerifyTokens("1.8", Real(1.8));
158 | VerifyTokens("54", Integer(54));
159 | }
160 | finally
161 | {
162 | CultureInfo.CurrentCulture = existingCulture;
163 | }
164 | }
165 |
166 | [Fact]
167 | public void WriteTokensPastLineLengthTest()
168 | {
169 | var tokens = new List();
170 | var maxItems = 22;
171 | for (int i = 0; i < maxItems; i++)
172 | {
173 | tokens.Add(new StepRealToken(0.0, -1, -1));
174 | if (i < maxItems - 1)
175 | {
176 | tokens.Add(StepCommaToken.Instance);
177 | }
178 | }
179 |
180 | // should wrap at 80 characters
181 | var writer = new StepWriter(null, false);
182 | var sb = new StringBuilder();
183 | writer.WriteTokens(tokens, sb);
184 | var expected = NormalizeLineEndings(@"
185 | 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,
186 | 0.0,0.0
187 | ".Trim());
188 | Assert.Equal(expected, sb.ToString());
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepAdvancedFace.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public class StepAdvancedFace : StepFaceSurface
7 | {
8 | public StepAdvancedFace(string name)
9 | : base(name)
10 | {
11 | }
12 |
13 | private StepAdvancedFace()
14 | : base(string.Empty)
15 | {
16 | }
17 |
18 | public override StepItemType ItemType => StepItemType.AdvancedFace;
19 |
20 | internal static StepAdvancedFace CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
21 | {
22 | var face = new StepAdvancedFace();
23 | syntaxList.AssertListCount(4);
24 | face.Name = syntaxList.Values[0].GetStringValue();
25 |
26 | var boundsList = syntaxList.Values[1].GetValueList();
27 | face.Bounds.Clear();
28 | face.Bounds.AddRange(Enumerable.Range(0, boundsList.Values.Count).Select(_ => (StepFaceBound)null));
29 | for (int i = 0; i < boundsList.Values.Count; i++)
30 | {
31 | var j = i; // capture to avoid rebinding
32 | binder.BindValue(boundsList.Values[j], v => face.Bounds[j] = v.AsType());
33 | }
34 | binder.BindValue(syntaxList.Values[2], v => face.FaceGeometry = v.AsType());
35 | face.SameSense = syntaxList.Values[3].GetBooleanValue();
36 |
37 | return face;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepAxis2Placement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IxMilia.Step.Items
4 | {
5 | public abstract class StepAxis2Placement : StepPlacement
6 | {
7 | private StepCartesianPoint _location;
8 | private StepDirection _refDirection;
9 |
10 | public StepCartesianPoint Location
11 | {
12 | get { return _location; }
13 | set
14 | {
15 | if (value == null)
16 | {
17 | throw new ArgumentNullException();
18 | }
19 |
20 | _location = value;
21 | }
22 | }
23 |
24 | public StepDirection RefDirection
25 | {
26 | get { return _refDirection; }
27 | set
28 | {
29 | if (value == null)
30 | {
31 | throw new ArgumentNullException();
32 | }
33 |
34 | _refDirection = value;
35 | }
36 | }
37 |
38 | protected StepAxis2Placement(string name)
39 | : base(name)
40 | {
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepAxis2Placement2D.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public class StepAxis2Placement2D : StepAxis2Placement
7 | {
8 | public override StepItemType ItemType => StepItemType.AxisPlacement2D;
9 |
10 | private StepAxis2Placement2D()
11 | : base(string.Empty)
12 | {
13 | }
14 |
15 | public StepAxis2Placement2D(string label, StepCartesianPoint location, StepDirection direction)
16 | : base(label)
17 | {
18 | Location = location;
19 | RefDirection = direction;
20 | }
21 |
22 | internal override IEnumerable GetReferencedItems()
23 | {
24 | yield return Location;
25 | yield return RefDirection;
26 | }
27 |
28 | internal override IEnumerable GetParameters(StepWriter writer)
29 | {
30 | foreach (var parameter in base.GetParameters(writer))
31 | {
32 | yield return parameter;
33 | }
34 |
35 | yield return writer.GetItemSyntax(Location);
36 | yield return writer.GetItemSyntax(RefDirection);
37 | }
38 |
39 | internal static StepAxis2Placement2D CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
40 | {
41 | var axis = new StepAxis2Placement2D();
42 | syntaxList.AssertListCount(3);
43 | axis.Name = syntaxList.Values[0].GetStringValue();
44 | binder.BindValue(syntaxList.Values[1], v => axis.Location = v.AsType());
45 | binder.BindValue(syntaxList.Values[2], v => axis.RefDirection = v.AsType());
46 | return axis;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepAxis2Placement3D.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepAxis2Placement3D : StepAxis2Placement
8 | {
9 | public override StepItemType ItemType => StepItemType.AxisPlacement3D;
10 |
11 | private StepDirection _axis;
12 |
13 | public StepDirection Axis
14 | {
15 | get { return _axis; }
16 | set
17 | {
18 | if (value == null)
19 | {
20 | throw new ArgumentNullException();
21 | }
22 |
23 | _axis = value;
24 | }
25 | }
26 |
27 | private StepAxis2Placement3D()
28 | : base(string.Empty)
29 | {
30 | }
31 |
32 | public StepAxis2Placement3D(string name, StepCartesianPoint location, StepDirection axis, StepDirection refDirection)
33 | : base(name)
34 | {
35 | Location = location;
36 | Axis = axis;
37 | RefDirection = refDirection;
38 | }
39 |
40 | internal override IEnumerable GetReferencedItems()
41 | {
42 | yield return Location;
43 | yield return Axis;
44 | yield return RefDirection;
45 | }
46 |
47 | internal override IEnumerable GetParameters(StepWriter writer)
48 | {
49 | foreach (var parameter in base.GetParameters(writer))
50 | {
51 | yield return parameter;
52 | }
53 |
54 | yield return writer.GetItemSyntax(Location);
55 | yield return writer.GetItemSyntax(Axis);
56 | yield return writer.GetItemSyntax(RefDirection);
57 | }
58 |
59 | internal static StepAxis2Placement3D CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
60 | {
61 | var axis = new StepAxis2Placement3D();
62 | syntaxList.AssertListCount(4);
63 | axis.Name = syntaxList.Values[0].GetStringValue();
64 | binder.BindValue(syntaxList.Values[1], v => axis.Location = v.AsType());
65 | binder.BindValue(syntaxList.Values[2], v => axis.Axis = v.AsType());
66 | binder.BindValue(syntaxList.Values[3], v => axis.RefDirection = v.AsType());
67 | return axis;
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepBSplineCurve.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using IxMilia.Step.Syntax;
5 |
6 | namespace IxMilia.Step.Items
7 | {
8 | public enum StepBSplineCurveForm
9 | {
10 | Polyline,
11 | CircularArc,
12 | EllipticalArc,
13 | ParabolicArc,
14 | HyperbolicArc,
15 | Unspecified
16 | };
17 |
18 | public abstract class StepBSplineCurve : StepBoundedCurve
19 | {
20 | public int Degree { get; set; }
21 |
22 | public List ControlPointsList { get; } = new List();
23 |
24 | public StepBSplineCurveForm CurveForm { get; set; } = StepBSplineCurveForm.Unspecified;
25 |
26 | public bool ClosedCurve { get; set; }
27 |
28 | public bool SelfIntersect { get; set; }
29 |
30 | public StepBSplineCurve(string name, IEnumerable controlPoints) : base(name)
31 | {
32 | ControlPointsList.AddRange(controlPoints);
33 | }
34 |
35 | public StepBSplineCurve(string name, params StepCartesianPoint[] controlPoints)
36 | : this(name, (IEnumerable)controlPoints)
37 | {
38 | }
39 |
40 | internal override IEnumerable GetReferencedItems()
41 | {
42 | return ControlPointsList;
43 | }
44 |
45 | internal override IEnumerable GetParameters(StepWriter writer)
46 | {
47 | foreach (var parameter in base.GetParameters(writer))
48 | {
49 | yield return parameter;
50 | }
51 |
52 | yield return new StepIntegerSyntax(Degree);
53 | yield return new StepSyntaxList(ControlPointsList.Select(c => writer.GetItemSyntax(c)));
54 | yield return new StepEnumerationValueSyntax(GetCurveFormString(CurveForm));
55 | yield return StepWriter.GetBooleanSyntax(ClosedCurve);
56 | yield return StepWriter.GetBooleanSyntax(SelfIntersect);
57 | }
58 |
59 | private const string POLYLINE_FORM = "POLYLINE_FORM";
60 | private const string CIRCULAR_ARC = "CIRCULAR_ARC";
61 | private const string ELLIPTIC_ARC = "ELLIPTIC_ARC";
62 | private const string PARABOLIC_ARC = "PARABOLIC_ARC";
63 | private const string HYPERBOLIC_ARC = "HYPERBOLIC_ARC";
64 | private const string UNSPECIFIED = "UNSPECIFIED";
65 |
66 | protected static StepBSplineCurveForm ParseCurveForm(string enumerationValue)
67 | {
68 | switch (enumerationValue.ToUpperInvariant())
69 | {
70 | case POLYLINE_FORM:
71 | return StepBSplineCurveForm.Polyline;
72 | case CIRCULAR_ARC:
73 | return StepBSplineCurveForm.CircularArc;
74 | case ELLIPTIC_ARC:
75 | return StepBSplineCurveForm.EllipticalArc;
76 | case PARABOLIC_ARC:
77 | return StepBSplineCurveForm.ParabolicArc;
78 | case HYPERBOLIC_ARC:
79 | return StepBSplineCurveForm.HyperbolicArc;
80 | default:
81 | return StepBSplineCurveForm.Unspecified;
82 | }
83 | }
84 |
85 | protected static string GetCurveFormString(StepBSplineCurveForm form)
86 | {
87 | switch (form)
88 | {
89 | case StepBSplineCurveForm.Polyline:
90 | return POLYLINE_FORM;
91 | case StepBSplineCurveForm.CircularArc:
92 | return CIRCULAR_ARC;
93 | case StepBSplineCurveForm.EllipticalArc:
94 | return ELLIPTIC_ARC;
95 | case StepBSplineCurveForm.ParabolicArc:
96 | return PARABOLIC_ARC;
97 | case StepBSplineCurveForm.HyperbolicArc:
98 | return HYPERBOLIC_ARC;
99 | case StepBSplineCurveForm.Unspecified:
100 | return UNSPECIFIED;
101 | }
102 |
103 | throw new NotImplementedException();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepBSplineCurveWithKnots.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using IxMilia.Step.Syntax;
5 |
6 | namespace IxMilia.Step.Items
7 | {
8 | public enum StepKnotType
9 | {
10 | UniformKnots,
11 | QuasiUniformKnots,
12 | PiecewiseBezierKnots,
13 | Unspecified
14 | };
15 |
16 | public class StepBSplineCurveWithKnots : StepBSplineCurve
17 | {
18 | public List KnotMultiplicities { get; } = new List();
19 |
20 | public List Knots { get; } = new List();
21 |
22 | public StepKnotType KnotSpec { get; set; } = StepKnotType.Unspecified;
23 |
24 | public StepBSplineCurveWithKnots(string name, IEnumerable controlPoints)
25 | : base(name, controlPoints)
26 | {
27 | }
28 |
29 | public StepBSplineCurveWithKnots(string name, params StepCartesianPoint[] controlPoints)
30 | : base(name, controlPoints)
31 | {
32 | }
33 |
34 | public override StepItemType ItemType => StepItemType.BSplineCurveWithKnots;
35 |
36 | private const string UNIFORM_KNOTS = "UNIFORM_KNOTS";
37 | private const string QUASI_UNIFORM_KNOTS = "QUASI_UNIFORM_KNOTS";
38 | private const string PIECEWISE_BEZIER_KNOTS = "PIECEWISE_BEZIER_KNOTS";
39 | private const string UNSPECIFIED = "UNSPECIFIED";
40 |
41 | private static StepKnotType ParseKnotSpec(string enumerationValue)
42 | {
43 | switch (enumerationValue.ToUpperInvariant())
44 | {
45 | case UNIFORM_KNOTS:
46 | return StepKnotType.UniformKnots;
47 | case QUASI_UNIFORM_KNOTS:
48 | return StepKnotType.QuasiUniformKnots;
49 | case PIECEWISE_BEZIER_KNOTS:
50 | return StepKnotType.PiecewiseBezierKnots;
51 | default:
52 | return StepKnotType.Unspecified;
53 | }
54 | }
55 |
56 | private static string GetKnotSpec(StepKnotType spec)
57 | {
58 | switch (spec)
59 | {
60 | case StepKnotType.UniformKnots:
61 | return UNIFORM_KNOTS;
62 | case StepKnotType.QuasiUniformKnots:
63 | return QUASI_UNIFORM_KNOTS;
64 | case StepKnotType.PiecewiseBezierKnots:
65 | return PIECEWISE_BEZIER_KNOTS;
66 | case StepKnotType.Unspecified:
67 | return UNSPECIFIED;
68 | }
69 |
70 | throw new NotImplementedException();
71 | }
72 |
73 | internal override IEnumerable GetParameters(StepWriter writer)
74 | {
75 | foreach (var parameter in base.GetParameters(writer))
76 | {
77 | yield return parameter;
78 | }
79 |
80 | yield return new StepSyntaxList(KnotMultiplicities.Select(m => new StepIntegerSyntax(m)));
81 | yield return new StepSyntaxList(Knots.Select(k => new StepRealSyntax(k)));
82 | yield return new StepEnumerationValueSyntax(GetKnotSpec(KnotSpec));
83 | }
84 |
85 | internal static StepBSplineCurveWithKnots CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
86 | {
87 | syntaxList.AssertListCount(9);
88 | var controlPointsList = syntaxList.Values[2].GetValueList();
89 |
90 | var spline = new StepBSplineCurveWithKnots(string.Empty, new StepCartesianPoint[controlPointsList.Values.Count]);
91 | spline.Name = syntaxList.Values[0].GetStringValue();
92 | spline.Degree = syntaxList.Values[1].GetIntegerValue();
93 |
94 | for (int i = 0; i < controlPointsList.Values.Count; i++)
95 | {
96 | var j = i; // capture to avoid rebinding
97 | binder.BindValue(controlPointsList.Values[j], v => spline.ControlPointsList[j] = v.AsType());
98 | }
99 |
100 | spline.CurveForm = ParseCurveForm(syntaxList.Values[3].GetEnumerationValue());
101 | spline.ClosedCurve = syntaxList.Values[4].GetBooleanValue();
102 | spline.SelfIntersect = syntaxList.Values[5].GetBooleanValue();
103 |
104 | var knotMultiplicitiesList = syntaxList.Values[6].GetValueList();
105 | spline.KnotMultiplicities.Clear();
106 | for (int i = 0; i < knotMultiplicitiesList.Values.Count; i++)
107 | {
108 | spline.KnotMultiplicities.Add(knotMultiplicitiesList.Values[i].GetIntegerValue());
109 | }
110 |
111 | var knotslist = syntaxList.Values[7].GetValueList();
112 | spline.Knots.Clear();
113 | for (int i = 0; i < knotslist.Values.Count; i++)
114 | {
115 | spline.Knots.Add(knotslist.Values[i].GetRealVavlue());
116 | }
117 |
118 | spline.KnotSpec = ParseKnotSpec(syntaxList.Values[8].GetEnumerationValue());
119 |
120 | return spline;
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepBoundedCurve.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepBoundedCurve : StepCurve
4 | {
5 | protected StepBoundedCurve(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepCartesianPoint.cs:
--------------------------------------------------------------------------------
1 | using IxMilia.Step.Syntax;
2 |
3 | namespace IxMilia.Step.Items
4 | {
5 | public class StepCartesianPoint : StepTriple
6 | {
7 | public override StepItemType ItemType => StepItemType.CartesianPoint;
8 | protected override int MinimumValueCount => 1;
9 |
10 | private StepCartesianPoint()
11 | {
12 | }
13 |
14 | public StepCartesianPoint(string label, double x, double y, double z)
15 | : base(label, x, y, z)
16 | {
17 | }
18 |
19 | internal static StepCartesianPoint CreateFromSyntaxList(StepSyntaxList syntaxList)
20 | {
21 | return (StepCartesianPoint)AssignTo(new StepCartesianPoint(), syntaxList);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepCircle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepCircle : StepConic
8 | {
9 | public override StepItemType ItemType => StepItemType.Circle;
10 |
11 | private StepAxis2Placement _position;
12 |
13 | public StepAxis2Placement Position
14 | {
15 | get { return _position; }
16 | set
17 | {
18 | if (value == null)
19 | {
20 | throw new ArgumentNullException();
21 | }
22 |
23 | _position = value;
24 | }
25 | }
26 |
27 | public double Radius { get; set; }
28 |
29 | private StepCircle()
30 | : base(string.Empty)
31 | {
32 | }
33 |
34 | public StepCircle(string label, StepAxis2Placement position, double radius)
35 | : base(label)
36 | {
37 | Position = position;
38 | Radius = radius;
39 | }
40 |
41 | internal override IEnumerable GetReferencedItems()
42 | {
43 | yield return Position;
44 | }
45 |
46 | internal override IEnumerable GetParameters(StepWriter writer)
47 | {
48 | foreach (var parameter in base.GetParameters(writer))
49 | {
50 | yield return parameter;
51 | }
52 |
53 | yield return writer.GetItemSyntax(Position);
54 | yield return new StepRealSyntax(Radius);
55 | }
56 |
57 | internal static StepCircle CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
58 | {
59 | var circle = new StepCircle();
60 | syntaxList.AssertListCount(3);
61 | circle.Name = syntaxList.Values[0].GetStringValue();
62 | binder.BindValue(syntaxList.Values[1], v => circle.Position = v.AsType());
63 | circle.Radius = syntaxList.Values[2].GetRealVavlue();
64 | return circle;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepConic.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepConic : StepCurve
4 | {
5 | protected StepConic(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepCurve.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepCurve : StepGeometricRepresentationItem
4 | {
5 | protected StepCurve(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepCylindricalSurface.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public class StepCylindricalSurface : StepElementarySurface
7 | {
8 | public override StepItemType ItemType => StepItemType.CylindricalSurface;
9 |
10 | public double Radius { get; set; }
11 |
12 | private StepCylindricalSurface()
13 | : base()
14 | {
15 | }
16 |
17 | public StepCylindricalSurface(string name, StepAxis2Placement3D position, double radius)
18 | : base(name, position)
19 | {
20 | Radius = radius;
21 | }
22 |
23 | internal override IEnumerable GetParameters(StepWriter writer)
24 | {
25 | foreach (var parameter in base.GetParameters(writer))
26 | {
27 | yield return parameter;
28 | }
29 |
30 | yield return new StepRealSyntax(Radius);
31 | }
32 |
33 | internal static StepRepresentationItem CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
34 | {
35 | syntaxList.AssertListCount(3);
36 | var surface = new StepCylindricalSurface();
37 | surface.Name = syntaxList.Values[0].GetStringValue();
38 | binder.BindValue(syntaxList.Values[1], v => surface.Position = v.AsType());
39 | surface.Radius = syntaxList.Values[2].GetRealVavlue();
40 | return surface;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepDirection.cs:
--------------------------------------------------------------------------------
1 | using IxMilia.Step.Syntax;
2 |
3 | namespace IxMilia.Step.Items
4 | {
5 | public class StepDirection : StepTriple
6 | {
7 | public override StepItemType ItemType => StepItemType.Direction;
8 | protected override int MinimumValueCount => 2;
9 |
10 | private StepDirection()
11 | {
12 | }
13 |
14 | public StepDirection(string name, double x, double y, double z)
15 | : base(name, x, y, z)
16 | {
17 | }
18 |
19 | internal static StepDirection CreateFromSyntaxList(StepSyntaxList syntaxList)
20 | {
21 | return (StepDirection)AssignTo(new StepDirection(), syntaxList);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepEdge.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public abstract class StepEdge : StepTopologicalRepresentationItem
7 | {
8 | public StepVertex EdgeStart { get; set; }
9 | public StepVertex EdgeEnd { get; set; }
10 |
11 | protected StepEdge()
12 | : base(string.Empty)
13 | {
14 | }
15 |
16 | protected StepEdge(string name, StepVertex edgeStart, StepVertex edgeEnd)
17 | : base(name)
18 | {
19 | EdgeStart = edgeStart;
20 | EdgeEnd = edgeEnd;
21 | }
22 |
23 | internal override IEnumerable GetReferencedItems()
24 | {
25 | if (EdgeStart != null)
26 | {
27 | yield return EdgeStart;
28 | }
29 |
30 | if (EdgeEnd != null)
31 | {
32 | yield return EdgeEnd;
33 | }
34 | }
35 |
36 | internal override IEnumerable GetParameters(StepWriter writer)
37 | {
38 | foreach (var parameter in base.GetParameters(writer))
39 | {
40 | yield return parameter;
41 | }
42 |
43 | yield return writer.GetItemSyntaxOrAuto(EdgeStart);
44 | yield return writer.GetItemSyntaxOrAuto(EdgeEnd);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepEdgeCurve.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepEdgeCurve : StepEdge
8 | {
9 | public override StepItemType ItemType => StepItemType.EdgeCurve;
10 |
11 | private StepCurve _edgeGeometry;
12 |
13 | public StepCurve EdgeGeometry
14 | {
15 | get { return _edgeGeometry; }
16 | set
17 | {
18 | if (value == null)
19 | {
20 | throw new ArgumentNullException();
21 | }
22 |
23 | _edgeGeometry = value;
24 | }
25 | }
26 |
27 | public bool IsSameSense { get; set; }
28 |
29 | private StepEdgeCurve()
30 | : base()
31 | {
32 | }
33 |
34 | public StepEdgeCurve(string name, StepVertex edgeStart, StepVertex edgeEnd, StepCurve edgeGeometry, bool isSameSense)
35 | : base(name, edgeStart, edgeEnd)
36 | {
37 | EdgeGeometry = edgeGeometry;
38 | IsSameSense = isSameSense;
39 | }
40 |
41 | internal override IEnumerable GetReferencedItems()
42 | {
43 | foreach (var item in base.GetReferencedItems())
44 | {
45 | yield return item;
46 | }
47 |
48 | yield return EdgeGeometry;
49 | }
50 |
51 | internal override IEnumerable GetParameters(StepWriter writer)
52 | {
53 | foreach (var parameter in base.GetParameters(writer))
54 | {
55 | yield return parameter;
56 | }
57 |
58 | yield return writer.GetItemSyntax(EdgeGeometry);
59 | yield return StepWriter.GetBooleanSyntax(IsSameSense);
60 | }
61 |
62 | internal static StepEdgeCurve CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
63 | {
64 | var edgeCurve = new StepEdgeCurve();
65 | syntaxList.AssertListCount(5);
66 | edgeCurve.Name = syntaxList.Values[0].GetStringValue();
67 | binder.BindValue(syntaxList.Values[1], v => edgeCurve.EdgeStart = v.AsType());
68 | binder.BindValue(syntaxList.Values[2], v => edgeCurve.EdgeEnd = v.AsType());
69 | binder.BindValue(syntaxList.Values[3], v => edgeCurve.EdgeGeometry = v.AsType());
70 | edgeCurve.IsSameSense = syntaxList.Values[4].GetBooleanValue();
71 | return edgeCurve;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepEdgeLoop.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepEdgeLoop : StepLoop
8 | {
9 | public override StepItemType ItemType => StepItemType.EdgeLoop;
10 |
11 | public List EdgeList { get; private set; }
12 |
13 | public StepEdgeLoop(string name, IEnumerable edgeList)
14 | : base(name)
15 | {
16 | EdgeList = new List(edgeList);
17 | }
18 |
19 | public StepEdgeLoop(string name, params StepOrientedEdge[] edgeList)
20 | : this(name, (IEnumerable)edgeList)
21 | {
22 | }
23 |
24 | internal override IEnumerable GetReferencedItems()
25 | {
26 | return EdgeList;
27 | }
28 |
29 | internal override IEnumerable GetParameters(StepWriter writer)
30 | {
31 | foreach (var parameter in base.GetParameters(writer))
32 | {
33 | yield return parameter;
34 | }
35 |
36 | yield return new StepSyntaxList(-1, -1, EdgeList.Select(e => writer.GetItemSyntax(e)));
37 | }
38 |
39 | internal static StepEdgeLoop CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
40 | {
41 | syntaxList.AssertListCount(2);
42 | var edgeSyntaxList = syntaxList.Values[1].GetValueList();
43 | var edgeLoop = new StepEdgeLoop(string.Empty, new StepOrientedEdge[edgeSyntaxList.Values.Count]);
44 | edgeLoop.Name = syntaxList.Values[0].GetStringValue();
45 | for (int i = 0; i < edgeSyntaxList.Values.Count; i++)
46 | {
47 | var j = i; // capture to avoid rebinding
48 | binder.BindValue(edgeSyntaxList.Values[j], v => edgeLoop.EdgeList[j] = v.AsType());
49 | }
50 |
51 | return edgeLoop;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepElementarySurface.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public abstract class StepElementarySurface : StepSurface
8 | {
9 | private StepAxis2Placement3D _position;
10 |
11 | public StepAxis2Placement3D Position
12 | {
13 | get { return _position; }
14 | set
15 | {
16 | if (value == null)
17 | {
18 | throw new ArgumentNullException();
19 | }
20 |
21 | _position = value;
22 | }
23 | }
24 |
25 | protected StepElementarySurface()
26 | : base(string.Empty)
27 | {
28 | }
29 |
30 | public StepElementarySurface(string name, StepAxis2Placement3D position)
31 | : base(name)
32 | {
33 | Position = position;
34 | }
35 |
36 | internal override IEnumerable GetReferencedItems()
37 | {
38 | yield return Position;
39 | }
40 |
41 | internal override IEnumerable GetParameters(StepWriter writer)
42 | {
43 | foreach (var parameter in base.GetParameters(writer))
44 | {
45 | yield return parameter;
46 | }
47 |
48 | yield return writer.GetItemSyntax(Position);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepEllipse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepEllipse : StepConic
8 | {
9 | public override StepItemType ItemType => StepItemType.Ellipse;
10 |
11 | private StepAxis2Placement _position;
12 |
13 | public StepAxis2Placement Position
14 | {
15 | get { return _position; }
16 | set
17 | {
18 | if (value == null)
19 | {
20 | throw new ArgumentNullException();
21 | }
22 |
23 | _position = value;
24 | }
25 | }
26 |
27 | public double SemiAxis1 { get; set; }
28 | public double SemiAxis2 { get; set; }
29 |
30 | private StepEllipse()
31 | : base(string.Empty)
32 | {
33 | }
34 |
35 | public StepEllipse(string name, StepAxis2Placement position, double semiAxis1, double semiAxis2)
36 | : base(name)
37 | {
38 | Position = position;
39 | SemiAxis1 = semiAxis1;
40 | SemiAxis2 = semiAxis2;
41 | }
42 |
43 | internal override IEnumerable GetReferencedItems()
44 | {
45 | yield return Position;
46 | }
47 |
48 | internal override IEnumerable GetParameters(StepWriter writer)
49 | {
50 | foreach (var parameter in base.GetParameters(writer))
51 | {
52 | yield return parameter;
53 | }
54 |
55 | yield return writer.GetItemSyntax(Position);
56 | yield return new StepRealSyntax(SemiAxis1);
57 | yield return new StepRealSyntax(SemiAxis2);
58 | }
59 |
60 | internal static StepEllipse CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
61 | {
62 | var ellipse = new StepEllipse();
63 | syntaxList.AssertListCount(4);
64 | ellipse.Name = syntaxList.Values[0].GetStringValue();
65 | binder.BindValue(syntaxList.Values[1], v => ellipse.Position = v.AsType());
66 | ellipse.SemiAxis1 = syntaxList.Values[2].GetRealVavlue();
67 | ellipse.SemiAxis2 = syntaxList.Values[3].GetRealVavlue();
68 | return ellipse;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepFace.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public abstract class StepFace : StepTopologicalRepresentationItem
8 | {
9 | public List Bounds { get; } = new List();
10 |
11 | public StepFace(string name)
12 | : base(name)
13 | {
14 | }
15 |
16 | internal override IEnumerable GetParameters(StepWriter writer)
17 | {
18 | foreach (var parameter in base.GetParameters(writer))
19 | {
20 | yield return parameter;
21 | }
22 |
23 | yield return new StepSyntaxList(Bounds.Select(b => writer.GetItemSyntax(b)));
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepFaceBound.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public class StepFaceBound : StepTopologicalRepresentationItem
7 | {
8 | public override StepItemType ItemType => StepItemType.FaceBound;
9 |
10 | public StepLoop Bound { get; set; }
11 | public bool Orientation { get; set; }
12 |
13 | protected StepFaceBound()
14 | : base(string.Empty)
15 | {
16 | }
17 |
18 | public StepFaceBound(string name, StepLoop bound, bool orientation)
19 | : base(name)
20 | {
21 | Bound = bound;
22 | Orientation = orientation;
23 | }
24 |
25 | internal override IEnumerable GetReferencedItems()
26 | {
27 | yield return Bound;
28 | }
29 |
30 | internal override IEnumerable GetParameters(StepWriter writer)
31 | {
32 | foreach (var parameter in base.GetParameters(writer))
33 | {
34 | yield return parameter;
35 | }
36 |
37 | yield return writer.GetItemSyntax(Bound);
38 | yield return StepWriter.GetBooleanSyntax(Orientation);
39 | }
40 |
41 | internal static StepFaceBound CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
42 | {
43 | syntaxList.AssertListCount(3);
44 | var faceBound = new StepFaceBound();
45 | faceBound.Name = syntaxList.Values[0].GetStringValue();
46 | binder.BindValue(syntaxList.Values[1], v => faceBound.Bound = v.AsType());
47 | faceBound.Orientation = syntaxList.Values[2].GetBooleanValue();
48 | return faceBound;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepFaceOuterBound.cs:
--------------------------------------------------------------------------------
1 | using IxMilia.Step.Syntax;
2 |
3 | namespace IxMilia.Step.Items
4 | {
5 | public class StepFaceOuterBound : StepFaceBound
6 | {
7 | public override StepItemType ItemType => StepItemType.FaceOuterBound;
8 |
9 | private StepFaceOuterBound()
10 | : base()
11 | {
12 | }
13 |
14 | public StepFaceOuterBound(string name, StepLoop bound, bool orientation)
15 | : base(name, bound, orientation)
16 | {
17 | }
18 |
19 | internal static new StepFaceOuterBound CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
20 | {
21 | syntaxList.AssertListCount(3);
22 | var faceOuterBound = new StepFaceOuterBound();
23 | faceOuterBound.Name = syntaxList.Values[0].GetStringValue();
24 | binder.BindValue(syntaxList.Values[1], v => faceOuterBound.Bound = v.AsType());
25 | faceOuterBound.Orientation = syntaxList.Values[2].GetBooleanValue();
26 | return faceOuterBound;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepFaceSurface.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public abstract class StepFaceSurface : StepFace
7 | {
8 | public StepSurface FaceGeometry { get; set; }
9 |
10 | public bool SameSense { get; set; }
11 |
12 | public StepFaceSurface(string name)
13 | : base(name)
14 | {
15 | }
16 |
17 | internal override IEnumerable GetParameters(StepWriter writer)
18 | {
19 | foreach (var parameter in base.GetParameters(writer))
20 | {
21 | yield return parameter;
22 | }
23 |
24 | yield return writer.GetItemSyntax(FaceGeometry);
25 | yield return StepWriter.GetBooleanSyntax(!SameSense);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepGeometricRepresentationItem.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepGeometricRepresentationItem : StepRepresentationItem
4 | {
5 | protected StepGeometricRepresentationItem(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepItemType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IxMilia.Step.Items
4 | {
5 | public enum StepItemType
6 | {
7 | AdvancedFace,
8 | AxisPlacement2D,
9 | AxisPlacement3D,
10 | BSplineCurveWithKnots,
11 | CartesianPoint,
12 | Circle,
13 | CylindricalSurface,
14 | Direction,
15 | EdgeCurve,
16 | EdgeLoop,
17 | Ellipse,
18 | FaceBound,
19 | FaceOuterBound,
20 | Line,
21 | OrientedEdge,
22 | Plane,
23 | Vector,
24 | VertexPoint
25 | }
26 |
27 | internal static class StepItemTypeExtensions
28 | {
29 | public const string AdvancedFaceText = "ADVANCED_FACE";
30 | public const string Axis2Placement2DText = "AXIS2_PLACEMENT_2D";
31 | public const string Axis2Placement3DText = "AXIS2_PLACEMENT_3D";
32 | public const string BSplineCurveWithKnotsText = "B_SPLINE_CURVE_WITH_KNOTS";
33 | public const string CartesianPointText = "CARTESIAN_POINT";
34 | public const string CircleText = "CIRCLE";
35 | public const string CylindricalSurfaceText = "CYLINDRICAL_SURFACE";
36 | public const string DirectionText = "DIRECTION";
37 | public const string EdgeCurveText = "EDGE_CURVE";
38 | public const string EdgeLoopText = "EDGE_LOOP";
39 | public const string EllipseText = "ELLIPSE";
40 | public const string FaceBoundText = "FACE_BOUND";
41 | public const string FaceOuterBoundText = "FACE_OUTER_BOUND";
42 | public const string LineText = "LINE";
43 | public const string OrientedEdgeText = "ORIENTED_EDGE";
44 | public const string PlaneText = "PLANE";
45 | public const string VectorText = "VECTOR";
46 | public const string VertexPointText = "VERTEX_POINT";
47 |
48 | public static string GetItemTypeString(this StepItemType type)
49 | {
50 | switch (type)
51 | {
52 | case StepItemType.AdvancedFace:
53 | return AdvancedFaceText;
54 | case StepItemType.AxisPlacement2D:
55 | return Axis2Placement2DText;
56 | case StepItemType.AxisPlacement3D:
57 | return Axis2Placement3DText;
58 | case StepItemType.BSplineCurveWithKnots:
59 | return BSplineCurveWithKnotsText;
60 | case StepItemType.CartesianPoint:
61 | return CartesianPointText;
62 | case StepItemType.Circle:
63 | return CircleText;
64 | case StepItemType.CylindricalSurface:
65 | return CylindricalSurfaceText;
66 | case StepItemType.Direction:
67 | return DirectionText;
68 | case StepItemType.EdgeCurve:
69 | return EdgeCurveText;
70 | case StepItemType.EdgeLoop:
71 | return EdgeLoopText;
72 | case StepItemType.Ellipse:
73 | return EllipseText;
74 | case StepItemType.FaceBound:
75 | return FaceBoundText;
76 | case StepItemType.FaceOuterBound:
77 | return FaceOuterBoundText;
78 | case StepItemType.Line:
79 | return LineText;
80 | case StepItemType.OrientedEdge:
81 | return OrientedEdgeText;
82 | case StepItemType.Plane:
83 | return PlaneText;
84 | case StepItemType.Vector:
85 | return VectorText;
86 | case StepItemType.VertexPoint:
87 | return VertexPointText;
88 | default:
89 | throw new InvalidOperationException("Unexpected item type " + type);
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepLine.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepLine : StepCurve
8 | {
9 | public override StepItemType ItemType => StepItemType.Line;
10 |
11 | private StepCartesianPoint _point;
12 | private StepVector _vector;
13 |
14 | public StepCartesianPoint Point
15 | {
16 | get { return _point; }
17 | set
18 | {
19 | if (value == null)
20 | {
21 | throw new ArgumentNullException();
22 | }
23 |
24 | _point = value;
25 | }
26 | }
27 |
28 | public StepVector Vector
29 | {
30 | get { return _vector; }
31 | set
32 | {
33 | if (value == null)
34 | {
35 | throw new ArgumentNullException();
36 | }
37 |
38 | _vector = value;
39 | }
40 | }
41 |
42 | private StepLine()
43 | : base(string.Empty)
44 | {
45 | }
46 |
47 | public StepLine(string label, StepCartesianPoint point, StepVector vector)
48 | : base(label)
49 | {
50 | Point = point;
51 | Vector = vector;
52 | }
53 |
54 | public static StepLine FromPoints(double x1, double y1, double z1, double x2, double y2, double z2)
55 | {
56 | var start = new StepCartesianPoint("", x1, y1, z1);
57 | var dx = x2 - x1;
58 | var dy = y2 - y1;
59 | var dz = z2 - z1;
60 | var length = Math.Sqrt(dx * dx + dy * dy + dz * dz);
61 | var dxn = dx / length;
62 | var dyn = dy / length;
63 | var dzn = dz / length;
64 | var vector = new StepVector("", new StepDirection("", dxn, dyn, dzn), length);
65 | return new StepLine("", start, vector);
66 | }
67 |
68 | internal override IEnumerable GetReferencedItems()
69 | {
70 | yield return Point;
71 | yield return Vector;
72 | }
73 |
74 | internal override IEnumerable GetParameters(StepWriter writer)
75 | {
76 | foreach (var parameter in base.GetParameters(writer))
77 | {
78 | yield return parameter;
79 | }
80 |
81 | yield return writer.GetItemSyntax(Point);
82 | yield return writer.GetItemSyntax(Vector);
83 | }
84 |
85 | internal static StepLine CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
86 | {
87 | var line = new StepLine();
88 | syntaxList.AssertListCount(3);
89 | line.Name = syntaxList.Values[0].GetStringValue();
90 | binder.BindValue(syntaxList.Values[1], v => line.Point = v.AsType());
91 | binder.BindValue(syntaxList.Values[2], v => line.Vector = v.AsType());
92 | return line;
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepLoop.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepLoop : StepTopologicalRepresentationItem
4 | {
5 | public StepLoop(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepOrientedEdge.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepOrientedEdge : StepEdge
8 | {
9 | public override StepItemType ItemType => StepItemType.OrientedEdge;
10 |
11 | private StepEdge _edgeElement;
12 |
13 | public StepEdge EdgeElement
14 | {
15 | get { return _edgeElement; }
16 | set
17 | {
18 | if (value == null)
19 | {
20 | throw new ArgumentNullException();
21 | }
22 |
23 | _edgeElement = value;
24 | }
25 | }
26 |
27 | public bool Orientation { get; set; }
28 |
29 | private StepOrientedEdge()
30 | {
31 | }
32 |
33 | public StepOrientedEdge(string name, StepVertex edgeStart, StepVertex edgeEnd, StepEdge edgeElement, bool orientation)
34 | : base(name, edgeStart, edgeEnd)
35 | {
36 | EdgeElement = edgeElement;
37 | Orientation = orientation;
38 | }
39 |
40 | internal override IEnumerable GetReferencedItems()
41 | {
42 | foreach (var item in base.GetReferencedItems())
43 | {
44 | yield return item;
45 | }
46 |
47 | yield return EdgeElement;
48 | }
49 |
50 | internal override IEnumerable GetParameters(StepWriter writer)
51 | {
52 | foreach (var parameter in base.GetParameters(writer))
53 | {
54 | yield return parameter;
55 | }
56 |
57 | yield return writer.GetItemSyntax(EdgeElement);
58 | yield return StepWriter.GetBooleanSyntax(Orientation);
59 | }
60 |
61 | internal static StepOrientedEdge CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
62 | {
63 | var orientedEdge = new StepOrientedEdge();
64 | syntaxList.AssertListCount(5);
65 | orientedEdge.Name = syntaxList.Values[0].GetStringValue();
66 | binder.BindValue(syntaxList.Values[1], v => orientedEdge.EdgeStart = v.AsType());
67 | binder.BindValue(syntaxList.Values[2], v => orientedEdge.EdgeEnd = v.AsType());
68 | binder.BindValue(syntaxList.Values[3], v => orientedEdge.EdgeElement = v.AsType());
69 | orientedEdge.Orientation = syntaxList.Values[4].GetBooleanValue();
70 | return orientedEdge;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepPlacement.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepPlacement : StepGeometricRepresentationItem
4 | {
5 | protected StepPlacement(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepPlane.cs:
--------------------------------------------------------------------------------
1 | using IxMilia.Step.Syntax;
2 |
3 | namespace IxMilia.Step.Items
4 | {
5 | public class StepPlane : StepElementarySurface
6 | {
7 | public override StepItemType ItemType => StepItemType.Plane;
8 |
9 | private StepPlane()
10 | : base()
11 | {
12 | }
13 |
14 | public StepPlane(string name, StepAxis2Placement3D position)
15 | : base(name, position)
16 | {
17 | }
18 |
19 | internal static StepPlane CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
20 | {
21 | var plane = new StepPlane();
22 | syntaxList.AssertListCount(2);
23 | plane.Name = syntaxList.Values[0].GetStringValue();
24 | binder.BindValue(syntaxList.Values[1], v => plane.Position = v.AsType());
25 | return plane;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepPoint.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepPoint : StepGeometricRepresentationItem
4 | {
5 | protected StepPoint(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepRepresentationItem.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public abstract partial class StepRepresentationItem
7 | {
8 | public abstract StepItemType ItemType { get; }
9 |
10 | public string Name { get; set; }
11 |
12 | protected StepRepresentationItem(string name)
13 | {
14 | Name = name;
15 | }
16 |
17 | internal virtual IEnumerable GetReferencedItems()
18 | {
19 | yield break;
20 | }
21 |
22 | internal virtual IEnumerable GetParameters(StepWriter writer)
23 | {
24 | yield return new StepStringSyntax(Name);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepRepresentationItem_FromTypedParameter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public abstract partial class StepRepresentationItem
8 | {
9 | internal static HashSet UnsupportedItemTypes { get; } = new HashSet();
10 |
11 | internal static StepRepresentationItem FromTypedParameter(StepBinder binder, StepItemSyntax itemSyntax)
12 | {
13 | StepRepresentationItem item = null;
14 | if (itemSyntax is StepSimpleItemSyntax)
15 | {
16 | var simpleItem = (StepSimpleItemSyntax)itemSyntax;
17 | switch (simpleItem.Keyword)
18 | {
19 | case StepItemTypeExtensions.AdvancedFaceText:
20 | item = StepAdvancedFace.CreateFromSyntaxList(binder, simpleItem.Parameters);
21 | break;
22 | case StepItemTypeExtensions.Axis2Placement2DText:
23 | item = StepAxis2Placement2D.CreateFromSyntaxList(binder, simpleItem.Parameters);
24 | break;
25 | case StepItemTypeExtensions.Axis2Placement3DText:
26 | item = StepAxis2Placement3D.CreateFromSyntaxList(binder, simpleItem.Parameters);
27 | break;
28 | case StepItemTypeExtensions.BSplineCurveWithKnotsText:
29 | item = StepBSplineCurveWithKnots.CreateFromSyntaxList(binder, simpleItem.Parameters);
30 | break;
31 | case StepItemTypeExtensions.CartesianPointText:
32 | item = StepCartesianPoint.CreateFromSyntaxList(simpleItem.Parameters);
33 | break;
34 | case StepItemTypeExtensions.CircleText:
35 | item = StepCircle.CreateFromSyntaxList(binder, simpleItem.Parameters);
36 | break;
37 | case StepItemTypeExtensions.CylindricalSurfaceText:
38 | item = StepCylindricalSurface.CreateFromSyntaxList(binder, simpleItem.Parameters);
39 | break;
40 | case StepItemTypeExtensions.DirectionText:
41 | item = StepDirection.CreateFromSyntaxList(simpleItem.Parameters);
42 | break;
43 | case StepItemTypeExtensions.EdgeCurveText:
44 | item = StepEdgeCurve.CreateFromSyntaxList(binder, simpleItem.Parameters);
45 | break;
46 | case StepItemTypeExtensions.EdgeLoopText:
47 | item = StepEdgeLoop.CreateFromSyntaxList(binder, simpleItem.Parameters);
48 | break;
49 | case StepItemTypeExtensions.EllipseText:
50 | item = StepEllipse.CreateFromSyntaxList(binder, simpleItem.Parameters);
51 | break;
52 | case StepItemTypeExtensions.FaceBoundText:
53 | item = StepFaceBound.CreateFromSyntaxList(binder, simpleItem.Parameters);
54 | break;
55 | case StepItemTypeExtensions.FaceOuterBoundText:
56 | item = StepFaceOuterBound.CreateFromSyntaxList(binder, simpleItem.Parameters);
57 | break;
58 | case StepItemTypeExtensions.LineText:
59 | item = StepLine.CreateFromSyntaxList(binder, simpleItem.Parameters);
60 | break;
61 | case StepItemTypeExtensions.OrientedEdgeText:
62 | item = StepOrientedEdge.CreateFromSyntaxList(binder, simpleItem.Parameters);
63 | break;
64 | case StepItemTypeExtensions.PlaneText:
65 | item = StepPlane.CreateFromSyntaxList(binder, simpleItem.Parameters);
66 | break;
67 | case StepItemTypeExtensions.VectorText:
68 | item = StepVector.CreateFromSyntaxList(binder, simpleItem.Parameters);
69 | break;
70 | case StepItemTypeExtensions.VertexPointText:
71 | item = StepVertexPoint.CreateFromSyntaxList(binder, simpleItem.Parameters);
72 | break;
73 | default:
74 | if (UnsupportedItemTypes.Add(simpleItem.Keyword))
75 | {
76 | Debug.WriteLine($"Unsupported item {simpleItem.Keyword} at {simpleItem.Line}, {simpleItem.Column}");
77 | }
78 | break;
79 | }
80 | }
81 | else
82 | {
83 | // TODO:
84 | }
85 |
86 | return item;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepSurface.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepSurface : StepGeometricRepresentationItem
4 | {
5 | public StepSurface(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepTopologicalRepresentationItem.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepTopologicalRepresentationItem : StepRepresentationItem
4 | {
5 | protected StepTopologicalRepresentationItem(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepTriple.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step.Items
5 | {
6 | public abstract class StepTriple : StepPoint
7 | {
8 | public double X { get; set; }
9 | public double Y { get; set; }
10 | public double Z { get; set; }
11 |
12 | protected abstract int MinimumValueCount { get; }
13 |
14 | protected StepTriple()
15 | : this(string.Empty, 0.0, 0.0, 0.0)
16 | {
17 | }
18 |
19 | protected StepTriple(string name, double x, double y, double z)
20 | : base(name)
21 | {
22 | X = x;
23 | Y = y;
24 | Z = z;
25 | }
26 |
27 | internal override IEnumerable GetParameters(StepWriter writer)
28 | {
29 | foreach (var parameter in base.GetParameters(writer))
30 | {
31 | yield return parameter;
32 | }
33 |
34 | yield return new StepSyntaxList(
35 | new StepRealSyntax(X),
36 | new StepRealSyntax(Y),
37 | new StepRealSyntax(Z)
38 | );
39 | }
40 |
41 | internal static StepTriple AssignTo(StepTriple triple, StepSyntaxList values)
42 | {
43 | values.AssertListCount(2);
44 | triple.Name = values.Values[0].GetStringValue();
45 | var pointValues = values.Values[1].GetValueList();
46 | pointValues.AssertListCount(triple.MinimumValueCount, 3);
47 | triple.X = pointValues.GetRealValueOrDefault(0);
48 | triple.Y = pointValues.GetRealValueOrDefault(1);
49 | triple.Z = pointValues.GetRealValueOrDefault(2);
50 | return triple;
51 | }
52 |
53 | public bool Equals(StepTriple other)
54 | {
55 | if ((object)other == null)
56 | {
57 | return false;
58 | }
59 |
60 | return ItemType == other.ItemType && X == other.X && Y == other.Y && Z == other.Z && Name == other.Name;
61 | }
62 |
63 | public override bool Equals(object obj)
64 | {
65 | return Equals(obj as StepTriple);
66 | }
67 |
68 | public override int GetHashCode()
69 | {
70 | return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode();
71 | }
72 |
73 | public static bool operator ==(StepTriple left, StepTriple right)
74 | {
75 | if (ReferenceEquals(left, right))
76 | {
77 | return true;
78 | }
79 |
80 | if ((object)left == null || (object)right == null)
81 | {
82 | return false;
83 | }
84 |
85 | return left.Equals(right);
86 | }
87 |
88 | public static bool operator !=(StepTriple left, StepTriple right)
89 | {
90 | return !(left == right);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepVector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepVector : StepGeometricRepresentationItem
8 | {
9 | public override StepItemType ItemType => StepItemType.Vector;
10 |
11 | private StepDirection _direction;
12 | public StepDirection Direction
13 | {
14 | get { return _direction; }
15 | set
16 | {
17 | if (value == null)
18 | {
19 | throw new ArgumentNullException();
20 | }
21 |
22 | _direction = value;
23 | }
24 | }
25 | public double Length { get; set; }
26 |
27 | private StepVector()
28 | : base(string.Empty)
29 | {
30 | }
31 |
32 | public StepVector(string name, StepDirection direction, double length)
33 | : base(name)
34 | {
35 | Direction = direction;
36 | Length = length;
37 | }
38 |
39 | internal override IEnumerable GetReferencedItems()
40 | {
41 | yield return Direction;
42 | }
43 |
44 | internal override IEnumerable GetParameters(StepWriter writer)
45 | {
46 | foreach (var parameter in base.GetParameters(writer))
47 | {
48 | yield return parameter;
49 | }
50 |
51 | yield return writer.GetItemSyntax(Direction);
52 | yield return new StepRealSyntax(Length);
53 | }
54 |
55 | internal static StepVector CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
56 | {
57 | var vector = new StepVector();
58 | syntaxList.AssertListCount(3);
59 | vector.Name = syntaxList.Values[0].GetStringValue();
60 | binder.BindValue(syntaxList.Values[1], v => vector.Direction = v.AsType());
61 | vector.Length = syntaxList.Values[2].GetRealVavlue();
62 | return vector;
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepVertex.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Items
2 | {
3 | public abstract class StepVertex : StepTopologicalRepresentationItem
4 | {
5 | protected StepVertex(string name)
6 | : base(name)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Items/StepVertexPoint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Syntax;
4 |
5 | namespace IxMilia.Step.Items
6 | {
7 | public class StepVertexPoint : StepVertex
8 | {
9 | public override StepItemType ItemType => StepItemType.VertexPoint;
10 |
11 | private StepCartesianPoint _location;
12 |
13 | public StepCartesianPoint Location
14 | {
15 | get { return _location; }
16 | set
17 | {
18 | if (value == null)
19 | {
20 | throw new ArgumentNullException();
21 | }
22 |
23 | _location = value;
24 | }
25 | }
26 |
27 | private StepVertexPoint()
28 | : base(string.Empty)
29 | {
30 | }
31 |
32 | public StepVertexPoint(string name, StepCartesianPoint location)
33 | : base(name)
34 | {
35 | Location = location;
36 | }
37 |
38 | internal override IEnumerable GetReferencedItems()
39 | {
40 | yield return Location;
41 | }
42 |
43 | internal override IEnumerable GetParameters(StepWriter writer)
44 | {
45 | foreach (var parameter in base.GetParameters(writer))
46 | {
47 | yield return parameter;
48 | }
49 |
50 | yield return writer.GetItemSyntax(Location);
51 | }
52 |
53 | internal static StepVertexPoint CreateFromSyntaxList(StepBinder binder, StepSyntaxList syntaxList)
54 | {
55 | var vertex = new StepVertexPoint();
56 | syntaxList.AssertListCount(2);
57 | vertex.Name = syntaxList.Values[0].GetStringValue();
58 | binder.BindValue(syntaxList.Values[1], v => vertex.Location = v.AsType());
59 | return vertex;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/IxMilia.Step.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | A portable .NET library for reading and writing STEP CAD files.
5 | Copyright 2017
6 | IxMilia.Step
7 | IxMilia
8 | netstandard2.0
9 | IxMilia.Step
10 | IxMilia.Step
11 | CAD;STEP;STP
12 | https://github.com/ixmilia/step
13 | MIT
14 |
15 |
16 | true
17 | true
18 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("IxMilia.Step.Test")]
4 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepBinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using IxMilia.Step.Items;
5 | using IxMilia.Step.Syntax;
6 |
7 | namespace IxMilia.Step
8 | {
9 | internal class StepBinder
10 | {
11 | private Dictionary _itemMap;
12 | private Dictionary>>> _unboundPointers = new Dictionary>>>();
13 |
14 | public StepBinder(Dictionary itemMap)
15 | {
16 | _itemMap = itemMap;
17 | }
18 |
19 | public void BindValue(StepSyntax syntax, Action bindAction)
20 | {
21 | if (syntax is StepSimpleItemSyntax)
22 | {
23 | var typedParameter = (StepSimpleItemSyntax)syntax;
24 | var item = StepRepresentationItem.FromTypedParameter(this, typedParameter);
25 | var boundItem = new StepBoundItem(item, syntax);
26 | bindAction(boundItem);
27 | }
28 | else if (syntax is StepEntityInstanceReferenceSyntax)
29 | {
30 | var itemInstance = (StepEntityInstanceReferenceSyntax)syntax;
31 | if (_itemMap.ContainsKey(itemInstance.Id))
32 | {
33 | // pointer already defined, bind immediately
34 | var boundItem = new StepBoundItem(_itemMap[itemInstance.Id], syntax);
35 | bindAction(boundItem);
36 | }
37 | else
38 | {
39 | // not already defined, save it for later
40 | if (!_unboundPointers.ContainsKey(itemInstance.Id))
41 | {
42 | _unboundPointers.Add(itemInstance.Id, new List>>());
43 | }
44 |
45 | _unboundPointers[itemInstance.Id].Add(Tuple.Create(syntax, bindAction));
46 | }
47 | }
48 | else if (syntax is StepAutoSyntax)
49 | {
50 | bindAction(StepBoundItem.AutoItem(syntax));
51 | }
52 | else
53 | {
54 | throw new StepReadException("Unable to bind pointer, this should be unreachable", syntax.Line, syntax.Column);
55 | }
56 | }
57 |
58 | public void BindRemainingValues()
59 | {
60 | foreach (var id in _unboundPointers.Keys)
61 | {
62 | if (!_itemMap.ContainsKey(id))
63 | {
64 | var syntax = _unboundPointers[id].First().Item1;
65 | throw new StepReadException($"Cannot bind undefined pointer {id}", syntax.Line, syntax.Column);
66 | }
67 |
68 | var item = _itemMap[id];
69 | foreach (var binder in _unboundPointers[id])
70 | {
71 | var boundItem = new StepBoundItem(item, binder.Item1);
72 | binder.Item2(boundItem);
73 | }
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepBoundItem.cs:
--------------------------------------------------------------------------------
1 | using IxMilia.Step.Items;
2 | using IxMilia.Step.Syntax;
3 |
4 | namespace IxMilia.Step
5 | {
6 | internal class StepBoundItem
7 | {
8 | public StepSyntax CreatingSyntax { get; }
9 | public StepRepresentationItem Item { get; }
10 | public bool IsAuto { get; private set; }
11 |
12 | public StepBoundItem(StepRepresentationItem item, StepSyntax creatingSyntax)
13 | {
14 | CreatingSyntax = creatingSyntax;
15 | Item = item;
16 | }
17 |
18 | public TItemType AsType() where TItemType : StepRepresentationItem
19 | {
20 | TItemType result = null;
21 | if (IsAuto)
22 | {
23 | // do nothing; null is expected
24 | }
25 | else
26 | {
27 | result = Item as TItemType;
28 | if (result == null)
29 | {
30 | throw new StepReadException("Unexpected type", CreatingSyntax.Line, CreatingSyntax.Column);
31 | }
32 | }
33 |
34 | return result;
35 | }
36 |
37 | public static StepBoundItem AutoItem(StepSyntax creatingSyntax)
38 | {
39 | var boundItem = new StepBoundItem(null, creatingSyntax);
40 | boundItem.IsAuto = true;
41 | return boundItem;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepFile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using IxMilia.Step.Items;
6 | using IxMilia.Step.Syntax;
7 |
8 | namespace IxMilia.Step
9 | {
10 | public class StepFile
11 | {
12 | internal const string MagicHeader = "ISO-10303-21";
13 | internal const string MagicFooter = "END-" + MagicHeader;
14 | internal const string HeaderText = "HEADER";
15 | internal const string EndSectionText = "ENDSEC";
16 | internal const string DataText = "DATA";
17 |
18 | internal const string FileDescriptionText = "FILE_DESCRIPTION";
19 | internal const string FileNameText = "FILE_NAME";
20 | internal const string FileSchemaText = "FILE_SCHEMA";
21 |
22 | // FILE_DESCRIPTION values
23 | public string Description { get; set; }
24 | public string ImplementationLevel { get; set; }
25 |
26 | // FILE_NAME values
27 | public string Name { get; set; }
28 | public DateTime Timestamp { get; set; }
29 | public string Author { get; set; }
30 | public string Organization { get; set; }
31 | public string PreprocessorVersion { get; set; }
32 | public string OriginatingSystem { get; set; }
33 | public string Authorization { get; set; }
34 |
35 | // FILE_SCHEMA values
36 | public HashSet Schemas { get; }
37 | public List UnsupportedSchemas { get; }
38 |
39 | public List Items { get; }
40 |
41 | public StepFile()
42 | {
43 | Timestamp = DateTime.Now;
44 | Schemas = new HashSet();
45 | UnsupportedSchemas = new List();
46 | Items = new List();
47 | }
48 |
49 | public static StepFile Load(string path)
50 | {
51 | using (var stream = new FileStream(path, FileMode.Open))
52 | {
53 | return Load(stream);
54 | }
55 | }
56 |
57 | public static StepFile Load(Stream stream)
58 | {
59 | return new StepReader(stream).ReadFile();
60 | }
61 |
62 | public static StepFile Parse(string data)
63 | {
64 | using (var stream = new MemoryStream())
65 | using (var writer = new StreamWriter(stream))
66 | {
67 | writer.Write(data);
68 | writer.Flush();
69 | stream.Seek(0, SeekOrigin.Begin);
70 | return Load(stream);
71 | }
72 | }
73 |
74 | public string GetContentsAsString(bool inlineReferences = false)
75 | {
76 | var writer = new StepWriter(this, inlineReferences);
77 | return writer.GetContents();
78 | }
79 |
80 | public void Save(string path, bool inlineReferences = false)
81 | {
82 | using (var stream = new FileStream(path, FileMode.Create))
83 | {
84 | Save(stream, inlineReferences);
85 | }
86 | }
87 |
88 | public void Save(Stream stream, bool inlineReferences = false)
89 | {
90 | using (var streamWriter = new StreamWriter(stream))
91 | {
92 | streamWriter.Write(GetContentsAsString(inlineReferences));
93 | streamWriter.Flush();
94 | }
95 | }
96 |
97 | ///
98 | /// Gets all top-level items (i.e., not referenced by any other item) in the file.
99 | ///
100 | public IEnumerable GetTopLevelItems()
101 | {
102 | var visitedItems = new HashSet();
103 | var referencedItems = new HashSet();
104 | foreach (var item in Items)
105 | {
106 | MarkReferencedItems(item, visitedItems, referencedItems);
107 | }
108 |
109 | return Items.Where(item => !referencedItems.Contains(item));
110 | }
111 |
112 | private static void MarkReferencedItems(StepRepresentationItem item, HashSet visitedItems, HashSet referencedItems)
113 | {
114 | if (visitedItems.Add(item))
115 | {
116 | foreach (var referenced in item.GetReferencedItems())
117 | {
118 | referencedItems.Add(referenced);
119 | MarkReferencedItems(referenced, visitedItems, referencedItems);
120 | }
121 | }
122 | }
123 |
124 | internal StepHeaderSectionSyntax GetHeaderSyntax()
125 | {
126 | var macros = new List()
127 | {
128 | new StepHeaderMacroSyntax(
129 | FileDescriptionText,
130 | new StepSyntaxList(
131 | new StepSyntaxList(StepWriter.SplitStringIntoParts(Description).Select(s => new StepStringSyntax(s))),
132 | new StepStringSyntax(ImplementationLevel))),
133 | new StepHeaderMacroSyntax(
134 | FileNameText,
135 | new StepSyntaxList(
136 | new StepStringSyntax(Name),
137 | new StepStringSyntax(Timestamp.ToString("O")),
138 | new StepSyntaxList(StepWriter.SplitStringIntoParts(Author).Select(s => new StepStringSyntax(s))),
139 | new StepSyntaxList(StepWriter.SplitStringIntoParts(Organization).Select(s => new StepStringSyntax(s))),
140 | new StepStringSyntax(PreprocessorVersion),
141 | new StepStringSyntax(OriginatingSystem),
142 | new StepStringSyntax(Authorization))),
143 | new StepHeaderMacroSyntax(
144 | FileSchemaText,
145 | new StepSyntaxList(
146 | new StepSyntaxList(
147 | Schemas
148 | .Select(s => s.ToSchemaName())
149 | .Concat(UnsupportedSchemas)
150 | .Select(s => new StepStringSyntax(s)))))
151 | };
152 |
153 | return new StepHeaderSectionSyntax(-1, -1, macros);
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepLexer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Syntax;
3 | using IxMilia.Step.Tokens;
4 |
5 | namespace IxMilia.Step
6 | {
7 | internal class StepLexer
8 | {
9 | private List _tokens;
10 | private int _offset = 0;
11 |
12 | public StepLexer(IEnumerable tokens)
13 | {
14 | _tokens = new List(tokens);
15 | }
16 |
17 | private bool TokensRemain()
18 | {
19 | return _offset < _tokens.Count;
20 | }
21 |
22 | private void MoveNext()
23 | {
24 | _offset++;
25 | }
26 |
27 | private StepToken Current => _tokens[_offset];
28 |
29 | public StepFileSyntax LexFileSyntax()
30 | {
31 | _offset = 0;
32 | SwallowKeywordAndSemicolon(StepFile.MagicHeader);
33 |
34 | var header = LexHeaderSection();
35 | var data = LexDataSection();
36 |
37 | var file = new StepFileSyntax(header, data);
38 |
39 | SwallowKeywordAndSemicolon(StepFile.MagicFooter);
40 |
41 | return file;
42 | }
43 |
44 | private StepHeaderSectionSyntax LexHeaderSection()
45 | {
46 | AssertTokensRemain();
47 | var headerLine = Current.Line;
48 | var headerColumn = Current.Column;
49 | SwallowKeywordAndSemicolon(StepFile.HeaderText);
50 | var macros = new List();
51 | while (TokensRemain() && Current.Kind == StepTokenKind.Keyword && !IsCurrentEndSec())
52 | {
53 | var macro = LexHeaderMacro();
54 | macros.Add(macro);
55 | }
56 |
57 | SwallowKeywordAndSemicolon(StepFile.EndSectionText);
58 | return new StepHeaderSectionSyntax(headerLine, headerColumn, macros);
59 | }
60 |
61 | private StepHeaderMacroSyntax LexHeaderMacro()
62 | {
63 | AssertNextTokenKind(StepTokenKind.Keyword);
64 | var name = ((StepKeywordToken)Current).Value;
65 | MoveNext();
66 | var syntaxList = LexSyntaxList();
67 | SwallowSemicolon();
68 | return new StepHeaderMacroSyntax(name, syntaxList);
69 | }
70 |
71 | private StepSyntax LexIndividualValue()
72 | {
73 | StepSyntax result;
74 | AssertTokensRemain();
75 | switch (Current.Kind)
76 | {
77 | case StepTokenKind.Integer:
78 | result = new StepIntegerSyntax((StepIntegerToken)Current);
79 | MoveNext();
80 | break;
81 | case StepTokenKind.Real:
82 | result = new StepRealSyntax((StepRealToken)Current);
83 | MoveNext();
84 | break;
85 | case StepTokenKind.String:
86 | result = new StepStringSyntax((StepStringToken)Current);
87 | MoveNext();
88 | break;
89 | case StepTokenKind.Asterisk:
90 | result = new StepAutoSyntax((StepAsteriskToken)Current);
91 | MoveNext();
92 | break;
93 | case StepTokenKind.Omitted:
94 | result = new StepOmittedSyntax((StepOmittedToken)Current);
95 | MoveNext();
96 | break;
97 | case StepTokenKind.Enumeration:
98 | result = new StepEnumerationValueSyntax((StepEnumerationToken)Current);
99 | MoveNext();
100 | break;
101 | case StepTokenKind.LeftParen:
102 | result = LexSyntaxList();
103 | break;
104 | case StepTokenKind.Keyword:
105 | result = LexSimpleItem();
106 | break;
107 | case StepTokenKind.EntityInstance:
108 | result = new StepEntityInstanceReferenceSyntax((StepEntityInstanceToken)Current);
109 | MoveNext();
110 | break;
111 | default:
112 | ReportError($"Unexpected syntax token '{Current.Kind}'");
113 | result = null; // unreachable
114 | break;
115 | }
116 |
117 | return result;
118 | }
119 |
120 | private StepSyntaxList LexSyntaxList()
121 | {
122 | AssertTokensRemain();
123 | var listLine = Current.Line;
124 | var listColumn = Current.Column;
125 | SwallowLeftParen();
126 | var values = new List();
127 | bool keepReading = true;
128 | bool expectingValue = true;
129 | while (keepReading)
130 | {
131 | AssertTokensRemain();
132 | if (expectingValue || values.Count == 0)
133 | {
134 | // expect a value or a close paren
135 | switch (Current.Kind)
136 | {
137 | case StepTokenKind.RightParen:
138 | keepReading = false;
139 | MoveNext();
140 | break;
141 | default:
142 | values.Add(LexIndividualValue());
143 | break;
144 | }
145 | }
146 | else
147 | {
148 | // expect a comma or close paren
149 | switch (Current.Kind)
150 | {
151 | case StepTokenKind.RightParen:
152 | keepReading = false;
153 | MoveNext();
154 | break;
155 | case StepTokenKind.Comma:
156 | MoveNext();
157 | break;
158 | default:
159 | ReportError($"Expected right paren or comma but found '{Current.Kind}'");
160 | break;
161 | }
162 | }
163 |
164 | expectingValue = !expectingValue;
165 | }
166 |
167 | return new StepSyntaxList(listLine, listColumn, values);
168 | }
169 |
170 | private StepDataSectionSyntax LexDataSection()
171 | {
172 | AssertTokensRemain();
173 | var dataLine = Current.Line;
174 | var dataColumn = Current.Column;
175 | SwallowKeywordAndSemicolon(StepFile.DataText);
176 | var itemInstsances = new List();
177 | while (TokensRemain() && Current.Kind == StepTokenKind.EntityInstance)
178 | {
179 | var itemInstance = LexItemInstance();
180 | itemInstsances.Add(itemInstance);
181 | }
182 |
183 | SwallowKeywordAndSemicolon(StepFile.EndSectionText);
184 | return new StepDataSectionSyntax(dataLine, dataColumn, itemInstsances);
185 | }
186 |
187 | private StepEntityInstanceSyntax LexItemInstance()
188 | {
189 | var line = Current.Line;
190 | var column = Current.Column;
191 |
192 | AssertNextTokenKind(StepTokenKind.EntityInstance);
193 | var reference = (StepEntityInstanceToken)Current;
194 | MoveNext();
195 |
196 | SwallowEquals();
197 |
198 | AssertTokensRemain();
199 | StepItemSyntax item = null;
200 | switch (Current.Kind)
201 | {
202 | case StepTokenKind.Keyword:
203 | item = LexSimpleItem();
204 | break;
205 | case StepTokenKind.LeftParen:
206 | item = LexComplexItem();
207 | break;
208 | default:
209 | ReportError($"Expected left paren but found {Current.Kind}");
210 | break; // unreachable
211 | }
212 |
213 | SwallowSemicolon();
214 |
215 | return new StepEntityInstanceSyntax(reference, item);
216 | }
217 |
218 | private StepSimpleItemSyntax LexSimpleItem()
219 | {
220 | AssertNextTokenKind(StepTokenKind.Keyword);
221 | var keyword = (StepKeywordToken)Current;
222 | MoveNext();
223 |
224 | var parameters = LexSyntaxList();
225 | return new StepSimpleItemSyntax(keyword, parameters);
226 | }
227 |
228 | private StepComplexItemSyntax LexComplexItem()
229 | {
230 | var entities = new List();
231 | var itemLine = Current.Line;
232 | var itemColumn = Current.Column;
233 | SwallowLeftParen();
234 | entities.Add(LexSimpleItem()); // there's always at least one
235 |
236 | bool keepReading = true;
237 | while (keepReading)
238 | {
239 | AssertTokensRemain();
240 | switch (Current.Kind)
241 | {
242 | case StepTokenKind.RightParen:
243 | SwallowRightParen();
244 | keepReading = false;
245 | break;
246 | case StepTokenKind.Keyword:
247 | entities.Add(LexSimpleItem());
248 | break;
249 | default:
250 | ReportError($"Expected right paren or keyword but found {Current.Kind}");
251 | break; // unreachable
252 | }
253 | }
254 |
255 | return new StepComplexItemSyntax(itemLine, itemColumn, entities);
256 | }
257 |
258 | private bool IsCurrentEndSec()
259 | {
260 | return Current.Kind == StepTokenKind.Keyword && ((StepKeywordToken)Current).Value == StepFile.EndSectionText;
261 | }
262 |
263 | private void SwallowKeyword(string keyword)
264 | {
265 | AssertNextTokenKind(StepTokenKind.Keyword);
266 | if (((StepKeywordToken)Current).Value != keyword)
267 | {
268 | ReportError($"Expected keyword '{keyword}' but found '{((StepKeywordToken)Current).Value}'");
269 | }
270 |
271 | MoveNext();
272 | }
273 |
274 | private void SwallowKeywordAndSemicolon(string keyword)
275 | {
276 | SwallowKeyword(keyword);
277 | SwallowSemicolon();
278 | }
279 |
280 | private void SwallowSemicolon()
281 | {
282 | SwallowToken(StepTokenKind.Semicolon);
283 | }
284 |
285 | private void SwallowLeftParen()
286 | {
287 | SwallowToken(StepTokenKind.LeftParen);
288 | }
289 |
290 | private void SwallowRightParen()
291 | {
292 | SwallowToken(StepTokenKind.RightParen);
293 | }
294 |
295 | private void SwallowEquals()
296 | {
297 | SwallowToken(StepTokenKind.Equals);
298 | }
299 |
300 | private void SwallowToken(StepTokenKind kind)
301 | {
302 | AssertNextTokenKind(kind);
303 | MoveNext();
304 | }
305 |
306 | private void AssertNextTokenKind(StepTokenKind kind)
307 | {
308 | AssertTokensRemain();
309 | if (Current.Kind != kind)
310 | {
311 | ReportError($"Expected '{kind}' token but found '{Current.Kind}'");
312 | }
313 | }
314 |
315 | private void AssertTokensRemain()
316 | {
317 | if (!TokensRemain())
318 | {
319 | ReportError("Unexpected end of token stream", 0, 0);
320 | }
321 | }
322 |
323 | private void ReportError(string message, int? line = null, int? column = null)
324 | {
325 | throw new StepReadException(message, line ?? Current.Line, column ?? Current.Column);
326 | }
327 | }
328 | }
329 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepReadException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IxMilia.Step
4 | {
5 | public class StepReadException : Exception
6 | {
7 | public int Line { get; }
8 | public int Column { get; }
9 |
10 | public StepReadException(string message, int line, int column)
11 | : base($"{message} at [{line}:{column}]")
12 | {
13 | Line = line;
14 | Column = column;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepReader.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Linq;
5 | using IxMilia.Step.Items;
6 | using IxMilia.Step.Syntax;
7 |
8 | namespace IxMilia.Step
9 | {
10 | internal class StepReader
11 | {
12 | private StepLexer _lexer;
13 | private StepFile _file;
14 |
15 | public StepReader(Stream stream)
16 | {
17 | _file = new StepFile();
18 | var tokenizer = new StepTokenizer(stream);
19 | _lexer = new StepLexer(tokenizer.GetTokens());
20 | }
21 |
22 | public StepFile ReadFile()
23 | {
24 | var fileSyntax = _lexer.LexFileSyntax();
25 | foreach (var headerMacro in fileSyntax.Header.Macros)
26 | {
27 | ApplyHeaderMacro(headerMacro);
28 | }
29 |
30 | var itemMap = new Dictionary();
31 | var binder = new StepBinder(itemMap);
32 | StepRepresentationItem.UnsupportedItemTypes.Clear();
33 | foreach (var itemInstance in fileSyntax.Data.ItemInstances)
34 | {
35 | if (itemMap.ContainsKey(itemInstance.Id))
36 | {
37 | throw new StepReadException("Duplicate item instance", itemInstance.Line, itemInstance.Column);
38 | }
39 |
40 | var item = StepRepresentationItem.FromTypedParameter(binder, itemInstance.SimpleItemInstance);
41 | if (item != null)
42 | {
43 | itemMap.Add(itemInstance.Id, item);
44 | _file.Items.Add(item);
45 | }
46 | }
47 |
48 | binder.BindRemainingValues();
49 |
50 | return _file;
51 | }
52 |
53 | private void ApplyHeaderMacro(StepHeaderMacroSyntax macro)
54 | {
55 | switch (macro.Name)
56 | {
57 | case StepFile.FileDescriptionText:
58 | ApplyFileDescription(macro.Values);
59 | break;
60 | case StepFile.FileNameText:
61 | ApplyFileName(macro.Values);
62 | break;
63 | case StepFile.FileSchemaText:
64 | ApplyFileSchema(macro.Values);
65 | break;
66 | default:
67 | Debug.WriteLine($"Unsupported header macro '{macro.Name}' at {macro.Line}, {macro.Column}");
68 | break;
69 | }
70 | }
71 |
72 | private void ApplyFileDescription(StepSyntaxList valueList)
73 | {
74 | valueList.AssertListCount(2);
75 | _file.Description = valueList.Values[0].GetConcatenatedStringValue();
76 | _file.ImplementationLevel = valueList.Values[1].GetStringValue(); // TODO: handle appropriate values
77 | }
78 |
79 | private void ApplyFileName(StepSyntaxList valueList)
80 | {
81 | valueList.AssertListCount(7);
82 | _file.Name = valueList.Values[0].GetStringValue();
83 | _file.Timestamp = valueList.Values[1].GetDateTimeValue();
84 | _file.Author = valueList.Values[2].GetConcatenatedStringValue();
85 | _file.Organization = valueList.Values[3].GetConcatenatedStringValue();
86 | _file.PreprocessorVersion = valueList.Values[4].GetStringValue();
87 | _file.OriginatingSystem = valueList.Values[5].GetStringValue();
88 | _file.Authorization = valueList.Values[6].GetStringValue();
89 | }
90 |
91 | private void ApplyFileSchema(StepSyntaxList valueList)
92 | {
93 | valueList.AssertListCount(1);
94 | foreach (var schemaName in valueList.Values[0].GetValueList().Values.Select(v => v.GetStringValue()))
95 | {
96 | StepSchemaTypes schemaType;
97 | if (StepSchemaTypeExtensions.TryGetSchemaTypeFromName(schemaName, out schemaType))
98 | {
99 | _file.Schemas.Add(schemaType);
100 | }
101 | else
102 | {
103 | _file.UnsupportedSchemas.Add(schemaName);
104 | }
105 | }
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepSchemaTypes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IxMilia.Step
4 | {
5 | public enum StepSchemaTypes
6 | {
7 | ExplicitDraughting = 201,
8 | AssociativeDraghting = 202,
9 | ConfigControlDesign = 203,
10 | StructuralAnalysisDesign = 209,
11 | ElectronicAssemblyInterconnect = 210,
12 | AutomotiveDesign = 214,
13 | ShipArrangement = 215,
14 | ShipMouldedForm = 216,
15 | ShipStructures = 218,
16 | DimensionalInspectionSchema = 219,
17 | FunctionalDataAndSchematics = 221,
18 | CastParts = 223,
19 | FeatureBasedProcessPlanning = 224,
20 | BuildingDeisgn = 225,
21 | PlantSpatialConfiguration = 227,
22 | TechnicalDataPackaging = 232,
23 | EngineeringProperties = 235,
24 | FurnitureCatalogAndInteriorDesign = 236,
25 | IntegratedCNC = 238,
26 | ProductLifeCycleSupport = 239,
27 | ProcessPlanning = 240,
28 | ManagedModelBased3DEngineering = 242
29 | }
30 |
31 | internal static class StepSchemaTypeExtensions
32 | {
33 | // SHAPE_APPEARANCE_LAYERS_GROUPS
34 | public const string AssociativeDraghtingText = "ASSOCIATIVE_DRAUGHTING";
35 | public const string AutomotiveDesignText = "AUTOMOTIVE_DESIGN";
36 | public const string BuildingDesignText = "BUILDING_DESIGN_SCHEMA";
37 | public const string CastPartsText = "CAST_PARTS_SCHEMA";
38 | public const string ConfigControlDesignText = "CONFIG_CONTROL_DESIGN";
39 | public const string ConfigurationControlled3DDesignText = "AP203_CONFIGURATION_CONTROLLED_3D_DESIGN_OF_MECHANICAL_PARTS_AND_ASSEMBLIES_MIM_LF";
40 | public const string DimensionalInspectionText = "DIMENSIONAL_INSPECTION_SCHEMA";
41 | public const string ElectronicAssemblyInterconnectText = "AP210_ELECTRONIC_ASSEMBLY_INTERCONNECT_AND_PACKAGING_DESIGN_MIM_LF";
42 | public const string EngineeringPropertiesText = "ENGINEERING_PROPERTIES_SCHEMA";
43 | public const string ExplicitDraughtingText = "EXPLICIT_DRAUGHTING";
44 | public const string FeatureBasedProcessPlanningText = "FEATURE_BASED_PROCESS_PLANNING";
45 | public const string FunctionalDataAndSchematicsText = "FUNCTIONAL_DATA_AND_SCHEMATIC_REPRESENTATION_MIM_LF";
46 | public const string FurnitureCatalogAndInteriorDesignText = "AP236_FURNITURE_CATALOG_AND_INTERIOR_DESIGN_MIM_LF";
47 | public const string IntegratedCNCText = "INTEGRATED_CNC_SCHEMA";
48 | public const string ManagedModelBased3DEngineeringText = "AP242_MANAGED_MODEL_BASED_3D_ENGINEERING_MIM_LF";
49 | public const string PlantSpatialConfigurationText = "PLANT_SPATIAL_CONFIGURATION";
50 | public const string ProcessPlanningText = "PROCESS_PLANNING_SCHEMA";
51 | public const string ProductLifeCycleSupportText = "AP239_PRODUCT_LIFE_CYCLE_SUPPORT_MIM_LF";
52 | public const string ShipArrangementText = "SHIP_ARRANGEMENT_SCHEMA";
53 | public const string ShipMouldedFormText = "SHIP_MOULDED_FORM_SCHEMA";
54 | public const string ShipStructuresText = "SHIP_STRUCTURES_SCHEMA";
55 | public const string StructuralAnalysisDesignText = "STRUCTURAL_ANALYSIS_DESIGN";
56 | public const string TechnicalDataPackagingText = "TECHNICAL_DATA_PACKAGING";
57 |
58 | public static string ToSchemaName(this StepSchemaTypes type)
59 | {
60 | switch (type)
61 | {
62 | case StepSchemaTypes.AssociativeDraghting:
63 | return AssociativeDraghtingText;
64 | case StepSchemaTypes.AutomotiveDesign:
65 | return AutomotiveDesignText;
66 | case StepSchemaTypes.BuildingDeisgn:
67 | return BuildingDesignText;
68 | case StepSchemaTypes.CastParts:
69 | return CastPartsText;
70 | case StepSchemaTypes.ConfigControlDesign:
71 | return ConfigControlDesignText;
72 | case StepSchemaTypes.DimensionalInspectionSchema:
73 | return DimensionalInspectionText;
74 | case StepSchemaTypes.ElectronicAssemblyInterconnect:
75 | return ElectronicAssemblyInterconnectText;
76 | case StepSchemaTypes.EngineeringProperties:
77 | return EngineeringPropertiesText;
78 | case StepSchemaTypes.ExplicitDraughting:
79 | return ExplicitDraughtingText;
80 | case StepSchemaTypes.FeatureBasedProcessPlanning:
81 | return FeatureBasedProcessPlanningText;
82 | case StepSchemaTypes.FunctionalDataAndSchematics:
83 | return FunctionalDataAndSchematicsText;
84 | case StepSchemaTypes.FurnitureCatalogAndInteriorDesign:
85 | return FurnitureCatalogAndInteriorDesignText;
86 | case StepSchemaTypes.IntegratedCNC:
87 | return IntegratedCNCText;
88 | case StepSchemaTypes.ManagedModelBased3DEngineering:
89 | return ManagedModelBased3DEngineeringText;
90 | case StepSchemaTypes.PlantSpatialConfiguration:
91 | return PlantSpatialConfigurationText;
92 | case StepSchemaTypes.ProcessPlanning:
93 | return ProcessPlanningText;
94 | case StepSchemaTypes.ProductLifeCycleSupport:
95 | return ProductLifeCycleSupportText;
96 | case StepSchemaTypes.ShipArrangement:
97 | return ShipArrangementText;
98 | case StepSchemaTypes.ShipMouldedForm:
99 | return ShipMouldedFormText;
100 | case StepSchemaTypes.ShipStructures:
101 | return ShipStructuresText;
102 | case StepSchemaTypes.StructuralAnalysisDesign:
103 | return StructuralAnalysisDesignText;
104 | case StepSchemaTypes.TechnicalDataPackaging:
105 | return TechnicalDataPackagingText;
106 | default:
107 | throw new ArgumentException($"Unsupported schema type '{type}'", nameof(type));
108 | }
109 | }
110 |
111 | public static bool TryGetSchemaTypeFromName(string schemaName, out StepSchemaTypes schemaType)
112 | {
113 | switch (schemaName)
114 | {
115 | case AssociativeDraghtingText:
116 | schemaType = StepSchemaTypes.AssociativeDraghting;
117 | break;
118 | case AutomotiveDesignText:
119 | schemaType = StepSchemaTypes.AutomotiveDesign;
120 | break;
121 | case BuildingDesignText:
122 | schemaType = StepSchemaTypes.BuildingDeisgn;
123 | break;
124 | case CastPartsText:
125 | schemaType = StepSchemaTypes.CastParts;
126 | break;
127 | case ConfigControlDesignText:
128 | case ConfigurationControlled3DDesignText:
129 | schemaType = StepSchemaTypes.ConfigControlDesign;
130 | break;
131 | case DimensionalInspectionText:
132 | schemaType = StepSchemaTypes.DimensionalInspectionSchema;
133 | break;
134 | case ElectronicAssemblyInterconnectText:
135 | schemaType = StepSchemaTypes.ElectronicAssemblyInterconnect;
136 | break;
137 | case EngineeringPropertiesText:
138 | schemaType = StepSchemaTypes.EngineeringProperties;
139 | break;
140 | case ExplicitDraughtingText:
141 | schemaType = StepSchemaTypes.ExplicitDraughting;
142 | break;
143 | case FeatureBasedProcessPlanningText:
144 | schemaType = StepSchemaTypes.FeatureBasedProcessPlanning;
145 | break;
146 | case FunctionalDataAndSchematicsText:
147 | schemaType = StepSchemaTypes.FunctionalDataAndSchematics;
148 | break;
149 | case FurnitureCatalogAndInteriorDesignText:
150 | schemaType = StepSchemaTypes.FurnitureCatalogAndInteriorDesign;
151 | break;
152 | case IntegratedCNCText:
153 | schemaType = StepSchemaTypes.IntegratedCNC;
154 | break;
155 | case ManagedModelBased3DEngineeringText:
156 | schemaType = StepSchemaTypes.ManagedModelBased3DEngineering;
157 | break;
158 | case PlantSpatialConfigurationText:
159 | schemaType = StepSchemaTypes.PlantSpatialConfiguration;
160 | break;
161 | case ProcessPlanningText:
162 | schemaType = StepSchemaTypes.ProcessPlanning;
163 | break;
164 | case ProductLifeCycleSupportText:
165 | schemaType = StepSchemaTypes.ProductLifeCycleSupport;
166 | break;
167 | case ShipArrangementText:
168 | schemaType = StepSchemaTypes.ShipArrangement;
169 | break;
170 | case ShipMouldedFormText:
171 | schemaType = StepSchemaTypes.ShipMouldedForm;
172 | break;
173 | case ShipStructuresText:
174 | schemaType = StepSchemaTypes.ShipStructures;
175 | break;
176 | case StructuralAnalysisDesignText:
177 | schemaType = StepSchemaTypes.StructuralAnalysisDesign;
178 | break;
179 | case TechnicalDataPackagingText:
180 | schemaType = StepSchemaTypes.TechnicalDataPackaging;
181 | break;
182 | default:
183 | schemaType = default(StepSchemaTypes);
184 | return false;
185 | }
186 |
187 | return true;
188 | }
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepTokenizer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.IO;
5 | using System.Text;
6 | using IxMilia.Step.Tokens;
7 |
8 | namespace IxMilia.Step
9 | {
10 | internal class StepTokenizer
11 | {
12 | private StreamReader _reader;
13 | private string _currentLine;
14 | private int _offset;
15 | private int _currentLineNumber;
16 | private int _currentColumn;
17 |
18 | public int CurrentLine => _currentLineNumber;
19 | public int CurrentColumn => _currentColumn;
20 |
21 | public StepTokenizer(Stream stream)
22 | {
23 | _reader = new StreamReader(stream);
24 | ReadNextLine();
25 | }
26 |
27 | private void ReadNextLine()
28 | {
29 | _currentLine = _reader.ReadLine();
30 | _offset = 0;
31 | _currentLineNumber++;
32 | _currentColumn = 1;
33 | }
34 |
35 | private char? PeekCharacter()
36 | {
37 | while (true)
38 | {
39 | if (_currentLine == null)
40 | {
41 | return null;
42 | }
43 |
44 | while (_offset >= _currentLine.Length)
45 | {
46 | ReadNextLine();
47 | if (_currentLine == null)
48 | {
49 | return null;
50 | }
51 | }
52 |
53 | switch (_currentLine[_offset])
54 | {
55 | case '/':
56 | if (_offset <= _currentLine.Length - 1 && _currentLine[_offset + 1] == '*')
57 | {
58 | // entered multiline comment
59 | Advance(); // swallow '/'
60 | Advance(); // swallow '*'
61 |
62 | var endIndex = _currentLine.IndexOf("*/", _offset);
63 | while (endIndex < 0 && _currentLine != null)
64 | {
65 | // end wasn't on this line
66 | ReadNextLine();
67 | if (_currentLine == null)
68 | {
69 | break;
70 | }
71 |
72 | endIndex = _currentLine.IndexOf("*/", _offset);
73 | }
74 |
75 | if (_currentLine == null)
76 | {
77 | // read past the end of the file
78 | return null;
79 | }
80 | else
81 | {
82 | // end was on this line
83 | _offset = endIndex + 2;
84 | }
85 | }
86 | else
87 | {
88 | goto default;
89 | }
90 | break;
91 | default:
92 | return _currentLine[_offset];
93 | }
94 | }
95 | }
96 |
97 | private void Advance()
98 | {
99 | _offset++;
100 | _currentColumn++;
101 | if (_offset > _currentLine.Length)
102 | {
103 | ReadNextLine();
104 | }
105 | }
106 |
107 | public IEnumerable GetTokens()
108 | {
109 | char? cn;
110 | SwallowWhitespace();
111 | while ((cn = PeekCharacter()) != null)
112 | {
113 | var tokenLine = _currentLineNumber;
114 | var tokenColumn = _currentColumn;
115 | var c = cn.GetValueOrDefault();
116 | if (c == '$')
117 | {
118 | Advance();
119 | yield return new StepOmittedToken(tokenLine, tokenColumn);
120 | }
121 | else if (c == ';')
122 | {
123 | Advance();
124 | yield return new StepSemicolonToken(tokenLine, tokenColumn);
125 | }
126 | else if (c == '=')
127 | {
128 | Advance();
129 | yield return new StepEqualsToken(tokenLine, tokenColumn);
130 | }
131 | else if (c == '*')
132 | {
133 | Advance();
134 | yield return new StepAsteriskToken(tokenLine, tokenColumn);
135 | }
136 | else if (IsNumberStart(c))
137 | {
138 | yield return ParseNumber();
139 | }
140 | else if (IsApostrophe(c))
141 | {
142 | yield return ParseString();
143 | }
144 | else if (IsHash(c))
145 | {
146 | // constant instance: #INCH
147 | // entity instance: #1234
148 | yield return ParseHashValue();
149 | }
150 | else if (IsAt(c))
151 | {
152 | // constant value: @PI
153 | // instance value: @12
154 | yield return ParseAtValue();
155 | }
156 | else if (IsDot(c))
157 | {
158 | yield return ParseEnumeration();
159 | }
160 | else if (IsLeftParen(c))
161 | {
162 | Advance();
163 | yield return new StepLeftParenToken(tokenLine, tokenColumn);
164 | }
165 | else if (IsRightParen(c))
166 | {
167 | Advance();
168 | yield return new StepRightParenToken(tokenLine, tokenColumn);
169 | }
170 | else if (IsComma(c))
171 | {
172 | Advance();
173 | yield return new StepCommaToken(tokenLine, tokenColumn);
174 | }
175 | else if (IsUpper(c))
176 | {
177 | yield return ParseKeyword();
178 | }
179 | else
180 | {
181 | throw new StepReadException($"Unexpected character '{c}'", _currentLineNumber, _currentColumn);
182 | }
183 |
184 | SwallowWhitespace();
185 | }
186 |
187 | yield break;
188 | }
189 |
190 | private void SwallowWhitespace()
191 | {
192 | char? cn;
193 | bool keepSwallowing = true;
194 | while (keepSwallowing && (cn = PeekCharacter()) != null)
195 | {
196 | switch (cn.GetValueOrDefault())
197 | {
198 | case ' ':
199 | case '\r':
200 | case '\n':
201 | case '\t':
202 | case '\f':
203 | case '\v':
204 | Advance();
205 | break;
206 | default:
207 | keepSwallowing = false;
208 | break;
209 | }
210 | }
211 | }
212 |
213 | private bool IsDigit(char c)
214 | {
215 | return c >= '0' && c <= '9';
216 | }
217 |
218 | private bool IsDot(char c)
219 | {
220 | return c == '.';
221 | }
222 |
223 | private bool IsE(char c)
224 | {
225 | return c == 'e' || c == 'E';
226 | }
227 |
228 | private bool IsPlus(char c)
229 | {
230 | return c == '+';
231 | }
232 |
233 | private bool IsMinus(char c)
234 | {
235 | return c == '-';
236 | }
237 |
238 | private bool IsUnderscore(char c)
239 | {
240 | return c == '_';
241 | }
242 |
243 | private bool IsNumberStart(char c)
244 | {
245 | return IsDigit(c)
246 | || c == '-'
247 | || c == '+';
248 | }
249 |
250 | private bool IsApostrophe(char c)
251 | {
252 | return c == '\'';
253 | }
254 |
255 | private bool IsBackslash(char c)
256 | {
257 | return c == '\\';
258 | }
259 |
260 | private bool IsHash(char c)
261 | {
262 | return c == '#';
263 | }
264 |
265 | private bool IsAt(char c)
266 | {
267 | return c == '@';
268 | }
269 |
270 | private bool IsUpper(char c)
271 | {
272 | return c >= 'A' && c <= 'Z';
273 | }
274 |
275 | private bool IsUpperOrDigit(char c)
276 | {
277 | return IsUpper(c) || IsDigit(c);
278 | }
279 |
280 | private bool IsEnumCharacter(char c)
281 | {
282 | return IsUpperOrDigit(c) || IsUnderscore(c);
283 | }
284 |
285 | private bool IsLeftParen(char c)
286 | {
287 | return c == '(';
288 | }
289 |
290 | private bool IsRightParen(char c)
291 | {
292 | return c == ')';
293 | }
294 |
295 | private bool IsComma(char c)
296 | {
297 | return c == ',';
298 | }
299 |
300 | private bool IsKeywordCharacter(char c)
301 | {
302 | return IsUpperOrDigit(c)
303 | || IsUnderscore(c)
304 | || IsMinus(c);
305 | }
306 |
307 | private StepToken ParseNumber()
308 | {
309 | var tokenLine = _currentLineNumber;
310 | var tokenColumn = _currentColumn;
311 | var sb = new StringBuilder();
312 | sb.Append(PeekCharacter());
313 | Advance();
314 |
315 | bool seenDecimal = false;
316 | bool seenE = false;
317 | char? cn;
318 | while ((cn = PeekCharacter()) != null)
319 | {
320 | var c = cn.GetValueOrDefault();
321 | if (IsDigit(c))
322 | {
323 | sb.Append(c);
324 | Advance();
325 | }
326 | else if (IsDot(c) && !seenDecimal && !seenE)
327 | {
328 | sb.Append(c);
329 | seenDecimal = true;
330 | Advance();
331 | }
332 | else if (IsE(c) && !seenE)
333 | {
334 | sb.Append(c);
335 | seenE = true;
336 | Advance();
337 | }
338 | else if ((IsPlus(c) || IsMinus(c)) && seenE)
339 | {
340 | // TODO: this will fail on "1.0E+-+-+-+-1"
341 | sb.Append(c);
342 | Advance();
343 | }
344 | else
345 | {
346 | break;
347 | }
348 | }
349 |
350 | var str = sb.ToString();
351 | return seenDecimal || seenE
352 | ? (StepToken)new StepRealToken(double.Parse(str, CultureInfo.InvariantCulture), tokenLine, tokenColumn)
353 | : new StepIntegerToken(int.Parse(str, CultureInfo.InvariantCulture), tokenLine, tokenColumn);
354 | }
355 |
356 | private StepStringToken ParseString()
357 | {
358 | var tokenLine = _currentLineNumber;
359 | var tokenColumn = _currentColumn;
360 | var sb = new StringBuilder();
361 | Advance();
362 |
363 | char? cn;
364 | bool wasApostropheLast = false;
365 | bool wasBackslashLast = false;
366 | while ((cn = PeekCharacter()) != null)
367 | {
368 | var c = cn.GetValueOrDefault();
369 | if (IsApostrophe(c) && wasApostropheLast)
370 | {
371 | // escaped
372 | sb.Append(c);
373 | Advance();
374 | }
375 | else if (IsApostrophe(c) && !wasApostropheLast)
376 | {
377 | // maybe the end
378 | wasApostropheLast = true;
379 | Advance();
380 | }
381 | else if (!IsApostrophe(c) && wasApostropheLast)
382 | {
383 | // end of string
384 | break;
385 | }
386 | else if (IsBackslash(c) && !wasBackslashLast)
387 | {
388 | // start escaping
389 | wasBackslashLast = true;
390 | Advance();
391 | }
392 | else if (wasBackslashLast)
393 | {
394 | // TODO: handle real escaping
395 | sb.Append(c);
396 | Advance();
397 | }
398 | else
399 | {
400 | // just a normal string
401 | sb.Append(c);
402 | Advance();
403 | }
404 | }
405 |
406 | var str = sb.ToString();
407 | return new StepStringToken(str, tokenLine, tokenColumn);
408 | }
409 |
410 | private StepToken ParseHashValue()
411 | {
412 | var tokenLine = _currentLineNumber;
413 | var tokenColumn = _currentColumn;
414 | Advance(); // swallow '#'
415 | var next = PeekCharacter();
416 | if (next == null)
417 | {
418 | throw new StepReadException("Expected constant instance or entity instance", tokenLine, tokenColumn);
419 | }
420 |
421 | if (IsDigit(next.GetValueOrDefault()))
422 | {
423 | // entity instance: #1234
424 | return new StepEntityInstanceToken(int.Parse(TakeWhile(IsDigit), CultureInfo.InvariantCulture), tokenLine, tokenColumn);
425 | }
426 | else if (IsUpper(next.GetValueOrDefault()))
427 | {
428 | // constant instance: #INCH
429 | return new StepConstantInstanceToken(TakeWhile(IsUpperOrDigit), tokenLine, tokenColumn);
430 | }
431 | else
432 | {
433 | throw new StepReadException("Expected constant instance or entity instance", tokenLine, tokenColumn);
434 | }
435 | }
436 |
437 | private StepToken ParseAtValue()
438 | {
439 | var tokenLine = _currentLineNumber;
440 | var tokenColumn = _currentColumn;
441 | Advance(); // swallow '@'
442 | var next = PeekCharacter();
443 | if (next == null)
444 | {
445 | throw new StepReadException("Expected constant value or instance value", tokenLine, tokenColumn);
446 | }
447 |
448 | if (IsDigit(next.GetValueOrDefault()))
449 | {
450 | // constant value: @PI
451 | return new StepConstantValueToken(TakeWhile(IsDigit), tokenLine, tokenColumn);
452 | }
453 | else if (IsUpper(next.GetValueOrDefault()))
454 | {
455 | // instance value: @12
456 | return new StepInstanceValueToken(int.Parse(TakeWhile(IsUpperOrDigit), CultureInfo.InvariantCulture), tokenLine, tokenColumn);
457 | }
458 | else
459 | {
460 | throw new StepReadException("Expected constant value or instance value", tokenLine, tokenColumn);
461 | }
462 | }
463 |
464 | private StepEnumerationToken ParseEnumeration()
465 | {
466 | var tokenLine = _currentLineNumber;
467 | var tokenColumn = _currentColumn;
468 | var sb = new StringBuilder();
469 | Advance(); // swallow leading '.'
470 | var value = TakeWhile(IsEnumCharacter);
471 | if (string.IsNullOrEmpty(value))
472 | {
473 | throw new StepReadException("Expected enumeration value", tokenLine, tokenColumn);
474 | }
475 |
476 | var next = PeekCharacter();
477 | if (next.HasValue && IsDot(next.GetValueOrDefault()))
478 | {
479 | Advance();
480 | return new StepEnumerationToken(value, tokenLine, tokenColumn);
481 | }
482 | else
483 | {
484 | throw new StepReadException("Expected enumeration ending dot", _currentLineNumber, _currentColumn);
485 | }
486 | }
487 |
488 | private StepKeywordToken ParseKeyword()
489 | {
490 | var tokenLine = _currentLineNumber;
491 | var tokenColumn = _currentColumn;
492 | var value = TakeWhile(IsKeywordCharacter);
493 | return new StepKeywordToken(value, tokenLine, tokenColumn);
494 | }
495 |
496 | private string TakeWhile(Func predicate)
497 | {
498 | var sb = new StringBuilder();
499 | char? c;
500 | while ((c = PeekCharacter()) != null && predicate(c.GetValueOrDefault()))
501 | {
502 | sb.Append(c);
503 | Advance();
504 | }
505 |
506 | return sb.ToString();
507 | }
508 | }
509 | }
510 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/StepWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using IxMilia.Step.Items;
5 | using IxMilia.Step.Syntax;
6 | using IxMilia.Step.Tokens;
7 |
8 | namespace IxMilia.Step
9 | {
10 | internal class StepWriter
11 | {
12 | private StepFile _file;
13 | private int _currentLineLength;
14 | private bool _honorLineLength = true;
15 | private bool _inlineReferences;
16 | private Dictionary _itemMap;
17 | private int _nextId;
18 |
19 | private const int MaxLineLength = 80;
20 |
21 | public StepWriter(StepFile stepFile, bool inlineReferences)
22 | {
23 | _file = stepFile;
24 | _itemMap = new Dictionary();
25 | _inlineReferences = inlineReferences;
26 | }
27 |
28 | public string GetContents()
29 | {
30 | var builder = new StringBuilder();
31 |
32 | _honorLineLength = false;
33 | WriteDelimitedLine(StepFile.MagicHeader, builder);
34 |
35 | // output header
36 | WriteDelimitedLine(StepFile.HeaderText, builder);
37 | var headerSyntax = _file.GetHeaderSyntax();
38 | foreach (var macro in headerSyntax.Macros)
39 | {
40 | WriteHeaderMacro(macro, builder);
41 | }
42 |
43 | WriteDelimitedLine(StepFile.EndSectionText, builder);
44 |
45 | _honorLineLength = true;
46 |
47 | // data section
48 | WriteDelimitedLine(StepFile.DataText, builder);
49 | foreach (var item in _file.Items)
50 | {
51 | WriteItem(item, builder);
52 | }
53 |
54 | WriteDelimitedLine(StepFile.EndSectionText, builder);
55 | WriteDelimitedLine(StepFile.MagicFooter, builder);
56 |
57 | return builder.ToString();
58 | }
59 |
60 | private void WriteHeaderMacro(StepHeaderMacroSyntax macro, StringBuilder builder)
61 | {
62 | WriteText(macro.Name, builder);
63 | WriteTokens(macro.Values.GetTokens(), builder);
64 | WriteToken(StepSemicolonToken.Instance, builder);
65 | WriteNewLine(builder);
66 | }
67 |
68 | private int WriteItem(StepRepresentationItem item, StringBuilder builder)
69 | {
70 | if (!_inlineReferences)
71 | {
72 | // not inlining references, need to write out entities as we see them
73 | foreach (var referencedItem in item.GetReferencedItems())
74 | {
75 | if (!_itemMap.ContainsKey(referencedItem))
76 | {
77 | var refid = WriteItem(referencedItem, builder);
78 | }
79 | }
80 | }
81 |
82 | var id = ++_nextId;
83 | var syntax = GetItemSyntax(item, id);
84 | WriteToken(new StepEntityInstanceToken(id, -1, -1), builder);
85 | WriteToken(StepEqualsToken.Instance, builder);
86 | WriteTokens(syntax.GetTokens(), builder);
87 | WriteToken(StepSemicolonToken.Instance, builder);
88 | WriteNewLine(builder);
89 | return id;
90 | }
91 |
92 | ///
93 | /// Internal for testing.
94 | ///
95 | internal void WriteTokens(IEnumerable tokens, StringBuilder builder)
96 | {
97 | foreach (var token in tokens)
98 | {
99 | WriteToken(token, builder);
100 | }
101 | }
102 |
103 | private void WriteToken(StepToken token, StringBuilder builder)
104 | {
105 | WriteText(token.ToString(this), builder);
106 | }
107 |
108 | private void WriteDelimitedLine(string text, StringBuilder builder)
109 | {
110 | WriteText(text, builder);
111 | WriteToken(StepSemicolonToken.Instance, builder);
112 | WriteNewLine(builder);
113 | }
114 |
115 | private void WriteText(string text, StringBuilder builder)
116 | {
117 | if (_honorLineLength && _currentLineLength + text.Length > MaxLineLength)
118 | {
119 | WriteNewLine(builder);
120 | }
121 |
122 | builder.Append(text);
123 | _currentLineLength += text.Length;
124 | }
125 |
126 | private void WriteNewLine(StringBuilder builder)
127 | {
128 | builder.Append("\r\n");
129 | _currentLineLength = 0;
130 | }
131 |
132 | private StepSyntax GetItemSyntax(StepRepresentationItem item, int expectedId)
133 | {
134 | if (!_itemMap.ContainsKey(item))
135 | {
136 | var parameters = new StepSyntaxList(-1, -1, item.GetParameters(this));
137 | var syntax = new StepSimpleItemSyntax(item.ItemType.GetItemTypeString(), parameters);
138 | _itemMap.Add(item, expectedId);
139 | return syntax;
140 | }
141 | else
142 | {
143 | return GetItemSyntax(item);
144 | }
145 | }
146 |
147 | public StepSyntax GetItemSyntax(StepRepresentationItem item)
148 | {
149 | if (_inlineReferences)
150 | {
151 | var parameters = new StepSyntaxList(-1, -1, item.GetParameters(this));
152 | return new StepSimpleItemSyntax(item.ItemType.GetItemTypeString(), parameters);
153 | }
154 | else
155 | {
156 | return new StepEntityInstanceReferenceSyntax(_itemMap[item]);
157 | }
158 | }
159 |
160 | public StepSyntax GetItemSyntaxOrAuto(StepRepresentationItem item)
161 | {
162 | return item == null
163 | ? new StepAutoSyntax()
164 | : GetItemSyntax(item);
165 | }
166 |
167 | public static StepEnumerationValueSyntax GetBooleanSyntax(bool value)
168 | {
169 | var text = value ? "T" : "F";
170 | return new StepEnumerationValueSyntax(text);
171 | }
172 |
173 | internal static IEnumerable SplitStringIntoParts(string str, int maxLength = 256)
174 | {
175 | var parts = new List();
176 | if (str != null)
177 | {
178 | int offset = 0;
179 | while (offset < str.Length)
180 | {
181 | var length = Math.Min(maxLength, str.Length - offset);
182 | parts.Add(str.Substring(offset, length));
183 | offset += length;
184 | }
185 | }
186 | else
187 | {
188 | parts.Add(string.Empty);
189 | }
190 |
191 | return parts;
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepAutoSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepAutoSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.Auto;
9 |
10 | public StepAsteriskToken Token { get; private set; }
11 |
12 | public StepAutoSyntax()
13 | : this(StepAsteriskToken.Instance)
14 | {
15 | }
16 |
17 | public StepAutoSyntax(StepAsteriskToken token)
18 | : base(token.Line, token.Column)
19 | {
20 | Token = token;
21 | }
22 |
23 | public override IEnumerable GetTokens()
24 | {
25 | yield return Token;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepComplexItemSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using IxMilia.Step.Tokens;
4 |
5 | namespace IxMilia.Step.Syntax
6 | {
7 | internal class StepComplexItemSyntax : StepItemSyntax
8 | {
9 | public override StepSyntaxType SyntaxType => StepSyntaxType.ComplexItem;
10 |
11 | public List Items { get; } = new List();
12 |
13 | public StepComplexItemSyntax(int line, int column, IEnumerable items)
14 | : base(line, column)
15 | {
16 | Items = items.ToList();
17 | }
18 |
19 | public override IEnumerable GetTokens()
20 | {
21 | return Items.SelectMany(i => i.GetTokens());
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepDataSectionSyntax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using IxMilia.Step.Tokens;
5 |
6 | namespace IxMilia.Step.Syntax
7 | {
8 | internal class StepDataSectionSyntax : StepSyntax
9 | {
10 | public override StepSyntaxType SyntaxType => StepSyntaxType.DataSection;
11 |
12 | public List ItemInstances { get; }
13 |
14 | public StepDataSectionSyntax(int line, int column, IEnumerable itemInstances)
15 | : base(line, column)
16 | {
17 | ItemInstances = itemInstances.ToList();
18 | }
19 |
20 | public override IEnumerable GetTokens()
21 | {
22 | throw new NotSupportedException();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepEntityInstanceReferenceSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepEntityInstanceReferenceSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.EntityInstanceReference;
9 |
10 | public int Id { get; }
11 |
12 | public StepEntityInstanceReferenceSyntax(int id)
13 | : base(-1, -1)
14 | {
15 | Id = id;
16 | }
17 |
18 | public StepEntityInstanceReferenceSyntax(StepEntityInstanceToken itemInstance)
19 | : base(itemInstance.Line, itemInstance.Column)
20 | {
21 | Id = itemInstance.Id;
22 | }
23 |
24 | public override IEnumerable GetTokens()
25 | {
26 | yield return new StepEntityInstanceToken(Id, -1, -1);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepEntityInstanceSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepEntityInstanceSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.EntityInstance;
9 |
10 | public int Id { get; }
11 | public StepItemSyntax SimpleItemInstance { get; }
12 |
13 | public StepEntityInstanceSyntax(StepEntityInstanceToken instanceId, StepItemSyntax itemInstance)
14 | : base(instanceId.Line, instanceId.Column)
15 | {
16 | Id = instanceId.Id;
17 | SimpleItemInstance = itemInstance;
18 | }
19 |
20 | public override IEnumerable GetTokens()
21 | {
22 | yield return new StepEntityInstanceToken(Id, -1, -1);
23 | foreach (var token in SimpleItemInstance.GetTokens())
24 | {
25 | yield return token;
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepEnumerationValueSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepEnumerationValueSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.Enumeration;
9 |
10 | public string Value { get; }
11 |
12 | public StepEnumerationValueSyntax(string value)
13 | : base(-1, -1)
14 | {
15 | Value = value;
16 | }
17 |
18 | public StepEnumerationValueSyntax(StepEnumerationToken value)
19 | : base(value.Line, value.Column)
20 | {
21 | Value = value.Value;
22 | }
23 |
24 | public override IEnumerable GetTokens()
25 | {
26 | yield return new StepEnumerationToken(Value, -1, -1);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepFileSyntax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Tokens;
4 |
5 | namespace IxMilia.Step.Syntax
6 | {
7 | internal class StepFileSyntax : StepSyntax
8 | {
9 | public override StepSyntaxType SyntaxType => StepSyntaxType.File;
10 |
11 | public StepHeaderSectionSyntax Header { get; }
12 | public StepDataSectionSyntax Data { get; }
13 |
14 | public StepFileSyntax(StepHeaderSectionSyntax header, StepDataSectionSyntax data)
15 | : base(header.Line, header.Column)
16 | {
17 | Header = header;
18 | Data = data;
19 | }
20 |
21 | public override IEnumerable GetTokens()
22 | {
23 | throw new NotSupportedException();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepHeaderMacroSyntax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using IxMilia.Step.Tokens;
4 |
5 | namespace IxMilia.Step.Syntax
6 | {
7 | internal class StepHeaderMacroSyntax : StepSyntax
8 | {
9 | public override StepSyntaxType SyntaxType => StepSyntaxType.HeaderMacro;
10 |
11 | public string Name { get; }
12 | public StepSyntaxList Values { get; }
13 |
14 | public StepHeaderMacroSyntax(string name, StepSyntaxList values)
15 | : base(values.Line, values.Column)
16 | {
17 | Name = name;
18 | Values = values;
19 | }
20 |
21 | public override IEnumerable GetTokens()
22 | {
23 | throw new NotSupportedException();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepHeaderSectionSyntax.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using IxMilia.Step.Tokens;
5 |
6 | namespace IxMilia.Step.Syntax
7 | {
8 | internal class StepHeaderSectionSyntax : StepSyntax
9 | {
10 | public override StepSyntaxType SyntaxType => StepSyntaxType.HeaderSection;
11 |
12 | public List Macros { get; }
13 |
14 | public StepHeaderSectionSyntax(int line, int column, IEnumerable macros)
15 | : base(line, column)
16 | {
17 | Macros = macros.ToList();
18 | }
19 |
20 | public override IEnumerable GetTokens()
21 | {
22 | throw new NotSupportedException();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepIntegerSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepIntegerSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.Integer;
9 |
10 | public int Value { get; }
11 |
12 | public StepIntegerSyntax( int value )
13 | : base(-1, -1)
14 | {
15 | Value = value;
16 | }
17 |
18 | public StepIntegerSyntax(StepIntegerToken value)
19 | : base(value.Line, value.Column)
20 | {
21 | Value = value.Value;
22 | }
23 |
24 | public override IEnumerable GetTokens()
25 | {
26 | yield return new StepIntegerToken(Value, -1, -1);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepItemSyntax.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Syntax
2 | {
3 | internal abstract class StepItemSyntax : StepSyntax
4 | {
5 | protected StepItemSyntax(int line, int column)
6 | : base(line, column)
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepOmittedSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepOmittedSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.Omitted;
9 |
10 | public StepOmittedSyntax(StepOmittedToken value)
11 | : base(value.Line, value.Column)
12 | {
13 | }
14 |
15 | public override IEnumerable GetTokens()
16 | {
17 | yield return StepOmittedToken.Instance;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepRealSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepRealSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.Real;
9 |
10 | public double Value { get; }
11 |
12 | public StepRealSyntax(double value)
13 | : base(-1, -1)
14 | {
15 | Value = value;
16 | }
17 |
18 | public StepRealSyntax(StepRealToken value)
19 | : base(value.Line, value.Column)
20 | {
21 | Value = value.Value;
22 | }
23 |
24 | public override IEnumerable GetTokens()
25 | {
26 | yield return new StepRealToken(Value, -1, -1);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepSimpleItemSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepSimpleItemSyntax : StepItemSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.SimpleItem;
9 |
10 | public string Keyword { get; }
11 | public StepSyntaxList Parameters { get; }
12 |
13 | public StepSimpleItemSyntax(string keyword, StepSyntaxList parameters)
14 | : base(-1, -1)
15 | {
16 | Keyword = keyword;
17 | Parameters = parameters;
18 | }
19 |
20 | public StepSimpleItemSyntax(StepKeywordToken keyword, StepSyntaxList parameters)
21 | : base(keyword.Line, keyword.Column)
22 | {
23 | Keyword = keyword.Value;
24 | Parameters = parameters;
25 | }
26 |
27 | public override IEnumerable GetTokens()
28 | {
29 | yield return new StepKeywordToken(Keyword, -1, -1);
30 | foreach (var token in Parameters.GetTokens())
31 | {
32 | yield return token;
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepStringSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal class StepStringSyntax : StepSyntax
7 | {
8 | public override StepSyntaxType SyntaxType => StepSyntaxType.String;
9 |
10 | public string Value { get; }
11 |
12 | public StepStringSyntax(string value)
13 | : base(-1, -1)
14 | {
15 | Value = value;
16 | }
17 |
18 | public StepStringSyntax(StepStringToken value)
19 | : base(value.Line, value.Column)
20 | {
21 | Value = value.Value;
22 | }
23 |
24 | public override IEnumerable GetTokens()
25 | {
26 | yield return new StepStringToken(Value, -1, -1);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepSyntax.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using IxMilia.Step.Tokens;
3 |
4 | namespace IxMilia.Step.Syntax
5 | {
6 | internal abstract class StepSyntax
7 | {
8 | public abstract StepSyntaxType SyntaxType { get; }
9 |
10 | public int Line { get; }
11 | public int Column { get; }
12 |
13 | protected StepSyntax(int line, int column)
14 | {
15 | Line = line;
16 | Column = column;
17 | }
18 |
19 | public abstract IEnumerable GetTokens();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepSyntaxExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Linq;
4 |
5 | namespace IxMilia.Step.Syntax
6 | {
7 | internal static class StepSyntaxExtensions
8 | {
9 | public static readonly string[] DateTimeFormats = new string[]
10 | {
11 | "yyyy-MM-ddT",
12 | "yyyy-M-dTh:mm:ss ttzzz",
13 | };
14 |
15 | public static void AssertListCount(this StepSyntaxList syntaxList, int count)
16 | {
17 | if (syntaxList.Values.Count != count)
18 | {
19 | ReportError($"Expected list to contain {count} items but it contained {syntaxList.Values.Count}", syntaxList);
20 | }
21 | }
22 |
23 | public static void AssertListCount(this StepSyntaxList syntaxList, int minCount, int maxCount)
24 | {
25 | if (syntaxList.Values.Count < minCount || syntaxList.Values.Count > maxCount)
26 | {
27 | ReportError($"Expected list to contain between {minCount} and {maxCount} items but it contained {syntaxList.Values.Count}", syntaxList);
28 | }
29 | }
30 |
31 | public static string GetStringValue(this StepSyntax syntax)
32 | {
33 | switch (syntax.SyntaxType)
34 | {
35 | case StepSyntaxType.Omitted:
36 | return string.Empty;
37 | case StepSyntaxType.String:
38 | return ((StepStringSyntax)syntax).Value;
39 | default:
40 | ReportError("Expected string value", syntax);
41 | return null; // this will never get here because `ReportError` throws
42 | }
43 | }
44 |
45 | public static DateTime GetDateTimeValue(this StepSyntax syntax)
46 | {
47 | var str = syntax.GetStringValue();
48 | DateTime result;
49 | if (DateTime.TryParseExact(str, DateTimeFormats, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out result))
50 | {
51 | return result;
52 | }
53 | else
54 | {
55 | return DateTime.Parse(str, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);
56 | }
57 | }
58 |
59 | public static double GetRealVavlue(this StepSyntax syntax)
60 | {
61 | if (syntax.SyntaxType != StepSyntaxType.Real)
62 | {
63 | ReportError("Expected real value", syntax);
64 | }
65 |
66 | return ((StepRealSyntax)syntax).Value;
67 | }
68 |
69 | public static int GetIntegerValue(this StepSyntax syntax)
70 | {
71 | if (syntax.SyntaxType != StepSyntaxType.Integer)
72 | {
73 | ReportError("Expected integer value", syntax);
74 | }
75 |
76 | return ((StepIntegerSyntax)syntax).Value;
77 | }
78 |
79 | public static string GetEnumerationValue(this StepSyntax syntax)
80 | {
81 | if (syntax.SyntaxType != StepSyntaxType.Enumeration)
82 | {
83 | ReportError("Expected enumeration value", syntax);
84 | }
85 |
86 | return ((StepEnumerationValueSyntax)syntax).Value;
87 | }
88 |
89 | public static bool GetBooleanValue(this StepSyntax syntax)
90 | {
91 | switch (syntax.GetEnumerationValue().ToUpperInvariant())
92 | {
93 | case "T":
94 | case "TRUE":
95 | return true;
96 | case "F":
97 | case "FALSE":
98 | return false;
99 | default:
100 | ReportError("Expected boolean value", syntax);
101 | return false; // unreachable
102 | }
103 | }
104 |
105 | public static double GetRealValueOrDefault(this StepSyntaxList syntaxList, int index)
106 | {
107 | return syntaxList.GetRealValueOrDefault(index, 0.0);
108 | }
109 |
110 | public static double GetRealValueOrDefault(this StepSyntaxList syntaxList, int index, double defaultValue)
111 | {
112 | if (index < 0)
113 | {
114 | throw new ArgumentOutOfRangeException(nameof(index));
115 | }
116 |
117 | if (index < syntaxList.Values.Count)
118 | {
119 | return syntaxList.Values[index].GetRealVavlue();
120 | }
121 | else
122 | {
123 | return defaultValue;
124 | }
125 | }
126 |
127 | public static StepSyntaxList GetValueList(this StepSyntax syntax)
128 | {
129 | if (syntax.SyntaxType != StepSyntaxType.List)
130 | {
131 | ReportError("Expected list value", syntax);
132 | }
133 |
134 | return (StepSyntaxList)syntax;
135 | }
136 |
137 | public static string GetConcatenatedStringValue(this StepSyntax syntax)
138 | {
139 | return string.Join(string.Empty, syntax.GetValueList().Values.Select(v => v.GetStringValue()));
140 | }
141 |
142 | private static void ReportError(string message, StepSyntax location)
143 | {
144 | ReportError(message, location.Line, location.Column);
145 | }
146 |
147 | private static void ReportError(string message, int line, int column)
148 | {
149 | throw new StepReadException(message, line, column);
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepSyntaxList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using IxMilia.Step.Tokens;
4 |
5 | namespace IxMilia.Step.Syntax
6 | {
7 | internal class StepSyntaxList : StepSyntax
8 | {
9 | public override StepSyntaxType SyntaxType => StepSyntaxType.List;
10 |
11 | public List Values { get; }
12 |
13 | public StepSyntaxList(params StepSyntax[] values)
14 | : this(-1, -1, values)
15 | {
16 | }
17 |
18 | public StepSyntaxList(IEnumerable values)
19 | : this(-1, -1, values)
20 | {
21 | }
22 |
23 | public StepSyntaxList(int line, int column, IEnumerable values)
24 | : base(line, column)
25 | {
26 | Values = values.ToList();
27 | }
28 |
29 | public override IEnumerable GetTokens()
30 | {
31 | yield return StepLeftParenToken.Instance;
32 | for (int i = 0; i < Values.Count; i++)
33 | {
34 | foreach (var token in Values[i].GetTokens())
35 | {
36 | yield return token;
37 | }
38 |
39 | if (i < Values.Count - 1)
40 | {
41 | yield return StepCommaToken.Instance;
42 | }
43 | }
44 |
45 | yield return StepRightParenToken.Instance;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Syntax/StepSyntaxType.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Syntax
2 | {
3 | internal enum StepSyntaxType
4 | {
5 | File,
6 | HeaderSection,
7 | DataSection,
8 | HeaderMacro,
9 | SimpleItem,
10 | ComplexItem,
11 | EntityInstance,
12 | EntityInstanceReference,
13 | Integer,
14 | Real,
15 | List,
16 | String,
17 | Auto,
18 | Enumeration,
19 | Omitted
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepAsteriskToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepAsteriskToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Asterisk;
6 |
7 | public StepAsteriskToken(int line, int column)
8 | : base(line, column)
9 | {
10 | }
11 |
12 | public override string ToString()
13 | {
14 | return "*";
15 | }
16 |
17 | public static StepAsteriskToken Instance { get; } = new StepAsteriskToken(-1, -1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepCommaToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepCommaToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Comma;
6 |
7 | public StepCommaToken(int line, int column)
8 | : base(line, column)
9 | {
10 | }
11 |
12 | public override string ToString()
13 | {
14 | return ",";
15 | }
16 |
17 | public static StepCommaToken Instance { get; } = new StepCommaToken(-1, -1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepConstantInstanceToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepConstantInstanceToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.ConstantInstance;
6 |
7 | public string Name { get; }
8 |
9 | public StepConstantInstanceToken(string name, int line, int column)
10 | : base(line, column)
11 | {
12 | Name = name;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return "#" + Name;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepConstantValueToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepConstantValueToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.ConstantValue;
6 |
7 | public string Name { get; }
8 |
9 | public StepConstantValueToken(string name, int line, int column)
10 | : base(line, column)
11 | {
12 | Name = name;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return "@" + Name;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepEntityInstanceToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepEntityInstanceToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.EntityInstance;
6 |
7 | public int Id { get; }
8 |
9 | public StepEntityInstanceToken(int id, int line, int column)
10 | : base(line, column)
11 | {
12 | Id = id;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return "#" + Id.ToString();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepEnumerationToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepEnumerationToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Enumeration;
6 |
7 | public string Value { get; }
8 |
9 | public StepEnumerationToken(string value, int line, int column)
10 | : base(line, column)
11 | {
12 | Value = value;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return "." + Value + ".";
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepEqualsToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepEqualsToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Equals;
6 |
7 | public StepEqualsToken(int line, int column)
8 | : base(line, column)
9 | {
10 | }
11 |
12 | public override string ToString()
13 | {
14 | return "=";
15 | }
16 |
17 | public static StepEqualsToken Instance { get; } = new StepEqualsToken(-1, -1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepInstanceValueToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepInstanceValueToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.InstanceValue;
6 |
7 | public int Id { get; }
8 |
9 | public StepInstanceValueToken(int id, int line, int column)
10 | : base(line, column)
11 | {
12 | Id = id;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return "@" + Id.ToString();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepIntegerToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepIntegerToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Integer;
6 |
7 | public int Value { get; }
8 |
9 | public StepIntegerToken(int value, int line, int column)
10 | : base(line, column)
11 | {
12 | Value = value;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return Value.ToString();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepKeywordToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepKeywordToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Keyword;
6 |
7 | public string Value { get; }
8 |
9 | public StepKeywordToken(string value, int line, int column)
10 | : base(line, column)
11 | {
12 | Value = value;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return Value;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepLeftParenToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepLeftParenToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.LeftParen;
6 |
7 | public StepLeftParenToken(int line, int column)
8 | : base(line, column)
9 | {
10 | }
11 |
12 | public override string ToString()
13 | {
14 | return "(";
15 | }
16 |
17 | public static StepLeftParenToken Instance { get; } = new StepLeftParenToken(-1, -1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepOmittedToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepOmittedToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Omitted;
6 |
7 | public StepOmittedToken(int line, int column)
8 | : base(line, column)
9 | {
10 | }
11 |
12 | public override string ToString()
13 | {
14 | return "$";
15 | }
16 |
17 | public static StepOmittedToken Instance { get; } = new StepOmittedToken(-1, -1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepRealToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepRealToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Real;
6 |
7 | public double Value { get; }
8 |
9 | public StepRealToken(double value, int line, int column)
10 | : base(line, column)
11 | {
12 | Value = value;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | return Value.ToString("0.0#");
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepRightParenToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepRightParenToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.RightParen;
6 |
7 | public StepRightParenToken(int line, int column)
8 | : base(line, column)
9 | {
10 | }
11 |
12 | public override string ToString()
13 | {
14 | return ")";
15 | }
16 |
17 | public static StepRightParenToken Instance { get; } = new StepRightParenToken(-1, -1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepSemiColonToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepSemicolonToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.Semicolon;
6 |
7 | public StepSemicolonToken(int line, int column)
8 | : base(line, column)
9 | {
10 | }
11 |
12 | public override string ToString()
13 | {
14 | return ";";
15 | }
16 |
17 | public static StepSemicolonToken Instance { get; } = new StepSemicolonToken(-1, -1);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepStringToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal class StepStringToken : StepToken
4 | {
5 | public override StepTokenKind Kind => StepTokenKind.String;
6 |
7 | public string Value { get; }
8 |
9 | public StepStringToken(string value, int line, int column)
10 | : base(line, column)
11 | {
12 | Value = value;
13 | }
14 |
15 | public override string ToString()
16 | {
17 | // TODO: escaping
18 | return "'" + Value + "'";
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepToken.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal abstract class StepToken
4 | {
5 | public abstract StepTokenKind Kind { get; }
6 |
7 | public int Line { get; }
8 | public int Column { get; }
9 |
10 | protected StepToken(int line, int column)
11 | {
12 | Line = line;
13 | Column = column;
14 | }
15 |
16 | public virtual string ToString(StepWriter writer)
17 | {
18 | return ToString();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/IxMilia.Step/Tokens/StepTokenKind.cs:
--------------------------------------------------------------------------------
1 | namespace IxMilia.Step.Tokens
2 | {
3 | internal enum StepTokenKind
4 | {
5 | Semicolon,
6 | Omitted,
7 | Integer,
8 | Real,
9 | String,
10 | ConstantInstance,
11 | ConstantValue,
12 | EntityInstance,
13 | InstanceValue,
14 | Enumeration,
15 | LeftParen,
16 | RightParen,
17 | Comma,
18 | Equals,
19 | Asterisk,
20 | Keyword
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/create-package.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | set PROJECT_NAME=IxMilia.Step
4 | set CONFIGURATION=Release
5 | set PROJECT=%~dp0\%PROJECT_NAME%\%PROJECT_NAME%.csproj
6 |
7 | dotnet restore "%PROJECT%"
8 | if errorlevel 1 exit /b 1
9 |
10 | dotnet build "%PROJECT%" --configuration %CONFIGURATION%
11 | if errorlevel 1 exit /b 1
12 |
13 | dotnet pack --no-restore --no-build --configuration %CONFIGURATION% "%PROJECT%"
14 | if errorlevel 1 exit /b 1
15 |
--------------------------------------------------------------------------------
/src/create-package.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh -e
2 |
3 | _SCRIPT_DIR="$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )"
4 | PROJECT_NAME=IxMilia.Step
5 | CONFIGURATION=Release
6 | PROJECT=$_SCRIPT_DIR/$PROJECT_NAME/$PROJECT_NAME.csproj
7 |
8 | dotnet restore "$PROJECT"
9 | dotnet build "$PROJECT" --configuration $CONFIGURATION
10 | dotnet pack --no-restore --no-build --configuration $CONFIGURATION "$PROJECT"
11 |
--------------------------------------------------------------------------------
/version.txt:
--------------------------------------------------------------------------------
1 | 0.1.0
2 |
--------------------------------------------------------------------------------